libdap++ Updated for version 3.8.2

Connect.cc

Go to the documentation of this file.
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 22703 2010-05-11 18:10:01Z 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             try {
00128                 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end();
00129                      i++) {
00130                     (*i)->deserialize(um, &data);
00131                 }
00132             }
00133             catch (Error &e) {
00134                 throw e;
00135             }
00136 
00137             return;
00138         }
00139 
00140     case dods_data:
00141     default: {
00142             // Parse the DDS; throw an exception on error.
00143             data.parse(rs->get_stream());
00144 #if FILE_METHODS
00145             XDRFileUnMarshaller um( rs->get_stream() ) ;
00146 #else
00147             fpistream in ( rs->get_stream() );
00148             XDRStreamUnMarshaller um( in ) ;
00149 #endif
00150             // Load the DDS with data.
00151             try {
00152                 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end();
00153                      i++) {
00154                     (*i)->deserialize(um, &data);
00155                 }
00156             }
00157             catch (Error &e) {
00158                 throw e;
00159             }
00160 
00161             return;
00162         }
00163     }
00164 }
00165 
00166 // Barely a parser... This is used when reading from local sources of DODS
00167 // Data objects. It simulates the important actions of the libwww MIME header
00168 // parser. Those actions fill in certain fields in the Connect object. jhrg
00169 // 5/20/97
00170 //
00171 // Make sure that this parser reads from data_source without disturbing the
00172 // information in data_source that follows the MIME header. Since the DDS
00173 // (which follows the MIME header) is parsed by a flex/bison scanner/parser,
00174 // make sure to use I/O calls that will mesh with ANSI C I/O calls. In the
00175 // old GNU libg++, the C++ calls were synchronized with the C calls, but that
00176 // may no longer be the case. 5/31/99 jhrg
00177 
00187 void
00188 Connect::parse_mime(Response *rs)
00189 {
00190     rs->set_version("dods/0.0"); // initial value; for backward compatibility.
00191     rs->set_protocol("2.0");
00192 
00193     FILE *data_source = rs->get_stream();
00194     string mime = get_next_mime_header(data_source);
00195     while (!mime.empty()) {
00196         string header, value;
00197         parse_mime_header(mime, header, value);
00198 
00199         // Note that this is an ordered list
00200         if (header == "content-description:") {
00201             DBG(cout << header << ": " << value << endl);
00202             rs->set_type(get_description_type(value));
00203         }
00204         // Use the value of xdods-server only if no other value has been read
00205         else if (header == "xdods-server:"
00206                  && rs->get_version() == "dods/0.0") {
00207             DBG(cout << header << ": " << value << endl);
00208             rs->set_version(value);
00209         }
00210         // This trumps 'xdods-server' and 'server'
00211         else if (header == "xopendap-server:") {
00212             DBG(cout << header << ": " << value << endl);
00213             rs->set_version(value);
00214         }
00215         else if (header == "xdap:") {
00216             DBG(cout << header << ": " << value << endl);
00217             rs->set_protocol(value);
00218         }
00219         // Only look for 'server' if no other header supplies this info.
00220         else if (rs->get_version() == "dods/0.0" && header == "server:") {
00221             DBG(cout << header << ": " << value << endl);
00222             rs->set_version(value);
00223         }
00224 
00225         mime = get_next_mime_header(data_source);
00226     }
00227 }
00228 
00229 // public mfuncs
00230 
00238 Connect::Connect(const string &n, string uname, string password)
00239 throw(Error, InternalErr)
00240         : d_http(0), d_version("unknown"), d_protocol("2.0")
00241 {
00242     string name = prune_spaces(n);
00243 
00244     // Figure out if the URL starts with 'http', if so, make sure that we
00245     // talk to an instance of HTTPConnect.
00246     if (name.find("http") == 0) {
00247         DBG(cerr << "Connect: The identifier is an http URL" << endl);
00248         d_http = new HTTPConnect(RCReader::instance());
00249 
00250         // Find and store any CE given with the URL.
00251         string::size_type dotpos = name.find('?');
00252         if (dotpos != name.npos) {
00253             _URL = name.substr(0, dotpos);
00254             string expr = name.substr(dotpos + 1);
00255 
00256             dotpos = expr.find('&');
00257             if (dotpos != expr.npos) {
00258                 _proj = expr.substr(0, dotpos);
00259                 _sel = expr.substr(dotpos); // XXX includes '&'
00260             }
00261             else {
00262                 _proj = expr;
00263                 _sel = "";
00264             }
00265         }
00266         else {
00267             _URL = name;
00268             _proj = "";
00269             _sel = "";
00270         }
00271 
00272         _local = false;
00273     }
00274     else {
00275         DBG(cerr << "Connect: The identifier is a local data source." << endl);
00276 
00277         d_http = 0;
00278         _URL = "";
00279         _local = true;  // local in this case means non-DAP
00280     }
00281 
00282     set_credentials(uname, password);
00283 }
00284 
00285 Connect::~Connect()
00286 {
00287     DBG2(cerr << "Entering the Connect dtor" << endl);
00288 
00289     if (d_http)
00290         delete d_http; d_http = 0;
00291 
00292     DBG2(cerr << "Leaving the Connect dtor" << endl);
00293 }
00294 
00302 string
00303 Connect::request_version()
00304 {
00305     string version_url = _URL + ".ver";
00306     if (_proj.length() + _sel.length())
00307         version_url = version_url + "?" + id2www_ce(_proj + _sel);
00308 
00309     Response *rs = 0;
00310     try {
00311         rs = d_http->fetch_url(version_url);
00312     }
00313     catch (Error &e) {
00314         delete rs; rs = 0;
00315         throw e;
00316     }
00317 
00318     d_version = rs->get_version();
00319     d_protocol = rs->get_protocol();
00320 
00321     delete rs; rs = 0;
00322 
00323     return d_version;
00324 }
00325 
00337 string
00338 Connect::request_protocol()
00339 {
00340     string version_url = _URL + ".ver";
00341     if (_proj.length() + _sel.length())
00342         version_url = version_url + "?" + id2www_ce(_proj + _sel);
00343 
00344     Response *rs = 0;
00345     try {
00346         rs = d_http->fetch_url(version_url);
00347     }
00348     catch (Error &e) {
00349         delete rs; rs = 0;
00350         throw e;
00351     }
00352 
00353     d_version = rs->get_version();
00354     d_protocol = rs->get_protocol();
00355 
00356     delete rs; rs = 0;
00357 
00358     return d_protocol;
00359 }
00360 
00368 void
00369 Connect::request_das(DAS &das)
00370 {
00371     string das_url = _URL + ".das";
00372     if (_proj.length() + _sel.length())
00373         das_url = das_url + "?" + id2www_ce(_proj + _sel);
00374 
00375     Response *rs = 0;
00376     try {
00377         rs = d_http->fetch_url(das_url);
00378     }
00379     catch (Error &e) {
00380         delete rs; rs = 0;
00381         throw e;
00382     }
00383 
00384     d_version = rs->get_version();
00385     d_protocol = rs->get_protocol();
00386 
00387     switch (rs->get_type()) {
00388     case dods_error: {
00389             Error e;
00390             if (!e.parse(rs->get_stream())) {
00391                 throw InternalErr(__FILE__, __LINE__,
00392                                   "Could not parse error returned from server.");
00393                 break;
00394             }
00395             throw e;
00396             break;
00397         }
00398 
00399     case web_error:
00400         // We should never get here; a web error should be picked up read_url
00401         // (called by fetch_url) and result in a thrown Error object.
00402         break;
00403 
00404     case dods_das:
00405     default:
00406         // DAS::parse throws an exception on error.
00407         try {
00408             das.parse(rs->get_stream()); // read and parse the das from a file
00409         }
00410         catch (Error &e) {
00411             delete rs; rs = 0;
00412             throw e;
00413         }
00414 
00415         break;
00416     }
00417 
00418     delete rs; rs = 0;
00419 }
00420 
00431 void
00432 Connect::request_das_url(DAS &das)
00433 {
00434     string use_url = _URL + "?" + _proj + _sel ;
00435     Response *rs = 0;
00436     try {
00437         rs = d_http->fetch_url(use_url);
00438     }
00439     catch (Error &e) {
00440         delete rs; rs = 0;
00441         throw e;
00442     }
00443 
00444     d_version = rs->get_version();
00445     d_protocol = rs->get_protocol();
00446 
00447     switch (rs->get_type()) {
00448     case dods_error: {
00449             Error e;
00450             if (!e.parse(rs->get_stream())) {
00451                 throw InternalErr(__FILE__, __LINE__,
00452                                   "Could not parse error returned from server.");
00453                 break;
00454             }
00455             throw e;
00456             break;
00457         }
00458 
00459     case web_error:
00460         // We should never get here; a web error should be picked up read_url
00461         // (called by fetch_url) and result in a thrown Error object.
00462         break;
00463 
00464     case dods_das:
00465     default:
00466         // DAS::parse throws an exception on error.
00467         try {
00468             das.parse(rs->get_stream()); // read and parse the das from a file
00469         }
00470         catch (Error &e) {
00471             delete rs; rs = 0;
00472             throw e;
00473         }
00474 
00475         break;
00476     }
00477 
00478     delete rs; rs = 0;
00479 }
00480 
00494 void
00495 Connect::request_dds(DDS &dds, string expr)
00496 {
00497     string proj, sel;
00498     string::size_type dotpos = expr.find('&');
00499     if (dotpos != expr.npos) {
00500         proj = expr.substr(0, dotpos);
00501         sel = expr.substr(dotpos);
00502     }
00503     else {
00504         proj = expr;
00505         sel = "";
00506     }
00507 
00508     string dds_url = _URL + ".dds" + "?"
00509                      + id2www_ce(_proj + proj + _sel + sel);
00510 
00511     Response *rs = 0;
00512     try {
00513         rs = d_http->fetch_url(dds_url);
00514     }
00515     catch (Error &e) {
00516         delete rs; rs = 0;
00517         throw e;
00518     }
00519 
00520     d_version = rs->get_version();
00521     d_protocol = rs->get_protocol();
00522 
00523     switch (rs->get_type()) {
00524     case dods_error: {
00525             Error e;
00526             if (!e.parse(rs->get_stream())) {
00527                 throw InternalErr(__FILE__, __LINE__,
00528                                   "Could not parse error returned from server.");
00529                 break;
00530             }
00531             throw e;
00532             break;
00533         }
00534 
00535     case web_error:
00536         // We should never get here; a web error should be picked up read_url
00537         // (called by fetch_url) and result in a thrown Error object.
00538         break;
00539 
00540     case dods_dds:
00541     default:
00542         // DDS::prase throws an exception on error.
00543         try {
00544             dds.parse(rs->get_stream()); // read and parse the dds from a file
00545         }
00546         catch (Error &e) {
00547             delete rs; rs = 0;
00548             throw e;
00549         }
00550         break;
00551     }
00552 
00553     delete rs; rs = 0;
00554 }
00555 
00572 void
00573 Connect::request_dds_url(DDS &dds)
00574 {
00575     string use_url = _URL + "?" + _proj + _sel ;
00576     Response *rs = 0;
00577     try {
00578         rs = d_http->fetch_url(use_url);
00579     }
00580     catch (Error &e) {
00581         delete rs; rs = 0;
00582         throw e;
00583     }
00584 
00585     d_version = rs->get_version();
00586     d_protocol = rs->get_protocol();
00587 
00588     switch (rs->get_type()) {
00589     case dods_error: {
00590             Error e;
00591             if (!e.parse(rs->get_stream())) {
00592                 throw InternalErr(__FILE__, __LINE__,
00593                                   "Could not parse error returned from server.");
00594                 break;
00595             }
00596             throw e;
00597             break;
00598         }
00599 
00600     case web_error:
00601         // We should never get here; a web error should be picked up read_url
00602         // (called by fetch_url) and result in a thrown Error object.
00603         break;
00604 
00605     case dods_dds:
00606     default:
00607         // DDS::prase throws an exception on error.
00608         try {
00609             dds.parse(rs->get_stream()); // read and parse the dds from a file
00610         }
00611         catch (Error &e) {
00612             delete rs; rs = 0;
00613             throw e;
00614         }
00615         break;
00616     }
00617 
00618     delete rs; rs = 0;
00619 }
00620 
00632 void
00633 Connect::request_ddx(DDS &dds, string expr)
00634 {
00635     string proj, sel;
00636     string::size_type dotpos = expr.find('&');
00637     if (dotpos != expr.npos) {
00638         proj = expr.substr(0, dotpos);
00639         sel = expr.substr(dotpos);
00640     }
00641     else {
00642         proj = expr;
00643         sel = "";
00644     }
00645 
00646     string ddx_url = _URL + ".ddx" + "?"
00647                      + id2www_ce(_proj + proj + _sel + sel);
00648 
00649     Response *rs = 0;
00650     try {
00651         rs = d_http->fetch_url(ddx_url);
00652     }
00653     catch (Error &e) {
00654         delete rs; rs = 0;
00655         throw e;
00656     }
00657 
00658     d_version = rs->get_version();
00659     d_protocol = rs->get_protocol();
00660 
00661     switch (rs->get_type()) {
00662     case dods_error: {
00663             Error e;
00664             if (!e.parse(rs->get_stream())) {
00665                 throw InternalErr(__FILE__, __LINE__,
00666                                   "Could not parse error returned from server.");
00667                 break;
00668             }
00669             throw e;
00670             break;
00671         }
00672 
00673     case web_error:
00674         // We should never get here; a web error should be picked up read_url
00675         // (called by fetch_url) and result in a thrown Error object.
00676         break;
00677 
00678     case dap4_ddx:
00679     case dods_ddx:
00680         try {
00681             string blob;
00682 
00683             DDXParser ddxp(dds.get_factory());
00684             ddxp.intern_stream(rs->get_stream(), &dds, blob);
00685         }
00686         catch (Error &e) {
00687             delete rs; rs = 0;
00688             throw e;
00689         }
00690         break;
00691 
00692     default:
00693         throw Error("The site did not return a valid response (it lacked the\n\
00694 expected content description header value of 'dap4-ddx' and\n\
00695 instead returned '" + long_to_string(rs->get_type()) + "').\n\
00696 This may indicate that the server at the site is not correctly\n\
00697 configured, or that the URL has changed.");
00698     }
00699 
00700     delete rs; rs = 0;
00701 }
00702 
00705 void
00706 Connect::request_ddx_url(DDS &dds)
00707 {
00708     string use_url = _URL + "?" + _proj + _sel ;
00709 
00710     Response *rs = 0;
00711     try {
00712         rs = d_http->fetch_url(use_url);
00713     }
00714     catch (Error &e) {
00715         delete rs; rs = 0;
00716         throw e;
00717     }
00718 
00719     d_version = rs->get_version();
00720     d_protocol = rs->get_protocol();
00721 
00722     switch (rs->get_type()) {
00723     case dods_error: {
00724             Error e;
00725             if (!e.parse(rs->get_stream())) {
00726                 throw InternalErr(__FILE__, __LINE__,
00727                                   "Could not parse error returned from server.");
00728                 break;
00729             }
00730             throw e;
00731             break;
00732         }
00733 
00734     case web_error:
00735         // We should never get here; a web error should be picked up read_url
00736         // (called by fetch_url) and result in a thrown Error object.
00737         break;
00738 
00739     case dap4_ddx:
00740     case dods_ddx:
00741         try {
00742             string blob;
00743 
00744             DDXParser ddxp(dds.get_factory());
00745             ddxp.intern_stream(rs->get_stream(), &dds, blob);
00746         }
00747         catch (Error &e) {
00748             delete rs; rs = 0;
00749             throw e;
00750         }
00751         break;
00752 
00753     default:
00754         throw Error("The site did not return a valid response (it lacked the\n\
00755 expected content description header value of 'dap4-ddx' and\n\
00756 instead returned '" + long_to_string(rs->get_type()) + "').\n\
00757 This may indicate that the server at the site is not correctly\n\
00758 configured, or that the URL has changed.");
00759     }
00760 
00761     delete rs; rs = 0;
00762 }
00763 
00779 void
00780 Connect::request_data(DataDDS &data, string expr)
00781 {
00782     string proj, sel;
00783     string::size_type dotpos = expr.find('&');
00784     if (dotpos != expr.npos) {
00785         proj = expr.substr(0, dotpos);
00786         sel = expr.substr(dotpos);
00787     }
00788     else {
00789         proj = expr;
00790         sel = "";
00791     }
00792 
00793     string data_url = _URL + ".dods?"
00794                       + id2www_ce(_proj + proj + _sel + sel);
00795 
00796     Response *rs = 0;
00797     // We need to catch Error exceptions to ensure calling close_output.
00798     try {
00799         rs = d_http->fetch_url(data_url);
00800 
00801         d_version = rs->get_version();
00802         d_protocol = rs->get_protocol();
00803 
00804         process_data(data, rs);
00805         delete rs; rs = 0;
00806     }
00807     catch (Error &e) {
00808         delete rs; rs = 0;
00809         throw e;
00810     }
00811 }
00812 
00830 void
00831 Connect::request_data_url(DataDDS &data)
00832 {
00833     string use_url = _URL + "?" + _proj + _sel ;
00834     Response *rs = 0;
00835     // We need to catch Error exceptions to ensure calling close_output.
00836     try {
00837         rs = d_http->fetch_url(use_url);
00838 
00839         d_version = rs->get_version();
00840         d_protocol = rs->get_protocol();
00841 
00842         process_data(data, rs);
00843         delete rs; rs = 0;
00844     }
00845     catch (Error &e) {
00846         delete rs; rs = 0;
00847         throw e;
00848     }
00849 }
00850 
00851 void
00852 Connect::request_data_ddx(DataDDS &data, string expr)
00853 {
00854     string proj, sel;
00855     string::size_type dotpos = expr.find('&');
00856     if (dotpos != expr.npos) {
00857         proj = expr.substr(0, dotpos);
00858         sel = expr.substr(dotpos);
00859     }
00860     else {
00861         proj = expr;
00862         sel = "";
00863     }
00864 
00865     string data_url = _URL + ".dap?"
00866                       + id2www_ce(_proj + proj + _sel + sel);
00867 
00868     Response *rs = 0;
00869     // We need to catch Error exceptions to ensure calling close_output.
00870     try {
00871         rs = d_http->fetch_url(data_url);
00872 
00873         d_version = rs->get_version();
00874         d_protocol = rs->get_protocol();
00875 
00876         process_data(data, rs);
00877         delete rs; rs = 0;
00878     }
00879     catch (Error &e) {
00880         delete rs; rs = 0;
00881         throw e;
00882     }
00883 }
00884 
00885 void
00886 Connect::request_data_ddx_url(DataDDS &data)
00887 {
00888     string use_url = _URL + "?" + _proj + _sel ;
00889     Response *rs = 0;
00890     // We need to catch Error exceptions to ensure calling close_output.
00891     try {
00892         rs = d_http->fetch_url(use_url);
00893 
00894         d_version = rs->get_version();
00895         d_protocol = rs->get_protocol();
00896 
00897         process_data(data, rs);
00898         delete rs; rs = 0;
00899     }
00900     catch (Error &e) {
00901         delete rs; rs = 0;
00902         throw e;
00903     }
00904 }
00905 
00919 void
00920 Connect::read_data(DataDDS &data, Response *rs)
00921 {
00922     if (!rs)
00923         throw InternalErr(__FILE__, __LINE__, "Response object is null.");
00924 
00925     // Read from data_source and parse the MIME headers specific to DAP2/4.
00926     parse_mime(rs);
00927 
00928     read_data_no_mime(data, rs);
00929 }
00930 
00931 // This function looks at the input stream and makes its best guess at what
00932 // lies in store for downstream processing code. Definitely heuristic.
00933 // Assumptions:
00934 // #1 The current file position is past any MIME headers (if they were present).
00935 // #2 We must reset the FILE* position to the start of the DDS or DDX headers
00936 static void
00937 divine_type_information(Response *rs)
00938 {
00939     // Consume whitespace
00940     char c = getc(rs->get_stream());
00941     while (isspace(c)) {
00942         c = getc(rs->get_stream());
00943     }
00944 
00945     // The heuristic here is that a DataDDX is a multipart MIME document and
00946     // The first non space character found after the headers is the start of
00947     // the first part which looks like '--<boundary>' while a DataDDS starts
00948     // with a DDS (;Dataset {' ...). I take into account that our parsers have
00949     // accepted both 'Dataset' and 'dataset' for a long time.
00950     switch (c) {
00951     case '-':
00952         rs->set_type(dap4_data_ddx);
00953         break;
00954     case 'D':
00955     case 'd':
00956         rs->set_type(dods_data);
00957         break;
00958     default:
00959         throw InternalErr(__FILE__, __LINE__, "Could not determine type of response object in stream.");
00960     }
00961 
00962     ungetc(c, rs->get_stream());
00963 }
00964 
00977 void
00978 Connect::read_data_no_mime(DataDDS &data, Response *rs)
00979 {
00980     if (rs->get_type() == unknown_type)
00981         divine_type_information(rs);
00982 
00983     switch (rs->get_type()) {
00984     case dods_data:
00985         d_version = rs->get_version();
00986         d_protocol = rs->get_protocol();
00987         process_data(data, rs);
00988         break;
00989     case dap4_data_ddx:
00990         process_data(data, rs);
00991         d_version = rs->get_version();
00992         d_protocol = data.get_protocol();
00993         break;
00994     default:
00995         throw InternalErr(__FILE__, __LINE__, "Should have been a DataDDS or DataDDX.");
00996     }
00997 }
00998 
00999 bool
01000 Connect::is_local()
01001 {
01002     return _local;
01003 }
01004 
01021 string
01022 Connect::URL(bool ce)
01023 {
01024     if (_local)
01025         throw InternalErr(__FILE__, __LINE__,
01026                           "URL(): This call is only valid for a DAP data source.");
01027 
01028     if (ce)
01029         return _URL + "?" + _proj + _sel;
01030     else
01031         return _URL;
01032 }
01033 
01042 string
01043 Connect::CE()
01044 {
01045     if (_local)
01046         throw InternalErr(__FILE__, __LINE__,
01047                           "CE(): This call is only valid for a DAP data source.");
01048 
01049     return _proj + _sel;
01050 }
01051 
01057 void
01058 Connect::set_credentials(string u, string p)
01059 {
01060     if (d_http)
01061         d_http->set_credentials(u, p);
01062 }
01063 
01067 void
01068 Connect::set_accept_deflate(bool deflate)
01069 {
01070     if (d_http)
01071         d_http->set_accept_deflate(deflate);
01072 }
01073 
01079 void
01080 Connect::set_xdap_protocol(int major, int minor)
01081 {
01082     if (d_http)
01083         d_http->set_xdap_protocol(major, minor);
01084 }
01085 
01089 void
01090 Connect::set_cache_enabled(bool cache)
01091 {
01092     if (d_http)
01093         d_http->set_cache_enabled(cache);
01094 }
01095 
01096 bool
01097 Connect::is_cache_enabled()
01098 {
01099     bool status;
01100     DBG(cerr << "Entering is_cache_enabled (" << hex << d_http << dec
01101         << ")... ");
01102     if (d_http)
01103         status = d_http->is_cache_enabled();
01104     else
01105         status = false;
01106     DBGN(cerr << "exiting" << endl);
01107     return status;
01108 }
01109 
01110 } // namespace libdap