|
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 |
// Implementation of the DODSFilter class. This class is used to build dods
|
|
Packit |
a4aae4 |
// filter programs which, along with a CGI program, comprise OPeNDAP servers.
|
|
Packit |
a4aae4 |
// jhrg 8/26/97
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "config.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <signal.h>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#ifndef WIN32
|
|
Packit |
a4aae4 |
#include <unistd.h> // for getopt
|
|
Packit |
a4aae4 |
#include <sys/wait.h>
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
#include <io.h>
|
|
Packit |
a4aae4 |
#include <fcntl.h>
|
|
Packit |
a4aae4 |
#include <process.h>
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <iostream>
|
|
Packit |
a4aae4 |
#include <sstream>
|
|
Packit |
a4aae4 |
#include <string>
|
|
Packit |
a4aae4 |
#include <algorithm>
|
|
Packit |
a4aae4 |
#include <cstdlib>
|
|
Packit |
a4aae4 |
#include <cstring>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#ifdef HAVE_UUID_UUID_H
|
|
Packit |
a4aae4 |
#include <uuid/uuid.h> // used to build CID header value for data ddx
|
|
Packit |
a4aae4 |
#elif defined(HAVE_UUID_H)
|
|
Packit |
a4aae4 |
#include <uuid.h>
|
|
Packit |
a4aae4 |
#else
|
|
Packit |
a4aae4 |
#error "Could not find UUID library header"
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <GetOpt.h>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "DAS.h"
|
|
Packit |
a4aae4 |
#include "DDS.h"
|
|
Packit |
a4aae4 |
#include "debug.h"
|
|
Packit |
a4aae4 |
#include "mime_util.h"
|
|
Packit |
a4aae4 |
#include "Ancillary.h"
|
|
Packit |
a4aae4 |
#include "util.h"
|
|
Packit |
a4aae4 |
#include "escaping.h"
|
|
Packit |
a4aae4 |
#include "DODSFilter.h"
|
|
Packit |
a4aae4 |
#include "XDRStreamMarshaller.h"
|
|
Packit |
a4aae4 |
#include "InternalErr.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#ifndef WIN32
|
|
Packit |
a4aae4 |
#include "SignalHandler.h"
|
|
Packit |
a4aae4 |
#include "EventHandler.h"
|
|
Packit |
a4aae4 |
#include "AlarmHandler.h"
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#define CRLF "\r\n" // Change here, expr-test.cc and DODSFilter.cc
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
using namespace std;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
namespace libdap {
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
const string usage =
|
|
Packit |
a4aae4 |
"Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\
|
|
Packit |
a4aae4 |
\n\
|
|
Packit |
a4aae4 |
options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\
|
|
Packit |
a4aae4 |
-u <url>: The complete URL minus the CE (required for DDX)\n\
|
|
Packit |
a4aae4 |
-c: Compress the response using the deflate algorithm.\n\
|
|
Packit |
a4aae4 |
-e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\
|
|
Packit |
a4aae4 |
-v <version>: Use <version> as the version number\n\
|
|
Packit |
a4aae4 |
-d <dir>: Look for ancillary file in <dir> (deprecated).\n\
|
|
Packit |
a4aae4 |
-f <file>: Look for ancillary data in <file> (deprecated).\n\
|
|
Packit |
a4aae4 |
-r <dir>: Use <dir> as a cache directory\n\
|
|
Packit |
a4aae4 |
-l <time>: Conditional request; if data source is unchanged since\n\
|
|
Packit |
a4aae4 |
<time>, return an HTTP 304 response.\n\
|
|
Packit |
a4aae4 |
-t <seconds>: Timeout the handler after <seconds>.\n\
|
|
Packit |
a4aae4 |
-h: This message.";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Create an instance of DODSFilter using the command line
|
|
Packit |
a4aae4 |
arguments passed by the CGI (or other) program. The default
|
|
Packit |
a4aae4 |
constructor is private; this and the copy constructor (which is
|
|
Packit |
a4aae4 |
just the default copy constructor) are the only way to create an
|
|
Packit |
a4aae4 |
instance of DODSFilter.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
These are the valid options:
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
filename
|
|
Packit |
a4aae4 |
The name of the file on which the filter is to operate. Usually
|
|
Packit |
a4aae4 |
this would be the file whose data has been requested. In fact, this class
|
|
Packit |
a4aae4 |
can be specialized and any meaning can be associated to this
|
|
Packit |
a4aae4 |
string. It could be the name of a database, for example.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
<tt>-o</tt> response
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Specifies the type of response desired. The \e response is a string
|
|
Packit |
a4aae4 |
and must be one of \c DAS, \c DDS, \c DataDDS or \c Version. Note
|
|
Packit |
a4aae4 |
that \c Version returns version information in the body of the response
|
|
Packit |
a4aae4 |
and is useful for debugging, et cetera. Each response returns version
|
|
Packit |
a4aae4 |
information in an HTTP header for internal use by a client.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
<tt>-c</tt>
|
|
Packit |
a4aae4 |
Send compressed data. Data are compressed using the deflate program.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
<tt>-e</tt> expression
|
|
Packit |
a4aae4 |
This option specifies a non-blank constraint expression used to
|
|
Packit |
a4aae4 |
subsample a dataset.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
<tt>-v</tt> cgi-version Set the CGI/Server version to
|
|
Packit |
a4aae4 |
<tt>cgi-version</tt>. This is a way for the caller to set version
|
|
Packit |
a4aae4 |
information passed back to the client either as the response to a
|
|
Packit |
a4aae4 |
version request of in the response headers.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
<tt>-d</tt> ancdir
|
|
Packit |
a4aae4 |
Specifies that ancillary data be sought in the ancdir
|
|
Packit |
a4aae4 |
directory. ancdir must end in '/'.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
<tt>-f</tt> ancfile
|
|
Packit |
a4aae4 |
Specifies that ancillary data may be found in a file called
|
|
Packit |
a4aae4 |
ancfile.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
<tt>-r</tt> cache directory
|
|
Packit |
a4aae4 |
Specify a directory to use if/when files are to be cached. Not all
|
|
Packit |
a4aae4 |
handlers support caching and each uses its own rules tailored to a
|
|
Packit |
a4aae4 |
specific file or data type.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
<tt>-t</tt> timeout Specifies a a timeout value in
|
|
Packit |
a4aae4 |
seconds. If the server runs longer than \e timeout seconds, an Error is
|
|
Packit |
a4aae4 |
returned to the client explaining that the request has timed out.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
<tt>-l</tt> time Indicates that the request is a
|
|
Packit |
a4aae4 |
conditional request; send a complete response if and only if the data has
|
|
Packit |
a4aae4 |
changed since time. If it has not changed since time, then
|
|
Packit |
a4aae4 |
send a 304 (Not Modified) response. The time parameter is the
|
|
Packit |
a4aae4 |
<tt>Last-Modified</tt> time from an If-Modified-Since condition GET
|
|
Packit |
a4aae4 |
request. It is given in seconds since the start of the Unix epoch
|
|
Packit |
a4aae4 |
(Midnight, 1 Jan 1970).
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief DODSFilter constructor. */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DODSFilter::DODSFilter(int argc, char *argv[]) throw(Error)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
initialize(argc, argv);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBG(cerr << "d_comp: " << d_comp << endl);
|
|
Packit |
a4aae4 |
DBG(cerr << "d_dap2ce: " << d_dap2ce << endl);
|
|
Packit |
a4aae4 |
DBG(cerr << "d_cgi_ver: " << d_cgi_ver << endl);
|
|
Packit |
a4aae4 |
DBG(cerr << "d_response: " << d_response << endl);
|
|
Packit |
a4aae4 |
DBG(cerr << "d_anc_dir: " << d_anc_dir << endl);
|
|
Packit |
a4aae4 |
DBG(cerr << "d_anc_file: " << d_anc_file << endl);
|
|
Packit |
a4aae4 |
DBG(cerr << "d_cache_dir: " << d_cache_dir << endl);
|
|
Packit |
a4aae4 |
DBG(cerr << "d_conditional_request: " << d_conditional_request << endl);
|
|
Packit |
a4aae4 |
DBG(cerr << "d_if_modified_since: " << d_if_modified_since << endl);
|
|
Packit |
a4aae4 |
DBG(cerr << "d_url: " << d_url << endl);
|
|
Packit |
a4aae4 |
DBG(cerr << "d_timeout: " << d_timeout << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DODSFilter::~DODSFilter()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Called when initializing a DODSFilter that's not going to be passed a
|
|
Packit |
a4aae4 |
command line arguments. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::initialize()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// Set default values. Don't use the C++ constructor initialization so
|
|
Packit |
a4aae4 |
// that a subclass can have more control over this process.
|
|
Packit |
a4aae4 |
d_comp = false;
|
|
Packit |
a4aae4 |
d_bad_options = false;
|
|
Packit |
a4aae4 |
d_conditional_request = false;
|
|
Packit |
a4aae4 |
d_dataset = "";
|
|
Packit |
a4aae4 |
d_dap2ce = "";
|
|
Packit |
a4aae4 |
d_cgi_ver = "";
|
|
Packit |
a4aae4 |
d_anc_dir = "";
|
|
Packit |
a4aae4 |
d_anc_file = "";
|
|
Packit |
a4aae4 |
d_cache_dir = "";
|
|
Packit |
a4aae4 |
d_response = Unknown_Response;;
|
|
Packit |
a4aae4 |
d_anc_das_lmt = 0;
|
|
Packit |
a4aae4 |
d_anc_dds_lmt = 0;
|
|
Packit |
a4aae4 |
d_if_modified_since = -1;
|
|
Packit |
a4aae4 |
d_url = "";
|
|
Packit |
a4aae4 |
d_program_name = "Unknown";
|
|
Packit |
a4aae4 |
d_timeout = 0;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#ifdef WIN32
|
|
Packit |
a4aae4 |
// We want serving from win32 to behave in a manner
|
|
Packit |
a4aae4 |
// similar to the UNIX way - no CR->NL terminated lines
|
|
Packit |
a4aae4 |
// in files. Hence stdout goes to binary mode.
|
|
Packit |
a4aae4 |
_setmode(_fileno(stdout), _O_BINARY);
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Initialize. Specializations can call this once an empty DODSFilter has
|
|
Packit |
a4aae4 |
been created using the default constructor. Using a method such as this
|
|
Packit |
a4aae4 |
provides a way to specialize the process_options() method and then have
|
|
Packit |
a4aae4 |
that specialization called by the subclass' constructor.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
This class and any class that specializes it should call this method in
|
|
Packit |
a4aae4 |
its constructor. Note that when this method is called, the object is \e
|
|
Packit |
a4aae4 |
not fully constructed.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param argc The argument count
|
|
Packit |
a4aae4 |
@param argv The vector of char * argument strings. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::initialize(int argc, char *argv[])
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
initialize();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_program_name = argv[0];
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This should be specialized by a subclass. This may throw Error.
|
|
Packit |
a4aae4 |
int next_arg = process_options(argc, argv);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Look at what's left after processing the command line options. Either
|
|
Packit |
a4aae4 |
// there MUST be a dataset name OR the caller is asking for version
|
|
Packit |
a4aae4 |
// information. If neither is true, then the options are bad.
|
|
Packit |
a4aae4 |
if (next_arg < argc) {
|
|
Packit |
a4aae4 |
d_dataset = argv[next_arg];
|
|
Packit |
a4aae4 |
d_dataset = www2id(d_dataset, "%", "%20");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (get_response() != Version_Response)
|
|
Packit |
a4aae4 |
print_usage(); // Throws Error
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Processing the command line options passed to the filter is handled by
|
|
Packit |
a4aae4 |
this method so that specializations can change the options easily.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param argc The argument count
|
|
Packit |
a4aae4 |
@param argv The vector of char * argument strings.
|
|
Packit |
a4aae4 |
@return The index of the next, unprocessed, argument. This must be the
|
|
Packit |
a4aae4 |
identifier passed to the filter program that identifies the data source.
|
|
Packit |
a4aae4 |
It's often a file name. */
|
|
Packit |
a4aae4 |
int
|
|
Packit |
a4aae4 |
DODSFilter::process_options(int argc, char *argv[])
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << "Entering process_options... ");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
int option_char;
|
|
Packit |
a4aae4 |
GetOpt getopt (argc, argv, "ce: v: d: f: r: l: o: u: t: ");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
while ((option_char = getopt()) != -1) {
|
|
Packit |
a4aae4 |
switch (option_char) {
|
|
Packit |
a4aae4 |
case 'c': d_comp = true; break;
|
|
Packit |
a4aae4 |
case 'e': set_ce(getopt.optarg); break;
|
|
Packit |
a4aae4 |
case 'v': set_cgi_version(getopt.optarg); break;
|
|
Packit |
a4aae4 |
case 'd': d_anc_dir = getopt.optarg; break;
|
|
Packit |
a4aae4 |
case 'f': d_anc_file = getopt.optarg; break;
|
|
Packit |
a4aae4 |
case 'r': d_cache_dir = getopt.optarg; break;
|
|
Packit |
a4aae4 |
case 'o': set_response(getopt.optarg); break;
|
|
Packit |
a4aae4 |
case 'u': set_URL(getopt.optarg); break;
|
|
Packit |
a4aae4 |
case 't': d_timeout = atoi(getopt.optarg); break;
|
|
Packit |
a4aae4 |
case 'l':
|
|
Packit |
a4aae4 |
d_conditional_request = true;
|
|
Packit |
a4aae4 |
d_if_modified_since
|
|
Packit |
a4aae4 |
= static_cast<time_t>(strtol(getopt.optarg, NULL, 10));
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
case 'h': print_usage();
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
// exit(1);
|
|
Packit |
a4aae4 |
// Removed 12/29/2011; exit should
|
|
Packit |
a4aae4 |
// not be called by a library. NB:
|
|
Packit |
a4aae4 |
// print_usage() throws Error.
|
|
Packit |
a4aae4 |
default: print_usage(); // Throws Error
|
|
Packit |
a4aae4 |
break;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBGN(cerr << "exiting." << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return getopt.optind; // return the index of the next argument
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @brief Is this request conditional?
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@return True if the request is conditional.
|
|
Packit |
a4aae4 |
@see get_request_if_modified_since(). */
|
|
Packit |
a4aae4 |
bool
|
|
Packit |
a4aae4 |
DODSFilter::is_conditional() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_conditional_request;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Set the CGI/Server version number. Servers use this when answering
|
|
Packit |
a4aae4 |
requests for version information. The version `number' should include
|
|
Packit |
a4aae4 |
both the name of the server (e.g., <tt>ff_dods</tt>) as well
|
|
Packit |
a4aae4 |
as the version
|
|
Packit |
a4aae4 |
number. Since this information is typically divined by configure,
|
|
Packit |
a4aae4 |
it's up to the executable to poke the correct value in using this
|
|
Packit |
a4aae4 |
method.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
Note that the -v switch that this class understands is deprecated
|
|
Packit |
a4aae4 |
since it is usually called by Perl code. It makes more sense to have
|
|
Packit |
a4aae4 |
the actual C++ software set the version string.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param version A version string for this server. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::set_cgi_version(string version)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
d_cgi_ver = version;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Return the version information passed to the instance when it was
|
|
Packit |
a4aae4 |
created. This string is passed to the DODSFilter ctor using the -v
|
|
Packit |
a4aae4 |
option.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@return The version string supplied at initialization. */
|
|
Packit |
a4aae4 |
string
|
|
Packit |
a4aae4 |
DODSFilter::get_cgi_version() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_cgi_ver;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Return the entire constraint expression in a string. This
|
|
Packit |
a4aae4 |
includes both the projection and selection clauses, but not the
|
|
Packit |
a4aae4 |
question mark.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Get the constraint expression.
|
|
Packit |
a4aae4 |
@return A string object that contains the constraint expression. */
|
|
Packit |
a4aae4 |
string
|
|
Packit |
a4aae4 |
DODSFilter::get_ce() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_dap2ce;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::set_ce(string _ce)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
d_dap2ce = www2id(_ce, "%", "%20");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** The ``dataset name'' is the filename or other string that the
|
|
Packit |
a4aae4 |
filter program will use to access the data. In some cases this
|
|
Packit |
a4aae4 |
will indicate a disk file containing the data. In others, it
|
|
Packit |
a4aae4 |
may represent a database query or some other exotic data
|
|
Packit |
a4aae4 |
access method.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Get the dataset name.
|
|
Packit |
a4aae4 |
@return A string object that contains the name of the dataset. */
|
|
Packit |
a4aae4 |
string
|
|
Packit |
a4aae4 |
DODSFilter::get_dataset_name() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_dataset;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::set_dataset_name(const string ds)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
d_dataset = www2id(ds, "%", "%20");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get the URL. This returns the URL, minus the constraint originally sent
|
|
Packit |
a4aae4 |
to the server.
|
|
Packit |
a4aae4 |
@return The URL. */
|
|
Packit |
a4aae4 |
string
|
|
Packit |
a4aae4 |
DODSFilter::get_URL() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_url;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Set the URL. Set the URL sent to the server.
|
|
Packit |
a4aae4 |
@param url The URL, minus the constraint. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::set_URL(const string &url)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (url.find('?') != url.npos)
|
|
Packit |
a4aae4 |
print_usage(); // Throws Error
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
d_url = url;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** To read version information that is specific to a certain
|
|
Packit |
a4aae4 |
dataset, override this method with an implementation that does
|
|
Packit |
a4aae4 |
what you want. By default, this returns an empty string.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Get the version information for the dataset.
|
|
Packit |
a4aae4 |
@return A string object that contains the dataset version
|
|
Packit |
a4aae4 |
information. */
|
|
Packit |
a4aae4 |
string
|
|
Packit |
a4aae4 |
DODSFilter::get_dataset_version() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return "";
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Set the response to be returned. Valid response names are "DAS", "DDS",
|
|
Packit |
a4aae4 |
"DataDDS, "Version".
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param r The name of the object.
|
|
Packit |
a4aae4 |
@exception InternalErr Thrown if the response is not one of the valid
|
|
Packit |
a4aae4 |
names. */
|
|
Packit |
a4aae4 |
void DODSFilter::set_response(const string &r)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
if (r == "DAS" || r == "das") {
|
|
Packit |
a4aae4 |
d_response = DAS_Response;
|
|
Packit |
a4aae4 |
d_action = "das" ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (r == "DDS" || r == "dds") {
|
|
Packit |
a4aae4 |
d_response = DDS_Response;
|
|
Packit |
a4aae4 |
d_action = "dds" ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (r == "DataDDS" || r == "dods") {
|
|
Packit |
a4aae4 |
d_response = DataDDS_Response;
|
|
Packit |
a4aae4 |
d_action = "dods" ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (r == "DDX" || r == "ddx") {
|
|
Packit |
a4aae4 |
d_response = DDX_Response;
|
|
Packit |
a4aae4 |
d_action = "ddx" ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (r == "DataDDX" || r == "dataddx") {
|
|
Packit |
a4aae4 |
d_response = DataDDX_Response;
|
|
Packit |
a4aae4 |
d_action = "dataddx" ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else if (r == "Version") {
|
|
Packit |
a4aae4 |
d_response = Version_Response;
|
|
Packit |
a4aae4 |
d_action = "version" ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
print_usage(); // Throws Error
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get the enum name of the response to be returned. */
|
|
Packit |
a4aae4 |
DODSFilter::Response
|
|
Packit |
a4aae4 |
DODSFilter::get_response() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_response;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get the string name of the response to be returned. */
|
|
Packit |
a4aae4 |
string DODSFilter::get_action() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_action;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get the dataset's last modified time. This returns the time at which
|
|
Packit |
a4aae4 |
the dataset was last modified as defined by UNIX's notion of
|
|
Packit |
a4aae4 |
modification. This does not take into account the modification of an
|
|
Packit |
a4aae4 |
ancillary DAS or DDS. Time is given in seconds since the epoch (1 Jan
|
|
Packit |
a4aae4 |
1970 00:00:00 GMT).
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
This method perform a simple check on the file named by the dataset
|
|
Packit |
a4aae4 |
given when the DODSFilter instance was created. If the dataset is not
|
|
Packit |
a4aae4 |
a filter, this method returns the current time. Servers which provide
|
|
Packit |
a4aae4 |
access to non-file-based data should subclass DODSFilter and supply a
|
|
Packit |
a4aae4 |
more suitable version of this method.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
From the stat(2) man page: ``Traditionally, <tt>st_mtime</tt>
|
|
Packit |
a4aae4 |
is changed by mknod(2), utime(2), and write(2). The
|
|
Packit |
a4aae4 |
<tt>st_mtime</tt> is not changed for
|
|
Packit |
a4aae4 |
changes in owner, group, hard link count, or mode.''
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@return Time of the last modification in seconds since the epoch.
|
|
Packit |
a4aae4 |
@see get_das_last_modified_time()
|
|
Packit |
a4aae4 |
@see get_dds_last_modified_time() */
|
|
Packit |
a4aae4 |
time_t
|
|
Packit |
a4aae4 |
DODSFilter::get_dataset_last_modified_time() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return last_modified_time(d_dataset);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get the last modified time for the dataset's DAS. This time, given in
|
|
Packit |
a4aae4 |
seconds since the epoch (1 Jan 1970 00:00:00 GMT), is the greater of
|
|
Packit |
a4aae4 |
the datasets's and any ancillary DAS' last modified time.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param anc_location A directory to search for ancillary files (in
|
|
Packit |
a4aae4 |
addition to the CWD).
|
|
Packit |
a4aae4 |
@return Time of last modification of the DAS.
|
|
Packit |
a4aae4 |
@see get_dataset_last_modified_time()
|
|
Packit |
a4aae4 |
@see get_dds_last_modified_time() */
|
|
Packit |
a4aae4 |
time_t
|
|
Packit |
a4aae4 |
DODSFilter::get_das_last_modified_time(const string &anc_location) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
|
|
Packit |
a4aae4 |
<< anc_location << "call faf(das) d_dataset=" << d_dataset
|
|
Packit |
a4aae4 |
<< " d_anc_file=" << d_anc_file << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
string name
|
|
Packit |
a4aae4 |
= Ancillary::find_ancillary_file(d_dataset, "das",
|
|
Packit |
a4aae4 |
(anc_location == "") ? d_anc_dir : anc_location,
|
|
Packit |
a4aae4 |
d_anc_file);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return max((name != "") ? last_modified_time(name) : 0,
|
|
Packit |
a4aae4 |
get_dataset_last_modified_time());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get the last modified time for the dataset's DDS. This time, given in
|
|
Packit |
a4aae4 |
seconds since the epoch (1 Jan 1970 00:00:00 GMT), is the greater of
|
|
Packit |
a4aae4 |
the datasets's and any ancillary DDS' last modified time.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@return Time of last modification of the DDS.
|
|
Packit |
a4aae4 |
@see get_dataset_last_modified_time()
|
|
Packit |
a4aae4 |
@see get_dds_last_modified_time() */
|
|
Packit |
a4aae4 |
time_t
|
|
Packit |
a4aae4 |
DODSFilter::get_dds_last_modified_time(const string &anc_location) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
|
|
Packit |
a4aae4 |
<< anc_location << "call faf(dds) d_dataset=" << d_dataset
|
|
Packit |
a4aae4 |
<< " d_anc_file=" << d_anc_file << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
string name
|
|
Packit |
a4aae4 |
= Ancillary::find_ancillary_file(d_dataset, "dds",
|
|
Packit |
a4aae4 |
(anc_location == "") ? d_anc_dir : anc_location,
|
|
Packit |
a4aae4 |
d_anc_file);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return max((name != "") ? last_modified_time(name) : 0,
|
|
Packit |
a4aae4 |
get_dataset_last_modified_time());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get the last modified time to be used for a particular data request.
|
|
Packit |
a4aae4 |
This method should look at both the constraint expression and any
|
|
Packit |
a4aae4 |
ancillary files for this dataset. The implementation provided here
|
|
Packit |
a4aae4 |
returns the latest time returned by the <tt>get_dataset</tt>...(),
|
|
Packit |
a4aae4 |
<tt>get_das</tt>...() and <tt>get_dds</tt>...() methods and
|
|
Packit |
a4aae4 |
does not currently check the CE.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param anc_location A directory to search for ancillary files (in
|
|
Packit |
a4aae4 |
addition to the CWD).
|
|
Packit |
a4aae4 |
@return Time of last modification of the data.
|
|
Packit |
a4aae4 |
@see get_dataset_last_modified_time()
|
|
Packit |
a4aae4 |
@see get_das_last_modified_time()
|
|
Packit |
a4aae4 |
@see get_dds_last_modified_time() */
|
|
Packit |
a4aae4 |
time_t
|
|
Packit |
a4aae4 |
DODSFilter::get_data_last_modified_time(const string &anc_location) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
|
|
Packit |
a4aae4 |
<< anc_location << "call faf(both) d_dataset=" << d_dataset
|
|
Packit |
a4aae4 |
<< " d_anc_file=" << d_anc_file << endl);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
string dds_name
|
|
Packit |
a4aae4 |
= Ancillary::find_ancillary_file(d_dataset, "dds",
|
|
Packit |
a4aae4 |
(anc_location == "") ? d_anc_dir : anc_location,
|
|
Packit |
a4aae4 |
d_anc_file);
|
|
Packit |
a4aae4 |
string das_name
|
|
Packit |
a4aae4 |
= Ancillary::find_ancillary_file(d_dataset, "das",
|
|
Packit |
a4aae4 |
(anc_location == "") ? d_anc_dir : anc_location,
|
|
Packit |
a4aae4 |
d_anc_file);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
time_t m = max((das_name != "") ? last_modified_time(das_name) : (time_t)0,
|
|
Packit |
a4aae4 |
(dds_name != "") ? last_modified_time(dds_name) : (time_t)0);
|
|
Packit |
a4aae4 |
// Note that this is a call to get_dataset_... not get_data_...
|
|
Packit |
a4aae4 |
time_t n = get_dataset_last_modified_time();
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
return max(m, n);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get the value of a conditional request's If-Modified-Since header.
|
|
Packit |
a4aae4 |
This value is used to determine if the request should get a full
|
|
Packit |
a4aae4 |
response or a Not Modified (304) response. The time is given in
|
|
Packit |
a4aae4 |
seconds since the Unix epoch (midnight, 1 Jan 1970). If no time was
|
|
Packit |
a4aae4 |
given with the request, this methods returns -1.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@return If-Modified-Since time from a condition GET request. */
|
|
Packit |
a4aae4 |
time_t
|
|
Packit |
a4aae4 |
DODSFilter::get_request_if_modified_since() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_if_modified_since;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** The <tt>cache_dir</tt> is used to hold the cached .dds and .das files.
|
|
Packit |
a4aae4 |
By default, this returns an empty string (store cache files in
|
|
Packit |
a4aae4 |
current directory.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Get the cache directory.
|
|
Packit |
a4aae4 |
@return A string object that contains the cache file directory. */
|
|
Packit |
a4aae4 |
string
|
|
Packit |
a4aae4 |
DODSFilter::get_cache_dir() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_cache_dir;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Set the server's timeout value. A value of zero (the default) means no
|
|
Packit |
a4aae4 |
timeout.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param t Server timeout in seconds. Default is zero (no timeout). */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::set_timeout(int t)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
d_timeout = t;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Get the server's timeout value. */
|
|
Packit |
a4aae4 |
int
|
|
Packit |
a4aae4 |
DODSFilter::get_timeout() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
return d_timeout;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Use values of this instance to establish a timeout alarm for the server.
|
|
Packit |
a4aae4 |
If the timeout value is zero, do nothing.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@todo When the alarm handler is called, two CRLF pairs are dumped to the
|
|
Packit |
a4aae4 |
stream and then an Error object is sent. No attempt is made to write the
|
|
Packit |
a4aae4 |
'correct' MIME headers for an Error object. Instead, a savvy client will
|
|
Packit |
a4aae4 |
know that when an exception is thrown during a deserialize operation, it
|
|
Packit |
a4aae4 |
should scan ahead in the input stream for an Error object. Add this, or a
|
|
Packit |
a4aae4 |
sensible variant once libdap++ supports reliable error delivery. Dumb
|
|
Packit |
a4aae4 |
clients will never get the Error object... */
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::establish_timeout(FILE *stream) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
#ifndef WIN32
|
|
Packit |
a4aae4 |
if (d_timeout > 0) {
|
|
Packit |
a4aae4 |
SignalHandler *sh = SignalHandler::instance();
|
|
Packit |
a4aae4 |
EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream));
|
|
Packit |
a4aae4 |
delete old_eh;
|
|
Packit |
a4aae4 |
alarm(d_timeout);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::establish_timeout(ostream &stream) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
#ifndef WIN32
|
|
Packit |
a4aae4 |
if (d_timeout > 0) {
|
|
Packit |
a4aae4 |
SignalHandler *sh = SignalHandler::instance();
|
|
Packit |
a4aae4 |
EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream));
|
|
Packit |
a4aae4 |
delete old_eh;
|
|
Packit |
a4aae4 |
alarm(d_timeout);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
static const char *emessage = "DODS internal server error; usage error. Please report this to the dataset maintainer, or to the opendap-tech@opendap.org mailing list.";
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** This message is printed when the filter program is incorrectly
|
|
Packit |
a4aae4 |
invoked by the dispatch CGI. This is an error in the server
|
|
Packit |
a4aae4 |
installation or the CGI implementation, so the error message is
|
|
Packit |
a4aae4 |
written to stderr instead of stdout. A server's stderr messages
|
|
Packit |
a4aae4 |
show up in the httpd log file. In addition, an error object is
|
|
Packit |
a4aae4 |
sent back to the client program telling them that the server is
|
|
Packit |
a4aae4 |
broken.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Print usage information for a filter program. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::print_usage() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// Write a message to the WWW server error log file.
|
|
Packit |
a4aae4 |
ErrMsgT(usage.c_str());
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
throw Error(emessage);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** This function formats and sends to stdout version
|
|
Packit |
a4aae4 |
information from the httpd server, the server dispatch scripts,
|
|
Packit |
a4aae4 |
the DODS core software, and (optionally) the dataset.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Send version information back to the client program. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::send_version_info() const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
do_version(d_cgi_ver, get_dataset_version());
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** This function formats and prints an ASCII representation of a
|
|
Packit |
a4aae4 |
DAS on stdout. This has the effect of sending the DAS object
|
|
Packit |
a4aae4 |
back to the client program.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Transmit a DAS.
|
|
Packit |
a4aae4 |
@param out The output FILE to which the DAS is to be sent.
|
|
Packit |
a4aae4 |
@param das The DAS object to be sent.
|
|
Packit |
a4aae4 |
@param anc_location The directory in which the external DAS file resides.
|
|
Packit |
a4aae4 |
@param with_mime_headers If true (the default) send MIME headers.
|
|
Packit |
a4aae4 |
@return void
|
|
Packit |
a4aae4 |
@see DAS */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::send_das(FILE *out, DAS &das, const string &anc_location,
|
|
Packit |
a4aae4 |
bool with_mime_headers) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
ostringstream oss;
|
|
Packit |
a4aae4 |
send_das(oss, das, anc_location, with_mime_headers);
|
|
Packit |
a4aae4 |
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** This function formats and prints an ASCII representation of a
|
|
Packit |
a4aae4 |
DAS on stdout. This has the effect of sending the DAS object
|
|
Packit |
a4aae4 |
back to the client program.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Transmit a DAS.
|
|
Packit |
a4aae4 |
@param out The output stream to which the DAS is to be sent.
|
|
Packit |
a4aae4 |
@param das The DAS object to be sent.
|
|
Packit |
a4aae4 |
@param anc_location The directory in which the external DAS file resides.
|
|
Packit |
a4aae4 |
@param with_mime_headers If true (the default) send MIME headers.
|
|
Packit |
a4aae4 |
@return void
|
|
Packit |
a4aae4 |
@see DAS */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::send_das(ostream &out, DAS &das, const string &anc_location,
|
|
Packit |
a4aae4 |
bool with_mime_headers) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
time_t das_lmt = get_das_last_modified_time(anc_location);
|
|
Packit |
a4aae4 |
if (is_conditional()
|
|
Packit |
a4aae4 |
&& das_lmt <= get_request_if_modified_since()
|
|
Packit |
a4aae4 |
&& with_mime_headers) {
|
|
Packit |
a4aae4 |
set_mime_not_modified(out);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
if (with_mime_headers)
|
|
Packit |
a4aae4 |
set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
|
|
Packit |
a4aae4 |
das.print(out);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
out << flush ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::send_das(DAS &das, const string &anc_location,
|
|
Packit |
a4aae4 |
bool with_mime_headers) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
send_das(cout, das, anc_location, with_mime_headers);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** This function formats and prints an ASCII representation of a
|
|
Packit |
a4aae4 |
DDS on stdout. When called by a CGI program, this has the
|
|
Packit |
a4aae4 |
effect of sending a DDS object back to the client
|
|
Packit |
a4aae4 |
program. Either an entire DDS or a constrained DDS may be sent.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Transmit a DDS.
|
|
Packit |
a4aae4 |
@param out The output FILE to which the DAS is to be sent.
|
|
Packit |
a4aae4 |
@param dds The DDS to send back to a client.
|
|
Packit |
a4aae4 |
@param eval A reference to the ConstraintEvaluator to use.
|
|
Packit |
a4aae4 |
@param constrained If this argument is true, evaluate the
|
|
Packit |
a4aae4 |
current constraint expression and send the `constrained DDS'
|
|
Packit |
a4aae4 |
back to the client.
|
|
Packit |
a4aae4 |
@param anc_location The directory in which the external DAS file resides.
|
|
Packit |
a4aae4 |
@param with_mime_headers If true (the default) send MIME headers.
|
|
Packit |
a4aae4 |
@return void
|
|
Packit |
a4aae4 |
@see DDS */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::send_dds(FILE *out, DDS &dds, ConstraintEvaluator &eval,
|
|
Packit |
a4aae4 |
bool constrained,
|
|
Packit |
a4aae4 |
const string &anc_location,
|
|
Packit |
a4aae4 |
bool with_mime_headers) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
ostringstream oss;
|
|
Packit |
a4aae4 |
send_dds(oss, dds, eval, constrained, anc_location, with_mime_headers);
|
|
Packit |
a4aae4 |
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** This function formats and prints an ASCII representation of a
|
|
Packit |
a4aae4 |
DDS on stdout. When called by a CGI program, this has the
|
|
Packit |
a4aae4 |
effect of sending a DDS object back to the client
|
|
Packit |
a4aae4 |
program. Either an entire DDS or a constrained DDS may be sent.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Transmit a DDS.
|
|
Packit |
a4aae4 |
@param out The output stream to which the DAS is to be sent.
|
|
Packit |
a4aae4 |
@param dds The DDS to send back to a client.
|
|
Packit |
a4aae4 |
@param eval A reference to the ConstraintEvaluator to use.
|
|
Packit |
a4aae4 |
@param constrained If this argument is true, evaluate the
|
|
Packit |
a4aae4 |
current constraint expression and send the `constrained DDS'
|
|
Packit |
a4aae4 |
back to the client.
|
|
Packit |
a4aae4 |
@param anc_location The directory in which the external DAS file resides.
|
|
Packit |
a4aae4 |
@param with_mime_headers If true (the default) send MIME headers.
|
|
Packit |
a4aae4 |
@return void
|
|
Packit |
a4aae4 |
@see DDS */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::send_dds(ostream &out, DDS &dds, ConstraintEvaluator &eval,
|
|
Packit |
a4aae4 |
bool constrained,
|
|
Packit |
a4aae4 |
const string &anc_location,
|
|
Packit |
a4aae4 |
bool with_mime_headers) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// If constrained, parse the constraint. Throws Error or InternalErr.
|
|
Packit |
a4aae4 |
if (constrained)
|
|
Packit |
a4aae4 |
eval.parse_constraint(d_dap2ce, dds);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (eval.functional_expression())
|
|
Packit |
a4aae4 |
throw Error("Function calls can only be used with data requests. To see the structure of the underlying data source, reissue the URL without the function.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
time_t dds_lmt = get_dds_last_modified_time(anc_location);
|
|
Packit |
a4aae4 |
if (is_conditional()
|
|
Packit |
a4aae4 |
&& dds_lmt <= get_request_if_modified_since()
|
|
Packit |
a4aae4 |
&& with_mime_headers) {
|
|
Packit |
a4aae4 |
set_mime_not_modified(out);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
if (with_mime_headers)
|
|
Packit |
a4aae4 |
set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt);
|
|
Packit |
a4aae4 |
if (constrained)
|
|
Packit |
a4aae4 |
dds.print_constrained(out);
|
|
Packit |
a4aae4 |
else
|
|
Packit |
a4aae4 |
dds.print(out);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << flush ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::send_dds(DDS &dds, ConstraintEvaluator &eval,
|
|
Packit |
a4aae4 |
bool constrained, const string &anc_location,
|
|
Packit |
a4aae4 |
bool with_mime_headers) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
send_dds(cout, dds, eval, constrained, anc_location, with_mime_headers);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// 'lmt' unused. Should it be used to supply a LMT or removed from the
|
|
Packit |
a4aae4 |
// method? jhrg 8/9/05
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::functional_constraint(BaseType &var, DDS &dds,
|
|
Packit |
a4aae4 |
ConstraintEvaluator &eval, FILE *out) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
ostringstream oss;
|
|
Packit |
a4aae4 |
functional_constraint(var, dds, eval, oss);
|
|
Packit |
a4aae4 |
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// 'lmt' unused. Should it be used to supply a LMT or removed from the
|
|
Packit |
a4aae4 |
// method? jhrg 8/9/05
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::functional_constraint(BaseType &var, DDS &dds,
|
|
Packit |
a4aae4 |
ConstraintEvaluator &eval, ostream &out) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
out << "Dataset {\n" ;
|
|
Packit |
a4aae4 |
var.print_decl(out, " ", true, false, true);
|
|
Packit |
a4aae4 |
out << "} function_value;\n" ;
|
|
Packit |
a4aae4 |
out << "Data:\n" ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
out << flush ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Grab a stream that encodes using XDR.
|
|
Packit |
a4aae4 |
XDRStreamMarshaller m( out ) ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
try {
|
|
Packit |
a4aae4 |
// In the following call to serialize, suppress CE evaluation.
|
|
Packit |
a4aae4 |
var.serialize(eval, dds, m, false);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
catch (Error &e) {
|
|
Packit |
a4aae4 |
throw;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
|
|
Packit |
a4aae4 |
FILE * out, bool ce_eval) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
ostringstream oss;
|
|
Packit |
a4aae4 |
dataset_constraint(dds, eval, oss, ce_eval);
|
|
Packit |
a4aae4 |
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
|
|
Packit |
a4aae4 |
ostream &out, bool ce_eval) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// send constrained DDS
|
|
Packit |
a4aae4 |
dds.print_constrained(out);
|
|
Packit |
a4aae4 |
out << "Data:\n" ;
|
|
Packit |
a4aae4 |
out << flush ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Grab a stream that encodes using XDR.
|
|
Packit |
a4aae4 |
XDRStreamMarshaller m( out ) ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
try {
|
|
Packit |
a4aae4 |
// Send all variables in the current projection (send_p())
|
|
Packit |
a4aae4 |
for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
|
|
Packit |
a4aae4 |
if ((*i)->send_p()) {
|
|
Packit |
a4aae4 |
DBG(cerr << "Sending " << (*i)->name() << endl);
|
|
Packit |
a4aae4 |
(*i)->serialize(eval, dds, m, ce_eval);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
catch (Error & e) {
|
|
Packit |
a4aae4 |
throw;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::dataset_constraint_ddx(DDS & dds, ConstraintEvaluator & eval,
|
|
Packit |
a4aae4 |
ostream &out, const string &boundary,
|
|
Packit |
a4aae4 |
const string &start, bool ce_eval) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// Write the MPM headers for the DDX (text/xml) part of the response
|
|
Packit |
a4aae4 |
set_mime_ddx_boundary(out, boundary, start, dods_ddx);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Make cid
|
|
Packit |
a4aae4 |
uuid_t uu;
|
|
Packit |
a4aae4 |
uuid_generate(uu);
|
|
Packit |
a4aae4 |
char uuid[37];
|
|
Packit |
a4aae4 |
uuid_unparse(uu, &uuid[0]);
|
|
Packit |
a4aae4 |
char domain[256];
|
|
Packit |
a4aae4 |
if (getdomainname(domain, 255) != 0 || strlen(domain) == 0)
|
|
Packit |
a4aae4 |
strncpy(domain, "opendap.org", 255);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
string cid = string(&uuid[0]) + "@" + string(&domain[0]);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Send constrained DDX with a data blob reference
|
|
Packit |
a4aae4 |
dds.print_xml_writer(out, true, cid);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Write the MPM headers for the data part of the response.
|
|
Packit |
a4aae4 |
set_mime_data_boundary(out, boundary, cid, dap4_data, binary);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Grab a stream that encodes using XDR.
|
|
Packit |
a4aae4 |
XDRStreamMarshaller m( out ) ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
try {
|
|
Packit |
a4aae4 |
// Send all variables in the current projection (send_p())
|
|
Packit |
a4aae4 |
for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
|
|
Packit |
a4aae4 |
if ((*i)->send_p()) {
|
|
Packit |
a4aae4 |
DBG(cerr << "Sending " << (*i)->name() << endl);
|
|
Packit |
a4aae4 |
(*i)->serialize(eval, dds, m, ce_eval);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
catch (Error & e) {
|
|
Packit |
a4aae4 |
throw;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Send the data in the DDS object back to the client program. The data is
|
|
Packit |
a4aae4 |
encoded using a Marshaller, and enclosed in a MIME document which is all sent
|
|
Packit |
a4aae4 |
to \c data_stream. If this is being called from a CGI, \c data_stream is
|
|
Packit |
a4aae4 |
probably \c stdout and writing to it has the effect of sending the
|
|
Packit |
a4aae4 |
response back to the client.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Transmit data.
|
|
Packit |
a4aae4 |
@param dds A DDS object containing the data to be sent.
|
|
Packit |
a4aae4 |
@param eval A reference to the ConstraintEvaluator to use.
|
|
Packit |
a4aae4 |
@param data_stream Write the response to this FILE.
|
|
Packit |
a4aae4 |
@param anc_location A directory to search for ancillary files (in
|
|
Packit |
a4aae4 |
addition to the CWD). This is used in a call to
|
|
Packit |
a4aae4 |
get_data_last_modified_time().
|
|
Packit |
a4aae4 |
@param with_mime_headers If true, include the MIME headers in the response.
|
|
Packit |
a4aae4 |
Defaults to true.
|
|
Packit |
a4aae4 |
@return void */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
|
|
Packit |
a4aae4 |
FILE * data_stream, const string & anc_location,
|
|
Packit |
a4aae4 |
bool with_mime_headers) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
ostringstream oss;
|
|
Packit |
a4aae4 |
send_data(dds, eval, oss, anc_location, with_mime_headers);
|
|
Packit |
a4aae4 |
fwrite(oss.str().data(), sizeof(char), oss.str().length(), data_stream);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Send the data in the DDS object back to the client program. The data is
|
|
Packit |
a4aae4 |
encoded using a Marshaller, and enclosed in a MIME document which is all sent
|
|
Packit |
a4aae4 |
to \c data_stream. If this is being called from a CGI, \c data_stream is
|
|
Packit |
a4aae4 |
probably \c stdout and writing to it has the effect of sending the
|
|
Packit |
a4aae4 |
response back to the client.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Transmit data.
|
|
Packit |
a4aae4 |
@param dds A DDS object containing the data to be sent.
|
|
Packit |
a4aae4 |
@param eval A reference to the ConstraintEvaluator to use.
|
|
Packit |
a4aae4 |
@param data_stream Write the response to this stream.
|
|
Packit |
a4aae4 |
@param anc_location A directory to search for ancillary files (in
|
|
Packit |
a4aae4 |
addition to the CWD). This is used in a call to
|
|
Packit |
a4aae4 |
get_data_last_modified_time().
|
|
Packit |
a4aae4 |
@param with_mime_headers If true, include the MIME headers in the response.
|
|
Packit |
a4aae4 |
Defaults to true.
|
|
Packit |
a4aae4 |
@return void */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
|
|
Packit |
a4aae4 |
ostream & data_stream, const string & anc_location,
|
|
Packit |
a4aae4 |
bool with_mime_headers) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// If this is a conditional request and the server should send a 304
|
|
Packit |
a4aae4 |
// response, do that and exit. Otherwise, continue on and send the full
|
|
Packit |
a4aae4 |
// response.
|
|
Packit |
a4aae4 |
time_t data_lmt = get_data_last_modified_time(anc_location);
|
|
Packit |
a4aae4 |
if (is_conditional()
|
|
Packit |
a4aae4 |
&& data_lmt <= get_request_if_modified_since()
|
|
Packit |
a4aae4 |
&& with_mime_headers) {
|
|
Packit |
a4aae4 |
set_mime_not_modified(data_stream);
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// Set up the alarm.
|
|
Packit |
a4aae4 |
establish_timeout(data_stream);
|
|
Packit |
a4aae4 |
dds.set_timeout(d_timeout);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
eval.parse_constraint(d_dap2ce, dds); // Throws Error if the ce doesn't
|
|
Packit |
a4aae4 |
// parse.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Start sending the response...
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Handle *functional* constraint expressions specially
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
if (eval.functional_expression()) {
|
|
Packit |
a4aae4 |
// Get the result and then start sending the headers. This provides a
|
|
Packit |
a4aae4 |
// way to send errors back to the client w/o colliding with the
|
|
Packit |
a4aae4 |
// normal response headers. There's some duplication of code with this
|
|
Packit |
a4aae4 |
// and the else-clause.
|
|
Packit |
a4aae4 |
BaseType *var = eval.eval_function(dds, d_dataset);
|
|
Packit |
a4aae4 |
if (!var)
|
|
Packit |
a4aae4 |
throw Error(unknown_error, "Error calling the CE function.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (with_mime_headers)
|
|
Packit |
a4aae4 |
set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
data_stream << flush ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
functional_constraint(*var, dds, eval, data_stream);
|
|
Packit |
a4aae4 |
delete var;
|
|
Packit |
a4aae4 |
var = 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
if (eval.function_clauses()) {
|
|
Packit |
a4aae4 |
DDS *fdds = eval.eval_function_clauses(dds);
|
|
Packit |
a4aae4 |
if (with_mime_headers)
|
|
Packit |
a4aae4 |
set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dataset_constraint(*fdds, eval, data_stream, false);
|
|
Packit |
a4aae4 |
delete fdds;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
if (with_mime_headers)
|
|
Packit |
a4aae4 |
set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dataset_constraint(dds, eval, data_stream);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
data_stream << flush ;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Send the DDX response. The DDX never contains data, instead it holds a
|
|
Packit |
a4aae4 |
reference to a Blob response which is used to get the data values. The
|
|
Packit |
a4aae4 |
DDS and DAS objects are built using code that already exists in the
|
|
Packit |
a4aae4 |
servers.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param dds The dataset's DDS \e with attributes in the variables.
|
|
Packit |
a4aae4 |
@param eval A reference to the ConstraintEvaluator to use.
|
|
Packit |
a4aae4 |
@param out Destination
|
|
Packit |
a4aae4 |
@param with_mime_headers If true, include the MIME headers in the response.
|
|
Packit |
a4aae4 |
Defaults to true. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out,
|
|
Packit |
a4aae4 |
bool with_mime_headers) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
ostringstream oss;
|
|
Packit |
a4aae4 |
send_ddx(dds, eval, oss, with_mime_headers);
|
|
Packit |
a4aae4 |
fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Send the DDX response. The DDX never contains data, instead it holds a
|
|
Packit |
a4aae4 |
reference to a Blob response which is used to get the data values. The
|
|
Packit |
a4aae4 |
DDS and DAS objects are built using code that already exists in the
|
|
Packit |
a4aae4 |
servers.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param dds The dataset's DDS \e with attributes in the variables.
|
|
Packit |
a4aae4 |
@param eval A reference to the ConstraintEvaluator to use.
|
|
Packit |
a4aae4 |
@param out Destination
|
|
Packit |
a4aae4 |
@param with_mime_headers If true, include the MIME headers in the response.
|
|
Packit |
a4aae4 |
Defaults to true. */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, ostream &out,
|
|
Packit |
a4aae4 |
bool with_mime_headers) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// If constrained, parse the constraint. Throws Error or InternalErr.
|
|
Packit |
a4aae4 |
if (!d_dap2ce.empty())
|
|
Packit |
a4aae4 |
eval.parse_constraint(d_dap2ce, dds);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (eval.functional_expression())
|
|
Packit |
a4aae4 |
throw Error("Function calls can only be used with data requests. To see the structure of the underlying data source, reissue the URL without the function.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// If this is a conditional request and the server should send a 304
|
|
Packit |
a4aae4 |
// response, do that and exit. Otherwise, continue on and send the full
|
|
Packit |
a4aae4 |
// response.
|
|
Packit |
a4aae4 |
if (is_conditional() && dds_lmt <= get_request_if_modified_since()
|
|
Packit |
a4aae4 |
&& with_mime_headers) {
|
|
Packit |
a4aae4 |
set_mime_not_modified(out);
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
if (with_mime_headers)
|
|
Packit |
a4aae4 |
set_mime_text(out, dods_ddx, d_cgi_ver, x_plain, dds_lmt);
|
|
Packit |
a4aae4 |
dds.print_xml_writer(out, !d_dap2ce.empty(), "");
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Send the data in the DDS object back to the client program. The data is
|
|
Packit |
a4aae4 |
encoded using a Marshaller, and enclosed in a MIME document which is all sent
|
|
Packit |
a4aae4 |
to \c data_stream. If this is being called from a CGI, \c data_stream is
|
|
Packit |
a4aae4 |
probably \c stdout and writing to it has the effect of sending the
|
|
Packit |
a4aae4 |
response back to the client.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@brief Transmit data.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param dds A DDS object containing the data to be sent.
|
|
Packit |
a4aae4 |
@param eval A reference to the ConstraintEvaluator to use.
|
|
Packit |
a4aae4 |
@param data_stream Write the response to this stream.
|
|
Packit |
a4aae4 |
@param start
|
|
Packit |
a4aae4 |
@param boundary
|
|
Packit |
a4aae4 |
@param anc_location A directory to search for ancillary files (in
|
|
Packit |
a4aae4 |
addition to the CWD). This is used in a call to
|
|
Packit |
a4aae4 |
get_data_last_modified_time().
|
|
Packit |
a4aae4 |
@param with_mime_headers If true, include the MIME headers in the response.
|
|
Packit |
a4aae4 |
Defaults to true.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@return void */
|
|
Packit |
a4aae4 |
void
|
|
Packit |
a4aae4 |
DODSFilter::send_data_ddx(DDS & dds, ConstraintEvaluator & eval,
|
|
Packit |
a4aae4 |
ostream & data_stream, const string &start,
|
|
Packit |
a4aae4 |
const string &boundary, const string & anc_location,
|
|
Packit |
a4aae4 |
bool with_mime_headers) const
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
// If this is a conditional request and the server should send a 304
|
|
Packit |
a4aae4 |
// response, do that and exit. Otherwise, continue on and send the full
|
|
Packit |
a4aae4 |
// response.
|
|
Packit |
a4aae4 |
time_t data_lmt = get_data_last_modified_time(anc_location);
|
|
Packit |
a4aae4 |
if (is_conditional()
|
|
Packit |
a4aae4 |
&& data_lmt <= get_request_if_modified_since()
|
|
Packit |
a4aae4 |
&& with_mime_headers) {
|
|
Packit |
a4aae4 |
set_mime_not_modified(data_stream);
|
|
Packit |
a4aae4 |
return;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
// Set up the alarm.
|
|
Packit |
a4aae4 |
establish_timeout(data_stream);
|
|
Packit |
a4aae4 |
dds.set_timeout(d_timeout);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
eval.parse_constraint(d_dap2ce, dds); // Throws Error if the ce doesn't
|
|
Packit |
a4aae4 |
// parse.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Start sending the response...
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Handle *functional* constraint expressions specially
|
|
Packit |
a4aae4 |
#if 0
|
|
Packit |
a4aae4 |
if (eval.functional_expression()) {
|
|
Packit |
a4aae4 |
BaseType *var = eval.eval_function(dds, d_dataset);
|
|
Packit |
a4aae4 |
if (!var)
|
|
Packit |
a4aae4 |
throw Error(unknown_error, "Error calling the CE function.");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (with_mime_headers)
|
|
Packit |
a4aae4 |
set_mime_multipart(data_stream, boundary, start, dods_data_ddx,
|
|
Packit |
a4aae4 |
d_cgi_ver, x_plain, data_lmt);
|
|
Packit |
a4aae4 |
data_stream << flush ;
|
|
Packit |
a4aae4 |
BaseTypeFactory btf;
|
|
Packit |
a4aae4 |
DDS var_dds(&btf, var->name());
|
|
Packit |
a4aae4 |
var->set_send_p(true);
|
|
Packit |
a4aae4 |
var_dds.add_var(var);
|
|
Packit |
a4aae4 |
serialize_dap2_data_ddx(var_dds, eval, data_stream, boundary, start);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// functional_constraint_ddx(*var, dds, eval, data_stream, boundary);
|
|
Packit |
a4aae4 |
delete var;
|
|
Packit |
a4aae4 |
var = 0;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
#endif
|
|
Packit |
a4aae4 |
if (eval.function_clauses()) {
|
|
Packit |
a4aae4 |
DDS *fdds = eval.eval_function_clauses(dds);
|
|
Packit |
a4aae4 |
if (with_mime_headers)
|
|
Packit |
a4aae4 |
set_mime_multipart(data_stream, boundary, start, dods_data_ddx,
|
|
Packit |
a4aae4 |
d_cgi_ver, x_plain, data_lmt);
|
|
Packit |
a4aae4 |
data_stream << flush ;
|
|
Packit |
a4aae4 |
dataset_constraint(*fdds, eval, data_stream, false);
|
|
Packit |
a4aae4 |
delete fdds;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
if (with_mime_headers)
|
|
Packit |
a4aae4 |
set_mime_multipart(data_stream, boundary, start, dods_data_ddx,
|
|
Packit |
a4aae4 |
d_cgi_ver, x_plain, data_lmt);
|
|
Packit |
a4aae4 |
data_stream << flush ;
|
|
Packit |
a4aae4 |
dataset_constraint_ddx(dds, eval, data_stream, boundary, start);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
data_stream << flush ;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (with_mime_headers)
|
|
Packit |
a4aae4 |
data_stream << CRLF << "--" << boundary << "--" << CRLF;
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // namespace libdap
|
|
Packit |
a4aae4 |
|