libdap Updated for version 3.20.10
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 <cstring>
41#include <cerrno>
42
43#include <fstream>
44#include <algorithm>
45
46#include "debug.h"
47#include "DataDDS.h"
48#include "Connect.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 "fdiostream.h"
56#include "XDRStreamUnMarshaller.h"
57#endif
58#include "mime_util.h"
59
60using std::cerr;
61using std::endl;
62using std::ifstream;
63using std::ofstream;
64using std::min;
65
66namespace libdap {
67
70void Connect::process_data(DataDDS &data, Response *rs)
71{
72 DBG(cerr << "Entering Connect::process_data" << endl);
73
74 data.set_version(rs->get_version());
75 data.set_protocol(rs->get_protocol());
76
77 DBG(cerr << "Entering process_data: d_stream = " << rs << endl);
78 switch (rs->get_type()) {
79 case dods_error: {
80 Error e;
81 if (!e.parse(rs->get_stream()))
82 throw InternalErr(__FILE__, __LINE__, "Could not parse the Error object returned by the server!");
83 throw e;
84 }
85
86 case web_error:
87 // Web errors (those reported in the return document's MIME header)
88 // are processed by the WWW library.
89 throw InternalErr(__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{
154 DBG(cerr << "Entering Connect::process_data" << endl);
155
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__, "Could not parse the Error object returned by the server!");
164 throw e;
165 }
166
167 case web_error:
168 // Web errors (those reported in the return document's MIME header)
169 // are processed by the WWW library.
170 throw InternalErr(__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{
251 rs->set_version("dods/0.0"); // initial value; for backward compatibility.
252 rs->set_protocol("2.0");
253
254 FILE *data_source = rs->get_stream();
255 string mime = get_next_mime_header(data_source);
256 while (!mime.empty()) {
257 string header, value;
258 parse_mime_header(mime, header, value);
259
260 // Note that this is an ordered list
261 if (header == "content-description:") {
262 DBG(cout << header << ": " << value << endl);
263 rs->set_type(get_description_type(value));
264 }
265 // Use the value of xdods-server only if no other value has been read
266 else if (header == "xdods-server:" && rs->get_version() == "dods/0.0") {
267 DBG(cout << header << ": " << value << endl);
268 rs->set_version(value);
269 }
270 // This trumps 'xdods-server' and 'server'
271 else if (header == "xopendap-server:") {
272 DBG(cout << header << ": " << value << endl);
273 rs->set_version(value);
274 }
275 else if (header == "xdap:") {
276 DBG(cout << header << ": " << value << endl);
277 rs->set_protocol(value);
278 }
279 // Only look for 'server' if no other header supplies this info.
280 else if (rs->get_version() == "dods/0.0" && header == "server:") {
281 DBG(cout << header << ": " << value << endl);
282 rs->set_version(value);
283 }
284
285 mime = get_next_mime_header(data_source);
286 }
287}
288
289// public mfuncs
290
298Connect::Connect(const string &n, string uname, string password) :
299 d_http(0), d_version("unknown"), d_protocol("2.0")
300{
301 string name = prune_spaces(n);
302
303 // Figure out if the URL starts with 'http', if so, make sure that we
304 // talk to an instance of HTTPConnect.
305 if (name.find("http") == 0) {
306 DBG(cerr << "Connect: The identifier is an http URL" << endl);
307 d_http = new HTTPConnect(RCReader::instance());
308
309 // Find and store any CE given with the URL.
310 string::size_type dotpos = name.find('?');
311 if (dotpos != name.npos) {
312 _URL = name.substr(0, dotpos);
313 string expr = name.substr(dotpos + 1);
314
315 dotpos = expr.find('&');
316 if (dotpos != expr.npos) {
317 _proj = expr.substr(0, dotpos);
318 _sel = expr.substr(dotpos); // XXX includes '&'
319 }
320 else {
321 _proj = expr;
322 _sel = "";
323 }
324 }
325 else {
326 _URL = name;
327 _proj = "";
328 _sel = "";
329 }
330
331 _local = false;
332 }
333 else {
334 DBG(cerr << "Connect: The identifier is a local data source." << endl);
335
336 d_http = 0;
337 _URL = "";
338 _local = true; // local in this case means non-DAP
339 }
340
341 set_credentials(uname, password);
342}
343
344Connect::~Connect()
345{
346 DBG2(cerr << "Entering the Connect dtor" << endl);
347
348 if (d_http)
349 delete d_http;
350 d_http = 0;
351
352 DBG2(cerr << "Leaving the Connect dtor" << endl);
353}
354
363{
364 string version_url = _URL + ".ver";
365 if (_proj.length() + _sel.length())
366 version_url = version_url + "?" + id2www_ce(_proj + _sel);
367
368 Response *rs = 0;
369 try {
370 rs = d_http->fetch_url(version_url);
371 }
372 catch (Error &e) {
373 delete rs;
374 rs = 0;
375 throw;
376 }
377
378 d_version = rs->get_version();
379 d_protocol = rs->get_protocol();
380
381 delete rs;
382 rs = 0;
383
384 return d_version;
385}
386
399{
400 string version_url = _URL + ".ver";
401 if (_proj.length() + _sel.length())
402 version_url = version_url + "?" + id2www_ce(_proj + _sel);
403
404 Response *rs = 0;
405 try {
406 rs = d_http->fetch_url(version_url);
407 }
408 catch (Error &e) {
409 delete rs;
410 rs = 0;
411 throw;
412 }
413
414 d_version = rs->get_version();
415 d_protocol = rs->get_protocol();
416
417 delete rs;
418 rs = 0;
419
420 return d_protocol;
421}
422
431{
432 string das_url = _URL + ".das";
433 if (_proj.length() + _sel.length())
434 das_url = das_url + "?" + id2www_ce(_proj + _sel);
435
436 Response *rs = 0;
437 try {
438 rs = d_http->fetch_url(das_url);
439 }
440 catch (Error &e) {
441 delete rs;
442 rs = 0;
443 throw;
444 }
445
446 d_version = rs->get_version();
447 d_protocol = rs->get_protocol();
448
449 switch (rs->get_type()) {
450 case dods_error: {
451 Error e;
452 if (!e.parse(rs->get_stream())) {
453 delete rs;
454 rs = 0;
455 throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
456 }
457 delete rs;
458 rs = 0;
459 throw e;
460 }
461
462 case web_error:
463 // We should never get here; a web error should be picked up read_url
464 // (called by fetch_url) and result in a thrown Error object.
465 break;
466
467 case dods_das:
468 default:
469 // DAS::parse throws an exception on error.
470 try {
471 das.parse(rs->get_stream()); // read and parse the das from a file
472 }
473 catch (Error &e) {
474 delete rs;
475 rs = 0;
476 throw;
477 }
478
479 break;
480 }
481
482 delete rs;
483 rs = 0;
484}
485
497{
498 string use_url = _URL + "?" + _proj + _sel;
499 Response *rs = 0;
500 try {
501 rs = d_http->fetch_url(use_url);
502 }
503 catch (Error &e) {
504 delete rs;
505 rs = 0;
506 throw;
507 }
508
509 d_version = rs->get_version();
510 d_protocol = rs->get_protocol();
511
512 switch (rs->get_type()) {
513 case dods_error: {
514 Error e;
515 if (!e.parse(rs->get_stream())) {
516 delete rs;
517 rs = 0;
518 throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
519 }
520 delete rs;
521 rs = 0;
522 throw e;
523 }
524
525 case web_error:
526 // We should never get here; a web error should be picked up read_url
527 // (called by fetch_url) and result in a thrown Error object.
528 break;
529
530 case dods_das:
531 default:
532 // DAS::parse throws an exception on error.
533 try {
534 das.parse(rs->get_stream()); // read and parse the das from a file
535 }
536 catch (Error &e) {
537 delete rs;
538 rs = 0;
539 throw;
540 }
541
542 break;
543 }
544
545 delete rs;
546 rs = 0;
547}
548
562void Connect::request_dds(DDS &dds, string expr)
563{
564 string proj, sel;
565 string::size_type dotpos = expr.find('&');
566 if (dotpos != expr.npos) {
567 proj = expr.substr(0, dotpos);
568 sel = expr.substr(dotpos);
569 }
570 else {
571 proj = expr;
572 sel = "";
573 }
574
575 string dds_url = _URL + ".dds" + "?" + id2www_ce(_proj + proj + _sel + sel);
576
577 Response *rs = 0;
578 try {
579 rs = d_http->fetch_url(dds_url);
580 }
581 catch (Error &e) {
582 delete rs;
583 rs = 0;
584 throw;
585 }
586
587 d_version = rs->get_version();
588 d_protocol = rs->get_protocol();
589
590 switch (rs->get_type()) {
591 case dods_error: {
592 Error e;
593 if (!e.parse(rs->get_stream())) {
594 delete rs;
595 rs = 0;
596 throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
597 }
598 delete rs;
599 rs = 0;
600 throw e;
601 }
602
603 case web_error:
604 // We should never get here; a web error should be picked up read_url
605 // (called by fetch_url) and result in a thrown Error object.
606 break;
607
608 case dods_dds:
609 default:
610 // DDS::prase throws an exception on error.
611 try {
612 dds.parse(rs->get_stream()); // read and parse the dds from a file
613 }
614 catch (Error &e) {
615 delete rs;
616 rs = 0;
617 throw;
618 }
619 break;
620 }
621
622 delete rs;
623 rs = 0;
624}
625
643{
644 string use_url = _URL + "?" + _proj + _sel;
645 Response *rs = 0;
646 try {
647 rs = d_http->fetch_url(use_url);
648 }
649 catch (Error &e) {
650 delete rs;
651 rs = 0;
652 throw;
653 }
654
655 d_version = rs->get_version();
656 d_protocol = rs->get_protocol();
657
658 switch (rs->get_type()) {
659 case dods_error: {
660 Error e;
661 if (!e.parse(rs->get_stream())) {
662 delete rs;
663 rs = 0;
664 throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
665 }
666 delete rs;
667 rs = 0;
668 throw e;
669 }
670
671 case web_error:
672 // We should never get here; a web error should be picked up read_url
673 // (called by fetch_url) and result in a thrown Error object.
674 break;
675
676 case dods_dds:
677 default:
678 // DDS::prase throws an exception on error.
679 try {
680 dds.parse(rs->get_stream()); // read and parse the dds from a file
681 }
682 catch (Error &e) {
683 delete rs;
684 rs = 0;
685 throw;
686 }
687 break;
688 }
689
690 delete rs;
691 rs = 0;
692}
693
705void Connect::request_ddx(DDS &dds, string expr)
706{
707 string proj, sel;
708 string::size_type dotpos = expr.find('&');
709 if (dotpos != expr.npos) {
710 proj = expr.substr(0, dotpos);
711 sel = expr.substr(dotpos);
712 }
713 else {
714 proj = expr;
715 sel = "";
716 }
717
718 string ddx_url = _URL + ".ddx" + "?" + id2www_ce(_proj + proj + _sel + sel);
719
720 Response *rs = 0;
721 try {
722 rs = d_http->fetch_url(ddx_url);
723 }
724 catch (Error &e) {
725 delete rs;
726 throw;
727 }
728
729 d_version = rs->get_version();
730 d_protocol = rs->get_protocol();
731
732 switch (rs->get_type()) {
733 case dods_error: {
734 Error e;
735 if (!e.parse(rs->get_stream())) {
736 delete rs;
737 rs = 0;
738 throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
739 }
740 delete rs;
741 throw e;
742 }
743
744 case web_error:
745 // We should never get here; a web error should be picked up read_url
746 // (called by fetch_url) and result in a thrown Error object.
747 break;
748
749 case dods_ddx:
750 try {
751 string blob;
752
753 DDXParser ddxp(dds.get_factory());
754 ddxp.intern_stream(rs->get_stream(), &dds, blob);
755 }
756 catch (Error &e) {
757 delete rs;
758 throw;
759 }
760 break;
761
762 default:
763 ObjectType ot = rs->get_type();
764 delete rs;
765 throw Error("Invalid response type when requesting a DDX response. Response type: " + long_to_string(ot));
766 }
767
768 delete rs;
769}
770
774{
775 string use_url = _URL + "?" + _proj + _sel;
776
777 Response *rs = 0;
778 try {
779 rs = d_http->fetch_url(use_url);
780 }
781 catch (Error &e) {
782 delete rs;
783 throw;
784 }
785
786 d_version = rs->get_version();
787 d_protocol = rs->get_protocol();
788
789 switch (rs->get_type()) {
790 case dods_error: {
791 Error e;
792 if (!e.parse(rs->get_stream())) {
793 delete rs;
794 throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
795 }
796 delete rs;
797 throw e;
798 }
799
800 case web_error:
801 // We should never get here; a web error should be picked up read_url
802 // (called by fetch_url) and result in a thrown Error object.
803 delete rs;
804 throw InternalErr(__FILE__, __LINE__, "Web error.");
805
806 case dods_ddx:
807 try {
808 string blob;
809
810 DDXParser ddxp(dds.get_factory());
811 ddxp.intern_stream(rs->get_stream(), &dds, blob);
812 }
813 catch (Error &e) {
814 delete rs;
815 throw;
816 }
817 break;
818
819 default: {
820 ObjectType ot = rs->get_type();
821 delete rs;
822
823 throw Error("Invalid response type when requesting a DDX response. Response type: " + long_to_string(ot));
824 }
825 }
826
827 delete rs;
828}
829
845void Connect::request_data(DataDDS &data, string expr)
846{
847 string proj, sel;
848 string::size_type dotpos = expr.find('&');
849 if (dotpos != expr.npos) {
850 proj = expr.substr(0, dotpos);
851 sel = expr.substr(dotpos);
852 }
853 else {
854 proj = expr;
855 sel = "";
856 }
857
858 string data_url = _URL + ".dods?" + id2www_ce(_proj + proj + _sel + sel);
859
860 Response *rs = 0;
861 // We need to catch Error exceptions to ensure calling close_output.
862 try {
863 rs = d_http->fetch_url(data_url);
864
865 d_version = rs->get_version();
866 d_protocol = rs->get_protocol();
867
868 process_data(data, rs);
869 delete rs;
870 rs = 0;
871 }
872 catch (Error &e) {
873 delete rs;
874 rs = 0;
875 throw;
876 }
877}
878
897{
898 string use_url = _URL + "?" + _proj + _sel;
899 Response *rs = 0;
900 // We need to catch Error exceptions to ensure calling close_output.
901 try {
902 rs = d_http->fetch_url(use_url);
903
904 d_version = rs->get_version();
905 d_protocol = rs->get_protocol();
906
907 process_data(data, rs);
908 delete rs;
909 rs = 0;
910 }
911 catch (Error &e) {
912 delete rs;
913 rs = 0;
914 throw;
915 }
916}
917
918// FIXME Unused?
919void Connect::request_data_ddx(DataDDS &data, string expr)
920{
921 string proj, sel;
922 string::size_type dotpos = expr.find('&');
923 if (dotpos != expr.npos) {
924 proj = expr.substr(0, dotpos);
925 sel = expr.substr(dotpos);
926 }
927 else {
928 proj = expr;
929 sel = "";
930 }
931
932 string data_url = _URL + ".dap?" + id2www_ce(_proj + proj + _sel + sel);
933
934 Response *rs = 0;
935 // We need to catch Error exceptions to ensure calling close_output.
936 try {
937 rs = d_http->fetch_url(data_url);
938
939 d_version = rs->get_version();
940 d_protocol = rs->get_protocol();
941
942 process_data(data, rs);
943 delete rs;
944 rs = 0;
945 }
946 catch (Error &e) {
947 delete rs;
948 rs = 0;
949 throw;
950 }
951}
952
953// FIXME Unused?
954void Connect::request_data_ddx_url(DataDDS &data)
955{
956 string use_url = _URL + "?" + _proj + _sel;
957 Response *rs = 0;
958 // We need to catch Error exceptions to ensure calling close_output.
959 try {
960 rs = d_http->fetch_url(use_url);
961
962 d_version = rs->get_version();
963 d_protocol = rs->get_protocol();
964
965 process_data(data, rs);
966 delete rs;
967 rs = 0;
968 }
969 catch (Error &e) {
970 delete rs;
971 rs = 0;
972 throw;
973 }
974}
975
990{
991 if (!rs)
992 throw InternalErr(__FILE__, __LINE__, "Response object is null.");
993
994 // Read from data_source and parse the MIME headers specific to DAP2/4.
995 parse_mime(rs);
996
997 read_data_no_mime(data, rs);
998}
999void
1001{
1002 if (!rs)
1003 throw InternalErr(__FILE__, __LINE__, "Response object is null.");
1004
1005 // Read from data_source and parse the MIME headers specific to DAP2/4.
1006 parse_mime(rs);
1007
1008 read_data_no_mime(data, rs);
1009}
1010
1011// This function looks at the input stream and makes its best guess at what
1012// lies in store for downstream processing code. Definitely heuristic.
1013// Assumptions:
1014// #1 The current file position is past any MIME headers (if they were present).
1015// #2 We must reset the FILE* position to the start of the DDS or DDX headers
1016static void divine_type_information(Response *rs)
1017{
1018 // Consume whitespace
1019 int c = getc(rs->get_stream());
1020 while (!feof(rs->get_stream()) && !ferror(rs->get_stream()) && isspace(c)) {
1021 c = getc(rs->get_stream());
1022 }
1023
1024
1025 if (ferror(rs->get_stream()))
1026 throw Error("Error reading response type information: " + string(strerror(errno)));
1027 if (feof(rs->get_stream()))
1028 throw Error("Error reading response type information: Found EOF");
1029
1030 // The heuristic here is that a DataDDX is a multipart MIME document and
1031 // The first non space character found after the headers is the start of
1032 // the first part which looks like '--<boundary>' while a DataDDS starts
1033 // with a DDS (;Dataset {' ...). I take into account that our parsers have
1034 // accepted both 'Dataset' and 'dataset' for a long time.
1035 switch (c) {
1036 case '-':
1037 rs->set_type(dods_data_ddx);
1038 break;
1039 case 'D':
1040 case 'd':
1041 rs->set_type(dods_data);
1042 break;
1043 default:
1044 throw InternalErr(__FILE__, __LINE__, "Could not determine type of response object in stream.");
1045 }
1046
1047 ungetc(c, rs->get_stream());
1048}
1049
1063{
1064 if (rs->get_type() == unknown_type)
1065 divine_type_information(rs);
1066
1067 switch (rs->get_type()) {
1068 case dods_data:
1069 d_version = rs->get_version();
1070 d_protocol = rs->get_protocol();
1071 process_data(data, rs);
1072 break;
1073 case dods_data_ddx:
1074 process_data(data, rs);
1075 d_version = rs->get_version();
1076 d_protocol = data.get_protocol();
1077 break;
1078 default:
1079 throw InternalErr(__FILE__, __LINE__, "Should have been a DataDDS or DataDDX.");
1080 }
1081}
1083{
1084 if (rs->get_type() == unknown_type)
1085 divine_type_information(rs);
1086
1087 switch (rs->get_type()) {
1088 case dods_data:
1089 d_version = rs->get_version();
1090 d_protocol = rs->get_protocol();
1091 process_data(data, rs);
1092 break;
1093 case dods_data_ddx:
1094 process_data(data, rs);
1095 d_version = rs->get_version();
1096 // TODO should check to see if this hack is a correct replacement
1097 // for get_protocol from DataDDS
1098 d_protocol = data.get_dap_version();
1099 break;
1100 default:
1101 throw InternalErr(__FILE__, __LINE__, "Should have been a DataDDS or DataDDX.");
1102 }
1103}
1104
1105bool
1106Connect::is_local()
1107{
1108 return _local;
1109}
1110
1127string Connect::URL(bool ce)
1128{
1129 if (_local)
1130 throw InternalErr(__FILE__, __LINE__, "URL(): This call is only valid for a DAP data source.");
1131
1132 if (ce)
1133 return _URL + "?" + _proj + _sel;
1134 else
1135 return _URL;
1136}
1137
1147{
1148 if (_local)
1149 throw InternalErr(__FILE__, __LINE__, "CE(): This call is only valid for a DAP data source.");
1150
1151 return _proj + _sel;
1152}
1153
1159void Connect::set_credentials(string u, string p)
1160{
1161 if (d_http)
1162 d_http->set_credentials(u, p);
1163}
1164
1169{
1170 if (d_http)
1171 d_http->set_accept_deflate(deflate);
1172}
1173
1179void Connect::set_xdap_protocol(int major, int minor)
1180{
1181 if (d_http)
1182 d_http->set_xdap_protocol(major, minor);
1183}
1184
1189{
1190 if (d_http)
1191 d_http->set_cache_enabled(cache);
1192}
1193
1194bool Connect::is_cache_enabled()
1195{
1196 bool status;
1197 DBG(cerr << "Entering is_cache_enabled (" << hex << d_http << dec
1198 << ")... ");
1199 if (d_http)
1200 status = d_http->is_cache_enabled();
1201 else
1202 status = false;
1203 DBGN(cerr << "exiting" << endl);
1204 return status;
1205}
1206
1207} // namespace libdap
virtual void request_dds_url(DDS &dds)
Get the DDS from a server.
Definition Connect.cc:642
virtual string CE()
Get the Connect's constraint expression.
Definition Connect.cc:1146
void set_accept_deflate(bool deflate)
Definition Connect.cc:1168
void set_cache_enabled(bool enabled)
Definition Connect.cc:1188
virtual void request_ddx(DDS &dds, string expr="")
Get the DDX from a server.
Definition Connect.cc:705
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:1062
void set_xdap_protocol(int major, int minor)
Definition Connect.cc:1179
virtual string URL(bool CE=true)
Get the object's URL.
Definition Connect.cc:1127
virtual void request_data(DataDDS &data, string expr="")
Get the DAS from a server.
Definition Connect.cc:845
virtual void request_das(DAS &das)
Get the DAS from a server.
Definition Connect.cc:430
void set_credentials(string u, string p)
Set the credentials for responding to challenges while dereferencing URLs.
Definition Connect.cc:1159
virtual void request_ddx_url(DDS &dds)
The 'url' version of request_ddx.
Definition Connect.cc:773
virtual string request_protocol()
Definition Connect.cc:398
virtual void request_dds(DDS &dds, string expr="")
Get the DDS from a server.
Definition Connect.cc:562
virtual void request_das_url(DAS &das)
Get the DAS from a server.
Definition Connect.cc:496
virtual string request_version()
Definition Connect.cc:362
virtual void request_data_url(DataDDS &data)
Get the DAS from a server.
Definition Connect.cc:896
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:989
Hold attribute data for a DAP2 dataset.
Definition DAS.h:122
void parse(string fname)
Parse a DDS from a file with the given d_name.
Definition DDS.cc:843
BaseTypeFactory * get_factory() const
Definition DDS.h:233
Holds a DAP2 DDS.
Definition DataDDS.h:78
A class for error processing.
Definition Error.h:94
void set_accept_deflate(bool defalte)
HTTPResponse * fetch_url(const string &url)
void set_credentials(const string &u, const string &p)
void set_cache_enabled(bool enabled)
void set_xdap_protocol(int major, int minor)
A class for software fault reporting.
Definition InternalErr.h:65
top level DAP object to house generic methods
string read_multipart_boundary(FILE *in, const string &boundary)
Definition mime_util.cc:957
ObjectType get_description_type(const string &value)
Definition mime_util.cc:337
string cid_to_header_value(const string &cid)
void parse_mime_header(const string &header, string &name, string &value)
Definition mime_util.cc:910
string prune_spaces(const string &name)
Definition util.cc:459
void read_multipart_headers(FILE *in, const string &content_type, const ObjectType object_type, const string &cid)
string id2www_ce(string in, const string &allowable)
Definition escaping.cc:178
ObjectType
The type of object in the stream coming from the data server.
Definition ObjectType.h:58
string get_next_mime_header(FILE *in)
Definition mime_util.cc:836