libdap++  Updated for version 3.8.2
Connect.cc
Go to the documentation of this file.
1 
2 // -*- mode: c++; c-basic-offset:4 -*-
3 
4 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
5 // Access Protocol.
6 
7 // Copyright (c) 2002,2003 OPeNDAP, Inc.
8 // Author: James Gallagher <jgallagher@opendap.org>
9 // Dan Holloway <dholloway@gso.uri.edu>
10 // Reza Nekovei <reza@intcomm.net>
11 //
12 // This library is free software; you can redistribute it and/or
13 // modify it under the terms of the GNU Lesser General Public
14 // License as published by the Free Software Foundation; either
15 // version 2.1 of the License, or (at your option) any later version.
16 //
17 // This library is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 // Lesser General Public License for more details.
21 //
22 // You should have received a copy of the GNU Lesser General Public
23 // License along with this library; if not, write to the Free Software
24 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 //
26 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
27 
28 // (c) COPYRIGHT URI/MIT 1994-2002
29 // Please read the full copyright statement in the file COPYRIGHT_URI.
30 //
31 // Authors:
32 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
33 // dan Dan Holloway <dholloway@gso.uri.edu>
34 // reza Reza Nekovei <reza@intcomm.net>
35 
36 
37 #include "config.h"
38 
39 //#define DODS_DEBUG
40 #define FILE_METHODS 1
41 
42 static char rcsid[] not_used =
43  { "$Id: Connect.cc 24370 2011-03-28 16:21:32Z jimg $"
44  };
45 
46 #include <cstring>
47 #include <fstream>
48 #include <algorithm>
49 
50 #include "debug.h"
51 #include "DataDDS.h"
52 #include "Connect.h"
53 #include "escaping.h"
54 #include "RCReader.h"
55 #include "DDXParserSAX2.h"
56 #if FILE_METHODS
57 #include "XDRFileUnMarshaller.h"
58 #else
59 #include "fdiostream.h"
60 #include "XDRStreamUnMarshaller.h"
61 #endif
62 #include "mime_util.h"
63 
64 using std::cerr;
65 using std::endl;
66 using std::ifstream;
67 using std::ofstream;
68 using std::min;
69 
70 namespace libdap {
71 
74 void
75 Connect::process_data(DataDDS &data, Response *rs)
76 {
77  DBG(cerr << "Entering Connect::process_data" << endl);
78 
79  data.set_version(rs->get_version());
80  data.set_protocol(rs->get_protocol());
81 
82  DBG(cerr << "Entering process_data: d_stream = " << rs << endl);
83  switch (rs->get_type()) {
84  case dods_error: {
85  Error e;
86  if (!e.parse(rs->get_stream()))
87  throw InternalErr(__FILE__, __LINE__,
88  "Could not parse the Error object returned by the server!");
89  throw e;
90  }
91 
92  case web_error:
93  // Web errors (those reported in the return document's MIME header)
94  // are processed by the WWW library.
95  throw InternalErr(__FILE__, __LINE__, "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
96 
97  case dap4_data_ddx: {
98  // Parse the DDX; throw an exception on error.
99  DDXParser ddx_parser(data.get_factory());
100 
101  // Read the MPM boundary and then read the subsequent headers
102  string boundary = read_multipart_boundary(rs->get_stream());
103  DBG(cerr << "MPM Boundary: " << boundary << endl);
104  read_multipart_headers(rs->get_stream(), "text/xml", dap4_ddx);
105 
106  // Parse the DDX, reading up to and including the next boundary.
107  // Return the CID for the matching data part
108  string data_cid;
109  ddx_parser.intern_stream(rs->get_stream(), &data, data_cid, boundary);
110 
111  // Munge the CID into something we can work with
112  data_cid = cid_to_header_value(data_cid);
113  DBG(cerr << "Data CID: " << data_cid << endl);
114 
115  // Read the data part's MPM part headers (boundary was read by
116  // DDXParse::intern)
117  read_multipart_headers(rs->get_stream(),
118  "application/octet-stream", dap4_data, data_cid);
119 
120  // Now read the data
121 #if FILE_METHODS
122  XDRFileUnMarshaller um( rs->get_stream() ) ;
123 #else
124  fpistream in ( rs->get_stream() );
125  XDRStreamUnMarshaller um( in ) ;
126 #endif
127 #if 0
128  try {
129 #endif
130  for (DDS::Vars_iter i = data.var_begin(); i != data.var_end();
131  i++) {
132  (*i)->deserialize(um, &data);
133  }
134 #if 0
135  }
136  catch (Error &e) {
137  throw ;
138  }
139 #endif
140  return;
141  }
142 
143  case dods_data:
144  default: {
145  // Parse the DDS; throw an exception on error.
146  data.parse(rs->get_stream());
147 #if FILE_METHODS
148  XDRFileUnMarshaller um( rs->get_stream() ) ;
149 #else
150  fpistream in ( rs->get_stream() );
151  XDRStreamUnMarshaller um( in ) ;
152 #endif
153  // Load the DDS with data.
154 #if 0
155  try {
156 #endif
157  for (DDS::Vars_iter i = data.var_begin(); i != data.var_end();
158  i++) {
159  (*i)->deserialize(um, &data);
160  }
161 #if 0
162  }
163  catch (Error &e) {
164  throw ;
165  }
166 #endif
167  return;
168  }
169  }
170 }
171 
172 // Barely a parser... This is used when reading from local sources of DODS
173 // Data objects. It simulates the important actions of the libwww MIME header
174 // parser. Those actions fill in certain fields in the Connect object. jhrg
175 // 5/20/97
176 //
177 // Make sure that this parser reads from data_source without disturbing the
178 // information in data_source that follows the MIME header. Since the DDS
179 // (which follows the MIME header) is parsed by a flex/bison scanner/parser,
180 // make sure to use I/O calls that will mesh with ANSI C I/O calls. In the
181 // old GNU libg++, the C++ calls were synchronized with the C calls, but that
182 // may no longer be the case. 5/31/99 jhrg
183 
193 void
194 Connect::parse_mime(Response *rs)
195 {
196  rs->set_version("dods/0.0"); // initial value; for backward compatibility.
197  rs->set_protocol("2.0");
198 
199  FILE *data_source = rs->get_stream();
200  string mime = get_next_mime_header(data_source);
201  while (!mime.empty()) {
202  string header, value;
203  parse_mime_header(mime, header, value);
204 
205  // Note that this is an ordered list
206  if (header == "content-description:") {
207  DBG(cout << header << ": " << value << endl);
208  rs->set_type(get_description_type(value));
209  }
210  // Use the value of xdods-server only if no other value has been read
211  else if (header == "xdods-server:"
212  && rs->get_version() == "dods/0.0") {
213  DBG(cout << header << ": " << value << endl);
214  rs->set_version(value);
215  }
216  // This trumps 'xdods-server' and 'server'
217  else if (header == "xopendap-server:") {
218  DBG(cout << header << ": " << value << endl);
219  rs->set_version(value);
220  }
221  else if (header == "xdap:") {
222  DBG(cout << header << ": " << value << endl);
223  rs->set_protocol(value);
224  }
225  // Only look for 'server' if no other header supplies this info.
226  else if (rs->get_version() == "dods/0.0" && header == "server:") {
227  DBG(cout << header << ": " << value << endl);
228  rs->set_version(value);
229  }
230 
231  mime = get_next_mime_header(data_source);
232  }
233 }
234 
235 // public mfuncs
236 
244 Connect::Connect(const string &n, string uname, string password)
245 throw(Error, InternalErr)
246  : d_http(0), d_version("unknown"), d_protocol("2.0")
247 {
248  string name = prune_spaces(n);
249 
250  // Figure out if the URL starts with 'http', if so, make sure that we
251  // talk to an instance of HTTPConnect.
252  if (name.find("http") == 0) {
253  DBG(cerr << "Connect: The identifier is an http URL" << endl);
254  d_http = new HTTPConnect(RCReader::instance());
255 
256  // Find and store any CE given with the URL.
257  string::size_type dotpos = name.find('?');
258  if (dotpos != name.npos) {
259  _URL = name.substr(0, dotpos);
260  string expr = name.substr(dotpos + 1);
261 
262  dotpos = expr.find('&');
263  if (dotpos != expr.npos) {
264  _proj = expr.substr(0, dotpos);
265  _sel = expr.substr(dotpos); // XXX includes '&'
266  }
267  else {
268  _proj = expr;
269  _sel = "";
270  }
271  }
272  else {
273  _URL = name;
274  _proj = "";
275  _sel = "";
276  }
277 
278  _local = false;
279  }
280  else {
281  DBG(cerr << "Connect: The identifier is a local data source." << endl);
282 
283  d_http = 0;
284  _URL = "";
285  _local = true; // local in this case means non-DAP
286  }
287 
288  set_credentials(uname, password);
289 }
290 
292 {
293  DBG2(cerr << "Entering the Connect dtor" << endl);
294 
295  if (d_http)
296  delete d_http; d_http = 0;
297 
298  DBG2(cerr << "Leaving the Connect dtor" << endl);
299 }
300 
308 string
310 {
311  string version_url = _URL + ".ver";
312  if (_proj.length() + _sel.length())
313  version_url = version_url + "?" + id2www_ce(_proj + _sel);
314 
315  Response *rs = 0;
316  try {
317  rs = d_http->fetch_url(version_url);
318  }
319  catch (Error &e) {
320  delete rs; rs = 0;
321  throw ;
322  }
323 
324  d_version = rs->get_version();
325  d_protocol = rs->get_protocol();
326 
327  delete rs; rs = 0;
328 
329  return d_version;
330 }
331 
343 string
345 {
346  string version_url = _URL + ".ver";
347  if (_proj.length() + _sel.length())
348  version_url = version_url + "?" + id2www_ce(_proj + _sel);
349 
350  Response *rs = 0;
351  try {
352  rs = d_http->fetch_url(version_url);
353  }
354  catch (Error &e) {
355  delete rs; rs = 0;
356  throw ;
357  }
358 
359  d_version = rs->get_version();
360  d_protocol = rs->get_protocol();
361 
362  delete rs; rs = 0;
363 
364  return d_protocol;
365 }
366 
374 void
376 {
377  string das_url = _URL + ".das";
378  if (_proj.length() + _sel.length())
379  das_url = das_url + "?" + id2www_ce(_proj + _sel);
380 
381  Response *rs = 0;
382  try {
383  rs = d_http->fetch_url(das_url);
384  }
385  catch (Error &e) {
386  delete rs; rs = 0;
387  throw ;
388  }
389 
390  d_version = rs->get_version();
391  d_protocol = rs->get_protocol();
392 
393  switch (rs->get_type()) {
394  case dods_error: {
395  Error e;
396  if (!e.parse(rs->get_stream())) {
397  delete rs; rs = 0;
398  throw InternalErr(__FILE__, __LINE__,
399  "Could not parse error returned from server.");
400  }
401  delete rs; rs = 0;
402  throw e;
403  }
404 
405  case web_error:
406  // We should never get here; a web error should be picked up read_url
407  // (called by fetch_url) and result in a thrown Error object.
408  break;
409 
410  case dods_das:
411  default:
412  // DAS::parse throws an exception on error.
413  try {
414  das.parse(rs->get_stream()); // read and parse the das from a file
415  }
416  catch (Error &e) {
417  delete rs; rs = 0;
418  throw ;
419  }
420 
421  break;
422  }
423 
424  delete rs; rs = 0;
425 }
426 
437 void
439 {
440  string use_url = _URL + "?" + _proj + _sel ;
441  Response *rs = 0;
442  try {
443  rs = d_http->fetch_url(use_url);
444  }
445  catch (Error &e) {
446  delete rs; rs = 0;
447  throw ;
448  }
449 
450  d_version = rs->get_version();
451  d_protocol = rs->get_protocol();
452 
453  switch (rs->get_type()) {
454  case dods_error: {
455  Error e;
456  if (!e.parse(rs->get_stream())) {
457  delete rs; rs = 0;
458  throw InternalErr(__FILE__, __LINE__,
459  "Could not parse error returned from server.");
460  }
461  delete rs; rs = 0;
462  throw e;
463  }
464 
465  case web_error:
466  // We should never get here; a web error should be picked up read_url
467  // (called by fetch_url) and result in a thrown Error object.
468  break;
469 
470  case dods_das:
471  default:
472  // DAS::parse throws an exception on error.
473  try {
474  das.parse(rs->get_stream()); // read and parse the das from a file
475  }
476  catch (Error &e) {
477  delete rs; rs = 0;
478  throw ;
479  }
480 
481  break;
482  }
483 
484  delete rs; rs = 0;
485 }
486 
500 void
501 Connect::request_dds(DDS &dds, string expr)
502 {
503  string proj, sel;
504  string::size_type dotpos = expr.find('&');
505  if (dotpos != expr.npos) {
506  proj = expr.substr(0, dotpos);
507  sel = expr.substr(dotpos);
508  }
509  else {
510  proj = expr;
511  sel = "";
512  }
513 
514  string dds_url = _URL + ".dds" + "?"
515  + id2www_ce(_proj + proj + _sel + sel);
516 
517  Response *rs = 0;
518  try {
519  rs = d_http->fetch_url(dds_url);
520  }
521  catch (Error &e) {
522  delete rs; rs = 0;
523  throw ;
524  }
525 
526  d_version = rs->get_version();
527  d_protocol = rs->get_protocol();
528 
529  switch (rs->get_type()) {
530  case dods_error: {
531  Error e;
532  if (!e.parse(rs->get_stream())) {
533  delete rs; rs = 0;
534  throw InternalErr(__FILE__, __LINE__,
535  "Could not parse error returned from server.");
536  }
537  delete rs; rs = 0;
538  throw e;
539  }
540 
541  case web_error:
542  // We should never get here; a web error should be picked up read_url
543  // (called by fetch_url) and result in a thrown Error object.
544  break;
545 
546  case dods_dds:
547  default:
548  // DDS::prase throws an exception on error.
549  try {
550  dds.parse(rs->get_stream()); // read and parse the dds from a file
551  }
552  catch (Error &e) {
553  delete rs; rs = 0;
554  throw ;
555  }
556  break;
557  }
558 
559  delete rs; rs = 0;
560 }
561 
578 void
580 {
581  string use_url = _URL + "?" + _proj + _sel ;
582  Response *rs = 0;
583  try {
584  rs = d_http->fetch_url(use_url);
585  }
586  catch (Error &e) {
587  delete rs; rs = 0;
588  throw ;
589  }
590 
591  d_version = rs->get_version();
592  d_protocol = rs->get_protocol();
593 
594  switch (rs->get_type()) {
595  case dods_error: {
596  Error e;
597  if (!e.parse(rs->get_stream())) {
598  delete rs; rs = 0;
599  throw InternalErr(__FILE__, __LINE__,
600  "Could not parse error returned from server.");
601  }
602  delete rs; rs = 0;
603  throw e;
604  }
605 
606  case web_error:
607  // We should never get here; a web error should be picked up read_url
608  // (called by fetch_url) and result in a thrown Error object.
609  break;
610 
611  case dods_dds:
612  default:
613  // DDS::prase throws an exception on error.
614  try {
615  dds.parse(rs->get_stream()); // read and parse the dds from a file
616  }
617  catch (Error &e) {
618  delete rs; rs = 0;
619  throw ;
620  }
621  break;
622  }
623 
624  delete rs; rs = 0;
625 }
626 
638 void
639 Connect::request_ddx(DDS &dds, string expr)
640 {
641  string proj, sel;
642  string::size_type dotpos = expr.find('&');
643  if (dotpos != expr.npos) {
644  proj = expr.substr(0, dotpos);
645  sel = expr.substr(dotpos);
646  }
647  else {
648  proj = expr;
649  sel = "";
650  }
651 
652  string ddx_url = _URL + ".ddx" + "?"
653  + id2www_ce(_proj + proj + _sel + sel);
654 
655  Response *rs = 0;
656  try {
657  rs = d_http->fetch_url(ddx_url);
658  }
659  catch (Error &e) {
660  delete rs; rs = 0;
661  throw ;
662  }
663 
664  d_version = rs->get_version();
665  d_protocol = rs->get_protocol();
666 
667  switch (rs->get_type()) {
668  case dods_error: {
669  Error e;
670  if (!e.parse(rs->get_stream())) {
671  delete rs; rs = 0;
672  throw InternalErr(__FILE__, __LINE__,
673  "Could not parse error returned from server.");
674  }
675  delete rs; rs = 0;
676  throw e;
677  }
678 
679  case web_error:
680  // We should never get here; a web error should be picked up read_url
681  // (called by fetch_url) and result in a thrown Error object.
682  break;
683 
684  case dap4_ddx:
685  case dods_ddx:
686  try {
687  string blob;
688 
689  DDXParser ddxp(dds.get_factory());
690  ddxp.intern_stream(rs->get_stream(), &dds, blob);
691  }
692  catch (Error &e) {
693  delete rs; rs = 0;
694  throw ;
695  }
696  break;
697 
698  default:
699  delete rs; rs = 0;
700  throw Error("The site did not return a valid response (it lacked the\n\
701 expected content description header value of 'dap4-ddx' and\n\
702 instead returned '" + long_to_string(rs->get_type()) + "').\n\
703 This may indicate that the server at the site is not correctly\n\
704 configured, or that the URL has changed.");
705  }
706 
707  delete rs; rs = 0;
708 }
709 
712 void
714 {
715  string use_url = _URL + "?" + _proj + _sel ;
716 
717  Response *rs = 0;
718  try {
719  rs = d_http->fetch_url(use_url);
720  }
721  catch (Error &e) {
722  delete rs; rs = 0;
723  throw ;
724  }
725 
726  d_version = rs->get_version();
727  d_protocol = rs->get_protocol();
728 
729  switch (rs->get_type()) {
730  case dods_error: {
731  Error e;
732  if (!e.parse(rs->get_stream())) {
733  delete rs; rs = 0;
734  throw InternalErr(__FILE__, __LINE__,
735  "Could not parse error returned from server.");
736  }
737  delete rs; rs = 0;
738  throw e;
739  }
740 
741  case web_error:
742  // We should never get here; a web error should be picked up read_url
743  // (called by fetch_url) and result in a thrown Error object.
744  break;
745 
746  case dap4_ddx:
747  case dods_ddx:
748  try {
749  string blob;
750 
751  DDXParser ddxp(dds.get_factory());
752  ddxp.intern_stream(rs->get_stream(), &dds, blob);
753  }
754  catch (Error &e) {
755  delete rs; rs = 0;
756  throw ;
757  }
758  break;
759 
760  default:
761  delete rs; rs = 0;
762  throw Error("The site did not return a valid response (it lacked the\n\
763 expected content description header value of 'dap4-ddx' and\n\
764 instead returned '" + long_to_string(rs->get_type()) + "').\n\
765 This may indicate that the server at the site is not correctly\n\
766 configured, or that the URL has changed.");
767  }
768 
769  delete rs; rs = 0;
770 }
771 
787 void
788 Connect::request_data(DataDDS &data, string expr)
789 {
790  string proj, sel;
791  string::size_type dotpos = expr.find('&');
792  if (dotpos != expr.npos) {
793  proj = expr.substr(0, dotpos);
794  sel = expr.substr(dotpos);
795  }
796  else {
797  proj = expr;
798  sel = "";
799  }
800 
801  string data_url = _URL + ".dods?"
802  + id2www_ce(_proj + proj + _sel + sel);
803 
804  Response *rs = 0;
805  // We need to catch Error exceptions to ensure calling close_output.
806  try {
807  rs = d_http->fetch_url(data_url);
808 
809  d_version = rs->get_version();
810  d_protocol = rs->get_protocol();
811 
812  process_data(data, rs);
813  delete rs; rs = 0;
814  }
815  catch (Error &e) {
816  delete rs; rs = 0;
817  throw ;
818  }
819 }
820 
838 void
840 {
841  string use_url = _URL + "?" + _proj + _sel ;
842  Response *rs = 0;
843  // We need to catch Error exceptions to ensure calling close_output.
844  try {
845  rs = d_http->fetch_url(use_url);
846 
847  d_version = rs->get_version();
848  d_protocol = rs->get_protocol();
849 
850  process_data(data, rs);
851  delete rs; rs = 0;
852  }
853  catch (Error &e) {
854  delete rs; rs = 0;
855  throw ;
856  }
857 }
858 
859 void
861 {
862  string proj, sel;
863  string::size_type dotpos = expr.find('&');
864  if (dotpos != expr.npos) {
865  proj = expr.substr(0, dotpos);
866  sel = expr.substr(dotpos);
867  }
868  else {
869  proj = expr;
870  sel = "";
871  }
872 
873  string data_url = _URL + ".dap?"
874  + id2www_ce(_proj + proj + _sel + sel);
875 
876  Response *rs = 0;
877  // We need to catch Error exceptions to ensure calling close_output.
878  try {
879  rs = d_http->fetch_url(data_url);
880 
881  d_version = rs->get_version();
882  d_protocol = rs->get_protocol();
883 
884  process_data(data, rs);
885  delete rs; rs = 0;
886  }
887  catch (Error &e) {
888  delete rs; rs = 0;
889  throw ;
890  }
891 }
892 
893 void
895 {
896  string use_url = _URL + "?" + _proj + _sel ;
897  Response *rs = 0;
898  // We need to catch Error exceptions to ensure calling close_output.
899  try {
900  rs = d_http->fetch_url(use_url);
901 
902  d_version = rs->get_version();
903  d_protocol = rs->get_protocol();
904 
905  process_data(data, rs);
906  delete rs; rs = 0;
907  }
908  catch (Error &e) {
909  delete rs; rs = 0;
910  throw ;
911  }
912 }
913 
927 void
929 {
930  if (!rs)
931  throw InternalErr(__FILE__, __LINE__, "Response object is null.");
932 
933  // Read from data_source and parse the MIME headers specific to DAP2/4.
934  parse_mime(rs);
935 
936  read_data_no_mime(data, rs);
937 }
938 
939 // This function looks at the input stream and makes its best guess at what
940 // lies in store for downstream processing code. Definitely heuristic.
941 // Assumptions:
942 // #1 The current file position is past any MIME headers (if they were present).
943 // #2 We must reset the FILE* position to the start of the DDS or DDX headers
944 static void
945 divine_type_information(Response *rs)
946 {
947  // Consume whitespace
948  char c = getc(rs->get_stream());
949  while (isspace(c)) {
950  c = getc(rs->get_stream());
951  }
952 
953  // The heuristic here is that a DataDDX is a multipart MIME document and
954  // The first non space character found after the headers is the start of
955  // the first part which looks like '--<boundary>' while a DataDDS starts
956  // with a DDS (;Dataset {' ...). I take into account that our parsers have
957  // accepted both 'Dataset' and 'dataset' for a long time.
958  switch (c) {
959  case '-':
960  rs->set_type(dap4_data_ddx);
961  break;
962  case 'D':
963  case 'd':
964  rs->set_type(dods_data);
965  break;
966  default:
967  throw InternalErr(__FILE__, __LINE__, "Could not determine type of response object in stream.");
968  }
969 
970  ungetc(c, rs->get_stream());
971 }
972 
985 void
987 {
988  if (rs->get_type() == unknown_type)
989  divine_type_information(rs);
990 
991  switch (rs->get_type()) {
992  case dods_data:
993  d_version = rs->get_version();
994  d_protocol = rs->get_protocol();
995  process_data(data, rs);
996  break;
997  case dap4_data_ddx:
998  process_data(data, rs);
999  d_version = rs->get_version();
1000  d_protocol = data.get_protocol();
1001  break;
1002  default:
1003  throw InternalErr(__FILE__, __LINE__, "Should have been a DataDDS or DataDDX.");
1004  }
1005 }
1006 
1007 bool
1009 {
1010  return _local;
1011 }
1012 
1029 string
1031 {
1032  if (_local)
1033  throw InternalErr(__FILE__, __LINE__,
1034  "URL(): This call is only valid for a DAP data source.");
1035 
1036  if (ce)
1037  return _URL + "?" + _proj + _sel;
1038  else
1039  return _URL;
1040 }
1041 
1050 string
1052 {
1053  if (_local)
1054  throw InternalErr(__FILE__, __LINE__,
1055  "CE(): This call is only valid for a DAP data source.");
1056 
1057  return _proj + _sel;
1058 }
1059 
1065 void
1066 Connect::set_credentials(string u, string p)
1067 {
1068  if (d_http)
1069  d_http->set_credentials(u, p);
1070 }
1071 
1075 void
1077 {
1078  if (d_http)
1079  d_http->set_accept_deflate(deflate);
1080 }
1081 
1087 void
1088 Connect::set_xdap_protocol(int major, int minor)
1089 {
1090  if (d_http)
1091  d_http->set_xdap_protocol(major, minor);
1092 }
1093 
1097 void
1099 {
1100  if (d_http)
1101  d_http->set_cache_enabled(cache);
1102 }
1103 
1104 bool
1106 {
1107  bool status;
1108  DBG(cerr << "Entering is_cache_enabled (" << hex << d_http << dec
1109  << ")... ");
1110  if (d_http)
1111  status = d_http->is_cache_enabled();
1112  else
1113  status = false;
1114  DBGN(cerr << "exiting" << endl);
1115  return status;
1116 }
1117 
1118 } // namespace libdap