libdap++  Updated for version 3.14.0
D4Connect.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 #include <cassert>
38 #include <cstring>
39 
40 #include "D4Connect.h"
41 #include "HTTPConnect.h"
42 #include "Response.h"
43 #include "DMR.h"
44 #include "D4Group.h"
45 
46 #include "D4ParserSax2.h"
47 #include "chunked_stream.h"
48 #include "chunked_istream.h"
49 #include "D4StreamUnMarshaller.h"
50 
51 #include "escaping.h"
52 #include "mime_util.h"
53 #include "debug.h"
54 
55 using namespace std;
56 
57 namespace libdap {
58 
59 
62 void D4Connect::process_dmr(DMR &dmr, Response &rs)
63 {
64  DBG(cerr << "Entering D4Connect::process_dmr" << endl);
65 
66  dmr.set_dap_version(rs.get_protocol());
67 
68  DBG(cerr << "Entering process_data: d_stream = " << rs << endl);
69  switch (rs.get_type()) {
70  case dap4_error: {
71 #if 0
72  Error e;
73  if (!e.parse(rs.get_stream()))
74  throw InternalErr(__FILE__, __LINE__, "Could not parse the Error object returned by the server!");
75  throw e;
76 #endif
77  throw InternalErr(__FILE__, __LINE__, "DAP4 errors not processed yet: FIXME!");
78  }
79 
80  case web_error:
81  // Web errors (those reported in the return document's MIME header)
82  // are processed by the WWW library.
83  throw InternalErr(__FILE__, __LINE__,
84  "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
85 
86  case dap4_dmr: {
87  // parse the DMR
88  try {
89  D4ParserSax2 parser;
90  parser.intern(*rs.get_cpp_stream(), &dmr, /*debug*/false);
91  }
92  catch (Error &e) {
93  cerr << "Exception: " << e.get_error_message() << endl;
94  return;
95  }
96  catch (std::exception &e) {
97  cerr << "Exception: " << e.what() << endl;
98  return;
99  }
100  catch (...) {
101  cerr << "Exception: unknown error" << endl;
102  return;
103  }
104 
105  return;
106  }
107 
108  default:
109  throw Error("Unknown response type");
110  }
111 }
112 
115 void D4Connect::process_data(DMR &data, Response &rs)
116 {
117  DBG(cerr << "Entering D4Connect::process_data" << endl);
118 
119  assert(rs.get_cpp_stream()); // DAP4 code uses cpp streams
120 
121  data.set_dap_version(rs.get_protocol());
122 
123  DBG(cerr << "Entering process_data: d_stream = " << rs << endl);
124  switch (rs.get_type()) {
125  case dap4_error: {
126 #if 0
127  Error e;
128  if (!e.parse(rs.get_cpp_stream()))
129  throw InternalErr(__FILE__, __LINE__, "Could not parse the Error object returned by the server!");
130  throw e;
131 #endif
132  throw InternalErr(__FILE__, __LINE__, "DAP4 errors not processed yet: FIXME!");
133  }
134 
135  case web_error:
136  // Web errors (those reported in the return document's MIME header)
137  // are processed by the WWW library.
138  throw InternalErr(__FILE__, __LINE__,
139  "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
140 
141  case dap4_data: {
142 #if BYTE_ORDER_PREFIX
143  // Read the byte-order byte; used later on
144  char byte_order;
145  *rs.get_cpp_stream() >> byte_order;
146  //if (debug) cerr << "Byte order: " << ((byte_order) ? "big endian" : "little endian") << endl;
147 #endif
148  // get a chunked input stream
149 #if BYTE_ORDER_PREFIX
150  chunked_istream cis(*rs.get_cpp_stream(), 1024, byte_order);
151 #else
152  chunked_istream cis(*(rs.get_cpp_stream()), CHUNK_SIZE);
153 #endif
154  // parse the DMR, stopping when the boundary is found.
155  try {
156  // force chunk read
157  // get chunk size
158  int chunk_size = cis.read_next_chunk();
159  // get chunk
160  char chunk[chunk_size];
161  cis.read(chunk, chunk_size);
162  // parse char * with given size
163  D4ParserSax2 parser;
164  // '-2' to discard the CRLF pair
165  parser.intern(chunk, chunk_size - 2, &data, /*debug*/false);
166  }
167  catch (Error &e) {
168  cerr << "Exception: " << e.get_error_message() << endl;
169  return;
170  }
171  catch (std::exception &e) {
172  cerr << "Exception: " << e.what() << endl;
173  return;
174  }
175  catch (...) {
176  cerr << "Exception: unknown error" << endl;
177  return;
178  }
179 
180 #if BYTE_ORDER_PREFIX
181  D4StreamUnMarshaller um(cis, byte_order);
182 #else
183  D4StreamUnMarshaller um(cis, cis.twiddle_bytes());
184 #endif
185  data.root()->deserialize(um, data);
186 
187  return;
188  }
189 
190  default:
191  throw Error("Unknown response type");
192  }
193 }
194 
203 void D4Connect::parse_mime(Response &rs)
204 {
205  rs.set_version("dods/0.0"); // initial value; for backward compatibility.
206  rs.set_protocol("2.0");
207 
208  istream &data_source = *rs.get_cpp_stream();
209  string mime = get_next_mime_header(data_source);
210  while (!mime.empty()) {
211  string header, value;
212  parse_mime_header(mime, header, value);
213 
214  // Note that this is an ordered list
215  if (header == "content-description") {
216  DBG(cout << header << ": " << value << endl);
217  rs.set_type(get_description_type(value));
218  }
219  // Use the value of xdods-server only if no other value has been read
220  else if (header == "xdods-server" && rs.get_version() == "dods/0.0") {
221  DBG(cout << header << ": " << value << endl);
222  rs.set_version(value);
223  }
224  // This trumps 'xdods-server' and 'server'
225  else if (header == "xopendap-server") {
226  DBG(cout << header << ": " << value << endl);
227  rs.set_version(value);
228  }
229  else if (header == "xdap") {
230  DBG(cout << header << ": " << value << endl);
231  rs.set_protocol(value);
232  }
233  // Only look for 'server' if no other header supplies this info.
234  else if (rs.get_version() == "dods/0.0" && header == "server") {
235  DBG(cout << header << ": " << value << endl);
236  rs.set_version(value);
237  }
238 
239  mime = get_next_mime_header(data_source);
240  }
241 }
242 
243 // public mfuncs
244 
251 D4Connect::D4Connect(const string &url, string uname, string password) :
252  d_http(0), d_local(false), d_URL(""), d_dap4ce(""), d_server("unknown"), d_protocol("4.0")
253 {
254  string name = prune_spaces(url);
255 
256  // Figure out if the URL starts with 'http', if so, make sure that we
257  // talk to an instance of HTTPConnect.
258  if (name.find("http") == 0) {
259  DBG(cerr << "Connect: The identifier is an http URL" << endl);
260  d_http = new HTTPConnect(RCReader::instance());
261  d_http->set_use_cpp_streams(true);
262 
263  // Find and store any CE given with the URL.
264  string::size_type dotpos = name.find('?');
265  if (dotpos != name.npos) {
266  d_URL = name.substr(0, dotpos);
267  d_dap4ce = name.substr(dotpos + 1);
268  }
269  else {
270  d_URL = name;
271  }
272  }
273  else {
274  DBG(cerr << "Connect: The identifier is a local data source." << endl);
275  d_local = true; // local in this case means non-DAP
276  }
277 
278  set_credentials(uname, password);
279 }
280 
282 {
283  if (d_http) delete d_http;
284 }
285 
286 void D4Connect::request_dmr(DMR &dmr, const string expr)
287 {
288  string url = d_URL + ".dmr" + "?" + id2www_ce(d_dap4ce + expr);
289 
290  Response *rs = 0;
291  try {
292  rs = d_http->fetch_url(url);
293 
294  d_server = rs->get_version();
295  d_protocol = rs->get_protocol();
296 
297  switch (rs->get_type()) {
298  case unknown_type: // FIXME Pure hackery!
299  cerr << "Response type unknown, assuming it's a DMR response." << endl;
300  /* no break */
301  case dap4_dmr: {
302  D4ParserSax2 parser;
303  parser.intern(*rs->get_cpp_stream(), &dmr, false /* debug */);
304  break;
305  }
306 
307  case dap4_error:
308  throw InternalErr(__FILE__, __LINE__, "DAP4 errors are not processed yet.");
309 
310  case web_error:
311  // We should never get here; a web error should be picked up read_url
312  // (called by fetch_url) and result in a thrown Error object.
313  throw InternalErr(__FILE__, __LINE__, "Web error found where it should never be.");
314  break;
315 
316  default:
317  throw InternalErr(__FILE__, __LINE__, "Response type not handled (got "
318  + long_to_string(rs->get_type()) + ").");
319  }
320  }
321  catch (...) {
322  delete rs;
323  throw;
324  }
325 
326  delete rs;
327 }
328 
329 void D4Connect::request_dap4_data(DMR &dmr, const string expr)
330 {
331  string url = d_URL + ".dap" + "?" + id2www_ce(d_dap4ce + expr);
332 
333  Response *rs = 0;
334  try {
335  rs = d_http->fetch_url(url);
336 
337  d_server = rs->get_version();
338  d_protocol = rs->get_protocol();
339 
340  switch (rs->get_type()) {
341  case unknown_type: // FIXME Pure hackery!
342  cerr << "Response type unknown, assuming it's a DAP4 Data response." << endl;
343  /* no break */
344  case dap4_data: {
345  // TODO Move to a function 11/9/13 process_data()???
346 #if BYTE_ORDER_PREFIX
347  istream &in = *rs->get_cpp_stream();
348  // Read the byte-order byte; used later on
349  char byte_order;
350  in >> byte_order;
351 #endif
352 
353  // get a chunked input stream
354 #if BYTE_ORDER_PREFIX
355  chunked_istream cis(*(rs->get_cpp_stream()), 1024, byte_order);
356 #else
358 #endif
359 
360  // parse the DMR, stopping when the boundary is found.
361 
362  // force chunk read
363  // get chunk size
364  int chunk_size = cis.read_next_chunk();
365  // get chunk
366  char chunk[chunk_size];
367  cis.read(chunk, chunk_size);
368  // parse char * with given size
369  D4ParserSax2 parser;
370  // '-2' to discard the CRLF pair
371  parser.intern(chunk, chunk_size - 2, &dmr, false /*debug*/);
372 
373  // Read data and store in the DMR
374 #if BYTE_ORDER_PREFIX
375  D4StreamUnMarshaller um(cis, byte_order);
376 #else
377  D4StreamUnMarshaller um(cis, cis.twiddle_bytes());
378 #endif
379  dmr.root()->deserialize(um, dmr);
380 
381  break;
382  }
383 
384  case dap4_error:
385  throw InternalErr(__FILE__, __LINE__, "DAP4 errors are not processed yet.");
386 
387  case web_error:
388  // We should never get here; a web error should be picked up read_url
389  // (called by fetch_url) and result in a thrown Error object.
390  throw InternalErr(__FILE__, __LINE__, "Web error found where it should never be.");
391  break;
392 
393  default:
394  throw InternalErr(__FILE__, __LINE__, "Response type not handled (got "
395  + long_to_string(rs->get_type()) + ").");
396  }
397  }
398  catch (...) {
399  delete rs;
400  throw;
401  }
402 
403  delete rs;
404 }
405 
406 #if 0
407 
414 string D4D4Connect::request_version()
415 {
416  string version_url = _URL + ".ver";
417  if (_proj.length() + _sel.length())
418  version_url = version_url + "?" + id2www_ce(_proj + _sel);
419 
420  Response *rs = 0;
421  try {
422  rs = d_http->fetch_url(version_url);
423  }
424  catch (Error &e) {
425  delete rs;
426  throw;
427  }
428 
429  d_server = rs.get_server();
430  d_protocol = rs.get_protocol();
431 
432  delete rs;
433 
434  return d_version;
435 }
436 
448 string D4D4Connect::request_protocol()
449 {
450  string version_url = _URL + ".ver";
451  if (_proj.length() + _sel.length())
452  version_url = version_url + "?" + id2www_ce(_proj + _sel);
453 
454  Response *rs = 0;
455  try {
456  rs = d_http->fetch_url(version_url);
457  }
458  catch (Error &e) {
459  delete rs;
460  rs = 0;
461  throw;
462  }
463 
464  d_version = rs.get_version();
465  d_protocol = rs.get_protocol();
466 
467  delete rs;
468  rs = 0;
469 
470  return d_protocol;
471 }
472 
480 void D4Connect::request_das(DAS &das)
481 {
482  string das_url = _URL + ".das";
483  if (_proj.length() + _sel.length())
484  das_url = das_url + "?" + id2www_ce(_proj + _sel);
485 
486  Response *rs = 0;
487  try {
488  rs = d_http->fetch_url(das_url);
489  }
490  catch (Error &e) {
491  delete rs;
492  rs = 0;
493  throw;
494  }
495 
496  d_version = rs.get_version();
497  d_protocol = rs.get_protocol();
498 
499  switch (rs.get_type()) {
500  case dods_error: {
501  Error e;
502  if (!e.parse(rs.get_stream())) {
503  delete rs;
504  rs = 0;
505  throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
506  }
507  delete rs;
508  rs = 0;
509  throw e;
510  }
511 
512  case web_error:
513  // We should never get here; a web error should be picked up read_url
514  // (called by fetch_url) and result in a thrown Error object.
515  break;
516 
517  case dods_das:
518  default:
519  // DAS::parse throws an exception on error.
520  try {
521  das.parse(rs.get_stream()); // read and parse the das from a file
522  }
523  catch (Error &e) {
524  delete rs;
525  rs = 0;
526  throw;
527  }
528 
529  break;
530  }
531 
532  delete rs;
533  rs = 0;
534 }
535 
546 void D4Connect::request_das_url(DAS &das)
547 {
548  string use_url = _URL + "?" + _proj + _sel;
549  Response *rs = 0;
550  try {
551  rs = d_http->fetch_url(use_url);
552  }
553  catch (Error &e) {
554  delete rs;
555  rs = 0;
556  throw;
557  }
558 
559  d_version = rs.get_version();
560  d_protocol = rs.get_protocol();
561 
562  switch (rs.get_type()) {
563  case dods_error: {
564  Error e;
565  if (!e.parse(rs.get_stream())) {
566  delete rs;
567  rs = 0;
568  throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
569  }
570  delete rs;
571  rs = 0;
572  throw e;
573  }
574 
575  case web_error:
576  // We should never get here; a web error should be picked up read_url
577  // (called by fetch_url) and result in a thrown Error object.
578  break;
579 
580  case dods_das:
581  default:
582  // DAS::parse throws an exception on error.
583  try {
584  das.parse(rs.get_stream()); // read and parse the das from a file
585  }
586  catch (Error &e) {
587  delete rs;
588  rs = 0;
589  throw;
590  }
591 
592  break;
593  }
594 
595  delete rs;
596  rs = 0;
597 }
598 
612 void D4Connect::request_dds(DDS &dds, string expr)
613 {
614  string proj, sel;
615  string::size_type dotpos = expr.find('&');
616  if (dotpos != expr.npos) {
617  proj = expr.substr(0, dotpos);
618  sel = expr.substr(dotpos);
619  }
620  else {
621  proj = expr;
622  sel = "";
623  }
624 
625  string dds_url = _URL + ".dds" + "?" + id2www_ce(_proj + proj + _sel + sel);
626 
627  Response *rs = 0;
628  try {
629  rs = d_http->fetch_url(dds_url);
630  }
631  catch (Error &e) {
632  delete rs;
633  rs = 0;
634  throw;
635  }
636 
637  d_version = rs.get_version();
638  d_protocol = rs.get_protocol();
639 
640  switch (rs.get_type()) {
641  case dods_error: {
642  Error e;
643  if (!e.parse(rs.get_stream())) {
644  delete rs;
645  rs = 0;
646  throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
647  }
648  delete rs;
649  rs = 0;
650  throw e;
651  }
652 
653  case web_error:
654  // We should never get here; a web error should be picked up read_url
655  // (called by fetch_url) and result in a thrown Error object.
656  break;
657 
658  case dods_dds:
659  default:
660  // DDS::prase throws an exception on error.
661  try {
662  dds.parse(rs.get_stream()); // read and parse the dds from a file
663  }
664  catch (Error &e) {
665  delete rs;
666  rs = 0;
667  throw;
668  }
669  break;
670  }
671 
672  delete rs;
673  rs = 0;
674 }
675 
692 void D4Connect::request_dds_url(DDS &dds)
693 {
694  string use_url = _URL + "?" + _proj + _sel;
695  Response *rs = 0;
696  try {
697  rs = d_http->fetch_url(use_url);
698  }
699  catch (Error &e) {
700  delete rs;
701  rs = 0;
702  throw;
703  }
704 
705  d_version = rs.get_version();
706  d_protocol = rs.get_protocol();
707 
708  switch (rs.get_type()) {
709  case dods_error: {
710  Error e;
711  if (!e.parse(rs.get_stream())) {
712  delete rs;
713  rs = 0;
714  throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
715  }
716  delete rs;
717  rs = 0;
718  throw e;
719  }
720 
721  case web_error:
722  // We should never get here; a web error should be picked up read_url
723  // (called by fetch_url) and result in a thrown Error object.
724  break;
725 
726  case dods_dds:
727  default:
728  // DDS::prase throws an exception on error.
729  try {
730  dds.parse(rs.get_stream()); // read and parse the dds from a file
731  }
732  catch (Error &e) {
733  delete rs;
734  rs = 0;
735  throw;
736  }
737  break;
738  }
739 
740  delete rs;
741  rs = 0;
742 }
743 
755 void D4Connect::request_ddx(DDS &dds, string expr)
756 {
757  string proj, sel;
758  string::size_type dotpos = expr.find('&');
759  if (dotpos != expr.npos) {
760  proj = expr.substr(0, dotpos);
761  sel = expr.substr(dotpos);
762  }
763  else {
764  proj = expr;
765  sel = "";
766  }
767 
768  string ddx_url = _URL + ".ddx" + "?" + id2www_ce(_proj + proj + _sel + sel);
769 
770  Response *rs = 0;
771  try {
772  rs = d_http->fetch_url(ddx_url);
773  }
774  catch (Error &e) {
775  delete rs;
776  rs = 0;
777  throw;
778  }
779 
780  d_version = rs.get_version();
781  d_protocol = rs.get_protocol();
782 
783  switch (rs.get_type()) {
784  case dods_error: {
785  Error e;
786  if (!e.parse(rs.get_stream())) {
787  delete rs;
788  rs = 0;
789  throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
790  }
791  delete rs;
792  rs = 0;
793  throw e;
794  }
795 
796  case web_error:
797  // We should never get here; a web error should be picked up read_url
798  // (called by fetch_url) and result in a thrown Error object.
799  break;
800 
801  case dods_ddx:
802  case dods_ddx:
803  try {
804  string blob;
805 
806  DDXParser ddxp(dds.get_factory());
807  ddxp.intern_stream(rs.get_stream(), &dds, blob);
808  }
809  catch (Error &e) {
810  delete rs;
811  rs = 0;
812  throw;
813  }
814  break;
815 
816  default:
817  delete rs;
818  rs = 0;
819  throw Error(
820  "The site did not return a valid response (it lacked the\n\
821 expected content description header value of 'dap4-ddx' and\n\
822 instead returned '"
823  + long_to_string(rs.get_type())
824  + "').\n\
825 This may indicate that the server at the site is not correctly\n\
826 configured, or that the URL has changed.");
827  }
828 
829  delete rs;
830  rs = 0;
831 }
832 
835 void D4Connect::request_ddx_url(DDS &dds)
836 {
837  string use_url = _URL + "?" + _proj + _sel;
838 
839  Response *rs = 0;
840  try {
841  rs = d_http->fetch_url(use_url);
842  }
843  catch (Error &e) {
844  delete rs;
845  rs = 0;
846  throw;
847  }
848 
849  d_version = rs.get_version();
850  d_protocol = rs.get_protocol();
851 
852  switch (rs.get_type()) {
853  case dods_error: {
854  Error e;
855  if (!e.parse(rs.get_stream())) {
856  delete rs;
857  rs = 0;
858  throw InternalErr(__FILE__, __LINE__, "Could not parse error returned from server.");
859  }
860  delete rs;
861  rs = 0;
862  throw e;
863  }
864 
865  case web_error:
866  // We should never get here; a web error should be picked up read_url
867  // (called by fetch_url) and result in a thrown Error object.
868  break;
869 
870  case dods_ddx:
871  case dods_ddx:
872  try {
873  string blob;
874 
875  DDXParser ddxp(dds.get_factory());
876  ddxp.intern_stream(rs.get_stream(), &dds, blob);
877  }
878  catch (Error &e) {
879  delete rs;
880  rs = 0;
881  throw;
882  }
883  break;
884 
885  default:
886  delete rs;
887  rs = 0;
888  throw Error(
889  "The site did not return a valid response (it lacked the\n\
890 expected content description header value of 'dap4-ddx' and\n\
891 instead returned '"
892  + long_to_string(rs.get_type())
893  + "').\n\
894 This may indicate that the server at the site is not correctly\n\
895 configured, or that the URL has changed.");
896  }
897 
898  delete rs;
899  rs = 0;
900 }
901 
917 void D4Connect::request_data(DataDDS &data, string expr)
918 {
919  string proj, sel;
920  string::size_type dotpos = expr.find('&');
921  if (dotpos != expr.npos) {
922  proj = expr.substr(0, dotpos);
923  sel = expr.substr(dotpos);
924  }
925  else {
926  proj = expr;
927  sel = "";
928  }
929 
930  string data_url = _URL + ".dods?" + id2www_ce(_proj + proj + _sel + sel);
931 
932  Response *rs = 0;
933  // We need to catch Error exceptions to ensure calling close_output.
934  try {
935  rs = d_http->fetch_url(data_url);
936 
937  d_version = rs.get_version();
938  d_protocol = rs.get_protocol();
939 
940  process_data(data, rs);
941  delete rs;
942  rs = 0;
943  }
944  catch (Error &e) {
945  delete rs;
946  rs = 0;
947  throw;
948  }
949 }
950 
968 void D4Connect::request_data_url(DataDDS &data)
969 {
970  string use_url = _URL + "?" + _proj + _sel;
971  Response *rs = 0;
972  // We need to catch Error exceptions to ensure calling close_output.
973  try {
974  rs = d_http->fetch_url(use_url);
975 
976  d_version = rs.get_version();
977  d_protocol = rs.get_protocol();
978 
979  process_data(data, rs);
980  delete rs;
981  rs = 0;
982  }
983  catch (Error &e) {
984  delete rs;
985  rs = 0;
986  throw;
987  }
988 }
989 
990 void D4Connect::request_data_ddx(DataDDS &data, string expr)
991 {
992  string proj, sel;
993  string::size_type dotpos = expr.find('&');
994  if (dotpos != expr.npos) {
995  proj = expr.substr(0, dotpos);
996  sel = expr.substr(dotpos);
997  }
998  else {
999  proj = expr;
1000  sel = "";
1001  }
1002 
1003  string data_url = _URL + ".dap?" + id2www_ce(_proj + proj + _sel + sel);
1004 
1005  Response *rs = 0;
1006  // We need to catch Error exceptions to ensure calling close_output.
1007  try {
1008  rs = d_http->fetch_url(data_url);
1009 
1010  d_version = rs.get_version();
1011  d_protocol = rs.get_protocol();
1012 
1013  process_data(data, rs);
1014  delete rs;
1015  rs = 0;
1016  }
1017  catch (Error &e) {
1018  delete rs;
1019  rs = 0;
1020  throw;
1021  }
1022 }
1023 
1024 void D4Connect::request_data_ddx_url(DataDDS &data)
1025 {
1026  string use_url = _URL + "?" + _proj + _sel;
1027  Response *rs = 0;
1028  // We need to catch Error exceptions to ensure calling close_output.
1029  try {
1030  rs = d_http->fetch_url(use_url);
1031 
1032  d_version = rs.get_version();
1033  d_protocol = rs.get_protocol();
1034 
1035  process_data(data, rs);
1036  delete rs;
1037  rs = 0;
1038  }
1039  catch (Error &e) {
1040  delete rs;
1041  rs = 0;
1042  throw;
1043  }
1044 }
1045 #endif
1046 
1047 void
1049 {
1050  parse_mime(rs);
1051  if (rs.get_type() == unknown_type)
1052  throw Error("Unknown response type.");
1053 
1054  read_dmr_no_mime(dmr, rs);
1055 }
1056 
1057 void
1059 {
1060  // Assume callers know what they are doing
1061  if (rs.get_type() == unknown_type)
1062  rs.set_type(dap4_dmr);
1063 
1064  switch (rs.get_type()) {
1065  case dap4_dmr:
1066  process_dmr(dmr, rs);
1067  d_server = rs.get_version();
1068  d_protocol = dmr.dap_version();
1069  break;
1070  default:
1071  throw Error("Expected a DAP4 DMR response.");
1072  }
1073 }
1074 
1075 void
1077 {
1078  parse_mime(rs);
1079  if (rs.get_type() == unknown_type)
1080  throw Error("Unknown response type.");
1081 
1082  read_data_no_mime(data, rs);
1083 }
1084 
1086 {
1087  // Assume callers know what they are doing
1088  if (rs.get_type() == unknown_type)
1089  rs.set_type(dap4_data);
1090 
1091  switch (rs.get_type()) {
1092  case dap4_data:
1093  process_data(data, rs);
1094  d_server = rs.get_version();
1095  d_protocol = data.dap_version();
1096  break;
1097  default:
1098  throw Error("Expected a DAP4 Data response.");
1099  }
1100 }
1101 
1107 void D4Connect::set_credentials(string u, string p)
1108 {
1109  if (d_http)
1110  d_http->set_credentials(u, p);
1111 }
1112 
1117 {
1118  if (d_http)
1119  d_http->set_accept_deflate(deflate);
1120 }
1121 
1127 void D4Connect::set_xdap_protocol(int major, int minor)
1128 {
1129  if (d_http)
1130  d_http->set_xdap_protocol(major, minor);
1131 }
1132 
1137 {
1138  if (d_http)
1139  d_http->set_cache_enabled(cache);
1140 }
1141 
1143 {
1144  if (d_http)
1145  return d_http->is_cache_enabled();
1146  else
1147  return false;
1148 }
1149 
1150 } // namespace libdap
string dap_version() const
Definition: DMR.h:140
string get_next_mime_header(FILE *in)
Definition: mime_util.cc:836
void set_credentials(std::string u, std::string p)
Set the credentials for responding to challenges while dereferencing URLs.
Definition: D4Connect.cc:1107
void intern(istream &f, DMR *dest_dmr, bool debug=false)
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)
D4Group * root()
Definition: DMR.cc:243
Read data from the stream made by D4StreamMarshaller.
virtual void set_type(ObjectType o)
Definition: Response.h:121
void set_xdap_protocol(int major, int minor)
Definition: D4Connect.cc:1127
virtual std::istream * get_cpp_stream() const
Definition: Response.h:107
void set_cache_enabled(bool enabled)
Definition: HTTPConnect.h:150
virtual std::string get_version() const
Definition: Response.h:110
virtual ObjectType get_type() const
Definition: Response.h:109
HTTPResponse * fetch_url(const string &url)
Definition: HTTPConnect.cc:615
A class for software fault reporting.
Definition: InternalErr.h:64
void parse_mime_header(const string &header, string &name, string &value)
Definition: mime_util.cc:898
void set_accept_deflate(bool deflate)
Definition: D4Connect.cc:1116
#define DBG(x)
Definition: debug.h:58
ObjectType get_description_type(const string &value)
Definition: mime_util.cc:339
virtual ~D4Connect()
Definition: D4Connect.cc:281
#define CHUNK_SIZE
void set_cache_enabled(bool enabled)
Definition: D4Connect.cc:1136
virtual void request_dmr(DMR &dmr, const std::string expr="")
Definition: D4Connect.cc:286
virtual void deserialize(D4StreamUnMarshaller &um, DMR &dmr)
Definition: D4Group.cc:504
virtual std::string get_protocol() const
Definition: Response.h:111
virtual void read_dmr(DMR &dmr, Response &rs)
Definition: D4Connect.cc:1048
void set_accept_deflate(bool defalte)
Definition: HTTPConnect.cc:988
string long_to_string(long val, int base)
Definition: util.cc:1012
virtual void request_dap4_data(DMR &dmr, const std::string expr="")
Definition: D4Connect.cc:329
virtual void read_dmr_no_mime(DMR &dmr, Response &rs)
Definition: D4Connect.cc:1058
void set_xdap_protocol(int major, int minor)
virtual void read_data_no_mime(DMR &data, Response &rs)
Definition: D4Connect.cc:1085
bool is_cache_enabled()
Definition: D4Connect.cc:1142
A class for error processing.
Definition: Error.h:90
virtual void read_data(DMR &data, Response &rs)
Definition: D4Connect.cc:1076
static RCReader * instance()
Definition: RCReader.cc:486