57 #include <uuid/uuid.h>
78 #define CRLF "\r\n" // Change here, expr-test.cc and DODSFilter.cc
85 "Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\
87 options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\
88 -u <url>: The complete URL minus the CE (required for DDX)\n\
89 -c: Compress the response using the deflate algorithm.\n\
90 -e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\
91 -v <version>: Use <version> as the version number\n\
92 -d <dir>: Look for ancillary file in <dir> (deprecated).\n\
93 -f <file>: Look for ancillary data in <file> (deprecated).\n\
94 -r <dir>: Use <dir> as a cache directory\n\
95 -l <time>: Conditional request; if data source is unchanged since\n\
96 <time>, return an HTTP 304 response.\n\
97 -t <seconds>: Timeout the handler after <seconds>.\n\
164 DODSFilter::DODSFilter(
int argc,
char *argv[])
throw(
Error)
166 initialize(argc, argv);
168 DBG(cerr <<
"d_comp: " << d_comp << endl);
169 DBG(cerr <<
"d_dap2ce: " << d_dap2ce << endl);
170 DBG(cerr <<
"d_cgi_ver: " << d_cgi_ver << endl);
171 DBG(cerr <<
"d_response: " << d_response << endl);
172 DBG(cerr <<
"d_anc_dir: " << d_anc_dir << endl);
173 DBG(cerr <<
"d_anc_file: " << d_anc_file << endl);
174 DBG(cerr <<
"d_cache_dir: " << d_cache_dir << endl);
175 DBG(cerr <<
"d_conditional_request: " << d_conditional_request << endl);
176 DBG(cerr <<
"d_if_modified_since: " << d_if_modified_since << endl);
177 DBG(cerr <<
"d_url: " << d_url << endl);
178 DBG(cerr <<
"d_timeout: " << d_timeout << endl);
181 DODSFilter::~DODSFilter()
188 DODSFilter::initialize()
193 d_bad_options =
false;
194 d_conditional_request =
false;
201 d_response = Unknown_Response;;
204 d_if_modified_since = -1;
206 d_program_name =
"Unknown";
213 _setmode(_fileno(stdout), _O_BINARY);
229 DODSFilter::initialize(
int argc,
char *argv[])
233 d_program_name = argv[0];
236 int next_arg = process_options(argc, argv);
241 if (next_arg < argc) {
242 d_dataset = argv[next_arg];
243 d_dataset =
www2id(d_dataset,
"%",
"%20");
245 else if (get_response() != Version_Response)
258 DODSFilter::process_options(
int argc,
char *argv[])
260 DBG(cerr <<
"Entering process_options... ");
263 GetOpt getopt (argc, argv,
"ce: v: d: f: r: l: o: u: t: ");
265 while ((option_char = getopt()) != -1) {
266 switch (option_char) {
267 case 'c': d_comp =
true;
break;
268 case 'e': set_ce(getopt.optarg);
break;
269 case 'v': set_cgi_version(getopt.optarg);
break;
270 case 'd': d_anc_dir = getopt.optarg;
break;
271 case 'f': d_anc_file = getopt.optarg;
break;
272 case 'r': d_cache_dir = getopt.optarg;
break;
273 case 'o': set_response(getopt.optarg);
break;
274 case 'u': set_URL(getopt.optarg);
break;
275 case 't': d_timeout = atoi(getopt.optarg);
break;
277 d_conditional_request =
true;
279 =
static_cast<time_t
>(strtol(getopt.optarg, NULL, 10));
281 case 'h': print_usage();
287 default: print_usage();
292 DBGN(cerr <<
"exiting." << endl);
294 return getopt.optind;
302 DODSFilter::is_conditional()
const
304 return d_conditional_request;
332 DODSFilter::get_cgi_version()
const
344 DODSFilter::get_ce()
const
350 DODSFilter::set_ce(
string _ce)
352 d_dap2ce =
www2id(_ce,
"%",
"%20");
364 DODSFilter::get_dataset_name()
const
370 DODSFilter::set_dataset_name(
const string ds)
372 d_dataset =
www2id(ds,
"%",
"%20");
379 DODSFilter::get_URL()
const
387 DODSFilter::set_URL(
const string &url)
389 if (url.find(
'?') != url.npos)
403 DODSFilter::get_dataset_version()
const
414 void DODSFilter::set_response(
const string &r)
416 if (r ==
"DAS" || r ==
"das") {
417 d_response = DAS_Response;
420 else if (r ==
"DDS" || r ==
"dds") {
421 d_response = DDS_Response;
424 else if (r ==
"DataDDS" || r ==
"dods") {
425 d_response = DataDDS_Response;
428 else if (r ==
"DDX" || r ==
"ddx") {
429 d_response = DDX_Response;
432 else if (r ==
"DataDDX" || r ==
"dataddx") {
433 d_response = DataDDX_Response;
434 d_action =
"dataddx" ;
436 else if (r ==
"Version") {
437 d_response = Version_Response;
438 d_action =
"version" ;
446 DODSFilter::get_response()
const
452 string DODSFilter::get_action()
const
478 DODSFilter::get_dataset_last_modified_time()
const
493 DODSFilter::get_das_last_modified_time(
const string &anc_location)
const
495 DBG(cerr <<
"DODSFilter::get_das_last_modified_time(anc_location="
496 << anc_location <<
"call faf(das) d_dataset=" << d_dataset
497 <<
" d_anc_file=" << d_anc_file << endl);
500 = Ancillary::find_ancillary_file(d_dataset,
"das",
501 (anc_location ==
"") ? d_anc_dir : anc_location,
505 get_dataset_last_modified_time());
516 DODSFilter::get_dds_last_modified_time(
const string &anc_location)
const
518 DBG(cerr <<
"DODSFilter::get_das_last_modified_time(anc_location="
519 << anc_location <<
"call faf(dds) d_dataset=" << d_dataset
520 <<
" d_anc_file=" << d_anc_file << endl);
523 = Ancillary::find_ancillary_file(d_dataset,
"dds",
524 (anc_location ==
"") ? d_anc_dir : anc_location,
528 get_dataset_last_modified_time());
545 DODSFilter::get_data_last_modified_time(
const string &anc_location)
const
547 DBG(cerr <<
"DODSFilter::get_das_last_modified_time(anc_location="
548 << anc_location <<
"call faf(both) d_dataset=" << d_dataset
549 <<
" d_anc_file=" << d_anc_file << endl);
552 = Ancillary::find_ancillary_file(d_dataset,
"dds",
553 (anc_location ==
"") ? d_anc_dir : anc_location,
556 = Ancillary::find_ancillary_file(d_dataset,
"das",
557 (anc_location ==
"") ? d_anc_dir : anc_location,
563 time_t n = get_dataset_last_modified_time();
576 DODSFilter::get_request_if_modified_since()
const
578 return d_if_modified_since;
588 DODSFilter::get_cache_dir()
const
598 DODSFilter::set_timeout(
int t)
605 DODSFilter::get_timeout()
const
622 DODSFilter::establish_timeout(FILE *stream)
const
635 DODSFilter::establish_timeout(ostream &stream)
const
647 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.";
659 DODSFilter::print_usage()
const
664 throw Error(emessage);
673 DODSFilter::send_version_info()
const
690 DODSFilter::send_das(FILE *out,
DAS &das,
const string &anc_location,
691 bool with_mime_headers)
const
694 send_das(oss, das, anc_location, with_mime_headers);
695 fwrite(oss.str().data(),
sizeof(char), oss.str().length(), out);
710 DODSFilter::send_das(ostream &out,
DAS &das,
const string &anc_location,
711 bool with_mime_headers)
const
713 time_t das_lmt = get_das_last_modified_time(anc_location);
715 && das_lmt <= get_request_if_modified_since()
716 && with_mime_headers) {
720 if (with_mime_headers)
728 DODSFilter::send_das(
DAS &das,
const string &anc_location,
729 bool with_mime_headers)
const
731 send_das(cout, das, anc_location, with_mime_headers);
753 const string &anc_location,
754 bool with_mime_headers)
const
757 send_dds(oss, dds, eval, constrained, anc_location, with_mime_headers);
758 fwrite(oss.str().data(),
sizeof(char), oss.str().length(), out);
780 const string &anc_location,
781 bool with_mime_headers)
const
788 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.");
790 time_t dds_lmt = get_dds_last_modified_time(anc_location);
792 && dds_lmt <= get_request_if_modified_since()
793 && with_mime_headers) {
797 if (with_mime_headers)
810 bool constrained,
const string &anc_location,
811 bool with_mime_headers)
const
813 send_dds(cout, dds, eval, constrained, anc_location, with_mime_headers);
823 functional_constraint(var, dds, eval, oss);
824 fwrite(oss.str().data(),
sizeof(char), oss.str().length(), out);
833 out <<
"Dataset {\n" ;
835 out <<
"} function_value;\n" ;
854 FILE * out,
bool ce_eval)
const
857 dataset_constraint(dds, eval, oss, ce_eval);
858 fwrite(oss.str().data(),
sizeof(char), oss.str().length(), out);
863 ostream &out,
bool ce_eval)
const
876 if ((*i)->send_p()) {
877 DBG(cerr <<
"Sending " << (*i)->name() << endl);
878 (*i)->serialize(eval, dds, m, ce_eval);
888 ostream &out,
const string &boundary,
889 const string &start,
bool ce_eval)
const
898 uuid_unparse(uu, &uuid[0]);
900 if (getdomainname(domain, 255) != 0 || strlen(domain) == 0)
901 strncpy(domain,
"opendap.org", 255);
903 string cid = string(&uuid[0]) +
"@" + string(&domain[0]);
917 if ((*i)->send_p()) {
918 DBG(cerr <<
"Sending " << (*i)->name() << endl);
919 (*i)->serialize(eval, dds, m, ce_eval);
945 FILE * data_stream,
const string & anc_location,
946 bool with_mime_headers)
const
949 send_data(dds, eval, oss, anc_location, with_mime_headers);
950 fwrite(oss.str().data(),
sizeof(char), oss.str().length(), data_stream);
971 ostream & data_stream,
const string & anc_location,
972 bool with_mime_headers)
const
977 time_t data_lmt = get_data_last_modified_time(anc_location);
979 && data_lmt <= get_request_if_modified_since()
980 && with_mime_headers) {
985 establish_timeout(data_stream);
1006 if (with_mime_headers)
1009 data_stream << flush ;
1011 functional_constraint(*var, dds, eval, data_stream);
1018 if (with_mime_headers)
1021 dataset_constraint(*fdds, eval, data_stream,
false);
1025 if (with_mime_headers)
1028 dataset_constraint(dds, eval, data_stream);
1031 data_stream << flush ;
1046 bool with_mime_headers)
const
1049 send_ddx(dds, eval, oss, with_mime_headers);
1050 fwrite(oss.str().data(),
sizeof(char), oss.str().length(), out);
1065 bool with_mime_headers)
const
1068 if (!d_dap2ce.empty())
1072 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.");
1074 time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
1079 if (is_conditional() && dds_lmt <= get_request_if_modified_since()
1080 && with_mime_headers) {
1085 if (with_mime_headers)
1113 ostream & data_stream,
const string &start,
1114 const string &boundary,
const string & anc_location,
1115 bool with_mime_headers)
const
1120 time_t data_lmt = get_data_last_modified_time(anc_location);
1121 if (is_conditional()
1122 && data_lmt <= get_request_if_modified_since()
1123 && with_mime_headers) {
1128 establish_timeout(data_stream);
1145 if (with_mime_headers)
1147 d_cgi_ver,
x_plain, data_lmt);
1148 data_stream << flush ;
1150 DDS var_dds(&btf, var->
name());
1152 var_dds.add_var(var);
1153 serialize_dap2_data_ddx(var_dds, eval, data_stream, boundary, start);
1162 if (with_mime_headers)
1164 d_cgi_ver,
x_plain, data_lmt);
1165 data_stream << flush ;
1166 dataset_constraint(*fdds, eval, data_stream,
false);
1170 if (with_mime_headers)
1172 d_cgi_ver,
x_plain, data_lmt);
1173 data_stream << flush ;
1174 dataset_constraint_ddx(dds, eval, data_stream, boundary, start);
1177 data_stream << flush ;
1179 if (with_mime_headers)
1180 data_stream <<
CRLF <<
"--" << boundary <<
"--" <<
CRLF;
virtual void print_decl(FILE *out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Print an ASCII representation of the variable structure.
void ErrMsgT(const string &Msgt)
Logs an error message.
void print(FILE *out)
Print the entire DDS to the specified file.
void set_mime_data_boundary(ostream &strm, const string &boundary, const string &cid, ObjectType type, EncodingType enc)
time_t last_modified_time(const string &name)
Vars_iter var_begin()
Return an iterator to the first variable.
void set_mime_text(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
void print_xml_writer(ostream &out, bool constrained, const string &blob="")
BaseType * eval_function(DDS &dds, const std::string &dataset)
Evaluate a function-valued constraint expression.
virtual void print(FILE *out, bool dereference=false)
#define unknown_error
Unknown error.
virtual bool serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval=true)
Move data to the net.
virtual void set_send_p(bool state)
DDS * eval_function_clauses(DDS &dds)
Evaluate a function-valued constraint expression that contains several function calls.
void set_mime_ddx_boundary(ostream &strm, const string &boundary, const string &cid, ObjectType type, EncodingType enc)
std::vector< BaseType * >::iterator Vars_iter
void set_mime_binary(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
void parse_constraint(const std::string &constraint, DDS &dds)
Parse the constraint expression given the current DDS.
string name() const
Returns the name of the class instance.
void set_mime_not_modified(FILE *out)
Send a `Not Modified' response.
string www2id(const string &in, const string &escape, const string &except)
Vars_iter var_end()
Return an iterator.
Evaluate a constraint expression.
void tag_nested_sequences()
Traverse DDS, set Sequence leaf nodes.
bool functional_expression()
Does the current constraint expression return a BaseType pointer? This method does not evaluate the c...
The basic data type for the DODS DAP types.
Hold attribute data for a DAP2 dataset.
void set_mime_multipart(ostream &strm, const string &boundary, const string &start, ObjectType type, const string &version, EncodingType enc, const time_t last_modified)
bool function_clauses()
Does the current constraint expression contain function clauses.
A class for error processing.
EventHandler * register_handler(int signum, EventHandler *eh, bool override=false)
marshaller that knows how to marshal/serialize dap data objects to a C++ iostream using XDR ...
bool do_version(const string &script_ver, const string &dataset_ver)
Send a version number.
void print_constrained(FILE *out)
Print a constrained DDS to the specified file.