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