libdap++  Updated for version 3.14.0
Connect.cc
Go to the documentation of this file.
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
4 // Access Protocol.
5 
6 // Copyright (c) 2002,2003 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@opendap.org>
8 // Dan Holloway <dholloway@gso.uri.edu>
9 // Reza Nekovei <reza@intcomm.net>
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
26 
27 // (c) COPYRIGHT URI/MIT 1994-2002
28 // Please read the full copyright statement in the file COPYRIGHT_URI.
29 //
30 // Authors:
31 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
32 // dan Dan Holloway <dholloway@gso.uri.edu>
33 // reza Reza Nekovei <reza@intcomm.net>
34 
35 #include "config.h"
36 
37 //#define DODS_DEBUG
38 #define FILE_UN_MARSHALLER 1
39 
40 #include <cstring>
41 #include <fstream>
42 #include <algorithm>
43 
44 #include "debug.h"
45 #include "DataDDS.h"
46 #include "Connect.h"
47 #include "escaping.h"
48 //#include "RCReader.h"
49 #include "DDXParserSAX2.h"
50 #if FILE_UN_MARSHALLER
51 #include "XDRFileUnMarshaller.h"
52 #else
53 #include "fdiostream.h"
54 #include "XDRStreamUnMarshaller.h"
55 #endif
56 #include "mime_util.h"
57 
58 using std::cerr;
59 using std::endl;
60 using std::ifstream;
61 using std::ofstream;
62 using std::min;
63 
64 namespace libdap {
65 
68 void Connect::process_data(DataDDS &data, Response *rs)
69 {
70  DBG(cerr << "Entering Connect::process_data" << endl);
71 
72  data.set_version(rs->get_version());
73  data.set_protocol(rs->get_protocol());
74 
75  DBG(cerr << "Entering process_data: d_stream = " << rs << endl);
76  switch (rs->get_type()) {
77  case dods_error: {
78  Error e;
79  if (!e.parse(rs->get_stream()))
80  throw InternalErr(__FILE__, __LINE__, "Could not parse the Error object returned by the server!");
81  throw e;
82  }
83 
84  case web_error:
85  // Web errors (those reported in the return document's MIME header)
86  // are processed by the WWW library.
87  throw InternalErr(__FILE__, __LINE__,
88  "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
89 
90  case dods_data_ddx: {
91  // Parse the DDX; throw an exception on error.
92  DDXParser ddx_parser(data.get_factory());
93 
94  // Read the MPM boundary and then read the subsequent headers
95  string boundary = read_multipart_boundary(rs->get_stream());
96  DBG(cerr << "MPM Boundary: " << boundary << endl);
97  read_multipart_headers(rs->get_stream(), "text/xml", dods_ddx);
98 
99  // Parse the DDX, reading up to and including the next boundary.
100  // Return the CID for the matching data part
101  string data_cid;
102  ddx_parser.intern_stream(rs->get_stream(), &data, data_cid, boundary);
103 
104  // Munge the CID into something we can work with
105  data_cid = cid_to_header_value(data_cid);
106  DBG(cerr << "Data CID: " << data_cid << endl);
107 
108  // Read the data part's MPM part headers (boundary was read by
109  // DDXParse::intern)
110  read_multipart_headers(rs->get_stream(), "application/octet-stream", dap4_data, data_cid);
111 
112  // Now read the data
113 #if FILE_UN_MARSHALLER
114  XDRFileUnMarshaller um(rs->get_stream());
115 #else
116  fpistream in ( rs->get_stream() );
117  XDRStreamUnMarshaller um( in );
118 #endif
119  for (DDS::Vars_iter i = data.var_begin(); i != data.var_end(); i++) {
120  (*i)->deserialize(um, &data);
121  }
122  return;
123  }
124 
125  case dods_data:
126  default: {
127  // Parse the DDS; throw an exception on error.
128  data.parse(rs->get_stream());
129 #if FILE_UN_MARSHALLER
130  XDRFileUnMarshaller um(rs->get_stream());
131 #else
132  fpistream in ( rs->get_stream() );
133  XDRStreamUnMarshaller um( in );
134 #endif
135  // Load the DDS with data.
136  for (DDS::Vars_iter i = data.var_begin(); i != data.var_end(); i++) {
137  (*i)->deserialize(um, &data);
138  }
139  return;
140  }
141  }
142 }
143 
146 void
147 Connect::process_data(DDS &data, Response *rs)
148 {
149  DBG(cerr << "Entering Connect::process_data" << endl);
150 
151 #if 0
152  data.set_version(rs->get_version());
153  data.set_protocol(rs->get_protocol());
154 #endif
155  // TODO is this the correct info?
156  data.set_dap_version(rs->get_protocol());
157 
158  DBG(cerr << "Entering process_data: d_stream = " << rs << endl);
159  switch (rs->get_type()) {
160  case dods_error: {
161  Error e;
162  if (!e.parse(rs->get_stream()))
163  throw InternalErr(__FILE__, __LINE__,
164  "Could not parse the Error object returned by the server!");
165  throw e;
166  }
167 
168  case web_error:
169  // Web errors (those reported in the return document's MIME header)
170  // are processed by the WWW library.
171  throw InternalErr(__FILE__, __LINE__, "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
172 
173  case dods_data_ddx: {
174  // Parse the DDX; throw an exception on error.
175  DDXParser ddx_parser(data.get_factory());
176 
177  // Read the MPM boundary and then read the subsequent headers
178  string boundary = read_multipart_boundary(rs->get_stream());
179  DBG(cerr << "MPM Boundary: " << boundary << endl);
180  read_multipart_headers(rs->get_stream(), "text/xml", dods_ddx);
181 
182  // Parse the DDX, reading up to and including the next boundary.
183  // Return the CID for the matching data part
184  string data_cid;
185  ddx_parser.intern_stream(rs->get_stream(), &data, data_cid, boundary);
186 
187  // Munge the CID into something we can work with
188  data_cid = cid_to_header_value(data_cid);
189  DBG(cerr << "Data CID: " << data_cid << endl);
190 
191  // Read the data part's MPM part headers (boundary was read by
192  // DDXParse::intern)
193  read_multipart_headers(rs->get_stream(),
194  "application/octet-stream", dap4_data, data_cid);
195 
196  // Now read the data
197 #if FILE_UN_MARSHALLER
198  XDRFileUnMarshaller um( rs->get_stream() ) ;
199 #else
200  fpistream in ( rs->get_stream() );
201  XDRStreamUnMarshaller um( in ) ;
202 #endif
203 #if 0
204  try {
205 #endif
206  for (DDS::Vars_iter i = data.var_begin(); i != data.var_end();
207  i++) {
208  (*i)->deserialize(um, &data);
209  }
210 #if 0
211  }
212  catch (Error &e) {
213  throw ;
214  }
215 #endif
216  return;
217  }
218 
219  case dods_data:
220  default: {
221  // Parse the DDS; throw an exception on error.
222  data.parse(rs->get_stream());
223 #if FILE_UN_MARSHALLER
224  XDRFileUnMarshaller um( rs->get_stream() ) ;
225 #else
226  fpistream in ( rs->get_stream() );
227  XDRStreamUnMarshaller um( in ) ;
228 #endif
229  // Load the DDS with data.
230 #if 0
231  try {
232 #endif
233  for (DDS::Vars_iter i = data.var_begin(); i != data.var_end();
234  i++) {
235  (*i)->deserialize(um, &data);
236  }
237 #if 0
238  }
239  catch (Error &e) {
240  throw ;
241  }
242 #endif
243  return;
244  }
245  }
246 }
247 
248 // Barely a parser... This is used when reading from local sources of DODS
249 // Data objects. It simulates the important actions of the libwww MIME header
250 // parser. Those actions fill in certain fields in the Connect object. jhrg
251 // 5/20/97
252 //
253 // Make sure that this parser reads from data_source without disturbing the
254 // information in data_source that follows the MIME header. Since the DDS
255 // (which follows the MIME header) is parsed by a flex/bison scanner/parser,
256 // make sure to use I/O calls that will mesh with ANSI C I/O calls. In the
257 // old GNU libg++, the C++ calls were synchronized with the C calls, but that
258 // may no longer be the case. 5/31/99 jhrg
259 
269 void Connect::parse_mime(Response *rs)
270 {
271  rs->set_version("dods/0.0"); // initial value; for backward compatibility.
272  rs->set_protocol("2.0");
273 
274  FILE *data_source = rs->get_stream();
275  string mime = get_next_mime_header(data_source);
276  while (!mime.empty()) {
277  string header, value;
278  parse_mime_header(mime, header, value);
279 
280  // Note that this is an ordered list
281  if (header == "content-description:") {
282  DBG(cout << header << ": " << value << endl);
283  rs->set_type(get_description_type(value));
284  }
285  // Use the value of xdods-server only if no other value has been read
286  else if (header == "xdods-server:" && rs->get_version() == "dods/0.0") {
287  DBG(cout << header << ": " << value << endl);
288  rs->set_version(value);
289  }
290  // This trumps 'xdods-server' and 'server'
291  else if (header == "xopendap-server:") {
292  DBG(cout << header << ": " << value << endl);
293  rs->set_version(value);
294  }
295  else if (header == "xdap:") {
296  DBG(cout << header << ": " << value << endl);
297  rs->set_protocol(value);
298  }
299  // Only look for 'server' if no other header supplies this info.
300  else if (rs->get_version() == "dods/0.0" && header == "server:") {
301  DBG(cout << header << ": " << value << endl);
302  rs->set_version(value);
303  }
304 
305  mime = get_next_mime_header(data_source);
306  }
307 }
308 
309 // public mfuncs
310 
318 Connect::Connect(const string &n, string uname, string password) throw (Error, InternalErr) :
319  d_http(0), d_version("unknown"), d_protocol("2.0")
320 {
321  string name = prune_spaces(n);
322 
323  // Figure out if the URL starts with 'http', if so, make sure that we
324  // talk to an instance of HTTPConnect.
325  if (name.find("http") == 0) {
326  DBG(cerr << "Connect: The identifier is an http URL" << endl);
327  d_http = new HTTPConnect(RCReader::instance());
328 
329  // Find and store any CE given with the URL.
330  string::size_type dotpos = name.find('?');
331  if (dotpos != name.npos) {
332  _URL = name.substr(0, dotpos);
333  string expr = name.substr(dotpos + 1);
334 
335  dotpos = expr.find('&');
336  if (dotpos != expr.npos) {
337  _proj = expr.substr(0, dotpos);
338  _sel = expr.substr(dotpos); // XXX includes '&'
339  }
340  else {
341  _proj = expr;
342  _sel = "";
343  }
344  }
345  else {
346  _URL = name;
347  _proj = "";
348  _sel = "";
349  }
350 
351  _local = false;
352  }
353  else {
354  DBG(cerr << "Connect: The identifier is a local data source." << endl);
355 
356  d_http = 0;
357  _URL = "";
358  _local = true; // local in this case means non-DAP
359  }
360 
361  set_credentials(uname, password);
362 }
363 
365 {
366  DBG2(cerr << "Entering the Connect dtor" << endl);
367 
368  if (d_http)
369  delete d_http;
370  d_http = 0;
371 
372  DBG2(cerr << "Leaving the Connect dtor" << endl);
373 }
374 
383 {
384  string version_url = _URL + ".ver";
385  if (_proj.length() + _sel.length())
386  version_url = version_url + "?" + id2www_ce(_proj + _sel);
387 
388  Response *rs = 0;
389  try {
390  rs = d_http->fetch_url(version_url);
391  }
392  catch (Error &e) {
393  delete rs;
394  rs = 0;
395  throw;
396  }
397 
398  d_version = rs->get_version();
399  d_protocol = rs->get_protocol();
400 
401  delete rs;
402  rs = 0;
403 
404  return d_version;
405 }
406 
419 {
420  string version_url = _URL + ".ver";
421  if (_proj.length() + _sel.length())
422  version_url = version_url + "?" + id2www_ce(_proj + _sel);
423 
424  Response *rs = 0;
425  try {
426  rs = d_http->fetch_url(version_url);
427  }
428  catch (Error &e) {
429  delete rs;
430  rs = 0;
431  throw;
432  }
433 
434  d_version = rs->get_version();
435  d_protocol = rs->get_protocol();
436 
437  delete rs;
438  rs = 0;
439 
440  return d_protocol;
441 }
442 
451 {
452  string das_url = _URL + ".das";
453  if (_proj.length() + _sel.length())
454  das_url = das_url + "?" + id2www_ce(_proj + _sel);
455 
456  Response *rs = 0;
457  try {
458  rs = d_http->fetch_url(das_url);
459  }
460  catch (Error &e) {
461  delete rs;
462  rs = 0;
463  throw;
464  }
465 
466  d_version = rs->get_version();
467  d_protocol = rs->get_protocol();
468 
469  switch (rs->get_type()) {
470  case dods_error: {
471  Error e;
472  if (!e.parse(rs->get_stream())) {
473  delete rs;
474  rs = 0;
475  throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
476  }
477  delete rs;
478  rs = 0;
479  throw e;
480  }
481 
482  case web_error:
483  // We should never get here; a web error should be picked up read_url
484  // (called by fetch_url) and result in a thrown Error object.
485  break;
486 
487  case dods_das:
488  default:
489  // DAS::parse throws an exception on error.
490  try {
491  das.parse(rs->get_stream()); // read and parse the das from a file
492  }
493  catch (Error &e) {
494  delete rs;
495  rs = 0;
496  throw;
497  }
498 
499  break;
500  }
501 
502  delete rs;
503  rs = 0;
504 }
505 
517 {
518  string use_url = _URL + "?" + _proj + _sel;
519  Response *rs = 0;
520  try {
521  rs = d_http->fetch_url(use_url);
522  }
523  catch (Error &e) {
524  delete rs;
525  rs = 0;
526  throw;
527  }
528 
529  d_version = rs->get_version();
530  d_protocol = rs->get_protocol();
531 
532  switch (rs->get_type()) {
533  case dods_error: {
534  Error e;
535  if (!e.parse(rs->get_stream())) {
536  delete rs;
537  rs = 0;
538  throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
539  }
540  delete rs;
541  rs = 0;
542  throw e;
543  }
544 
545  case web_error:
546  // We should never get here; a web error should be picked up read_url
547  // (called by fetch_url) and result in a thrown Error object.
548  break;
549 
550  case dods_das:
551  default:
552  // DAS::parse throws an exception on error.
553  try {
554  das.parse(rs->get_stream()); // read and parse the das from a file
555  }
556  catch (Error &e) {
557  delete rs;
558  rs = 0;
559  throw;
560  }
561 
562  break;
563  }
564 
565  delete rs;
566  rs = 0;
567 }
568 
582 void Connect::request_dds(DDS &dds, string expr)
583 {
584  string proj, sel;
585  string::size_type dotpos = expr.find('&');
586  if (dotpos != expr.npos) {
587  proj = expr.substr(0, dotpos);
588  sel = expr.substr(dotpos);
589  }
590  else {
591  proj = expr;
592  sel = "";
593  }
594 
595  string dds_url = _URL + ".dds" + "?" + id2www_ce(_proj + proj + _sel + sel);
596 
597  Response *rs = 0;
598  try {
599  rs = d_http->fetch_url(dds_url);
600  }
601  catch (Error &e) {
602  delete rs;
603  rs = 0;
604  throw;
605  }
606 
607  d_version = rs->get_version();
608  d_protocol = rs->get_protocol();
609 
610  switch (rs->get_type()) {
611  case dods_error: {
612  Error e;
613  if (!e.parse(rs->get_stream())) {
614  delete rs;
615  rs = 0;
616  throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
617  }
618  delete rs;
619  rs = 0;
620  throw e;
621  }
622 
623  case web_error:
624  // We should never get here; a web error should be picked up read_url
625  // (called by fetch_url) and result in a thrown Error object.
626  break;
627 
628  case dods_dds:
629  default:
630  // DDS::prase throws an exception on error.
631  try {
632  dds.parse(rs->get_stream()); // read and parse the dds from a file
633  }
634  catch (Error &e) {
635  delete rs;
636  rs = 0;
637  throw;
638  }
639  break;
640  }
641 
642  delete rs;
643  rs = 0;
644 }
645 
663 {
664  string use_url = _URL + "?" + _proj + _sel;
665  Response *rs = 0;
666  try {
667  rs = d_http->fetch_url(use_url);
668  }
669  catch (Error &e) {
670  delete rs;
671  rs = 0;
672  throw;
673  }
674 
675  d_version = rs->get_version();
676  d_protocol = rs->get_protocol();
677 
678  switch (rs->get_type()) {
679  case dods_error: {
680  Error e;
681  if (!e.parse(rs->get_stream())) {
682  delete rs;
683  rs = 0;
684  throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
685  }
686  delete rs;
687  rs = 0;
688  throw e;
689  }
690 
691  case web_error:
692  // We should never get here; a web error should be picked up read_url
693  // (called by fetch_url) and result in a thrown Error object.
694  break;
695 
696  case dods_dds:
697  default:
698  // DDS::prase throws an exception on error.
699  try {
700  dds.parse(rs->get_stream()); // read and parse the dds from a file
701  }
702  catch (Error &e) {
703  delete rs;
704  rs = 0;
705  throw;
706  }
707  break;
708  }
709 
710  delete rs;
711  rs = 0;
712 }
713 
725 void Connect::request_ddx(DDS &dds, string expr)
726 {
727  string proj, sel;
728  string::size_type dotpos = expr.find('&');
729  if (dotpos != expr.npos) {
730  proj = expr.substr(0, dotpos);
731  sel = expr.substr(dotpos);
732  }
733  else {
734  proj = expr;
735  sel = "";
736  }
737 
738  string ddx_url = _URL + ".ddx" + "?" + id2www_ce(_proj + proj + _sel + sel);
739 
740  Response *rs = 0;
741  try {
742  rs = d_http->fetch_url(ddx_url);
743  }
744  catch (Error &e) {
745  delete rs;
746  rs = 0;
747  throw;
748  }
749 
750  d_version = rs->get_version();
751  d_protocol = rs->get_protocol();
752 
753  switch (rs->get_type()) {
754  case dods_error: {
755  Error e;
756  if (!e.parse(rs->get_stream())) {
757  delete rs;
758  rs = 0;
759  throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
760  }
761  delete rs;
762  rs = 0;
763  throw e;
764  }
765 
766  case web_error:
767  // We should never get here; a web error should be picked up read_url
768  // (called by fetch_url) and result in a thrown Error object.
769  break;
770 
771  case dods_ddx:
772  try {
773  string blob;
774 
775  DDXParser ddxp(dds.get_factory());
776  ddxp.intern_stream(rs->get_stream(), &dds, blob);
777  }
778  catch (Error &e) {
779  delete rs;
780  rs = 0;
781  throw;
782  }
783  break;
784 
785  default:
786  delete rs;
787  rs = 0;
788  throw Error(
789  "The site did not return a valid response (it lacked the\n\
790 expected content description header value of 'dap4-ddx' and\n\
791 instead returned '"
792  + long_to_string(rs->get_type())
793  + "').\n\
794 This may indicate that the server at the site is not correctly\n\
795 configured, or that the URL has changed.");
796  }
797 
798  delete rs;
799  rs = 0;
800 }
801 
805 {
806  string use_url = _URL + "?" + _proj + _sel;
807 
808  Response *rs = 0;
809  try {
810  rs = d_http->fetch_url(use_url);
811  }
812  catch (Error &e) {
813  delete rs;
814  rs = 0;
815  throw;
816  }
817 
818  d_version = rs->get_version();
819  d_protocol = rs->get_protocol();
820 
821  switch (rs->get_type()) {
822  case dods_error: {
823  Error e;
824  if (!e.parse(rs->get_stream())) {
825  delete rs;
826  rs = 0;
827  throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
828  }
829  delete rs;
830  rs = 0;
831  throw e;
832  }
833 
834  case web_error:
835  // We should never get here; a web error should be picked up read_url
836  // (called by fetch_url) and result in a thrown Error object.
837  break;
838 
839  case dods_ddx:
840  try {
841  string blob;
842 
843  DDXParser ddxp(dds.get_factory());
844  ddxp.intern_stream(rs->get_stream(), &dds, blob);
845  }
846  catch (Error &e) {
847  delete rs;
848  rs = 0;
849  throw;
850  }
851  break;
852 
853  default:
854  delete rs;
855  rs = 0;
856  throw Error(
857  "The site did not return a valid response (it lacked the\n\
858 expected content description header value of 'dap4-ddx' and\n\
859 instead returned '"
860  + long_to_string(rs->get_type())
861  + "').\n\
862 This may indicate that the server at the site is not correctly\n\
863 configured, or that the URL has changed.");
864  }
865 
866  delete rs;
867  rs = 0;
868 }
869 
885 void Connect::request_data(DataDDS &data, string expr)
886 {
887  string proj, sel;
888  string::size_type dotpos = expr.find('&');
889  if (dotpos != expr.npos) {
890  proj = expr.substr(0, dotpos);
891  sel = expr.substr(dotpos);
892  }
893  else {
894  proj = expr;
895  sel = "";
896  }
897 
898  string data_url = _URL + ".dods?" + id2www_ce(_proj + proj + _sel + sel);
899 
900  Response *rs = 0;
901  // We need to catch Error exceptions to ensure calling close_output.
902  try {
903  rs = d_http->fetch_url(data_url);
904 
905  d_version = rs->get_version();
906  d_protocol = rs->get_protocol();
907 
908  process_data(data, rs);
909  delete rs;
910  rs = 0;
911  }
912  catch (Error &e) {
913  delete rs;
914  rs = 0;
915  throw;
916  }
917 }
918 
937 {
938  string use_url = _URL + "?" + _proj + _sel;
939  Response *rs = 0;
940  // We need to catch Error exceptions to ensure calling close_output.
941  try {
942  rs = d_http->fetch_url(use_url);
943 
944  d_version = rs->get_version();
945  d_protocol = rs->get_protocol();
946 
947  process_data(data, rs);
948  delete rs;
949  rs = 0;
950  }
951  catch (Error &e) {
952  delete rs;
953  rs = 0;
954  throw;
955  }
956 }
957 
958 void Connect::request_data_ddx(DataDDS &data, string expr)
959 {
960  string proj, sel;
961  string::size_type dotpos = expr.find('&');
962  if (dotpos != expr.npos) {
963  proj = expr.substr(0, dotpos);
964  sel = expr.substr(dotpos);
965  }
966  else {
967  proj = expr;
968  sel = "";
969  }
970 
971  string data_url = _URL + ".dap?" + id2www_ce(_proj + proj + _sel + sel);
972 
973  Response *rs = 0;
974  // We need to catch Error exceptions to ensure calling close_output.
975  try {
976  rs = d_http->fetch_url(data_url);
977 
978  d_version = rs->get_version();
979  d_protocol = rs->get_protocol();
980 
981  process_data(data, rs);
982  delete rs;
983  rs = 0;
984  }
985  catch (Error &e) {
986  delete rs;
987  rs = 0;
988  throw;
989  }
990 }
991 
993 {
994  string use_url = _URL + "?" + _proj + _sel;
995  Response *rs = 0;
996  // We need to catch Error exceptions to ensure calling close_output.
997  try {
998  rs = d_http->fetch_url(use_url);
999 
1000  d_version = rs->get_version();
1001  d_protocol = rs->get_protocol();
1002 
1003  process_data(data, rs);
1004  delete rs;
1005  rs = 0;
1006  }
1007  catch (Error &e) {
1008  delete rs;
1009  rs = 0;
1010  throw;
1011  }
1012 }
1013 
1028 {
1029  if (!rs)
1030  throw InternalErr(__FILE__, __LINE__, "Response object is null.");
1031 
1032  // Read from data_source and parse the MIME headers specific to DAP2/4.
1033  parse_mime(rs);
1034 
1035  read_data_no_mime(data, rs);
1036 }
1037 void
1039 {
1040  if (!rs)
1041  throw InternalErr(__FILE__, __LINE__, "Response object is null.");
1042 
1043  // Read from data_source and parse the MIME headers specific to DAP2/4.
1044  parse_mime(rs);
1045 
1046  read_data_no_mime(data, rs);
1047 }
1048 
1049 // This function looks at the input stream and makes its best guess at what
1050 // lies in store for downstream processing code. Definitely heuristic.
1051 // Assumptions:
1052 // #1 The current file position is past any MIME headers (if they were present).
1053 // #2 We must reset the FILE* position to the start of the DDS or DDX headers
1054 static void divine_type_information(Response *rs)
1055 {
1056  // Consume whitespace
1057  char c = getc(rs->get_stream());
1058  while (isspace(c)) {
1059  c = getc(rs->get_stream());
1060  }
1061 
1062  // The heuristic here is that a DataDDX is a multipart MIME document and
1063  // The first non space character found after the headers is the start of
1064  // the first part which looks like '--<boundary>' while a DataDDS starts
1065  // with a DDS (;Dataset {' ...). I take into account that our parsers have
1066  // accepted both 'Dataset' and 'dataset' for a long time.
1067  switch (c) {
1068  case '-':
1069  rs->set_type(dods_data_ddx);
1070  break;
1071  case 'D':
1072  case 'd':
1073  rs->set_type(dods_data);
1074  break;
1075  default:
1076  throw InternalErr(__FILE__, __LINE__, "Could not determine type of response object in stream.");
1077  }
1078 
1079  ungetc(c, rs->get_stream());
1080 }
1081 
1095 {
1096  if (rs->get_type() == unknown_type)
1097  divine_type_information(rs);
1098 
1099  switch (rs->get_type()) {
1100  case dods_data:
1101  d_version = rs->get_version();
1102  d_protocol = rs->get_protocol();
1103  process_data(data, rs);
1104  break;
1105  case dods_data_ddx:
1106  process_data(data, rs);
1107  d_version = rs->get_version();
1108  d_protocol = data.get_protocol();
1109  break;
1110  default:
1111  throw InternalErr(__FILE__, __LINE__, "Should have been a DataDDS or DataDDX.");
1112  }
1113 }
1115 {
1116  if (rs->get_type() == unknown_type)
1117  divine_type_information(rs);
1118 
1119  switch (rs->get_type()) {
1120  case dods_data:
1121  d_version = rs->get_version();
1122  d_protocol = rs->get_protocol();
1123  process_data(data, rs);
1124  break;
1125  case dods_data_ddx:
1126  process_data(data, rs);
1127  d_version = rs->get_version();
1128  // TODO should check to see if this hack is a correct replacement
1129  // for get_protocol from DataDDS
1130  d_protocol = data.get_dap_version();
1131  break;
1132  default:
1133  throw InternalErr(__FILE__, __LINE__, "Should have been a DataDDS or DataDDX.");
1134  }
1135 }
1136 
1137 bool
1139 {
1140  return _local;
1141 }
1142 
1159 string Connect::URL(bool ce)
1160 {
1161  if (_local)
1162  throw InternalErr(__FILE__, __LINE__, "URL(): This call is only valid for a DAP data source.");
1163 
1164  if (ce)
1165  return _URL + "?" + _proj + _sel;
1166  else
1167  return _URL;
1168 }
1169 
1178 string Connect::CE()
1179 {
1180  if (_local)
1181  throw InternalErr(__FILE__, __LINE__, "CE(): This call is only valid for a DAP data source.");
1182 
1183  return _proj + _sel;
1184 }
1185 
1191 void Connect::set_credentials(string u, string p)
1192 {
1193  if (d_http)
1194  d_http->set_credentials(u, p);
1195 }
1196 
1201 {
1202  if (d_http)
1203  d_http->set_accept_deflate(deflate);
1204 }
1205 
1211 void Connect::set_xdap_protocol(int major, int minor)
1212 {
1213  if (d_http)
1214  d_http->set_xdap_protocol(major, minor);
1215 }
1216 
1221 {
1222  if (d_http)
1223  d_http->set_cache_enabled(cache);
1224 }
1225 
1227 {
1228  bool status;
1229  DBG(cerr << "Entering is_cache_enabled (" << hex << d_http << dec
1230  << ")... ");
1231  if (d_http)
1232  status = d_http->is_cache_enabled();
1233  else
1234  status = false;
1235  DBGN(cerr << "exiting" << endl);
1236  return status;
1237 }
1238 
1239 } // namespace libdap
virtual string CE()
Get the Connect's constraint expression.
Definition: Connect.cc:1178
virtual void request_das_url(DAS &das)
Get the DAS from a server.
Definition: Connect.cc:516
string get_next_mime_header(FILE *in)
Definition: mime_util.cc:836
void intern_stream(FILE *in, DDS *dds, string &cid, const string &boundary="")
Read the DDX from a stream instead of a file.
virtual void request_ddx(DDS &dds, string expr="")
Get the DDX from a server.
Definition: Connect.cc:725
virtual string URL(bool CE=true)
Get the object's URL.
Definition: Connect.cc:1159
string id2www_ce(string in, const string &allowable)
Definition: escaping.cc:178
string prune_spaces(const string &name)
Definition: util.cc:468
void set_credentials(const string &u, const string &p)
void set_xdap_protocol(int major, int minor)
Definition: Connect.cc:1211
void read_multipart_headers(FILE *in, const string &content_type, const ObjectType object_type, const string &cid)
Definition: mime_util.cc:993
#define DBGN(x)
Definition: debug.h:59
virtual void set_type(ObjectType o)
Definition: Response.h:121
virtual void request_dds_url(DDS &dds)
Get the DDS from a server.
Definition: Connect.cc:662
bool parse(FILE *fp)
Parse an Error object.
Definition: Error.cc:155
void set_cache_enabled(bool enabled)
Definition: HTTPConnect.h:150
virtual std::string get_version() const
Definition: Response.h:110
string cid_to_header_value(const string &cid)
Definition: mime_util.cc:1064
virtual ObjectType get_type() const
Definition: Response.h:109
HTTPResponse * fetch_url(const string &url)
Definition: HTTPConnect.cc:615
#define DBG2(x)
Definition: debug.h:73
bool is_local()
Definition: Connect.cc:1138
A class for software fault reporting.
Definition: InternalErr.h:64
void parse(string fname)
Parse a DDS from a file with the given d_name.
Definition: DDS.cc:929
void parse_mime_header(const string &header, string &name, string &value)
Definition: mime_util.cc:898
virtual void read_data(DataDDS &data, Response *rs)
Read data which is preceded by MIME headers. This method works for both data dds and data ddx respons...
Definition: Connect.cc:1027
#define DBG(x)
Definition: debug.h:58
string get_dap_version() const
Definition: DDS.h:268
ObjectType get_description_type(const string &value)
Definition: mime_util.cc:339
void set_cache_enabled(bool enabled)
Definition: Connect.cc:1220
bool is_cache_enabled()
Definition: Connect.cc:1226
std::vector< BaseType * >::iterator Vars_iter
Definition: DDS.h:219
virtual void request_dds(DDS &dds, string expr="")
Get the DDS from a server.
Definition: Connect.cc:582
void set_accept_deflate(bool deflate)
Definition: Connect.cc:1200
virtual void request_data(DataDDS &data, string expr="")
Get the DAS from a server.
Definition: Connect.cc:885
string read_multipart_boundary(FILE *in, const string &boundary)
Definition: mime_util.cc:945
virtual std::string get_protocol() const
Definition: Response.h:111
virtual void read_data_no_mime(DataDDS &data, Response *rs)
Read data from a file which does not have response MIME headers. This method is a companion to read_d...
Definition: Connect.cc:1094
virtual void request_das(DAS &das)
Get the DAS from a server.
Definition: Connect.cc:450
void set_accept_deflate(bool defalte)
Definition: HTTPConnect.cc:988
string long_to_string(long val, int base)
Definition: util.cc:1012
BaseTypeFactory * get_factory() const
Definition: DDS.h:239
void set_xdap_protocol(int major, int minor)
virtual void parse(string fname)
Reads a DAS from the named file.
Definition: DAS.cc:249
virtual string request_version()
Definition: Connect.cc:382
virtual void request_data_ddx_url(DataDDS &data)
Definition: Connect.cc:992
virtual void request_data_ddx(DataDDS &data, string expr="")
Definition: Connect.cc:958
void set_credentials(string u, string p)
Set the credentials for responding to challenges while dereferencing URLs.
Definition: Connect.cc:1191
virtual string request_protocol()
Definition: Connect.cc:418
string get_protocol() const
Definition: DataDDS.h:129
Hold attribute data for a DAP2 dataset.
Definition: DAS.h:121
virtual void request_data_url(DataDDS &data)
Get the DAS from a server.
Definition: Connect.cc:936
A class for error processing.
Definition: Error.h:90
Holds a DAP2 DDS.
Definition: DataDDS.h:77
virtual void request_ddx_url(DDS &dds)
The 'url' version of request_ddx.
Definition: Connect.cc:804
virtual ~Connect()
Definition: Connect.cc:364
static RCReader * instance()
Definition: RCReader.cc:486
virtual FILE * get_stream() const
Definition: Response.h:106