Blame D4Connect.cc

Packit a4aae4
// -*- mode: c++; c-basic-offset:4 -*-
Packit a4aae4
Packit a4aae4
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
Packit a4aae4
// Access Protocol.
Packit a4aae4
Packit a4aae4
// Copyright (c) 2002,2003 OPeNDAP, Inc.
Packit a4aae4
// Author: James Gallagher <jgallagher@opendap.org>
Packit a4aae4
//         Dan Holloway <dholloway@gso.uri.edu>
Packit a4aae4
//         Reza Nekovei <reza@intcomm.net>
Packit a4aae4
//
Packit a4aae4
// This library is free software; you can redistribute it and/or
Packit a4aae4
// modify it under the terms of the GNU Lesser General Public
Packit a4aae4
// License as published by the Free Software Foundation; either
Packit a4aae4
// version 2.1 of the License, or (at your option) any later version.
Packit a4aae4
//
Packit a4aae4
// This library is distributed in the hope that it will be useful,
Packit a4aae4
// but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit a4aae4
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit a4aae4
// Lesser General Public License for more details.
Packit a4aae4
//
Packit a4aae4
// You should have received a copy of the GNU Lesser General Public
Packit a4aae4
// License along with this library; if not, write to the Free Software
Packit a4aae4
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit a4aae4
//
Packit a4aae4
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
Packit a4aae4
Packit a4aae4
// (c) COPYRIGHT URI/MIT 1994-2002
Packit a4aae4
// Please read the full copyright statement in the file COPYRIGHT_URI.
Packit a4aae4
//
Packit a4aae4
// Authors:
Packit a4aae4
//      jhrg,jimg       James Gallagher <jgallagher@gso.uri.edu>
Packit a4aae4
//      dan             Dan Holloway <dholloway@gso.uri.edu>
Packit a4aae4
//      reza            Reza Nekovei <reza@intcomm.net>
Packit a4aae4
Packit a4aae4
#include "config.h"
Packit a4aae4
// #define DODS_DEBUG 1
Packit a4aae4
Packit a4aae4
Packit a4aae4
Packit a4aae4
#include <cassert>
Packit a4aae4
#include <cstring>
Packit a4aae4
#include <sstream>
Packit a4aae4
Packit a4aae4
#include "D4Connect.h"
Packit a4aae4
#include "HTTPConnect.h"
Packit a4aae4
#include "Response.h"
Packit a4aae4
#include "DMR.h"
Packit a4aae4
#include "D4Group.h"
Packit a4aae4
Packit a4aae4
#include "D4ParserSax2.h"
Packit a4aae4
#include "chunked_stream.h"
Packit a4aae4
#include "chunked_istream.h"
Packit a4aae4
#include "D4StreamUnMarshaller.h"
Packit a4aae4
Packit a4aae4
#include "escaping.h"
Packit a4aae4
#include "mime_util.h"
Packit a4aae4
#include "debug.h"
Packit a4aae4
Packit a4aae4
Packit a4aae4
Packit a4aae4
using namespace std;
Packit a4aae4
Packit a4aae4
namespace libdap {
Packit a4aae4
Packit a4aae4
/** This private method process data from both local and remote sources. It
Packit a4aae4
 exists to eliminate duplication of code. */
Packit a4aae4
void D4Connect::process_dmr(DMR &dmr, Response &rs)
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "Entering D4Connect::process_dmr" << endl);
Packit a4aae4
Packit a4aae4
    dmr.set_dap_version(rs.get_protocol());
Packit a4aae4
Packit a4aae4
    DBG(cerr << "Entering process_data. Response.getVersion() = " << rs.get_version() << endl);
Packit a4aae4
    switch (rs.get_type()) {
Packit a4aae4
    case dap4_error: {
Packit a4aae4
#if 0
Packit a4aae4
        Error e;
Packit a4aae4
        if (!e.parse(rs.get_stream()))
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not parse the Error object returned by the server!");
Packit a4aae4
        throw e;
Packit a4aae4
#endif
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "DAP4 errors not processed yet: FIXME!");
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    case web_error:
Packit a4aae4
        // Web errors (those reported in the return document's MIME header)
Packit a4aae4
        // are processed by the WWW library.
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__,
Packit a4aae4
            "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
Packit a4aae4
Packit a4aae4
    case dap4_dmr: {
Packit a4aae4
        // parse the DMR
Packit a4aae4
        try {
Packit a4aae4
            D4ParserSax2 parser;
Packit a4aae4
            // When parsing a data response, we use the permissive mode of the DMR parser
Packit a4aae4
            // (which allows Map elements to reference Arrays that are not in the DMR).
Packit a4aae4
            // Do not use that mode when parsing the DMR response - assume the DMR is
Packit a4aae4
            // valid. jhrg 4/13/16
Packit a4aae4
            parser.intern(*rs.get_cpp_stream(), &dmr);
Packit a4aae4
        }
Packit a4aae4
        catch (Error &e) {
Packit a4aae4
            cerr << "Exception: " << e.get_error_message() << endl;
Packit a4aae4
            return;
Packit a4aae4
        }
Packit a4aae4
        catch (std::exception &e) {
Packit a4aae4
            cerr << "Exception: " << e.what() << endl;
Packit a4aae4
            return;
Packit a4aae4
        }
Packit a4aae4
        catch (...) {
Packit a4aae4
            cerr << "Exception: unknown error" << endl;
Packit a4aae4
            return;
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
        return;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    default:
Packit a4aae4
        throw Error("Unknown response type");
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** This private method process data from both local and remote sources. It
Packit a4aae4
 exists to eliminate duplication of code. */
Packit a4aae4
void D4Connect::process_data(DMR &data, Response &rs)
Packit a4aae4
{
Packit a4aae4
    DBG(cerr << "Entering D4Connect::process_data" << endl);
Packit a4aae4
Packit a4aae4
    assert(rs.get_cpp_stream());	// DAP4 code uses cpp streams
Packit a4aae4
Packit a4aae4
    data.set_dap_version(rs.get_protocol());
Packit a4aae4
Packit a4aae4
    DBG(cerr << "Entering process_data. Response.getVersion() = " << rs.get_version() << endl);
Packit a4aae4
    switch (rs.get_type()) {
Packit a4aae4
    case dap4_error: {
Packit a4aae4
#if 0
Packit a4aae4
        Error e;
Packit a4aae4
        if (!e.parse(rs.get_cpp_stream()))
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "Could not parse the Error object returned by the server!");
Packit a4aae4
        throw e;
Packit a4aae4
#endif
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__, "DAP4 errors not processed yet: FIXME!");
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    case web_error:
Packit a4aae4
        // Web errors (those reported in the return document's MIME header)
Packit a4aae4
        // are processed by the WWW library.
Packit a4aae4
        throw InternalErr(__FILE__, __LINE__,
Packit a4aae4
            "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
Packit a4aae4
Packit a4aae4
    case dap4_data: {
Packit a4aae4
#if BYTE_ORDER_PREFIX
Packit a4aae4
        // Read the byte-order byte; used later on
Packit a4aae4
        char byte_order;
Packit a4aae4
        *rs.get_cpp_stream() >> byte_order;
Packit a4aae4
        //if (debug) cerr << "Byte order: " << ((byte_order) ? "big endian" : "little endian") << endl;
Packit a4aae4
#endif
Packit a4aae4
        // get a chunked input stream
Packit a4aae4
#if BYTE_ORDER_PREFIX
Packit a4aae4
        chunked_istream cis(*rs.get_cpp_stream(), 1024, byte_order);
Packit a4aae4
#else
Packit a4aae4
        chunked_istream cis(*(rs.get_cpp_stream()), CHUNK_SIZE);
Packit a4aae4
#endif
Packit a4aae4
        // parse the DMR, stopping when the boundary is found.
Packit a4aae4
        try {
Packit a4aae4
            // force chunk read
Packit a4aae4
            // get chunk size
Packit a4aae4
            int chunk_size = cis.read_next_chunk();
Packit a4aae4
            if (chunk_size < 0)
Packit a4aae4
                throw Error("Found an unexpected end of input (EOF) while reading a DAP4 data response. (1)");
Packit a4aae4
Packit a4aae4
            // get chunk
Packit a4aae4
            char chunk[chunk_size];
Packit a4aae4
            cis.read(chunk, chunk_size);
Packit a4aae4
            // parse char * with given size
Packit a4aae4
            D4ParserSax2 parser;
Packit a4aae4
            // permissive mode allows references to Maps that are not in the response.
Packit a4aae4
            // Use this mode when parsing a data response (but not the DMR). jhrg 4/13/16
Packit a4aae4
            parser.set_strict(false);
Packit a4aae4
Packit a4aae4
            // '-2' to discard the CRLF pair
Packit a4aae4
            parser.intern(chunk, chunk_size - 2, &data);
Packit a4aae4
        }
Packit a4aae4
        catch (Error &e) {
Packit a4aae4
            cerr << "Exception: " << e.get_error_message() << endl;
Packit a4aae4
            return;
Packit a4aae4
        }
Packit a4aae4
        catch (std::exception &e) {
Packit a4aae4
            cerr << "Exception: " << e.what() << endl;
Packit a4aae4
            return;
Packit a4aae4
        }
Packit a4aae4
        catch (...) {
Packit a4aae4
            cerr << "Exception: unknown error" << endl;
Packit a4aae4
            return;
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
#if BYTE_ORDER_PREFIX
Packit a4aae4
        D4StreamUnMarshaller um(cis, byte_order);
Packit a4aae4
#else
Packit a4aae4
        D4StreamUnMarshaller um(cis, cis.twiddle_bytes());
Packit a4aae4
#endif
Packit a4aae4
        data.root()->deserialize(um, data);
Packit a4aae4
Packit a4aae4
        return;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    default:
Packit a4aae4
        throw Error("Unknown response type");
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Use when you cannot use libcurl.
Packit a4aae4
Packit a4aae4
 @note This method tests for MIME headers with lines terminated by CRLF
Packit a4aae4
 (\r\n) and Newlines (\n). In either case, the line terminators are removed
Packit a4aae4
 before each header is processed.
Packit a4aae4
Packit a4aae4
 @param rs Value/Result parameter. Dump version and type information here.
Packit a4aae4
 */
Packit a4aae4
void D4Connect::parse_mime(Response &rs)
Packit a4aae4
{
Packit a4aae4
    rs.set_version("dods/0.0"); // initial value; for backward compatibility.
Packit a4aae4
    rs.set_protocol("2.0");
Packit a4aae4
Packit a4aae4
    istream &data_source = *rs.get_cpp_stream();
Packit a4aae4
    string mime = get_next_mime_header(data_source);
Packit a4aae4
    while (!mime.empty()) {
Packit a4aae4
        string header, value;
Packit a4aae4
        parse_mime_header(mime, header, value);
Packit a4aae4
Packit a4aae4
        // Note that this is an ordered list
Packit a4aae4
        if (header == "content-description") {
Packit a4aae4
            DBG(cout << header << ": " << value << endl);
Packit a4aae4
            rs.set_type(get_description_type(value));
Packit a4aae4
        }
Packit a4aae4
        // Use the value of xdods-server only if no other value has been read
Packit a4aae4
        else if (header == "xdods-server" && rs.get_version() == "dods/0.0") {
Packit a4aae4
            DBG(cout << header << ": " << value << endl);
Packit a4aae4
            rs.set_version(value);
Packit a4aae4
        }
Packit a4aae4
        // This trumps 'xdods-server' and 'server'
Packit a4aae4
        else if (header == "xopendap-server") {
Packit a4aae4
            DBG(cout << header << ": " << value << endl);
Packit a4aae4
            rs.set_version(value);
Packit a4aae4
        }
Packit a4aae4
        else if (header == "xdap") {
Packit a4aae4
            DBG(cout << header << ": " << value << endl);
Packit a4aae4
            rs.set_protocol(value);
Packit a4aae4
        }
Packit a4aae4
        // Only look for 'server' if no other header supplies this info.
Packit a4aae4
        else if (rs.get_version() == "dods/0.0" && header == "server") {
Packit a4aae4
            DBG(cout << header << ": " << value << endl);
Packit a4aae4
            rs.set_version(value);
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
        mime = get_next_mime_header(data_source);
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// public mfuncs
Packit a4aae4
Packit a4aae4
/** The D4Connect constructor requires a URL or local file.
Packit a4aae4
Packit a4aae4
 @param n The URL for the virtual connection.
Packit a4aae4
 @param uname Use this username for authentication. Null by default.
Packit a4aae4
 @param password Password to use for authentication. Null by default.
Packit a4aae4
 @brief Create an instance of Connect. */
Packit a4aae4
D4Connect::D4Connect(const string &url, string uname, string password) :
Packit a4aae4
    d_http(0), d_local(false), d_URL(""), d_UrlQueryString(""), d_server("unknown"), d_protocol("4.0")
Packit a4aae4
{
Packit a4aae4
    string name = prune_spaces(url);
Packit a4aae4
Packit a4aae4
    // Figure out if the URL starts with 'http', if so, make sure that we
Packit a4aae4
    // talk to an instance of HTTPConnect.
Packit a4aae4
    if (name.find("http") == 0) {
Packit a4aae4
        DBG(cerr << "Connect: The identifier is an http URL" << endl);
Packit a4aae4
        d_http = new HTTPConnect(RCReader::instance());
Packit a4aae4
        d_http->set_use_cpp_streams(true);
Packit a4aae4
Packit a4aae4
        d_URL = name;
Packit a4aae4
Packit a4aae4
        // Find and store any CE given with the URL.
Packit a4aae4
        string::size_type dotpos = name.find('?');
Packit a4aae4
        if (dotpos != std::string::npos) { // Found a match.
Packit a4aae4
            d_URL = name.substr(0, dotpos);
Packit a4aae4
Packit a4aae4
            d_UrlQueryString = name.substr(dotpos + 1);
Packit a4aae4
Packit a4aae4
            if (d_UrlQueryString.find(DAP4_CE_QUERY_KEY) != std::string::npos) {
Packit a4aae4
                std::stringstream msg;
Packit a4aae4
                msg << endl;
Packit a4aae4
                msg << "WARNING: A DAP4 constraint expression key was found in the query string!" << endl;
Packit a4aae4
                msg << "The submitted dataset URL: " << name << endl;
Packit a4aae4
                msg << "Contains the query string: " << d_UrlQueryString << endl;
Packit a4aae4
                msg << "This will cause issues when making DAP4 requests that specify additional constraints. " << endl;
Packit a4aae4
                cerr << msg.str() << endl;
Packit a4aae4
                // throw Error(malformed_expr, msg.str());
Packit a4aae4
            }
Packit a4aae4
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
        DBG(cerr << "Connect: The identifier is a local data source." << endl);
Packit a4aae4
        d_local = true; // local in this case means non-DAP
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    set_credentials(uname, password);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
D4Connect::~D4Connect()
Packit a4aae4
{
Packit a4aae4
    if (d_http) delete d_http;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
std::string D4Connect::build_dap4_ce(const string requestSuffix, const string dap4ce)
Packit a4aae4
{
Packit a4aae4
    std::stringstream url;
Packit a4aae4
    bool needsAmpersand = false;
Packit a4aae4
Packit a4aae4
    url << d_URL << requestSuffix << "?";
Packit a4aae4
Packit a4aae4
    if (d_UrlQueryString.length() > 0) {
Packit a4aae4
        url << d_UrlQueryString;
Packit a4aae4
        needsAmpersand = true;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    if (dap4ce.length() > 0) {
Packit a4aae4
        if (needsAmpersand) url << "&";
Packit a4aae4
Packit a4aae4
        url << DAP4_CE_QUERY_KEY << "=" << id2www_ce(dap4ce);
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    DBG(cerr << "D4Connect::build_dap4_ce() - Source URL: " << d_URL << endl);
Packit a4aae4
    DBG(cerr << "D4Connect::build_dap4_ce() - Source URL Query String: " << d_UrlQueryString << endl);
Packit a4aae4
    DBG(cerr << "D4Connect::build_dap4_ce() - dap4ce: " << dap4ce << endl);
Packit a4aae4
    DBG(cerr << "D4Connect::build_dap4_ce() - request URL: " << url.str() << endl);
Packit a4aae4
Packit a4aae4
    return url.str();
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void D4Connect::request_dmr(DMR &dmr, const string expr)
Packit a4aae4
{
Packit a4aae4
    string url = build_dap4_ce(".dmr", expr);
Packit a4aae4
Packit a4aae4
    Response *rs = 0;
Packit a4aae4
    try {
Packit a4aae4
        rs = d_http->fetch_url(url);
Packit a4aae4
Packit a4aae4
        d_server = rs->get_version();
Packit a4aae4
        d_protocol = rs->get_protocol();
Packit a4aae4
Packit a4aae4
        switch (rs->get_type()) {
Packit a4aae4
        case unknown_type:
Packit a4aae4
            DBG(cerr << "Response type unknown, assuming it's a DMR response." << endl);
Packit a4aae4
            /* no break */
Packit a4aae4
        case dap4_dmr: {
Packit a4aae4
            D4ParserSax2 parser;
Packit a4aae4
            parser.intern(*rs->get_cpp_stream(), &dmr);
Packit a4aae4
            break;
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
        case dap4_error:
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "DAP4 errors are not processed yet.");
Packit a4aae4
Packit a4aae4
        case web_error:
Packit a4aae4
            // We should never get here; a web error should be picked up read_url
Packit a4aae4
            // (called by fetch_url) and result in a thrown Error object.
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Web error found where it should never be.");
Packit a4aae4
            break;
Packit a4aae4
Packit a4aae4
        default:
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__,
Packit a4aae4
                "Response type not handled (got " + long_to_string(rs->get_type()) + ").");
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
    catch (...) {
Packit a4aae4
        delete rs;
Packit a4aae4
        throw;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    delete rs;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void D4Connect::request_dap4_data(DMR &dmr, const string expr)
Packit a4aae4
{
Packit a4aae4
    string url = build_dap4_ce(".dap", expr);
Packit a4aae4
Packit a4aae4
    Response *rs = 0;
Packit a4aae4
    try {
Packit a4aae4
        rs = d_http->fetch_url(url);
Packit a4aae4
Packit a4aae4
        d_server = rs->get_version();
Packit a4aae4
        d_protocol = rs->get_protocol();
Packit a4aae4
Packit a4aae4
        switch (rs->get_type()) {
Packit a4aae4
        case unknown_type:
Packit a4aae4
            DBG(cerr << "Response type unknown, assuming it's a DAP4 Data response." << endl);
Packit a4aae4
            /* no break */
Packit a4aae4
        case dap4_data: {
Packit a4aae4
#if BYTE_ORDER_PREFIX
Packit a4aae4
            istream &in = *rs->get_cpp_stream();
Packit a4aae4
            // Read the byte-order byte; used later on
Packit a4aae4
            char byte_order;
Packit a4aae4
            in >> byte_order;
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
            // get a chunked input stream
Packit a4aae4
#if BYTE_ORDER_PREFIX
Packit a4aae4
            chunked_istream cis(*(rs->get_cpp_stream()), 1024, byte_order);
Packit a4aae4
#else
Packit a4aae4
            chunked_istream cis(*(rs->get_cpp_stream()), CHUNK_SIZE);
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
            // parse the DMR, stopping when the boundary is found.
Packit a4aae4
Packit a4aae4
            // force chunk read
Packit a4aae4
            // get chunk size
Packit a4aae4
            int chunk_size = cis.read_next_chunk();
Packit a4aae4
            if (chunk_size < 0)
Packit a4aae4
                throw Error("Found an unexpected end of input (EOF) while reading a DAP4 data response. (2)");
Packit a4aae4
Packit a4aae4
            // get chunk
Packit a4aae4
            char chunk[chunk_size];
Packit a4aae4
            cis.read(chunk, chunk_size);
Packit a4aae4
            // parse char * with given size
Packit a4aae4
            D4ParserSax2 parser;
Packit a4aae4
            // permissive mode allows references to Maps that are not in the response.
Packit a4aae4
            parser.set_strict(false);
Packit a4aae4
            // '-2' to discard the CRLF pair
Packit a4aae4
            parser.intern(chunk, chunk_size - 2, &dmr, false /*debug*/);
Packit a4aae4
Packit a4aae4
            // Read data and store in the DMR
Packit a4aae4
#if BYTE_ORDER_PREFIX
Packit a4aae4
            D4StreamUnMarshaller um(cis, byte_order);
Packit a4aae4
#else
Packit a4aae4
            D4StreamUnMarshaller um(cis, cis.twiddle_bytes());
Packit a4aae4
#endif
Packit a4aae4
            dmr.root()->deserialize(um, dmr);
Packit a4aae4
Packit a4aae4
            break;
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
        case dap4_error:
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "DAP4 errors are not processed yet.");
Packit a4aae4
Packit a4aae4
        case web_error:
Packit a4aae4
            // We should never get here; a web error should be picked up read_url
Packit a4aae4
            // (called by fetch_url) and result in a thrown Error object.
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__, "Web error found where it should never be.");
Packit a4aae4
            break;
Packit a4aae4
Packit a4aae4
        default:
Packit a4aae4
            throw InternalErr(__FILE__, __LINE__,
Packit a4aae4
                "Response type not handled (got " + long_to_string(rs->get_type()) + ").");
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
    catch (...) {
Packit a4aae4
        delete rs;
Packit a4aae4
        throw;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    delete rs;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void D4Connect::read_dmr(DMR &dmr, Response &rs)
Packit a4aae4
{
Packit a4aae4
    parse_mime(rs);
Packit a4aae4
    if (rs.get_type() == unknown_type) throw Error("Unknown response type.");
Packit a4aae4
Packit a4aae4
    read_dmr_no_mime(dmr, rs);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void D4Connect::read_dmr_no_mime(DMR &dmr, Response &rs)
Packit a4aae4
{
Packit a4aae4
    // Assume callers know what they are doing
Packit a4aae4
    if (rs.get_type() == unknown_type) rs.set_type(dap4_dmr);
Packit a4aae4
Packit a4aae4
    switch (rs.get_type()) {
Packit a4aae4
    case dap4_dmr:
Packit a4aae4
        process_dmr(dmr, rs);
Packit a4aae4
        d_server = rs.get_version();
Packit a4aae4
        d_protocol = dmr.dap_version();
Packit a4aae4
        break;
Packit a4aae4
    default:
Packit a4aae4
        throw Error("Expected a DAP4 DMR response.");
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void D4Connect::read_data(DMR &data, Response &rs)
Packit a4aae4
{
Packit a4aae4
    parse_mime(rs);
Packit a4aae4
    if (rs.get_type() == unknown_type) throw Error("Unknown response type.");
Packit a4aae4
Packit a4aae4
    read_data_no_mime(data, rs);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
void D4Connect::read_data_no_mime(DMR &data, Response &rs)
Packit a4aae4
{
Packit a4aae4
    // Assume callers know what they are doing
Packit a4aae4
    if (rs.get_type() == unknown_type) rs.set_type(dap4_data);
Packit a4aae4
Packit a4aae4
    switch (rs.get_type()) {
Packit a4aae4
    case dap4_data:
Packit a4aae4
        process_data(data, rs);
Packit a4aae4
        d_server = rs.get_version();
Packit a4aae4
        d_protocol = data.dap_version();
Packit a4aae4
        break;
Packit a4aae4
    default:
Packit a4aae4
        throw Error("Expected a DAP4 Data response.");
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** @brief Set the credentials for responding to challenges while dereferencing
Packit a4aae4
 URLs.
Packit a4aae4
 @param u The username.
Packit a4aae4
 @param p The password.
Packit a4aae4
 @see extract_auth_info() */
Packit a4aae4
void D4Connect::set_credentials(string u, string p)
Packit a4aae4
{
Packit a4aae4
    if (d_http) d_http->set_credentials(u, p);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Set the \e accept deflate property.
Packit a4aae4
 @param deflate True if the client can accept compressed responses, False
Packit a4aae4
 otherwise. */
Packit a4aae4
void D4Connect::set_accept_deflate(bool deflate)
Packit a4aae4
{
Packit a4aae4
    if (d_http) d_http->set_accept_deflate(deflate);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Set the \e XDAP-Accept property/header. This is used to send to a server
Packit a4aae4
 the (highest) DAP protocol version number that this client understands.
Packit a4aae4
Packit a4aae4
 @param major The client dap protocol major version
Packit a4aae4
 @param minor The client dap protocol minor version */
Packit a4aae4
void D4Connect::set_xdap_protocol(int major, int minor)
Packit a4aae4
{
Packit a4aae4
    if (d_http) d_http->set_xdap_protocol(major, minor);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
/** Disable any further use of the client-side cache. In a future version
Packit a4aae4
 of this software, this should be handled so that the www library is
Packit a4aae4
 not initialized with the cache running by default. */
Packit a4aae4
void D4Connect::set_cache_enabled(bool cache)
Packit a4aae4
{
Packit a4aae4
    if (d_http) d_http->set_cache_enabled(cache);
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
bool D4Connect::is_cache_enabled()
Packit a4aae4
{
Packit a4aae4
    if (d_http)
Packit a4aae4
        return d_http->is_cache_enabled();
Packit a4aae4
    else
Packit a4aae4
        return false;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
} // namespace libdap