Blame getdap4.cc

Packit a4aae4
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
//
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 1997-1999
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
Packit a4aae4
// This is the source to `getdap'; a simple tool to exercise the Connect
Packit a4aae4
// class. It can be used to get naked URLs as well as the DAP2 DAS and DDS
Packit a4aae4
// objects.  jhrg.
Packit a4aae4
Packit a4aae4
#include "config.h"
Packit a4aae4
Packit a4aae4
#ifdef WIN32
Packit a4aae4
#include <io.h>
Packit a4aae4
#include <fcntl.h>
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
#include <cstring>
Packit a4aae4
#include <string>
Packit a4aae4
#include <sstream>
Packit a4aae4
Packit a4aae4
#include "GetOpt.h"
Packit a4aae4
Packit a4aae4
#include "DMR.h"
Packit a4aae4
#include "XMLWriter.h"
Packit a4aae4
#include "D4BaseTypeFactory.h"
Packit a4aae4
#include "D4Group.h"
Packit a4aae4
#include "D4Sequence.h"
Packit a4aae4
#include "D4Connect.h"
Packit a4aae4
#include "StdinResponse.h"
Packit a4aae4
#include "HTTPConnect.h"
Packit a4aae4
#include "RCReader.h"
Packit a4aae4
Packit a4aae4
using namespace std;
Packit a4aae4
using namespace libdap ;
Packit a4aae4
Packit a4aae4
const char *version = CVER " (" DVR " DAP/" DAP_PROTOCOL_VERSION ")";
Packit a4aae4
#if 0
Packit a4aae4
extern int libdap::dods_keep_temps;     // defined in HTTPResponse.h
Packit a4aae4
extern int libdap::www_trace;
Packit a4aae4
#endif
Packit a4aae4
static void usage(const string &name)
Packit a4aae4
{
Packit a4aae4
	cerr << "Usage: " << name << endl;
Packit a4aae4
	cerr << " [dD vVikmzstM][-c <expr>][-m <num>] <url> [<url> ...] | <file> [<file> ...]" << endl;
Packit a4aae4
	cerr << endl;
Packit a4aae4
	cerr << "In the first form of the command, dereference the URL and" << endl;
Packit a4aae4
	cerr << "perform the requested operations. This includes routing" << endl;
Packit a4aae4
	cerr << "the returned information through the DAP processing" << endl;
Packit a4aae4
	cerr << "library (parsing the returned objects, et c.). If none" << endl;
Packit a4aae4
	cerr << "of a, d, or D are used with a URL, then the DAP library" << endl;
Packit a4aae4
	cerr << "routines are NOT used and the URLs contents are dumped" << endl;
Packit a4aae4
	cerr << "to standard output." << endl;
Packit a4aae4
	cerr << "Note: If the URL contains a query string the query string" << endl;
Packit a4aae4
	cerr << "will be preserved in the request. However, if the query " << endl;
Packit a4aae4
	cerr << "string contains DAP4 keys they may interfere with the" << endl;
Packit a4aae4
	cerr << "operation of " << name << ". A warning will be" << endl;
Packit a4aae4
	cerr << "written to stderr when "<< name << " identifies" << endl;
Packit a4aae4
	cerr << "the presence of a DAP4 query key in the submitted" << endl;
Packit a4aae4
	cerr << "URL's query string." << endl;
Packit a4aae4
	cerr << endl;
Packit a4aae4
	cerr << "In the second form of the command, assume the files are" << endl;
Packit a4aae4
	cerr << "DataDDS objects (stored in files or read from pipes)" << endl;
Packit a4aae4
	cerr << "and process them as if -D were given. In this case the" << endl;
Packit a4aae4
	cerr << "information *must* contain valid MIME header in order" << endl;
Packit a4aae4
	cerr << "to be processed." << endl;
Packit a4aae4
	cerr << endl;
Packit a4aae4
	cerr << "Options:" << endl;
Packit a4aae4
	cerr << "        d: For each URL, get the (DAP4) DMR object. Does not get data." << endl;
Packit a4aae4
	cerr << "        D: For each URL, get the DAP4 Data response." << endl;
Packit a4aae4
	cerr << endl;
Packit a4aae4
	cerr << "        v: Verbose output." << endl;
Packit a4aae4
	cerr << "        V: Version of this client; see 'i' for server version." << endl;
Packit a4aae4
	cerr << "        i: For each URL, get the server version." << endl;
Packit a4aae4
	cerr << "        k: Keep temporary files created by libdap." << endl;
Packit a4aae4
	cerr << "        m: Request the same URL <num> times." << endl;
Packit a4aae4
	cerr << "        z: Ask the server to compress data." << endl;
Packit a4aae4
	cerr << "        s: Print Sequences using numbered rows." << endl;
Packit a4aae4
	cerr << "        t: Trace www accesses." << endl;
Packit a4aae4
	cerr << "        M: Assume data read from a file has no MIME headers; use only with files" << endl;
Packit a4aae4
	cerr << endl;
Packit a4aae4
	cerr << "        c: <expr> is a constraint expression. Used with -d/D" << endl;
Packit a4aae4
	cerr << "           NB: You can use a `?' for the CE also." << endl;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
// Used for raw http access/transfer
Packit a4aae4
bool read_data(FILE * fp)
Packit a4aae4
{
Packit a4aae4
    if (!fp) {
Packit a4aae4
        fprintf(stderr, "getdap4: Whoa!!! Null stream pointer.\n");
Packit a4aae4
        return false;
Packit a4aae4
    }
Packit a4aae4
    // Changed from a loop that used getc() to one that uses fread(). getc()
Packit a4aae4
    // worked fine for transfers of text information, but *not* for binary
Packit a4aae4
    // transfers. fread() will handle both.
Packit a4aae4
    char c;
Packit a4aae4
    while (fp && !feof(fp) && fread(&c, 1, 1, fp))
Packit a4aae4
        printf("%c", c);        // stick with stdio
Packit a4aae4
Packit a4aae4
    return true;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
static void read_response_from_file(D4Connect *url, DMR &dmr, Response &r, bool mime_headers, bool get_dap4_data, bool get_dmr)
Packit a4aae4
{
Packit a4aae4
    if (mime_headers) {
Packit a4aae4
    	if (get_dap4_data)
Packit a4aae4
    		url->read_data(dmr, r);
Packit a4aae4
    	else if (get_dmr)
Packit a4aae4
    		url->read_dmr(dmr, r);
Packit a4aae4
    	else
Packit a4aae4
    		throw Error("Only supports Data or DMR responses");
Packit a4aae4
    }
Packit a4aae4
    else {
Packit a4aae4
    	if (get_dap4_data)
Packit a4aae4
    		url->read_data_no_mime(dmr, r);
Packit a4aae4
    	else if (get_dmr)
Packit a4aae4
    		url->read_dmr_no_mime(dmr, r);
Packit a4aae4
    	else
Packit a4aae4
    		throw Error("Only supports Data or DMR responses");
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
static void print_group_data(D4Group *g, bool print_rows = false)
Packit a4aae4
{
Packit a4aae4
    for (Constructor::Vars_iter i = g->var_begin(), e = g->var_end(); i != e; i++) {
Packit a4aae4
        if (print_rows && (*i)->type() == dods_sequence_c)
Packit a4aae4
            dynamic_cast<D4Sequence &>(**i).print_val_by_rows(cout);
Packit a4aae4
        else
Packit a4aae4
            (*i)->print_val(cout);
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    for (D4Group::groupsIter gi = g->grp_begin(), ge = g->grp_end(); gi != ge; ++gi) {
Packit a4aae4
        print_group_data(*gi, print_rows);
Packit a4aae4
    }
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
static void print_data(DMR &dmr, bool print_rows = false)
Packit a4aae4
{
Packit a4aae4
    cout << "The data:" << endl;
Packit a4aae4
Packit a4aae4
    D4Group *g = dmr.root();
Packit a4aae4
Packit a4aae4
    print_group_data(g, print_rows);
Packit a4aae4
Packit a4aae4
    cout << endl << flush;
Packit a4aae4
}
Packit a4aae4
Packit a4aae4
int main(int argc, char *argv[])
Packit a4aae4
{
Packit a4aae4
    GetOpt getopt(argc, argv, "[dDvVikrm:Mzstc:]");
Packit a4aae4
    int option_char;
Packit a4aae4
Packit a4aae4
    bool get_dmr = false;
Packit a4aae4
    bool get_dap4_data = false;
Packit a4aae4
    bool get_version = false;
Packit a4aae4
    bool cexpr = false;
Packit a4aae4
    bool verbose = false;
Packit a4aae4
    bool multi = false;
Packit a4aae4
    bool accept_deflate = false;
Packit a4aae4
    bool print_rows = false;
Packit a4aae4
    bool mime_headers = true;
Packit a4aae4
    bool report_errors = false;
Packit a4aae4
    int times = 1;
Packit a4aae4
    int dap_client_major = 4;
Packit a4aae4
    int dap_client_minor = 0;
Packit a4aae4
    string expr = "";
Packit a4aae4
Packit a4aae4
#ifdef WIN32
Packit a4aae4
    _setmode(_fileno(stdout), _O_BINARY);
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
    while ((option_char = getopt()) != -1)
Packit a4aae4
        switch (option_char) {
Packit a4aae4
        case 'd':
Packit a4aae4
            get_dmr = true;
Packit a4aae4
            break;
Packit a4aae4
        case 'D':
Packit a4aae4
            get_dap4_data = true;
Packit a4aae4
            break;
Packit a4aae4
        case 'v':
Packit a4aae4
            verbose = true;
Packit a4aae4
            break;
Packit a4aae4
        case 'V':
Packit a4aae4
        	cerr << "getdap4 version: " << version << endl;
Packit a4aae4
            exit(0);
Packit a4aae4
        case 'i':
Packit a4aae4
            get_version = true;
Packit a4aae4
            break;
Packit a4aae4
#if 0
Packit a4aae4
        case 'k':
Packit a4aae4
            dods_keep_temps = 1;
Packit a4aae4
            break;              // keep_temp is in Connect.cc
Packit a4aae4
#endif
Packit a4aae4
        case 'r':
Packit a4aae4
        	report_errors = true;
Packit a4aae4
        	break;
Packit a4aae4
        case 'm':
Packit a4aae4
            multi = true;
Packit a4aae4
            times = atoi(getopt.optarg);
Packit a4aae4
            break;
Packit a4aae4
        case 'z':
Packit a4aae4
            accept_deflate = true;
Packit a4aae4
            break;
Packit a4aae4
        case 's':
Packit a4aae4
            print_rows = true;
Packit a4aae4
            break;
Packit a4aae4
        case 'M':
Packit a4aae4
            mime_headers = false;
Packit a4aae4
            break;
Packit a4aae4
#if 0
Packit a4aae4
        case 't':
Packit a4aae4
            www_trace = 1;
Packit a4aae4
            break;
Packit a4aae4
#endif
Packit a4aae4
        case 'c':
Packit a4aae4
            cexpr = true;
Packit a4aae4
            expr = getopt.optarg;
Packit a4aae4
            break;
Packit a4aae4
        case 'h':
Packit a4aae4
        case '?':
Packit a4aae4
        default:
Packit a4aae4
            usage(argv[0]);
Packit a4aae4
            exit(1);
Packit a4aae4
            break;
Packit a4aae4
        }
Packit a4aae4
Packit a4aae4
    try {
Packit a4aae4
        // If after processing all the command line options there is nothing
Packit a4aae4
        // left (no URL or file) assume that we should read from stdin.
Packit a4aae4
        for (int i = getopt.optind; i < argc; ++i) {
Packit a4aae4
            if (verbose)
Packit a4aae4
                cerr << "Fetching: " << argv[i] << endl;
Packit a4aae4
Packit a4aae4
            string name = argv[i];
Packit a4aae4
            D4Connect *url = 0;
Packit a4aae4
            // auto_ptr? jhrg 10/19/15
Packit a4aae4
            url = new D4Connect(name);
Packit a4aae4
Packit a4aae4
            // This overrides the value set in the .dodsrc file.
Packit a4aae4
            if (accept_deflate)
Packit a4aae4
                url->set_accept_deflate(accept_deflate);
Packit a4aae4
Packit a4aae4
            if (dap_client_major > 2)
Packit a4aae4
                url->set_xdap_protocol(dap_client_major, dap_client_minor);
Packit a4aae4
Packit a4aae4
            if (url->is_local()) {
Packit a4aae4
                if (verbose)
Packit a4aae4
                    cerr << "Assuming " << argv[i] << " is a file that contains a response object; decoding." << endl;
Packit a4aae4
Packit a4aae4
                try {
Packit a4aae4
                    D4BaseTypeFactory factory;
Packit a4aae4
                    DMR dmr(&factory);
Packit a4aae4
Packit a4aae4
                    if (strcmp(argv[i], "-") == 0) {
Packit a4aae4
                        StdinResponse r(cin);
Packit a4aae4
Packit a4aae4
                        if (!r.get_cpp_stream())
Packit a4aae4
                            throw Error("Could not open standard input.");
Packit a4aae4
Packit a4aae4
                        read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
Packit a4aae4
                    }
Packit a4aae4
                    else {
Packit a4aae4
                    	fstream f(argv[i], std::ios_base::in);
Packit a4aae4
                    	if (!f.is_open() || f.bad() || f.eof())
Packit a4aae4
                    		throw Error((string)"Could not open: " + argv[i]);
Packit a4aae4
Packit a4aae4
                    	Response r(&f, 0);
Packit a4aae4
Packit a4aae4
                        read_response_from_file(url, dmr, r, mime_headers, get_dap4_data, get_dmr);
Packit a4aae4
                    }
Packit a4aae4
Packit a4aae4
                    if (verbose)
Packit a4aae4
                        cerr << "DAP version: " << url->get_protocol().c_str() << " Server version: "
Packit a4aae4
    						<< url->get_version().c_str() << endl;
Packit a4aae4
Packit a4aae4
                    // Always write the DMR
Packit a4aae4
                    XMLWriter xml;
Packit a4aae4
                    dmr.print_dap4(xml);
Packit a4aae4
                    cout << xml.get_doc() << endl;
Packit a4aae4
Packit a4aae4
                    if (get_dap4_data)
Packit a4aae4
                    	print_data(dmr, print_rows);
Packit a4aae4
                }
Packit a4aae4
                catch (Error & e) {
Packit a4aae4
                    cerr << "Error: " << e.get_error_message() << endl;
Packit a4aae4
                    delete url; url = 0;
Packit a4aae4
                    if (report_errors)
Packit a4aae4
                        return EXIT_FAILURE;
Packit a4aae4
                }
Packit a4aae4
            }
Packit a4aae4
            else if (get_dmr) {
Packit a4aae4
                for (int j = 0; j < times; ++j) {
Packit a4aae4
                    D4BaseTypeFactory factory;
Packit a4aae4
                    DMR dmr(&factory);
Packit a4aae4
                    try {
Packit a4aae4
                        url->request_dmr(dmr, expr);
Packit a4aae4
Packit a4aae4
                        if (verbose) {
Packit a4aae4
                            cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version() << endl;
Packit a4aae4
                            cout << "DMR:" << endl;
Packit a4aae4
                        }
Packit a4aae4
Packit a4aae4
                        XMLWriter xml;
Packit a4aae4
                        dmr.print_dap4(xml);
Packit a4aae4
                        cout << xml.get_doc() << endl;
Packit a4aae4
                    }
Packit a4aae4
                    catch (Error & e) {
Packit a4aae4
                        cerr << e.get_error_message() << endl;
Packit a4aae4
                        if (report_errors)
Packit a4aae4
                        	return EXIT_FAILURE;
Packit a4aae4
                        continue;       // Goto the next URL or exit the loop.
Packit a4aae4
                    }
Packit a4aae4
                }
Packit a4aae4
            }
Packit a4aae4
            else if (get_dap4_data) {
Packit a4aae4
                 for (int j = 0; j < times; ++j) {
Packit a4aae4
                     D4BaseTypeFactory factory;
Packit a4aae4
                     DMR dmr(&factory);
Packit a4aae4
                     try {
Packit a4aae4
                         url->request_dap4_data(dmr, expr);
Packit a4aae4
Packit a4aae4
                         if (verbose) {
Packit a4aae4
                             cout << "DAP version: " << url->get_protocol() << ", Server version: " << url->get_version() << endl;
Packit a4aae4
                             cout << "DMR:" << endl;
Packit a4aae4
                         }
Packit a4aae4
Packit a4aae4
                         XMLWriter xml;
Packit a4aae4
                         dmr.print_dap4(xml);
Packit a4aae4
                         cout << xml.get_doc() << endl;
Packit a4aae4
Packit a4aae4
                         print_data(dmr, print_rows);
Packit a4aae4
                    }
Packit a4aae4
                     catch (Error & e) {
Packit a4aae4
                         cerr << e.get_error_message() << endl;
Packit a4aae4
                         if (report_errors)
Packit a4aae4
                             return EXIT_FAILURE;
Packit a4aae4
                         continue;       // Goto the next URL or exit the loop.
Packit a4aae4
                     }
Packit a4aae4
                 }
Packit a4aae4
            }
Packit a4aae4
            else {
Packit a4aae4
                HTTPConnect http(RCReader::instance());
Packit a4aae4
Packit a4aae4
                // This overrides the value set in the .dodsrc file.
Packit a4aae4
                if (accept_deflate)
Packit a4aae4
                    http.set_accept_deflate(accept_deflate);
Packit a4aae4
Packit a4aae4
                if (dap_client_major > 2)
Packit a4aae4
                    url->set_xdap_protocol(dap_client_major, dap_client_minor);
Packit a4aae4
Packit a4aae4
                string url_string = argv[i];
Packit a4aae4
                for (int j = 0; j < times; ++j) {
Packit a4aae4
                    try {
Packit a4aae4
                        HTTPResponse *r = http.fetch_url(url_string);
Packit a4aae4
                        if (verbose) {
Packit a4aae4
                        	vector<string> *headers = r->get_headers();
Packit a4aae4
                        	copy(headers->begin(), headers->end(), ostream_iterator<string>(cout, "\n"));
Packit a4aae4
                        }
Packit a4aae4
                        if (!read_data(r->get_stream())) {
Packit a4aae4
                            continue;
Packit a4aae4
                        }
Packit a4aae4
                        delete r;
Packit a4aae4
                        r = 0;
Packit a4aae4
                    }
Packit a4aae4
                    catch (Error & e) {
Packit a4aae4
                        cerr << e.get_error_message() << endl;
Packit a4aae4
                        if (report_errors)
Packit a4aae4
                            return EXIT_FAILURE;
Packit a4aae4
                        continue;
Packit a4aae4
                    }
Packit a4aae4
                }
Packit a4aae4
            }
Packit a4aae4
Packit a4aae4
#if 0
Packit a4aae4
            else if (get_version) {
Packit a4aae4
                fprintf(stderr, "DAP version: %s, Server version: %s\n",
Packit a4aae4
                        url->request_protocol().c_str(),
Packit a4aae4
                        url->get_version().c_str());
Packit a4aae4
            }
Packit a4aae4
#endif
Packit a4aae4
Packit a4aae4
            delete url;  url = 0;
Packit a4aae4
        }
Packit a4aae4
    }
Packit a4aae4
    catch (Error &e) {
Packit a4aae4
Packit a4aae4
    	if(e.get_error_code() == malformed_expr || e.get_error_code() == malformed_expr){
Packit a4aae4
        	cerr << e.get_error_message() << endl;
Packit a4aae4
        	usage(argv[0]);
Packit a4aae4
    	}
Packit a4aae4
    	else {
Packit a4aae4
        	cerr << e.get_error_message() << endl;
Packit a4aae4
Packit a4aae4
    	}
Packit a4aae4
Packit a4aae4
        cerr << "Exiting." << endl;
Packit a4aae4
        return 1;
Packit a4aae4
    }
Packit a4aae4
    catch (exception &e) {
Packit a4aae4
        cerr << "C++ library exception: " << e.what() << endl;
Packit a4aae4
        cerr << "Exiting." << endl;
Packit a4aae4
        return 1;
Packit a4aae4
    }
Packit a4aae4
Packit a4aae4
    return 0;
Packit a4aae4
}