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 
00041 static char rcsid[] not_used =
00042     { "$Id: Connect.cc 19917 2008-11-25 23:47:56Z jimg $"
00043     };
00044 
00045 #include <cstring>
00046 #include <fstream>
00047 #include <algorithm>
00048 
00049 #include "debug.h"
00050 #include "DataDDS.h"
00051 #include "Connect.h"
00052 #include "escaping.h"
00053 #include "RCReader.h"
00054 #include "DDXParser.h"
00055 #include "XDRFileUnMarshaller.h"
00056 
00057 using std::cerr;
00058 using std::endl;
00059 using std::ifstream;
00060 using std::ofstream;
00061 using std::min;
00062 
00063 namespace libdap {
00064 
00067 void
00068 Connect::process_data(DataDDS &data, Response *rs)
00069 {
00070     DBG(cerr << "Entering Connect::process_data" << endl);
00071 
00072     // Use the implementation and protocol versions from the Response object
00073     // since the copies in Connect might go away. Regardless, we must keep the
00074     // Response object alive until we no longer need the stream, since
00075     // destroying it will close the stream. So, might as well use it for the
00076     // version info too...
00077     data.set_version(rs->get_version());
00078     data.set_protocol(rs->get_protocol());
00079 
00080     DBG(cerr << "Entering process_data: d_stream = " << rs << endl);
00081     switch (rs->get_type()) {
00082     case dods_error: {
00083             Error e;
00084             if (!e.parse(rs->get_stream()))
00085                 throw InternalErr(__FILE__, __LINE__,
00086                                   "Could not parse the Error object returned by the server!");
00087             throw e;
00088         }
00089 
00090     case web_error:
00091         // Web errors (those reported in the return document's MIME header)
00092         // are processed by the WWW library.
00093         throw InternalErr(__FILE__, __LINE__, "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
00094 
00095     case dods_data:
00096     default: {
00097             // Parse the DDS; throw an exception on error.
00098             data.parse(rs->get_stream());
00099             XDRFileUnMarshaller um( rs->get_stream() ) ;
00100 
00101             // Load the DDS with data.
00102             try {
00103                 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end();
00104                      i++) {
00105                     (*i)->deserialize(um, &data);
00106                 }
00107             }
00108             catch (Error &e) {
00109                 throw e;
00110             }
00111 
00112             return;
00113         }
00114 
00115 #if 0
00116         // According to the spec (DAP 2), servers MUST return the dods_data
00117         // Content-Type. But, many older servers do not do this, so the
00118         // default case is not to throw an error, but to treat the response
00119         // as data... See bug 706. 03/22/04 jhrg
00120     default:
00121         throw Error("The site did not return a valid response (it lacked the\nexpected content description header value of 'dods_data').\nThis may indicate that the server at the site is not correctly\nconfigured, or that the URL has changed.");
00122 #endif
00123     }
00124 }
00125 
00126 // Barely a parser... This is used when reading from local sources of DODS
00127 // Data objects. It simulates the important actions of the libwww MIME header
00128 // parser. Those actions fill in certain fields in the Connect object. jhrg
00129 // 5/20/97
00130 //
00131 // Make sure that this parser reads from data_source without disturbing the
00132 // information in data_source that follows the MIME header. Since the DDS
00133 // (which follows the MIME header) is parsed by a flex/bison scanner/parser,
00134 // make sure to use I/O calls that will mesh with ANSI C I/O calls. In the
00135 // old GNU libg++, the C++ calls were synchronized with the C calls, but that
00136 // may no longer be the case. 5/31/99 jhrg
00137 
00147 void
00148 Connect::parse_mime(Response *rs)
00149 {
00150     rs->set_version("dods/0.0"); // initial value; for backward compat.
00151     rs->set_protocol("2.0");
00152 
00153     // If the first line does not start with HTTP, XDODS or XDAP, assume
00154     // there's no MIME header here and return without reading anymore
00155     FILE *data_source = rs->get_stream();
00156 
00157     char line[256];
00158     fgets(line, 255, data_source);
00159 
00160     int slen = strlen(line);
00161     slen = min(slen, 256); // use min to limit slen to 256 (fortify)
00162     line[slen - 1] = '\0'; // remove the newline
00163     if (line[slen - 2] == '\r') // ...and the preceding carriage return
00164         line[slen - 2] = '\0';
00165 
00166     while (line[0] != '\0') {
00167         char h[256], v[256];
00168         sscanf(line, "%s %s\n", h, v);
00169         string header = h;
00170         string value = v;
00171         downcase(header);
00172         downcase(value);
00173 
00174         if (header == "content-description:") {
00175             DBG(cout << header << ": " << value << endl);
00176             rs->set_type(get_description_type(value));
00177         }
00178         else if (header == "xdods-server:"
00179                  && rs->get_version() == "dods/0.0") {
00180             DBG(cout << header << ": " << value << endl);
00181             rs->set_version(value);
00182         }
00183         else if (header == "xopendap-server:") {
00184             DBG(cout << header << ": " << value << endl);
00185             rs->set_version(value);
00186         }
00187         else if (header == "xdap:") {
00188             DBG(cout << header << ": " << value << endl);
00189             rs->set_protocol(value);
00190         }
00191         else if (rs->get_version() == "dods/0.0" && header == "server:") {
00192             DBG(cout << header << ": " << value << endl);
00193             rs->set_version(value);
00194         }
00195 
00196         fgets(line, 255, data_source);
00197         slen = strlen(line);
00198         slen = min(slen, 256); // use min to limit slen to 256
00199         line[slen - 1] = '\0';
00200         if (line[slen - 2] == '\r')
00201             line[slen - 2] = '\0';
00202     }
00203 }
00204 
00205 // public mfuncs
00206 
00214 Connect::Connect(const string &n, string uname, string password)
00215 throw(Error, InternalErr)
00216         : d_http(0), d_version("unknown"), d_protocol("2.0")
00217 {
00218     string name = prune_spaces(n);
00219 
00220     // Figure out if the URL starts with 'http', if so, make sure that we
00221     // talk to an instance of HTTPConnect.
00222     if (name.find("http") == 0) {
00223         DBG(cerr << "Connect: The identifier is an http URL" << endl);
00224         d_http = new HTTPConnect(RCReader::instance());
00225 
00226         // Find and store any CE given with the URL.
00227         string::size_type dotpos = name.find('?');
00228         if (dotpos != name.npos) {
00229             _URL = name.substr(0, dotpos);
00230             string expr = name.substr(dotpos + 1);
00231 
00232             dotpos = expr.find('&');
00233             if (dotpos != expr.npos) {
00234                 _proj = expr.substr(0, dotpos);
00235                 _sel = expr.substr(dotpos); // XXX includes '&'
00236             }
00237             else {
00238                 _proj = expr;
00239                 _sel = "";
00240             }
00241         }
00242         else {
00243             _URL = name;
00244             _proj = "";
00245             _sel = "";
00246         }
00247 
00248         _local = false;
00249     }
00250     else {
00251         DBG(cerr << "Connect: The identifier is a local data source." << endl);
00252 
00253         d_http = 0;
00254         _URL = "";
00255         _local = true;  // local in this case means non-DAP
00256     }
00257 
00258     set_credentials(uname, password);
00259 }
00260 
00261 Connect::~Connect()
00262 {
00263     DBG2(cerr << "Entering the Connect dtor" << endl);
00264 
00265     if (d_http)
00266         delete d_http; d_http = 0;
00267 
00268     DBG2(cerr << "Leaving the Connect dtor" << endl);
00269 }
00270 
00278 string
00279 Connect::request_version()
00280 {
00281     string version_url = _URL + ".ver";
00282     if (_proj.length() + _sel.length())
00283         version_url = version_url + "?" + id2www_ce(_proj + _sel);
00284 
00285     Response *rs = 0;
00286     try {
00287         rs = d_http->fetch_url(version_url);
00288     }
00289     catch (Error &e) {
00290         delete rs; rs = 0;
00291         throw e;
00292     }
00293 
00294     d_version = rs->get_version();
00295     d_protocol = rs->get_protocol();
00296     delete rs; rs = 0;
00297 
00298     return d_version;
00299 }
00300 
00312 string
00313 Connect::request_protocol()
00314 {
00315     string version_url = _URL + ".ver";
00316     if (_proj.length() + _sel.length())
00317         version_url = version_url + "?" + id2www_ce(_proj + _sel);
00318 
00319     Response *rs = 0;
00320     try {
00321         rs = d_http->fetch_url(version_url);
00322     }
00323     catch (Error &e) {
00324         delete rs; rs = 0;
00325         throw e;
00326     }
00327 
00328     d_version = rs->get_version();
00329     d_protocol = rs->get_protocol();
00330     delete rs; rs = 0;
00331 
00332     return d_protocol;
00333 }
00334 
00342 void
00343 Connect::request_das(DAS &das)
00344 {
00345     string das_url = _URL + ".das";
00346     if (_proj.length() + _sel.length())
00347         das_url = das_url + "?" + id2www_ce(_proj + _sel);
00348 
00349     Response *rs = 0;
00350     try {
00351         rs = d_http->fetch_url(das_url);
00352     }
00353     catch (Error &e) {
00354         delete rs; rs = 0;
00355         throw e;
00356     }
00357 
00358     d_version = rs->get_version();
00359     d_protocol = rs->get_protocol();
00360 
00361     switch (rs->get_type()) {
00362     case dods_error: {
00363             Error e;
00364             if (!e.parse(rs->get_stream())) {
00365                 throw InternalErr(__FILE__, __LINE__,
00366                                   "Could not parse error returned from server.");
00367                 break;
00368             }
00369             throw e;
00370             break;
00371         }
00372 
00373     case web_error:
00374         // We should never get here; a web error should be picked up read_url
00375         // (called by fetch_url) and result in a thrown Error object.
00376         break;
00377 
00378     case dods_das:
00379     default:
00380         // DAS::parse throws an exception on error.
00381         try {
00382             das.parse(rs->get_stream()); // read and parse the das from a file
00383         }
00384         catch (Error &e) {
00385             delete rs; rs = 0;
00386             throw e;
00387         }
00388 
00389         break;
00390 
00391 #if 0
00392         // See the comment in process_data() and bug 706. 03/22/04 jhrg
00393     default:
00394         throw Error("The site did not return a valid response (it lacked the\nexpected content description header value of 'dods_das').\nThis may indicate that the server at the site is not correctly\nconfigured, or that the URL has changed.");
00395 #endif
00396     }
00397 
00398     delete rs; rs = 0;
00399 }
00400 
00411 void
00412 Connect::request_das_url(DAS &das)
00413 {
00414     string use_url = _URL + "?" + _proj + _sel ;
00415     Response *rs = 0;
00416     try {
00417         rs = d_http->fetch_url(use_url);
00418     }
00419     catch (Error &e) {
00420         delete rs; rs = 0;
00421         throw e;
00422     }
00423 
00424     d_version = rs->get_version();
00425     d_protocol = rs->get_protocol();
00426 
00427     switch (rs->get_type()) {
00428     case dods_error: {
00429             Error e;
00430             if (!e.parse(rs->get_stream())) {
00431                 throw InternalErr(__FILE__, __LINE__,
00432                                   "Could not parse error returned from server.");
00433                 break;
00434             }
00435             throw e;
00436             break;
00437         }
00438 
00439     case web_error:
00440         // We should never get here; a web error should be picked up read_url
00441         // (called by fetch_url) and result in a thrown Error object.
00442         break;
00443 
00444     case dods_das:
00445     default:
00446         // DAS::parse throws an exception on error.
00447         try {
00448             das.parse(rs->get_stream()); // read and parse the das from a file
00449         }
00450         catch (Error &e) {
00451             delete rs; rs = 0;
00452             throw e;
00453         }
00454 
00455         break;
00456     }
00457 
00458     delete rs; rs = 0;
00459 }
00460 
00474 void
00475 Connect::request_dds(DDS &dds, string expr)
00476 {
00477     string proj, sel;
00478     string::size_type dotpos = expr.find('&');
00479     if (dotpos != expr.npos) {
00480         proj = expr.substr(0, dotpos);
00481         sel = expr.substr(dotpos);
00482     }
00483     else {
00484         proj = expr;
00485         sel = "";
00486     }
00487 
00488     string dds_url = _URL + ".dds" + "?"
00489                      + id2www_ce(_proj + proj + _sel + sel);
00490 
00491     Response *rs = 0;
00492     try {
00493         rs = d_http->fetch_url(dds_url);
00494     }
00495     catch (Error &e) {
00496         delete rs; rs = 0;
00497         throw e;
00498     }
00499 
00500     d_version = rs->get_version();
00501     d_protocol = rs->get_protocol();
00502 
00503     switch (rs->get_type()) {
00504     case dods_error: {
00505             Error e;
00506             if (!e.parse(rs->get_stream())) {
00507                 throw InternalErr(__FILE__, __LINE__,
00508                                   "Could not parse error returned from server.");
00509                 break;
00510             }
00511             throw e;
00512             break;
00513         }
00514 
00515     case web_error:
00516         // We should never get here; a web error should be picked up read_url
00517         // (called by fetch_url) and result in a thrown Error object.
00518         break;
00519 
00520     case dods_dds:
00521     default:
00522         // DDS::prase throws an exception on error.
00523         try {
00524             dds.parse(rs->get_stream()); // read and parse the dds from a file
00525         }
00526         catch (Error &e) {
00527             delete rs; rs = 0;
00528             throw e;
00529         }
00530         break;
00531 
00532 #if 0
00533         // See the comment in process_data() and bug 706. 03/22/04 jhrg
00534     default:
00535         throw Error("The site did not return a valid response (it lacked the\nexpected content description header value of 'dods_dds').\nThis may indicate that the server at the site is not correctly\nconfigured, or that the URL has changed.");
00536 #endif
00537     }
00538 
00539     delete rs; rs = 0;
00540 }
00541 
00558 void
00559 Connect::request_dds_url(DDS &dds)
00560 {
00561     string use_url = _URL + "?" + _proj + _sel ;
00562     Response *rs = 0;
00563     try {
00564         rs = d_http->fetch_url(use_url);
00565     }
00566     catch (Error &e) {
00567         delete rs; rs = 0;
00568         throw e;
00569     }
00570 
00571     d_version = rs->get_version();
00572     d_protocol = rs->get_protocol();
00573 
00574     switch (rs->get_type()) {
00575     case dods_error: {
00576             Error e;
00577             if (!e.parse(rs->get_stream())) {
00578                 throw InternalErr(__FILE__, __LINE__,
00579                                   "Could not parse error returned from server.");
00580                 break;
00581             }
00582             throw e;
00583             break;
00584         }
00585 
00586     case web_error:
00587         // We should never get here; a web error should be picked up read_url
00588         // (called by fetch_url) and result in a thrown Error object.
00589         break;
00590 
00591     case dods_dds:
00592     default:
00593         // DDS::prase throws an exception on error.
00594         try {
00595             dds.parse(rs->get_stream()); // read and parse the dds from a file
00596         }
00597         catch (Error &e) {
00598             delete rs; rs = 0;
00599             throw e;
00600         }
00601         break;
00602     }
00603 
00604     delete rs; rs = 0;
00605 }
00606 
00618 void
00619 Connect::request_ddx(DDS &dds, string expr)
00620 {
00621     string proj, sel;
00622     string::size_type dotpos = expr.find('&');
00623     if (dotpos != expr.npos) {
00624         proj = expr.substr(0, dotpos);
00625         sel = expr.substr(dotpos);
00626     }
00627     else {
00628         proj = expr;
00629         sel = "";
00630     }
00631 
00632     string ddx_url = _URL + ".ddx" + "?"
00633                      + id2www_ce(_proj + proj + _sel + sel);
00634 
00635     Response *rs = 0;
00636     try {
00637         rs = d_http->fetch_url(ddx_url);
00638     }
00639     catch (Error &e) {
00640         delete rs; rs = 0;
00641         throw e;
00642     }
00643 
00644     d_version = rs->get_version();
00645     d_protocol = rs->get_protocol();
00646 
00647     switch (rs->get_type()) {
00648     case dods_error: {
00649             Error e;
00650             if (!e.parse(rs->get_stream())) {
00651                 throw InternalErr(__FILE__, __LINE__,
00652                                   "Could not parse error returned from server.");
00653                 break;
00654             }
00655             throw e;
00656             break;
00657         }
00658 
00659     case web_error:
00660         // We should never get here; a web error should be picked up read_url
00661         // (called by fetch_url) and result in a thrown Error object.
00662         break;
00663 
00664     case dap4_ddx:
00665     default:
00666         // DDS::parse throws an exception on error.
00667         try {
00668 #if 0
00669             string blob;
00670 #endif
00671             DDXParser ddxp(dds.get_factory());
00672             ddxp.intern_stream(rs->get_stream(), &dds/*, &blob***/);
00673 #if 0
00674             dds.parse(rs->get_stream()); // read and parse the dds from a file
00675 #endif
00676         }
00677         catch (Error &e) {
00678             delete rs; rs = 0;
00679             throw e;
00680         }
00681         break;
00682 
00683 #if 0
00684         // See the comment in process_data() and bug 706. 03/22/04 jhrg
00685     default:
00686         throw Error("The site did not return a valid response (it lacked the\nexpected content description header value of 'dods_ddx').\nThis may indicate that the server at the site is not correctly\nconfigured, or that the URL has changed.");
00687 #endif
00688     }
00689 
00690     delete rs; rs = 0;
00691 }
00692 
00695 void
00696 Connect::request_ddx_url(DDS &dds)
00697 {
00698     string use_url = _URL + "?" + _proj + _sel ;
00699 
00700     Response *rs = 0;
00701     try {
00702         rs = d_http->fetch_url(use_url);
00703     }
00704     catch (Error &e) {
00705         delete rs; rs = 0;
00706         throw e;
00707     }
00708 
00709     d_version = rs->get_version();
00710     d_protocol = rs->get_protocol();
00711 
00712     switch (rs->get_type()) {
00713     case dods_error: {
00714             Error e;
00715             if (!e.parse(rs->get_stream())) {
00716                 throw InternalErr(__FILE__, __LINE__,
00717                                   "Could not parse error returned from server.");
00718                 break;
00719             }
00720             throw e;
00721             break;
00722         }
00723 
00724     case web_error:
00725         // We should never get here; a web error should be picked up read_url
00726         // (called by fetch_url) and result in a thrown Error object.
00727         break;
00728 
00729     case dap4_ddx:
00730     default:
00731         // DDS::prase throws an exception on error.
00732         try {
00733             dds.parse(rs->get_stream()); // read and parse the dds from a file
00734         }
00735         catch (Error &e) {
00736             delete rs; rs = 0;
00737             throw e;
00738         }
00739         break;
00740 
00741 #if 0
00742         // See the comment in process_data() and bug 706. 03/22/04 jhrg
00743     default:
00744         throw Error("The site did not return a valid response (it lacked the\nexpected content description header value of 'dods_ddx').\nThis may indicate that the server at the site is not correctly\nconfigured, or that the URL has changed.");
00745 #endif
00746     }
00747 
00748     delete rs; rs = 0;
00749 }
00750 
00766 void
00767 Connect::request_data(DataDDS &data, string expr)
00768 {
00769     string proj, sel;
00770     string::size_type dotpos = expr.find('&');
00771     if (dotpos != expr.npos) {
00772         proj = expr.substr(0, dotpos);
00773         sel = expr.substr(dotpos);
00774     }
00775     else {
00776         proj = expr;
00777         sel = "";
00778     }
00779 
00780     string data_url = _URL + ".dods?"
00781                       + id2www_ce(_proj + proj + _sel + sel);
00782 
00783     Response *rs = 0;
00784     // We need to catch Error exceptions to ensure calling close_output.
00785     try {
00786         rs = d_http->fetch_url(data_url);
00787         d_version = rs->get_version();
00788         d_protocol = rs->get_protocol();
00789 
00790         process_data(data, rs);
00791         delete rs; rs = 0;
00792     }
00793     catch (Error &e) {
00794         delete rs; rs = 0;
00795         throw e;
00796     }
00797 }
00798 
00816 void
00817 Connect::request_data_url(DataDDS &data)
00818 {
00819     string use_url = _URL + "?" + _proj + _sel ;
00820     Response *rs = 0;
00821     // We need to catch Error exceptions to ensure calling close_output.
00822     try {
00823         rs = d_http->fetch_url(use_url);
00824         d_version = rs->get_version();
00825         d_protocol = rs->get_protocol();
00826 
00827         process_data(data, rs);
00828         delete rs; rs = 0;
00829     }
00830     catch (Error &e) {
00831         delete rs; rs = 0;
00832         throw e;
00833     }
00834 }
00835 
00836 
00853 void
00854 Connect::read_data(DataDDS &data, Response *rs)
00855 {
00856     if (!rs)
00857         throw InternalErr(__FILE__, __LINE__, "Response object is null.");
00858 
00859     // Read from data_source and parse the MIME headers specific to DAP2.
00860     parse_mime(rs);
00861 
00862     read_data_no_mime(data, rs);
00863 }
00864 
00873 void
00874 Connect::read_data_no_mime(DataDDS &data, Response *rs)
00875 {
00876     d_version = rs->get_version();
00877     d_protocol = rs->get_protocol();
00878 
00879     process_data(data, rs);
00880 }
00881 
00882 bool
00883 Connect::is_local()
00884 {
00885     return _local;
00886 }
00887 
00904 string
00905 Connect::URL(bool ce)
00906 {
00907     if (_local)
00908         throw InternalErr(__FILE__, __LINE__,
00909                           "URL(): This call is only valid for a DAP data source.");
00910 
00911     if (ce)
00912         return _URL + "?" + _proj + _sel;
00913     else
00914         return _URL;
00915 }
00916 
00925 string
00926 Connect::CE()
00927 {
00928     if (_local)
00929         throw InternalErr(__FILE__, __LINE__,
00930                           "CE(): This call is only valid for a DAP data source.");
00931 
00932     return _proj + _sel;
00933 }
00934 
00940 void
00941 Connect::set_credentials(string u, string p)
00942 {
00943     if (d_http)
00944         d_http->set_credentials(u, p);
00945 }
00946 
00950 void
00951 Connect::set_accept_deflate(bool deflate)
00952 {
00953     if (d_http)
00954         d_http->set_accept_deflate(deflate);
00955 }
00956 
00962 void
00963 Connect::set_xdap_protocol(int major, int minor)
00964 {
00965     if (d_http)
00966         d_http->set_xdap_protocol(major, minor);
00967 }
00968 
00972 void
00973 Connect::set_cache_enabled(bool cache)
00974 {
00975     if (d_http)
00976         d_http->set_cache_enabled(cache);
00977 }
00978 
00979 bool
00980 Connect::is_cache_enabled()
00981 {
00982     bool status;
00983     DBG(cerr << "Entering is_cache_enabled (" << hex << d_http << dec
00984         << ")... ");
00985     if (d_http)
00986         status = d_http->is_cache_enabled();
00987     else
00988         status = false;
00989     DBGN(cerr << "exiting" << endl);
00990     return status;
00991 }
00992 
00993 } // namespace libdap

Generated on Fri Apr 24 22:10:22 2009 for libdap++ by  doxygen 1.4.7