56#ifdef HAVE_UUID_UUID_H
58#elif defined(HAVE_UUID_H)
61#error "Could not find UUID library header"
69#include "DODSFilter.h"
70#include "InternalErr.h"
71#include "XDRStreamMarshaller.h"
78#include "AlarmHandler.h"
79#include "EventHandler.h"
80#include "SignalHandler.h"
89const string usage =
"Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\
91 options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\
92 -u <url>: The complete URL minus the CE (required for DDX)\n\
93 -c: Compress the response using the deflate algorithm.\n\
94 -e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\
95 -v <version>: Use <version> as the version number\n\
96 -d <dir>: Look for ancillary file in <dir> (deprecated).\n\
97 -f <file>: Look for ancillary data in <file> (deprecated).\n\
98 -r <dir>: Use <dir> as a cache directory\n\
99 -l <time>: Conditional request; if data source is unchanged since\n\
100 <time>, return an HTTP 304 response.\n\
101 -t <seconds>: Timeout the handler after <seconds>.\n\
168DODSFilter::DODSFilter(
int argc,
char *argv[])
throw(
Error) {
169 initialize(argc, argv);
171 DBG(cerr <<
"d_comp: " << d_comp << endl);
172 DBG(cerr <<
"d_dap2ce: " << d_dap2ce << endl);
173 DBG(cerr <<
"d_cgi_ver: " << d_cgi_ver << endl);
174 DBG(cerr <<
"d_response: " << d_response << endl);
175 DBG(cerr <<
"d_anc_dir: " << d_anc_dir << endl);
176 DBG(cerr <<
"d_anc_file: " << d_anc_file << endl);
177 DBG(cerr <<
"d_cache_dir: " << d_cache_dir << endl);
178 DBG(cerr <<
"d_conditional_request: " << d_conditional_request << endl);
179 DBG(cerr <<
"d_if_modified_since: " << d_if_modified_since << endl);
180 DBG(cerr <<
"d_url: " << d_url << endl);
181 DBG(cerr <<
"d_timeout: " << d_timeout << endl);
184DODSFilter::~DODSFilter() {}
188void DODSFilter::initialize() {
192 d_bad_options =
false;
193 d_conditional_request =
false;
200 d_response = Unknown_Response;
204 d_if_modified_since = -1;
206 d_program_name =
"Unknown";
213 _setmode(_fileno(stdout), _O_BINARY);
228void DODSFilter::initialize(
int argc,
char *argv[]) {
231 d_program_name = argv[0];
239 if (next_arg < argc) {
240 d_dataset = argv[next_arg];
241 d_dataset =
www2id(d_dataset,
"%",
"%20");
254int DODSFilter::process_options(
int argc,
char *argv[]) {
255 DBG(cerr <<
"Entering process_options... ");
258 GetOpt getopt(argc, argv,
"ce: v: d: f: r: l: o: u: t: ");
260 while ((option_char = getopt()) != -1) {
261 switch (option_char) {
266 set_ce(getopt.optarg);
269 set_cgi_version(getopt.optarg);
272 d_anc_dir = getopt.optarg;
275 d_anc_file = getopt.optarg;
278 d_cache_dir = getopt.optarg;
287 d_timeout = atoi(getopt.optarg);
290 d_conditional_request =
true;
291 d_if_modified_since =
static_cast<time_t
>(strtol(getopt.optarg, NULL, 10));
306 DBGN(cerr <<
"exiting." << endl);
308 return getopt.optind;
315bool DODSFilter::is_conditional()
const {
return d_conditional_request; }
330void DODSFilter::set_cgi_version(
string version) { d_cgi_ver = version; }
337string DODSFilter::get_cgi_version()
const {
return d_cgi_ver; }
345string DODSFilter::get_ce()
const {
return d_dap2ce; }
347void DODSFilter::set_ce(
string _ce) { d_dap2ce =
www2id(_ce,
"%",
"%20"); }
357string DODSFilter::get_dataset_name()
const {
return d_dataset; }
359void DODSFilter::set_dataset_name(
const string ds) { d_dataset =
www2id(ds,
"%",
"%20"); }
364string DODSFilter::get_URL()
const {
return d_url; }
368void DODSFilter::set_URL(
const string &url) {
369 if (url.find(
'?') != url.npos)
382string DODSFilter::get_dataset_version()
const {
return ""; }
390void DODSFilter::set_response(
const string &r) {
391 if (r ==
"DAS" || r ==
"das") {
392 d_response = DAS_Response;
394 }
else if (r ==
"DDS" || r ==
"dds") {
395 d_response = DDS_Response;
397 }
else if (r ==
"DataDDS" || r ==
"dods") {
398 d_response = DataDDS_Response;
400 }
else if (r ==
"DDX" || r ==
"ddx") {
401 d_response = DDX_Response;
403 }
else if (r ==
"DataDDX" || r ==
"dataddx") {
404 d_response = DataDDX_Response;
405 d_action =
"dataddx";
406 }
else if (r ==
"Version") {
407 d_response = Version_Response;
408 d_action =
"version";
414DODSFilter::Response DODSFilter::get_response()
const {
return d_response; }
417string DODSFilter::get_action()
const {
return d_action; }
439time_t DODSFilter::get_dataset_last_modified_time()
const {
return last_modified_time(d_dataset); }
450time_t DODSFilter::get_das_last_modified_time(
const string &anc_location)
const {
451 DBG(cerr <<
"DODSFilter::get_das_last_modified_time(anc_location=" << anc_location
452 <<
"call faf(das) d_dataset=" << d_dataset <<
" d_anc_file=" << d_anc_file << endl);
457 return max((name !=
"") ?
last_modified_time(name) : 0, get_dataset_last_modified_time());
467time_t DODSFilter::get_dds_last_modified_time(
const string &anc_location)
const {
468 DBG(cerr <<
"DODSFilter::get_das_last_modified_time(anc_location=" << anc_location
469 <<
"call faf(dds) d_dataset=" << d_dataset <<
" d_anc_file=" << d_anc_file << endl);
474 return max((name !=
"") ?
last_modified_time(name) : 0, get_dataset_last_modified_time());
490time_t DODSFilter::get_data_last_modified_time(
const string &anc_location)
const {
491 DBG(cerr <<
"DODSFilter::get_das_last_modified_time(anc_location=" << anc_location
492 <<
"call faf(both) d_dataset=" << d_dataset <<
" d_anc_file=" << d_anc_file << endl);
502 time_t n = get_dataset_last_modified_time();
514time_t DODSFilter::get_request_if_modified_since()
const {
return d_if_modified_since; }
522string DODSFilter::get_cache_dir()
const {
return d_cache_dir; }
528void DODSFilter::set_timeout(
int t) { d_timeout = t; }
531int DODSFilter::get_timeout()
const {
return d_timeout; }
544void DODSFilter::establish_timeout(FILE *stream)
const {
555void DODSFilter::establish_timeout(ostream &stream)
const {
566static const char *emessage =
"DODS internal server error; usage error. Please report this to the dataset maintainer, "
567 "or to the opendap-tech@opendap.org mailing list.";
578void DODSFilter::print_usage()
const {
582 throw Error(emessage);
603void DODSFilter::send_das(FILE *out,
DAS &das,
const string &anc_location,
bool with_mime_headers)
const {
605 send_das(oss, das, anc_location, with_mime_headers);
606 fwrite(oss.str().data(),
sizeof(
char), oss.str().length(), out);
620void DODSFilter::send_das(ostream &out,
DAS &das,
const string &anc_location,
bool with_mime_headers)
const {
623 set_mime_not_modified(out);
625 if (with_mime_headers)
632void DODSFilter::send_das(DAS &das,
const string &anc_location,
bool with_mime_headers)
const {
633 send_das(cout, das, anc_location, with_mime_headers);
652void DODSFilter::send_dds(FILE *out,
DDS &dds,
ConstraintEvaluator &eval,
bool constrained,
const string &anc_location,
653 bool with_mime_headers)
const {
655 send_dds(oss, dds, eval, constrained, anc_location, with_mime_headers);
656 fwrite(oss.str().data(),
sizeof(
char), oss.str().length(), out);
676 const string &anc_location,
bool with_mime_headers)
const {
679 eval.parse_constraint(d_dap2ce, dds);
681 if (eval.functional_expression())
682 throw Error(
"Function calls can only be used with data requests. To see the structure of the underlying data "
683 "source, reissue the URL without the function.");
687 set_mime_not_modified(out);
689 if (with_mime_headers)
692 dds.print_constrained(out);
700void DODSFilter::send_dds(
DDS &dds,
ConstraintEvaluator &eval,
bool constrained,
const string &anc_location,
701 bool with_mime_headers)
const {
702 send_dds(cout, dds, eval, constrained, anc_location, with_mime_headers);
709 functional_constraint(
var, dds, eval, oss);
710 fwrite(oss.str().data(),
sizeof(
char), oss.str().length(), out);
716 out <<
"Dataset {\n";
717 var.print_decl(out,
" ",
true,
false,
true);
718 out <<
"} function_value;\n";
728 var.serialize(eval, dds, m,
false);
736 dataset_constraint(dds, eval, oss, ce_eval);
737 fwrite(oss.str().data(),
sizeof(
char), oss.str().length(), out);
740void DODSFilter::dataset_constraint(
DDS &dds,
ConstraintEvaluator &eval, ostream &out,
bool ce_eval)
const {
742 dds.print_constrained(out);
751 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
752 if ((*i)->send_p()) {
753 DBG(cerr <<
"Sending " << (*i)->name() << endl);
754 (*i)->serialize(eval, dds, m, ce_eval);
761void DODSFilter::dataset_constraint_ddx(
DDS &dds,
ConstraintEvaluator &eval, ostream &out,
const string &boundary,
762 const string &start,
bool ce_eval)
const {
764 set_mime_ddx_boundary(out, boundary, start, dods_ddx);
770 uuid_unparse(uu, uuid);
772 if (getdomainname(domain, 255) != 0 || strlen(domain) == 0)
773 strncpy(domain,
"opendap.org", 255);
775 string cid = string(uuid) +
"@" + string(domain);
778 dds.print_xml_writer(out,
true, cid);
781 set_mime_data_boundary(out, boundary, cid, dap4_data, binary);
788 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
789 if ((*i)->send_p()) {
790 DBG(cerr <<
"Sending " << (*i)->name() << endl);
791 (*i)->serialize(eval, dds, m, ce_eval);
814void DODSFilter::send_data(
DDS &dds,
ConstraintEvaluator &eval, FILE *data_stream,
const string &anc_location,
815 bool with_mime_headers)
const {
817 send_data(dds, eval, oss, anc_location, with_mime_headers);
818 fwrite(oss.str().data(),
sizeof(
char), oss.str().length(), data_stream);
837void DODSFilter::send_data(
DDS &dds,
ConstraintEvaluator &eval, ostream &data_stream,
const string &anc_location,
838 bool with_mime_headers)
const {
844 set_mime_not_modified(data_stream);
848 establish_timeout(data_stream);
849 dds.set_timeout(d_timeout);
851 eval.parse_constraint(d_dap2ce, dds);
854 dds.tag_nested_sequences();
860 if (eval.functional_expression()) {
865 BaseType *
var = eval.eval_function(dds, d_dataset);
867 throw Error(unknown_error,
"Error calling the CE function.");
869 if (with_mime_headers)
872 data_stream << flush ;
874 functional_constraint(*
var, dds, eval, data_stream);
879 if (eval.function_clauses()) {
880 DDS *fdds = eval.eval_function_clauses(dds);
881 if (with_mime_headers)
884 dataset_constraint(*fdds, eval, data_stream,
false);
887 if (with_mime_headers)
890 dataset_constraint(dds, eval, data_stream);
893 data_stream << flush;
908 send_ddx(dds, eval, oss, with_mime_headers);
909 fwrite(oss.str().data(),
sizeof(
char), oss.str().length(), out);
922void DODSFilter::send_ddx(
DDS &dds,
ConstraintEvaluator &eval, ostream &out,
bool with_mime_headers)
const {
924 if (!d_dap2ce.empty())
925 eval.parse_constraint(d_dap2ce, dds);
927 if (eval.functional_expression())
928 throw Error(
"Function calls can only be used with data requests. To see the structure of the underlying data "
929 "source, reissue the URL without the function.");
937 set_mime_not_modified(out);
940 if (with_mime_headers)
942 dds.print_xml_writer(out, !d_dap2ce.empty(),
"");
966void DODSFilter::send_data_ddx(
DDS &dds,
ConstraintEvaluator &eval, ostream &data_stream,
const string &start,
967 const string &boundary,
const string &anc_location,
bool with_mime_headers)
const {
973 set_mime_not_modified(data_stream);
977 establish_timeout(data_stream);
978 dds.set_timeout(d_timeout);
980 eval.parse_constraint(d_dap2ce, dds);
983 dds.tag_nested_sequences();
989 if (eval.functional_expression()) {
990 BaseType *
var = eval.eval_function(dds, d_dataset);
992 throw Error(unknown_error,
"Error calling the CE function.");
994 if (with_mime_headers)
995 set_mime_multipart(data_stream, boundary, start, dods_data_ddx,
996 d_cgi_ver, x_plain, data_lmt);
997 data_stream << flush ;
999 DDS var_dds(&btf,
var->name());
1000 var->set_send_p(
true);
1001 var_dds.add_var(
var);
1002 serialize_dap2_data_ddx(var_dds, eval, data_stream, boundary, start);
1009 if (eval.function_clauses()) {
1010 DDS *fdds = eval.eval_function_clauses(dds);
1011 if (with_mime_headers)
1012 set_mime_multipart(data_stream, boundary, start, dods_data_ddx, d_cgi_ver, x_plain, data_lmt);
1013 data_stream << flush;
1014 dataset_constraint(*fdds, eval, data_stream,
false);
1017 if (with_mime_headers)
1018 set_mime_multipart(data_stream, boundary, start, dods_data_ddx, d_cgi_ver, x_plain, data_lmt);
1019 data_stream << flush;
1020 dataset_constraint_ddx(dds, eval, data_stream, boundary, start);
1023 data_stream << flush;
1025 if (with_mime_headers)
1026 data_stream << CRLF <<
"--" << boundary <<
"--" << CRLF;
static string find_ancillary_file(const string &pathname, const string &ext, const string &dir, const string &file)
Find a file with ancillary data.
Evaluate a constraint expression.
Hold attribute data for a DAP2 dataset.
virtual void print(FILE *out, bool dereference=false)
A class for error processing.
static SignalHandler * instance()
Marshaller that knows how serialize dap data objects to a C++ iostream using XDR.
top level DAP object to house generic methods
virtual time_t get_dds_last_modified_time(const string &anc_location="") const
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=nullptr)
Returns a pointer to a member of a constructor class.
string www2id(const string &in, const string &escape, const string &except)
time_t last_modified_time(const string &name)
virtual Response get_response() const
void set_mime_binary(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
virtual int process_options(int argc, char *argv[])
virtual void set_URL(const string &url)
bool do_version(const string &script_ver, const string &dataset_ver)
Send a version number.
virtual void print_usage() const
Print usage information for a filter program.
virtual string get_dataset_version() const
Get the version information for the dataset.
virtual bool is_conditional() const
Is this request conditional?
void ErrMsgT(const string &Msgt)
Logs an error message.
virtual void set_response(const string &r)
virtual time_t get_das_last_modified_time(const string &anc_location="") const
virtual time_t get_request_if_modified_since() const
void set_mime_text(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
virtual time_t get_data_last_modified_time(const string &anc_location="") const