libdap++ Updated for version 3.8.2
|
00001 00002 // -*- mode: c++; c-basic-offset:4 -*- 00003 00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data 00005 // Access Protocol. 00006 00007 // Copyright (c) 2002,2003 OPeNDAP, Inc. 00008 // Author: James Gallagher <jgallagher@opendap.org> 00009 // Dan Holloway <dholloway@gso.uri.edu> 00010 // Reza Nekovei <reza@intcomm.net> 00011 // 00012 // This library is free software; you can redistribute it and/or 00013 // modify it under the terms of the GNU Lesser General Public 00014 // License as published by the Free Software Foundation; either 00015 // version 2.1 of the License, or (at your option) any later version. 00016 // 00017 // This library is distributed in the hope that it will be useful, 00018 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00020 // Lesser General Public License for more details. 00021 // 00022 // You should have received a copy of the GNU Lesser General Public 00023 // License along with this library; if not, write to the Free Software 00024 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00025 // 00026 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112. 00027 00028 // (c) COPYRIGHT URI/MIT 1994-2002 00029 // Please read the full copyright statement in the file COPYRIGHT_URI. 00030 // 00031 // Authors: 00032 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu> 00033 // dan Dan Holloway <dholloway@gso.uri.edu> 00034 // reza Reza Nekovei <reza@intcomm.net> 00035 00036 00037 #include "config.h" 00038 00039 //#define DODS_DEBUG 00040 #define FILE_METHODS 1 00041 00042 static char rcsid[] not_used = 00043 { "$Id: Connect.cc 24370 2011-03-28 16:21:32Z jimg $" 00044 }; 00045 00046 #include <cstring> 00047 #include <fstream> 00048 #include <algorithm> 00049 00050 #include "debug.h" 00051 #include "DataDDS.h" 00052 #include "Connect.h" 00053 #include "escaping.h" 00054 #include "RCReader.h" 00055 #include "DDXParserSAX2.h" 00056 #if FILE_METHODS 00057 #include "XDRFileUnMarshaller.h" 00058 #else 00059 #include "fdiostream.h" 00060 #include "XDRStreamUnMarshaller.h" 00061 #endif 00062 #include "mime_util.h" 00063 00064 using std::cerr; 00065 using std::endl; 00066 using std::ifstream; 00067 using std::ofstream; 00068 using std::min; 00069 00070 namespace libdap { 00071 00074 void 00075 Connect::process_data(DataDDS &data, Response *rs) 00076 { 00077 DBG(cerr << "Entering Connect::process_data" << endl); 00078 00079 data.set_version(rs->get_version()); 00080 data.set_protocol(rs->get_protocol()); 00081 00082 DBG(cerr << "Entering process_data: d_stream = " << rs << endl); 00083 switch (rs->get_type()) { 00084 case dods_error: { 00085 Error e; 00086 if (!e.parse(rs->get_stream())) 00087 throw InternalErr(__FILE__, __LINE__, 00088 "Could not parse the Error object returned by the server!"); 00089 throw e; 00090 } 00091 00092 case web_error: 00093 // Web errors (those reported in the return document's MIME header) 00094 // are processed by the WWW library. 00095 throw InternalErr(__FILE__, __LINE__, "An error was reported by the remote httpd; this should have been processed by HTTPConnect.."); 00096 00097 case dap4_data_ddx: { 00098 // Parse the DDX; throw an exception on error. 00099 DDXParser ddx_parser(data.get_factory()); 00100 00101 // Read the MPM boundary and then read the subsequent headers 00102 string boundary = read_multipart_boundary(rs->get_stream()); 00103 DBG(cerr << "MPM Boundary: " << boundary << endl); 00104 read_multipart_headers(rs->get_stream(), "text/xml", dap4_ddx); 00105 00106 // Parse the DDX, reading up to and including the next boundary. 00107 // Return the CID for the matching data part 00108 string data_cid; 00109 ddx_parser.intern_stream(rs->get_stream(), &data, data_cid, boundary); 00110 00111 // Munge the CID into something we can work with 00112 data_cid = cid_to_header_value(data_cid); 00113 DBG(cerr << "Data CID: " << data_cid << endl); 00114 00115 // Read the data part's MPM part headers (boundary was read by 00116 // DDXParse::intern) 00117 read_multipart_headers(rs->get_stream(), 00118 "application/octet-stream", dap4_data, data_cid); 00119 00120 // Now read the data 00121 #if FILE_METHODS 00122 XDRFileUnMarshaller um( rs->get_stream() ) ; 00123 #else 00124 fpistream in ( rs->get_stream() ); 00125 XDRStreamUnMarshaller um( in ) ; 00126 #endif 00127 #if 0 00128 try { 00129 #endif 00130 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end(); 00131 i++) { 00132 (*i)->deserialize(um, &data); 00133 } 00134 #if 0 00135 } 00136 catch (Error &e) { 00137 throw ; 00138 } 00139 #endif 00140 return; 00141 } 00142 00143 case dods_data: 00144 default: { 00145 // Parse the DDS; throw an exception on error. 00146 data.parse(rs->get_stream()); 00147 #if FILE_METHODS 00148 XDRFileUnMarshaller um( rs->get_stream() ) ; 00149 #else 00150 fpistream in ( rs->get_stream() ); 00151 XDRStreamUnMarshaller um( in ) ; 00152 #endif 00153 // Load the DDS with data. 00154 #if 0 00155 try { 00156 #endif 00157 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end(); 00158 i++) { 00159 (*i)->deserialize(um, &data); 00160 } 00161 #if 0 00162 } 00163 catch (Error &e) { 00164 throw ; 00165 } 00166 #endif 00167 return; 00168 } 00169 } 00170 } 00171 00172 // Barely a parser... This is used when reading from local sources of DODS 00173 // Data objects. It simulates the important actions of the libwww MIME header 00174 // parser. Those actions fill in certain fields in the Connect object. jhrg 00175 // 5/20/97 00176 // 00177 // Make sure that this parser reads from data_source without disturbing the 00178 // information in data_source that follows the MIME header. Since the DDS 00179 // (which follows the MIME header) is parsed by a flex/bison scanner/parser, 00180 // make sure to use I/O calls that will mesh with ANSI C I/O calls. In the 00181 // old GNU libg++, the C++ calls were synchronized with the C calls, but that 00182 // may no longer be the case. 5/31/99 jhrg 00183 00193 void 00194 Connect::parse_mime(Response *rs) 00195 { 00196 rs->set_version("dods/0.0"); // initial value; for backward compatibility. 00197 rs->set_protocol("2.0"); 00198 00199 FILE *data_source = rs->get_stream(); 00200 string mime = get_next_mime_header(data_source); 00201 while (!mime.empty()) { 00202 string header, value; 00203 parse_mime_header(mime, header, value); 00204 00205 // Note that this is an ordered list 00206 if (header == "content-description:") { 00207 DBG(cout << header << ": " << value << endl); 00208 rs->set_type(get_description_type(value)); 00209 } 00210 // Use the value of xdods-server only if no other value has been read 00211 else if (header == "xdods-server:" 00212 && rs->get_version() == "dods/0.0") { 00213 DBG(cout << header << ": " << value << endl); 00214 rs->set_version(value); 00215 } 00216 // This trumps 'xdods-server' and 'server' 00217 else if (header == "xopendap-server:") { 00218 DBG(cout << header << ": " << value << endl); 00219 rs->set_version(value); 00220 } 00221 else if (header == "xdap:") { 00222 DBG(cout << header << ": " << value << endl); 00223 rs->set_protocol(value); 00224 } 00225 // Only look for 'server' if no other header supplies this info. 00226 else if (rs->get_version() == "dods/0.0" && header == "server:") { 00227 DBG(cout << header << ": " << value << endl); 00228 rs->set_version(value); 00229 } 00230 00231 mime = get_next_mime_header(data_source); 00232 } 00233 } 00234 00235 // public mfuncs 00236 00244 Connect::Connect(const string &n, string uname, string password) 00245 throw(Error, InternalErr) 00246 : d_http(0), d_version("unknown"), d_protocol("2.0") 00247 { 00248 string name = prune_spaces(n); 00249 00250 // Figure out if the URL starts with 'http', if so, make sure that we 00251 // talk to an instance of HTTPConnect. 00252 if (name.find("http") == 0) { 00253 DBG(cerr << "Connect: The identifier is an http URL" << endl); 00254 d_http = new HTTPConnect(RCReader::instance()); 00255 00256 // Find and store any CE given with the URL. 00257 string::size_type dotpos = name.find('?'); 00258 if (dotpos != name.npos) { 00259 _URL = name.substr(0, dotpos); 00260 string expr = name.substr(dotpos + 1); 00261 00262 dotpos = expr.find('&'); 00263 if (dotpos != expr.npos) { 00264 _proj = expr.substr(0, dotpos); 00265 _sel = expr.substr(dotpos); // XXX includes '&' 00266 } 00267 else { 00268 _proj = expr; 00269 _sel = ""; 00270 } 00271 } 00272 else { 00273 _URL = name; 00274 _proj = ""; 00275 _sel = ""; 00276 } 00277 00278 _local = false; 00279 } 00280 else { 00281 DBG(cerr << "Connect: The identifier is a local data source." << endl); 00282 00283 d_http = 0; 00284 _URL = ""; 00285 _local = true; // local in this case means non-DAP 00286 } 00287 00288 set_credentials(uname, password); 00289 } 00290 00291 Connect::~Connect() 00292 { 00293 DBG2(cerr << "Entering the Connect dtor" << endl); 00294 00295 if (d_http) 00296 delete d_http; d_http = 0; 00297 00298 DBG2(cerr << "Leaving the Connect dtor" << endl); 00299 } 00300 00308 string 00309 Connect::request_version() 00310 { 00311 string version_url = _URL + ".ver"; 00312 if (_proj.length() + _sel.length()) 00313 version_url = version_url + "?" + id2www_ce(_proj + _sel); 00314 00315 Response *rs = 0; 00316 try { 00317 rs = d_http->fetch_url(version_url); 00318 } 00319 catch (Error &e) { 00320 delete rs; rs = 0; 00321 throw ; 00322 } 00323 00324 d_version = rs->get_version(); 00325 d_protocol = rs->get_protocol(); 00326 00327 delete rs; rs = 0; 00328 00329 return d_version; 00330 } 00331 00343 string 00344 Connect::request_protocol() 00345 { 00346 string version_url = _URL + ".ver"; 00347 if (_proj.length() + _sel.length()) 00348 version_url = version_url + "?" + id2www_ce(_proj + _sel); 00349 00350 Response *rs = 0; 00351 try { 00352 rs = d_http->fetch_url(version_url); 00353 } 00354 catch (Error &e) { 00355 delete rs; rs = 0; 00356 throw ; 00357 } 00358 00359 d_version = rs->get_version(); 00360 d_protocol = rs->get_protocol(); 00361 00362 delete rs; rs = 0; 00363 00364 return d_protocol; 00365 } 00366 00374 void 00375 Connect::request_das(DAS &das) 00376 { 00377 string das_url = _URL + ".das"; 00378 if (_proj.length() + _sel.length()) 00379 das_url = das_url + "?" + id2www_ce(_proj + _sel); 00380 00381 Response *rs = 0; 00382 try { 00383 rs = d_http->fetch_url(das_url); 00384 } 00385 catch (Error &e) { 00386 delete rs; rs = 0; 00387 throw ; 00388 } 00389 00390 d_version = rs->get_version(); 00391 d_protocol = rs->get_protocol(); 00392 00393 switch (rs->get_type()) { 00394 case dods_error: { 00395 Error e; 00396 if (!e.parse(rs->get_stream())) { 00397 delete rs; rs = 0; 00398 throw InternalErr(__FILE__, __LINE__, 00399 "Could not parse error returned from server."); 00400 } 00401 delete rs; rs = 0; 00402 throw e; 00403 } 00404 00405 case web_error: 00406 // We should never get here; a web error should be picked up read_url 00407 // (called by fetch_url) and result in a thrown Error object. 00408 break; 00409 00410 case dods_das: 00411 default: 00412 // DAS::parse throws an exception on error. 00413 try { 00414 das.parse(rs->get_stream()); // read and parse the das from a file 00415 } 00416 catch (Error &e) { 00417 delete rs; rs = 0; 00418 throw ; 00419 } 00420 00421 break; 00422 } 00423 00424 delete rs; rs = 0; 00425 } 00426 00437 void 00438 Connect::request_das_url(DAS &das) 00439 { 00440 string use_url = _URL + "?" + _proj + _sel ; 00441 Response *rs = 0; 00442 try { 00443 rs = d_http->fetch_url(use_url); 00444 } 00445 catch (Error &e) { 00446 delete rs; rs = 0; 00447 throw ; 00448 } 00449 00450 d_version = rs->get_version(); 00451 d_protocol = rs->get_protocol(); 00452 00453 switch (rs->get_type()) { 00454 case dods_error: { 00455 Error e; 00456 if (!e.parse(rs->get_stream())) { 00457 delete rs; rs = 0; 00458 throw InternalErr(__FILE__, __LINE__, 00459 "Could not parse error returned from server."); 00460 } 00461 delete rs; rs = 0; 00462 throw e; 00463 } 00464 00465 case web_error: 00466 // We should never get here; a web error should be picked up read_url 00467 // (called by fetch_url) and result in a thrown Error object. 00468 break; 00469 00470 case dods_das: 00471 default: 00472 // DAS::parse throws an exception on error. 00473 try { 00474 das.parse(rs->get_stream()); // read and parse the das from a file 00475 } 00476 catch (Error &e) { 00477 delete rs; rs = 0; 00478 throw ; 00479 } 00480 00481 break; 00482 } 00483 00484 delete rs; rs = 0; 00485 } 00486 00500 void 00501 Connect::request_dds(DDS &dds, string expr) 00502 { 00503 string proj, sel; 00504 string::size_type dotpos = expr.find('&'); 00505 if (dotpos != expr.npos) { 00506 proj = expr.substr(0, dotpos); 00507 sel = expr.substr(dotpos); 00508 } 00509 else { 00510 proj = expr; 00511 sel = ""; 00512 } 00513 00514 string dds_url = _URL + ".dds" + "?" 00515 + id2www_ce(_proj + proj + _sel + sel); 00516 00517 Response *rs = 0; 00518 try { 00519 rs = d_http->fetch_url(dds_url); 00520 } 00521 catch (Error &e) { 00522 delete rs; rs = 0; 00523 throw ; 00524 } 00525 00526 d_version = rs->get_version(); 00527 d_protocol = rs->get_protocol(); 00528 00529 switch (rs->get_type()) { 00530 case dods_error: { 00531 Error e; 00532 if (!e.parse(rs->get_stream())) { 00533 delete rs; rs = 0; 00534 throw InternalErr(__FILE__, __LINE__, 00535 "Could not parse error returned from server."); 00536 } 00537 delete rs; rs = 0; 00538 throw e; 00539 } 00540 00541 case web_error: 00542 // We should never get here; a web error should be picked up read_url 00543 // (called by fetch_url) and result in a thrown Error object. 00544 break; 00545 00546 case dods_dds: 00547 default: 00548 // DDS::prase throws an exception on error. 00549 try { 00550 dds.parse(rs->get_stream()); // read and parse the dds from a file 00551 } 00552 catch (Error &e) { 00553 delete rs; rs = 0; 00554 throw ; 00555 } 00556 break; 00557 } 00558 00559 delete rs; rs = 0; 00560 } 00561 00578 void 00579 Connect::request_dds_url(DDS &dds) 00580 { 00581 string use_url = _URL + "?" + _proj + _sel ; 00582 Response *rs = 0; 00583 try { 00584 rs = d_http->fetch_url(use_url); 00585 } 00586 catch (Error &e) { 00587 delete rs; rs = 0; 00588 throw ; 00589 } 00590 00591 d_version = rs->get_version(); 00592 d_protocol = rs->get_protocol(); 00593 00594 switch (rs->get_type()) { 00595 case dods_error: { 00596 Error e; 00597 if (!e.parse(rs->get_stream())) { 00598 delete rs; rs = 0; 00599 throw InternalErr(__FILE__, __LINE__, 00600 "Could not parse error returned from server."); 00601 } 00602 delete rs; rs = 0; 00603 throw e; 00604 } 00605 00606 case web_error: 00607 // We should never get here; a web error should be picked up read_url 00608 // (called by fetch_url) and result in a thrown Error object. 00609 break; 00610 00611 case dods_dds: 00612 default: 00613 // DDS::prase throws an exception on error. 00614 try { 00615 dds.parse(rs->get_stream()); // read and parse the dds from a file 00616 } 00617 catch (Error &e) { 00618 delete rs; rs = 0; 00619 throw ; 00620 } 00621 break; 00622 } 00623 00624 delete rs; rs = 0; 00625 } 00626 00638 void 00639 Connect::request_ddx(DDS &dds, string expr) 00640 { 00641 string proj, sel; 00642 string::size_type dotpos = expr.find('&'); 00643 if (dotpos != expr.npos) { 00644 proj = expr.substr(0, dotpos); 00645 sel = expr.substr(dotpos); 00646 } 00647 else { 00648 proj = expr; 00649 sel = ""; 00650 } 00651 00652 string ddx_url = _URL + ".ddx" + "?" 00653 + id2www_ce(_proj + proj + _sel + sel); 00654 00655 Response *rs = 0; 00656 try { 00657 rs = d_http->fetch_url(ddx_url); 00658 } 00659 catch (Error &e) { 00660 delete rs; rs = 0; 00661 throw ; 00662 } 00663 00664 d_version = rs->get_version(); 00665 d_protocol = rs->get_protocol(); 00666 00667 switch (rs->get_type()) { 00668 case dods_error: { 00669 Error e; 00670 if (!e.parse(rs->get_stream())) { 00671 delete rs; rs = 0; 00672 throw InternalErr(__FILE__, __LINE__, 00673 "Could not parse error returned from server."); 00674 } 00675 delete rs; rs = 0; 00676 throw e; 00677 } 00678 00679 case web_error: 00680 // We should never get here; a web error should be picked up read_url 00681 // (called by fetch_url) and result in a thrown Error object. 00682 break; 00683 00684 case dap4_ddx: 00685 case dods_ddx: 00686 try { 00687 string blob; 00688 00689 DDXParser ddxp(dds.get_factory()); 00690 ddxp.intern_stream(rs->get_stream(), &dds, blob); 00691 } 00692 catch (Error &e) { 00693 delete rs; rs = 0; 00694 throw ; 00695 } 00696 break; 00697 00698 default: 00699 delete rs; rs = 0; 00700 throw Error("The site did not return a valid response (it lacked the\n\ 00701 expected content description header value of 'dap4-ddx' and\n\ 00702 instead returned '" + long_to_string(rs->get_type()) + "').\n\ 00703 This may indicate that the server at the site is not correctly\n\ 00704 configured, or that the URL has changed."); 00705 } 00706 00707 delete rs; rs = 0; 00708 } 00709 00712 void 00713 Connect::request_ddx_url(DDS &dds) 00714 { 00715 string use_url = _URL + "?" + _proj + _sel ; 00716 00717 Response *rs = 0; 00718 try { 00719 rs = d_http->fetch_url(use_url); 00720 } 00721 catch (Error &e) { 00722 delete rs; rs = 0; 00723 throw ; 00724 } 00725 00726 d_version = rs->get_version(); 00727 d_protocol = rs->get_protocol(); 00728 00729 switch (rs->get_type()) { 00730 case dods_error: { 00731 Error e; 00732 if (!e.parse(rs->get_stream())) { 00733 delete rs; rs = 0; 00734 throw InternalErr(__FILE__, __LINE__, 00735 "Could not parse error returned from server."); 00736 } 00737 delete rs; rs = 0; 00738 throw e; 00739 } 00740 00741 case web_error: 00742 // We should never get here; a web error should be picked up read_url 00743 // (called by fetch_url) and result in a thrown Error object. 00744 break; 00745 00746 case dap4_ddx: 00747 case dods_ddx: 00748 try { 00749 string blob; 00750 00751 DDXParser ddxp(dds.get_factory()); 00752 ddxp.intern_stream(rs->get_stream(), &dds, blob); 00753 } 00754 catch (Error &e) { 00755 delete rs; rs = 0; 00756 throw ; 00757 } 00758 break; 00759 00760 default: 00761 delete rs; rs = 0; 00762 throw Error("The site did not return a valid response (it lacked the\n\ 00763 expected content description header value of 'dap4-ddx' and\n\ 00764 instead returned '" + long_to_string(rs->get_type()) + "').\n\ 00765 This may indicate that the server at the site is not correctly\n\ 00766 configured, or that the URL has changed."); 00767 } 00768 00769 delete rs; rs = 0; 00770 } 00771 00787 void 00788 Connect::request_data(DataDDS &data, string expr) 00789 { 00790 string proj, sel; 00791 string::size_type dotpos = expr.find('&'); 00792 if (dotpos != expr.npos) { 00793 proj = expr.substr(0, dotpos); 00794 sel = expr.substr(dotpos); 00795 } 00796 else { 00797 proj = expr; 00798 sel = ""; 00799 } 00800 00801 string data_url = _URL + ".dods?" 00802 + id2www_ce(_proj + proj + _sel + sel); 00803 00804 Response *rs = 0; 00805 // We need to catch Error exceptions to ensure calling close_output. 00806 try { 00807 rs = d_http->fetch_url(data_url); 00808 00809 d_version = rs->get_version(); 00810 d_protocol = rs->get_protocol(); 00811 00812 process_data(data, rs); 00813 delete rs; rs = 0; 00814 } 00815 catch (Error &e) { 00816 delete rs; rs = 0; 00817 throw ; 00818 } 00819 } 00820 00838 void 00839 Connect::request_data_url(DataDDS &data) 00840 { 00841 string use_url = _URL + "?" + _proj + _sel ; 00842 Response *rs = 0; 00843 // We need to catch Error exceptions to ensure calling close_output. 00844 try { 00845 rs = d_http->fetch_url(use_url); 00846 00847 d_version = rs->get_version(); 00848 d_protocol = rs->get_protocol(); 00849 00850 process_data(data, rs); 00851 delete rs; rs = 0; 00852 } 00853 catch (Error &e) { 00854 delete rs; rs = 0; 00855 throw ; 00856 } 00857 } 00858 00859 void 00860 Connect::request_data_ddx(DataDDS &data, string expr) 00861 { 00862 string proj, sel; 00863 string::size_type dotpos = expr.find('&'); 00864 if (dotpos != expr.npos) { 00865 proj = expr.substr(0, dotpos); 00866 sel = expr.substr(dotpos); 00867 } 00868 else { 00869 proj = expr; 00870 sel = ""; 00871 } 00872 00873 string data_url = _URL + ".dap?" 00874 + id2www_ce(_proj + proj + _sel + sel); 00875 00876 Response *rs = 0; 00877 // We need to catch Error exceptions to ensure calling close_output. 00878 try { 00879 rs = d_http->fetch_url(data_url); 00880 00881 d_version = rs->get_version(); 00882 d_protocol = rs->get_protocol(); 00883 00884 process_data(data, rs); 00885 delete rs; rs = 0; 00886 } 00887 catch (Error &e) { 00888 delete rs; rs = 0; 00889 throw ; 00890 } 00891 } 00892 00893 void 00894 Connect::request_data_ddx_url(DataDDS &data) 00895 { 00896 string use_url = _URL + "?" + _proj + _sel ; 00897 Response *rs = 0; 00898 // We need to catch Error exceptions to ensure calling close_output. 00899 try { 00900 rs = d_http->fetch_url(use_url); 00901 00902 d_version = rs->get_version(); 00903 d_protocol = rs->get_protocol(); 00904 00905 process_data(data, rs); 00906 delete rs; rs = 0; 00907 } 00908 catch (Error &e) { 00909 delete rs; rs = 0; 00910 throw ; 00911 } 00912 } 00913 00927 void 00928 Connect::read_data(DataDDS &data, Response *rs) 00929 { 00930 if (!rs) 00931 throw InternalErr(__FILE__, __LINE__, "Response object is null."); 00932 00933 // Read from data_source and parse the MIME headers specific to DAP2/4. 00934 parse_mime(rs); 00935 00936 read_data_no_mime(data, rs); 00937 } 00938 00939 // This function looks at the input stream and makes its best guess at what 00940 // lies in store for downstream processing code. Definitely heuristic. 00941 // Assumptions: 00942 // #1 The current file position is past any MIME headers (if they were present). 00943 // #2 We must reset the FILE* position to the start of the DDS or DDX headers 00944 static void 00945 divine_type_information(Response *rs) 00946 { 00947 // Consume whitespace 00948 char c = getc(rs->get_stream()); 00949 while (isspace(c)) { 00950 c = getc(rs->get_stream()); 00951 } 00952 00953 // The heuristic here is that a DataDDX is a multipart MIME document and 00954 // The first non space character found after the headers is the start of 00955 // the first part which looks like '--<boundary>' while a DataDDS starts 00956 // with a DDS (;Dataset {' ...). I take into account that our parsers have 00957 // accepted both 'Dataset' and 'dataset' for a long time. 00958 switch (c) { 00959 case '-': 00960 rs->set_type(dap4_data_ddx); 00961 break; 00962 case 'D': 00963 case 'd': 00964 rs->set_type(dods_data); 00965 break; 00966 default: 00967 throw InternalErr(__FILE__, __LINE__, "Could not determine type of response object in stream."); 00968 } 00969 00970 ungetc(c, rs->get_stream()); 00971 } 00972 00985 void 00986 Connect::read_data_no_mime(DataDDS &data, Response *rs) 00987 { 00988 if (rs->get_type() == unknown_type) 00989 divine_type_information(rs); 00990 00991 switch (rs->get_type()) { 00992 case dods_data: 00993 d_version = rs->get_version(); 00994 d_protocol = rs->get_protocol(); 00995 process_data(data, rs); 00996 break; 00997 case dap4_data_ddx: 00998 process_data(data, rs); 00999 d_version = rs->get_version(); 01000 d_protocol = data.get_protocol(); 01001 break; 01002 default: 01003 throw InternalErr(__FILE__, __LINE__, "Should have been a DataDDS or DataDDX."); 01004 } 01005 } 01006 01007 bool 01008 Connect::is_local() 01009 { 01010 return _local; 01011 } 01012 01029 string 01030 Connect::URL(bool ce) 01031 { 01032 if (_local) 01033 throw InternalErr(__FILE__, __LINE__, 01034 "URL(): This call is only valid for a DAP data source."); 01035 01036 if (ce) 01037 return _URL + "?" + _proj + _sel; 01038 else 01039 return _URL; 01040 } 01041 01050 string 01051 Connect::CE() 01052 { 01053 if (_local) 01054 throw InternalErr(__FILE__, __LINE__, 01055 "CE(): This call is only valid for a DAP data source."); 01056 01057 return _proj + _sel; 01058 } 01059 01065 void 01066 Connect::set_credentials(string u, string p) 01067 { 01068 if (d_http) 01069 d_http->set_credentials(u, p); 01070 } 01071 01075 void 01076 Connect::set_accept_deflate(bool deflate) 01077 { 01078 if (d_http) 01079 d_http->set_accept_deflate(deflate); 01080 } 01081 01087 void 01088 Connect::set_xdap_protocol(int major, int minor) 01089 { 01090 if (d_http) 01091 d_http->set_xdap_protocol(major, minor); 01092 } 01093 01097 void 01098 Connect::set_cache_enabled(bool cache) 01099 { 01100 if (d_http) 01101 d_http->set_cache_enabled(cache); 01102 } 01103 01104 bool 01105 Connect::is_cache_enabled() 01106 { 01107 bool status; 01108 DBG(cerr << "Entering is_cache_enabled (" << hex << d_http << dec 01109 << ")... "); 01110 if (d_http) 01111 status = d_http->is_cache_enabled(); 01112 else 01113 status = false; 01114 DBGN(cerr << "exiting" << endl); 01115 return status; 01116 } 01117 01118 } // namespace libdap