libdap Updated for version 3.21.0
libdap4 is an implementation of OPeNDAP's DAP protocol.
Connect.cc
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 <cerrno>
41#include <cstring>
42
43#include <algorithm>
44#include <fstream>
45
46#include "Connect.h"
47#include "DataDDS.h"
48#include "debug.h"
49#include "escaping.h"
50// #include "RCReader.h"
51#include "DDXParserSAX2.h"
52#if FILE_UN_MARSHALLER
53#include "XDRFileUnMarshaller.h"
54#else
55#include "XDRStreamUnMarshaller.h"
56#include "fdiostream.h"
57#endif
58#include "mime_util.h"
59
60using std::cerr;
61using std::endl;
62using std::ifstream;
63using std::min;
64using std::ofstream;
65
66namespace libdap {
67
70void Connect::process_data(DataDDS &data, Response *rs) {
71 DBG(cerr << "Entering Connect::process_data" << endl);
72
73 data.set_version(rs->get_version());
74 data.set_protocol(rs->get_protocol());
75
76 DBG(cerr << "Entering process_data: d_stream = " << rs << endl);
77 switch (rs->get_type()) {
78 case dods_error: {
79 Error e;
80 if (!e.parse(rs->get_stream()))
81 throw InternalErr(__FILE__, __LINE__, "Could not parse the Error object returned by the server!");
82 throw e;
83 }
84
85 case web_error:
86 // Web errors (those reported in the return document's MIME header)
87 // are processed by the WWW library.
88 throw InternalErr(
89 __FILE__, __LINE__,
90 "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
91
92#if 0
93 // This code triggers a security warning from Coverity; since it is not used,
94 // I have removed it. jhrg 5/5/16
95 case dods_data_ddx: {
96 // Parse the DDX; throw an exception on error.
97 DDXParser ddx_parser(data.get_factory());
98
99 // Read the MPM boundary and then read the subsequent headers
100 string boundary = read_multipart_boundary(rs->get_stream());
101 DBG(cerr << "MPM Boundary: " << boundary << endl);
102 read_multipart_headers(rs->get_stream(), "text/xml", dods_ddx);
103
104 // Parse the DDX, reading up to and including the next boundary.
105 // Return the CID for the matching data part
106 string data_cid;
107 ddx_parser.intern_stream(rs->get_stream(), &data, data_cid, boundary);
108
109 // Munge the CID into something we can work with
110 data_cid = cid_to_header_value(data_cid);
111 DBG(cerr << "Data CID: " << data_cid << endl);
112
113 // Read the data part's MPM part headers (boundary was read by
114 // DDXParse::intern)
115 read_multipart_headers(rs->get_stream(), "application/octet-stream", dap4_data, data_cid);
116
117 // Now read the data
118#if FILE_UN_MARSHALLER
119 XDRFileUnMarshaller um(rs->get_stream());
120#else
121 fpistream in ( rs->get_stream() );
122 XDRStreamUnMarshaller um( in );
123#endif
124 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end(); i++) {
125 (*i)->deserialize(um, &data);
126 }
127 return;
128 }
129#endif
130
131 case dods_data:
132 default: {
133 // Parse the DDS; throw an exception on error.
134 data.parse(rs->get_stream());
135#if FILE_UN_MARSHALLER
136 XDRFileUnMarshaller um(rs->get_stream());
137#else
138 fpistream in(rs->get_stream());
139 XDRStreamUnMarshaller um(in);
140#endif
141 // Load the DDS with data.
142 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end(); i++) {
143 (*i)->deserialize(um, &data);
144 }
145 return;
146 }
147 }
148}
149
152void Connect::process_data(DDS &data, Response *rs) {
153 DBG(cerr << "Entering Connect::process_data" << endl);
154
155 data.set_dap_version(rs->get_protocol());
156
157 DBG(cerr << "Entering process_data: d_stream = " << rs << endl);
158 switch (rs->get_type()) {
159 case dods_error: {
160 Error e;
161 if (!e.parse(rs->get_stream()))
162 throw InternalErr(__FILE__, __LINE__, "Could not parse the Error object returned by the server!");
163 throw e;
164 }
165
166 case web_error:
167 // Web errors (those reported in the return document's MIME header)
168 // are processed by the WWW library.
169 throw InternalErr(
170 __FILE__, __LINE__,
171 "An error was reported by the remote web server; this should have been processed by HTTPConnect.");
172
173#if 0
174 // FIXME: The following case is never used. There is no such response. jhrg 10/20/15
175 // This code triggers a security warning from Coverity; since it is not used,
176 // I have removed it. jhrg 5/5/16
177 case dods_data_ddx: {
178 // Parse the DDX; throw an exception on error.
179 DDXParser ddx_parser(data.get_factory());
180
181 // Read the MPM boundary and then read the subsequent headers
182 string boundary = read_multipart_boundary(rs->get_stream());
183 DBG(cerr << "MPM Boundary: " << boundary << endl);
184 read_multipart_headers(rs->get_stream(), "text/xml", dods_ddx);
185
186 // Parse the DDX, reading up to and including the next boundary.
187 // Return the CID for the matching data part
188 string data_cid;
189 ddx_parser.intern_stream(rs->get_stream(), &data, data_cid, boundary);
190
191 // Munge the CID into something we can work with
192 data_cid = cid_to_header_value(data_cid);
193 DBG(cerr << "Data CID: " << data_cid << endl);
194
195 // Read the data part's MPM part headers (boundary was read by
196 // DDXParse::intern)
197 read_multipart_headers(rs->get_stream(), "application/octet-stream", dap4_data, data_cid);
198
199 // Now read the data
200 XDRFileUnMarshaller um(rs->get_stream());
201 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end(); i++) {
202 (*i)->deserialize(um, &data);
203 }
204 return;
205 }
206#endif
207
208 case dods_data:
209 default: {
210 // Parse the DDS; throw an exception on error.
211 data.parse(rs->get_stream());
212
213 XDRFileUnMarshaller um(rs->get_stream());
214
215 // Load the DDS with data.
216 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end(); i++) {
217 (*i)->deserialize(um, &data);
218 }
219
220 return;
221 }
222 }
223}
224
225// Barely a parser... This is used when reading from local sources of DODS
226// Data objects. It simulates the important actions of the libwww MIME header
227// parser. Those actions fill in certain fields in the Connect object. jhrg
228// 5/20/97
229//
230// Make sure that this parser reads from data_source without disturbing the
231// information in data_source that follows the MIME header. Since the DDS
232// (which follows the MIME header) is parsed by a flex/bison scanner/parser,
233// make sure to use I/O calls that will mesh with ANSI C I/O calls. In the
234// old GNU libg++, the C++ calls were synchronized with the C calls, but that
235// may no longer be the case. 5/31/99 jhrg
236
249void Connect::parse_mime(Response *rs) {
250 rs->set_version("dods/0.0"); // initial value; for backward compatibility.
251 rs->set_protocol("2.0");
252
253 FILE *data_source = rs->get_stream();
254 string mime = get_next_mime_header(data_source);
255 while (!mime.empty()) {
256 string header, value;
257 parse_mime_header(mime, header, value);
258
259 // Note that this is an ordered list
260 if (header == "content-description:") {
261 DBG(cout << header << ": " << value << endl);
262 rs->set_type(get_description_type(value));
263 }
264 // Use the value of xdods-server only if no other value has been read
265 else if (header == "xdods-server:" && rs->get_version() == "dods/0.0") {
266 DBG(cout << header << ": " << value << endl);
267 rs->set_version(value);
268 }
269 // This trumps 'xdods-server' and 'server'
270 else if (header == "xopendap-server:") {
271 DBG(cout << header << ": " << value << endl);
272 rs->set_version(value);
273 } else if (header == "xdap:") {
274 DBG(cout << header << ": " << value << endl);
275 rs->set_protocol(value);
276 }
277 // Only look for 'server' if no other header supplies this info.
278 else if (rs->get_version() == "dods/0.0" && header == "server:") {
279 DBG(cout << header << ": " << value << endl);
280 rs->set_version(value);
281 }
282
283 mime = get_next_mime_header(data_source);
284 }
285}
286
287// public mfuncs
288
296Connect::Connect(const string &n, string uname, string password) : d_http(0), d_version("unknown"), d_protocol("2.0") {
297 string name = prune_spaces(n);
298
299 // Figure out if the URL starts with 'http', if so, make sure that we
300 // talk to an instance of HTTPConnect.
301 if (name.find("http") == 0) {
302 DBG(cerr << "Connect: The identifier is an http URL" << endl);
303 d_http = new HTTPConnect(RCReader::instance());
304
305 // Find and store any CE given with the URL.
306 string::size_type dotpos = name.find('?');
307 if (dotpos != name.npos) {
308 _URL = name.substr(0, dotpos);
309 string expr = name.substr(dotpos + 1);
310
311 dotpos = expr.find('&');
312 if (dotpos != expr.npos) {
313 _proj = expr.substr(0, dotpos);
314 _sel = expr.substr(dotpos); // XXX includes '&'
315 } else {
316 _proj = expr;
317 _sel = "";
318 }
319 } else {
320 _URL = name;
321 _proj = "";
322 _sel = "";
323 }
324
325 _local = false;
326 } else {
327 DBG(cerr << "Connect: The identifier is a local data source." << endl);
328
329 d_http = 0;
330 _URL = "";
331 _local = true; // local in this case means non-DAP
332 }
333
334 set_credentials(uname, password);
335}
336
337Connect::~Connect() {
338 DBG2(cerr << "Entering the Connect dtor" << endl);
339
340 if (d_http)
341 delete d_http;
342 d_http = 0;
343
344 DBG2(cerr << "Leaving the Connect dtor" << endl);
345}
346
355 string version_url = _URL + ".ver";
356 if (_proj.length() + _sel.length())
357 version_url = version_url + "?" + id2www_ce(_proj + _sel);
358
359 Response *rs = 0;
360 try {
361 rs = d_http->fetch_url(version_url);
362 } catch (Error &e) {
363 delete rs;
364 rs = 0;
365 throw;
366 }
367
368 d_version = rs->get_version();
369 d_protocol = rs->get_protocol();
370
371 delete rs;
372 rs = 0;
373
374 return d_version;
375}
376
389 string version_url = _URL + ".ver";
390 if (_proj.length() + _sel.length())
391 version_url = version_url + "?" + id2www_ce(_proj + _sel);
392
393 Response *rs = 0;
394 try {
395 rs = d_http->fetch_url(version_url);
396 } catch (Error &e) {
397 delete rs;
398 rs = 0;
399 throw;
400 }
401
402 d_version = rs->get_version();
403 d_protocol = rs->get_protocol();
404
405 delete rs;
406 rs = 0;
407
408 return d_protocol;
409}
410
419 string das_url = _URL + ".das";
420 if (_proj.length() + _sel.length())
421 das_url = das_url + "?" + id2www_ce(_proj + _sel);
422
423 Response *rs = 0;
424 try {
425 rs = d_http->fetch_url(das_url);
426 } catch (Error &e) {
427 delete rs;
428 rs = 0;
429 throw;
430 }
431
432 d_version = rs->get_version();
433 d_protocol = rs->get_protocol();
434
435 switch (rs->get_type()) {
436 case dods_error: {
437 Error e;
438 if (!e.parse(rs->get_stream())) {
439 delete rs;
440 rs = 0;
441 throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
442 }
443 delete rs;
444 rs = 0;
445 throw e;
446 }
447
448 case web_error:
449 // We should never get here; a web error should be picked up read_url
450 // (called by fetch_url) and result in a thrown Error object.
451 break;
452
453 case dods_das:
454 default:
455 // DAS::parse throws an exception on error.
456 try {
457 das.parse(rs->get_stream()); // read and parse the das from a file
458 } catch (Error &e) {
459 delete rs;
460 rs = 0;
461 throw;
462 }
463
464 break;
465 }
466
467 delete rs;
468 rs = 0;
469}
470
482 string use_url = _URL + "?" + _proj + _sel;
483 Response *rs = 0;
484 try {
485 rs = d_http->fetch_url(use_url);
486 } catch (Error &e) {
487 delete rs;
488 rs = 0;
489 throw;
490 }
491
492 d_version = rs->get_version();
493 d_protocol = rs->get_protocol();
494
495 switch (rs->get_type()) {
496 case dods_error: {
497 Error e;
498 if (!e.parse(rs->get_stream())) {
499 delete rs;
500 rs = 0;
501 throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
502 }
503 delete rs;
504 rs = 0;
505 throw e;
506 }
507
508 case web_error:
509 // We should never get here; a web error should be picked up read_url
510 // (called by fetch_url) and result in a thrown Error object.
511 break;
512
513 case dods_das:
514 default:
515 // DAS::parse throws an exception on error.
516 try {
517 das.parse(rs->get_stream()); // read and parse the das from a file
518 } catch (Error &e) {
519 delete rs;
520 rs = 0;
521 throw;
522 }
523
524 break;
525 }
526
527 delete rs;
528 rs = 0;
529}
530
544void Connect::request_dds(DDS &dds, string expr) {
545 string proj, sel;
546 string::size_type dotpos = expr.find('&');
547 if (dotpos != expr.npos) {
548 proj = expr.substr(0, dotpos);
549 sel = expr.substr(dotpos);
550 } else {
551 proj = expr;
552 sel = "";
553 }
554
555 string dds_url = _URL + ".dds" + "?" + id2www_ce(_proj + proj + _sel + sel);
556
557 Response *rs = 0;
558 try {
559 rs = d_http->fetch_url(dds_url);
560 } catch (Error &e) {
561 delete rs;
562 rs = 0;
563 throw;
564 }
565
566 d_version = rs->get_version();
567 d_protocol = rs->get_protocol();
568
569 switch (rs->get_type()) {
570 case dods_error: {
571 Error e;
572 if (!e.parse(rs->get_stream())) {
573 delete rs;
574 rs = 0;
575 throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
576 }
577 delete rs;
578 rs = 0;
579 throw e;
580 }
581
582 case web_error:
583 // We should never get here; a web error should be picked up read_url
584 // (called by fetch_url) and result in a thrown Error object.
585 break;
586
587 case dods_dds:
588 default:
589 // DDS::prase throws an exception on error.
590 try {
591 dds.parse(rs->get_stream()); // read and parse the dds from a file
592 } catch (Error &e) {
593 delete rs;
594 rs = 0;
595 throw;
596 }
597 break;
598 }
599
600 delete rs;
601 rs = 0;
602}
603
621 string use_url = _URL + "?" + _proj + _sel;
622 Response *rs = 0;
623 try {
624 rs = d_http->fetch_url(use_url);
625 } catch (Error &e) {
626 delete rs;
627 rs = 0;
628 throw;
629 }
630
631 d_version = rs->get_version();
632 d_protocol = rs->get_protocol();
633
634 switch (rs->get_type()) {
635 case dods_error: {
636 Error e;
637 if (!e.parse(rs->get_stream())) {
638 delete rs;
639 rs = 0;
640 throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
641 }
642 delete rs;
643 rs = 0;
644 throw e;
645 }
646
647 case web_error:
648 // We should never get here; a web error should be picked up read_url
649 // (called by fetch_url) and result in a thrown Error object.
650 break;
651
652 case dods_dds:
653 default:
654 // DDS::prase throws an exception on error.
655 try {
656 dds.parse(rs->get_stream()); // read and parse the dds from a file
657 } catch (Error &e) {
658 delete rs;
659 rs = 0;
660 throw;
661 }
662 break;
663 }
664
665 delete rs;
666 rs = 0;
667}
668
680void Connect::request_ddx(DDS &dds, string expr) {
681 string proj, sel;
682 string::size_type dotpos = expr.find('&');
683 if (dotpos != expr.npos) {
684 proj = expr.substr(0, dotpos);
685 sel = expr.substr(dotpos);
686 } else {
687 proj = expr;
688 sel = "";
689 }
690
691 string ddx_url = _URL + ".ddx" + "?" + id2www_ce(_proj + proj + _sel + sel);
692
693 Response *rs = 0;
694 try {
695 rs = d_http->fetch_url(ddx_url);
696 } catch (Error &e) {
697 delete rs;
698 throw;
699 }
700
701 d_version = rs->get_version();
702 d_protocol = rs->get_protocol();
703
704 switch (rs->get_type()) {
705 case dods_error: {
706 Error e;
707 if (!e.parse(rs->get_stream())) {
708 delete rs;
709 rs = 0;
710 throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
711 }
712 delete rs;
713 throw e;
714 }
715
716 case web_error:
717 // We should never get here; a web error should be picked up read_url
718 // (called by fetch_url) and result in a thrown Error object.
719 break;
720
721 case dods_ddx:
722 try {
723 string blob;
724
725 DDXParser ddxp(dds.get_factory());
726 ddxp.intern_stream(rs->get_stream(), &dds, blob);
727 } catch (Error &e) {
728 delete rs;
729 throw;
730 }
731 break;
732
733 default:
734 ObjectType ot = rs->get_type();
735 delete rs;
736 throw Error("Invalid response type when requesting a DDX response. Response type: " + long_to_string(ot));
737 }
738
739 delete rs;
740}
741
745 string use_url = _URL + "?" + _proj + _sel;
746
747 Response *rs = 0;
748 try {
749 rs = d_http->fetch_url(use_url);
750 } catch (Error &e) {
751 delete rs;
752 throw;
753 }
754
755 d_version = rs->get_version();
756 d_protocol = rs->get_protocol();
757
758 switch (rs->get_type()) {
759 case dods_error: {
760 Error e;
761 if (!e.parse(rs->get_stream())) {
762 delete rs;
763 throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
764 }
765 delete rs;
766 throw e;
767 }
768
769 case web_error:
770 // We should never get here; a web error should be picked up read_url
771 // (called by fetch_url) and result in a thrown Error object.
772 delete rs;
773 throw InternalErr(__FILE__, __LINE__, "Web error.");
774
775 case dods_ddx:
776 try {
777 string blob;
778
779 DDXParser ddxp(dds.get_factory());
780 ddxp.intern_stream(rs->get_stream(), &dds, blob);
781 } catch (Error &e) {
782 delete rs;
783 throw;
784 }
785 break;
786
787 default: {
788 ObjectType ot = rs->get_type();
789 delete rs;
790
791 throw Error("Invalid response type when requesting a DDX response. Response type: " + long_to_string(ot));
792 }
793 }
794
795 delete rs;
796}
797
813void Connect::request_data(DataDDS &data, string expr) {
814 string proj, sel;
815 string::size_type dotpos = expr.find('&');
816 if (dotpos != expr.npos) {
817 proj = expr.substr(0, dotpos);
818 sel = expr.substr(dotpos);
819 } else {
820 proj = expr;
821 sel = "";
822 }
823
824 string data_url = _URL + ".dods?" + id2www_ce(_proj + proj + _sel + sel);
825
826 Response *rs = 0;
827 // We need to catch Error exceptions to ensure calling close_output.
828 try {
829 rs = d_http->fetch_url(data_url);
830
831 d_version = rs->get_version();
832 d_protocol = rs->get_protocol();
833
834 process_data(data, rs);
835 delete rs;
836 rs = 0;
837 } catch (Error &e) {
838 delete rs;
839 rs = 0;
840 throw;
841 }
842}
843
862 string use_url = _URL + "?" + _proj + _sel;
863 Response *rs = 0;
864 // We need to catch Error exceptions to ensure calling close_output.
865 try {
866 rs = d_http->fetch_url(use_url);
867
868 d_version = rs->get_version();
869 d_protocol = rs->get_protocol();
870
871 process_data(data, rs);
872 delete rs;
873 rs = 0;
874 } catch (Error &e) {
875 delete rs;
876 rs = 0;
877 throw;
878 }
879}
880
881// FIXME Unused?
882void Connect::request_data_ddx(DataDDS &data, string expr) {
883 string proj, sel;
884 string::size_type dotpos = expr.find('&');
885 if (dotpos != expr.npos) {
886 proj = expr.substr(0, dotpos);
887 sel = expr.substr(dotpos);
888 } else {
889 proj = expr;
890 sel = "";
891 }
892
893 string data_url = _URL + ".dap?" + id2www_ce(_proj + proj + _sel + sel);
894
895 Response *rs = 0;
896 // We need to catch Error exceptions to ensure calling close_output.
897 try {
898 rs = d_http->fetch_url(data_url);
899
900 d_version = rs->get_version();
901 d_protocol = rs->get_protocol();
902
903 process_data(data, rs);
904 delete rs;
905 rs = 0;
906 } catch (Error &e) {
907 delete rs;
908 rs = 0;
909 throw;
910 }
911}
912
913// FIXME Unused?
914void Connect::request_data_ddx_url(DataDDS &data) {
915 string use_url = _URL + "?" + _proj + _sel;
916 Response *rs = 0;
917 // We need to catch Error exceptions to ensure calling close_output.
918 try {
919 rs = d_http->fetch_url(use_url);
920
921 d_version = rs->get_version();
922 d_protocol = rs->get_protocol();
923
924 process_data(data, rs);
925 delete rs;
926 rs = 0;
927 } catch (Error &e) {
928 delete rs;
929 rs = 0;
930 throw;
931 }
932}
933
946
948 if (!rs)
949 throw InternalErr(__FILE__, __LINE__, "Response object is null.");
950
951 // Read from data_source and parse the MIME headers specific to DAP2/4.
952 parse_mime(rs);
953
954 read_data_no_mime(data, rs);
955}
956void Connect::read_data(DDS &data, Response *rs) {
957 if (!rs)
958 throw InternalErr(__FILE__, __LINE__, "Response object is null.");
959
960 // Read from data_source and parse the MIME headers specific to DAP2/4.
961 parse_mime(rs);
962
963 read_data_no_mime(data, rs);
964}
965
966// This function looks at the input stream and makes its best guess at what
967// lies in store for downstream processing code. Definitely heuristic.
968// Assumptions:
969// #1 The current file position is past any MIME headers (if they were present).
970// #2 We must reset the FILE* position to the start of the DDS or DDX headers
971static void divine_type_information(Response *rs) {
972 // Consume whitespace
973 int c = getc(rs->get_stream());
974 while (!feof(rs->get_stream()) && !ferror(rs->get_stream()) && isspace(c)) {
975 c = getc(rs->get_stream());
976 }
977
978 if (ferror(rs->get_stream()))
979 throw Error("Error reading response type information: " + string(strerror(errno)));
980 if (feof(rs->get_stream()))
981 throw Error("Error reading response type information: Found EOF");
982
983 // The heuristic here is that a DataDDX is a multipart MIME document and
984 // The first non space character found after the headers is the start of
985 // the first part which looks like '--<boundary>' while a DataDDS starts
986 // with a DDS (;Dataset {' ...). I take into account that our parsers have
987 // accepted both 'Dataset' and 'dataset' for a long time.
988 switch (c) {
989 case '-':
990 rs->set_type(dods_data_ddx);
991 break;
992 case 'D':
993 case 'd':
994 rs->set_type(dods_data);
995 break;
996 default:
997 throw InternalErr(__FILE__, __LINE__, "Could not determine type of response object in stream.");
998 }
999
1000 ungetc(c, rs->get_stream());
1001}
1002
1016 if (rs->get_type() == unknown_type)
1017 divine_type_information(rs);
1018
1019 switch (rs->get_type()) {
1020 case dods_data:
1021 d_version = rs->get_version();
1022 d_protocol = rs->get_protocol();
1023 process_data(data, rs);
1024 break;
1025 case dods_data_ddx:
1026 process_data(data, rs);
1027 d_version = rs->get_version();
1028 d_protocol = data.get_protocol();
1029 break;
1030 default:
1031 throw InternalErr(__FILE__, __LINE__, "Should have been a DataDDS or DataDDX.");
1032 }
1033}
1034void Connect::read_data_no_mime(DDS &data, Response *rs) {
1035 if (rs->get_type() == unknown_type)
1036 divine_type_information(rs);
1037
1038 switch (rs->get_type()) {
1039 case dods_data:
1040 d_version = rs->get_version();
1041 d_protocol = rs->get_protocol();
1042 process_data(data, rs);
1043 break;
1044 case dods_data_ddx:
1045 process_data(data, rs);
1046 d_version = rs->get_version();
1047 // TODO should check to see if this hack is a correct replacement
1048 // for get_protocol from DataDDS
1049 d_protocol = data.get_dap_version();
1050 break;
1051 default:
1052 throw InternalErr(__FILE__, __LINE__, "Should have been a DataDDS or DataDDX.");
1053 }
1054}
1055
1056bool Connect::is_local() { return _local; }
1057
1074string Connect::URL(bool ce) {
1075 if (_local)
1076 throw InternalErr(__FILE__, __LINE__, "URL(): This call is only valid for a DAP data source.");
1077
1078 if (ce)
1079 return _URL + "?" + _proj + _sel;
1080 else
1081 return _URL;
1082}
1083
1092string Connect::CE() {
1093 if (_local)
1094 throw InternalErr(__FILE__, __LINE__, "CE(): This call is only valid for a DAP data source.");
1095
1096 return _proj + _sel;
1097}
1098
1104void Connect::set_credentials(string u, string p) {
1105 if (d_http)
1106 d_http->set_credentials(u, p);
1107}
1108
1113 if (d_http)
1114 d_http->set_accept_deflate(deflate);
1115}
1116
1122void Connect::set_xdap_protocol(int major, int minor) {
1123 if (d_http)
1124 d_http->set_xdap_protocol(major, minor);
1125}
1126
1131 if (d_http)
1132 d_http->set_cache_enabled(cache);
1133}
1134
1135bool Connect::is_cache_enabled() {
1136 bool status;
1137 DBG(cerr << "Entering is_cache_enabled (" << hex << d_http << dec << ")... ");
1138 if (d_http)
1139 status = d_http->is_cache_enabled();
1140 else
1141 status = false;
1142 DBGN(cerr << "exiting" << endl);
1143 return status;
1144}
1145
1146} // namespace libdap
virtual void request_dds_url(DDS &dds)
Get the DDS from a server.
Definition Connect.cc:620
virtual string CE()
Get the Connect's constraint expression.
Definition Connect.cc:1092
void set_accept_deflate(bool deflate)
Definition Connect.cc:1112
void set_cache_enabled(bool enabled)
Definition Connect.cc:1130
virtual void request_ddx(DDS &dds, string expr="")
Get the DDX from a server.
Definition Connect.cc:680
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:1015
void set_xdap_protocol(int major, int minor)
Definition Connect.cc:1122
virtual string URL(bool CE=true)
Get the object's URL.
Definition Connect.cc:1074
virtual void request_data(DataDDS &data, string expr="")
Get the DAS from a server.
Definition Connect.cc:813
virtual void request_das(DAS &das)
Get the DAS from a server.
Definition Connect.cc:418
void set_credentials(string u, string p)
Set the credentials for responding to challenges while dereferencing URLs.
Definition Connect.cc:1104
virtual void request_ddx_url(DDS &dds)
The 'url' version of request_ddx.
Definition Connect.cc:744
virtual string request_protocol()
Definition Connect.cc:388
virtual void request_dds(DDS &dds, string expr="")
Get the DDS from a server.
Definition Connect.cc:544
virtual void request_das_url(DAS &das)
Get the DAS from a server.
Definition Connect.cc:481
virtual string request_version()
Definition Connect.cc:354
virtual void request_data_url(DataDDS &data)
Get the DAS from a server.
Definition Connect.cc:861
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:947
Hold attribute data for a DAP2 dataset.
Definition DAS.h:119
virtual void parse(string fname)
Reads a DAS from the named file.
Definition DAS.cc:213
void parse(string fname)
Parse a DDS from a file with the given d_name.
Definition DDS.cc:740
BaseTypeFactory * get_factory() const
Definition DDS.h:231
void intern_stream(FILE *in, DDS *dds, string &cid, const string &boundary="")
Read the DDX from a stream instead of a file.
Holds a DAP2 DDS.
Definition DataDDS.h:76
A class for error processing.
Definition Error.h:92
bool parse(FILE *fp)
Parse an Error object.
Definition Error.cc:106
A class for software fault reporting.
Definition InternalErr.h:61
top level DAP object to house generic methods
Definition AISConnect.cc:30
string read_multipart_boundary(FILE *in, const string &boundary)
Definition mime_util.cc:893
ObjectType get_description_type(const string &value)
Definition mime_util.cc:309
string cid_to_header_value(const string &cid)
void parse_mime_header(const string &header, string &name, string &value)
Definition mime_util.cc:848
string prune_spaces(const string &name)
Definition util.cc:451
void read_multipart_headers(FILE *in, const string &content_type, const ObjectType object_type, const string &cid)
Definition mime_util.cc:935
string id2www_ce(string in, const string &allowable)
Definition escaping.cc:166
ObjectType
The type of object in the stream coming from the data server.
Definition ObjectType.h:57
string get_next_mime_header(FILE *in)
Definition mime_util.cc:777