40 {
"$Id: DODSFilter.cc 25112 2011-12-29 21:44:54Z jimg $"
60 #include <uuid/uuid.h>
84 #define CRLF "\r\n" // Change here, expr-test.cc and DODSFilter.cc
93 "Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\
95 options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\
96 -u <url>: The complete URL minus the CE (required for DDX)\n\
97 -c: Compress the response using the deflate algorithm.\n\
98 -e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\
99 -v <version>: Use <version> as the version number\n\
100 -d <dir>: Look for ancillary file in <dir> (deprecated).\n\
101 -f <file>: Look for ancillary data in <file> (deprecated).\n\
102 -r <dir>: Use <dir> as a cache directory\n\
103 -l <time>: Conditional request; if data source is unchanged since\n\
104 <time>, return an HTTP 304 response.\n\
105 -t <seconds>: Timeout the handler after <seconds>.\n\
172 DODSFilter::DODSFilter(
int argc,
char *argv[])
throw(
Error)
174 initialize(argc, argv);
176 DBG(cerr <<
"d_comp: " << d_comp << endl);
177 DBG(cerr <<
"d_ce: " << d_ce << endl);
178 DBG(cerr <<
"d_cgi_ver: " << d_cgi_ver << endl);
179 DBG(cerr <<
"d_response: " << d_response << endl);
180 DBG(cerr <<
"d_anc_dir: " << d_anc_dir << endl);
181 DBG(cerr <<
"d_anc_file: " << d_anc_file << endl);
182 DBG(cerr <<
"d_cache_dir: " << d_cache_dir << endl);
183 DBG(cerr <<
"d_conditional_request: " << d_conditional_request << endl);
184 DBG(cerr <<
"d_if_modified_since: " << d_if_modified_since << endl);
185 DBG(cerr <<
"d_url: " << d_url << endl);
186 DBG(cerr <<
"d_timeout: " << d_timeout << endl);
189 DODSFilter::~DODSFilter()
196 DODSFilter::initialize()
201 d_bad_options =
false;
202 d_conditional_request =
false;
209 d_response = Unknown_Response;;
212 d_if_modified_since = -1;
214 d_program_name =
"Unknown";
221 _setmode(_fileno(stdout), _O_BINARY);
237 DODSFilter::initialize(
int argc,
char *argv[])
241 d_program_name = argv[0];
244 int next_arg = process_options(argc, argv);
249 if (next_arg < argc) {
250 d_dataset = argv[next_arg];
251 d_dataset =
www2id(d_dataset,
"%",
"%20");
253 else if (get_response() != Version_Response)
266 DODSFilter::process_options(
int argc,
char *argv[])
268 DBG(cerr <<
"Entering process_options... ");
271 GetOpt getopt (argc, argv,
"ce: v: d: f: r: l: o: u: t: ");
273 while ((option_char = getopt()) != EOF) {
274 switch (option_char) {
275 case 'c': d_comp =
true;
break;
276 case 'e': set_ce(getopt.optarg);
break;
277 case 'v': set_cgi_version(getopt.optarg);
break;
278 case 'd': d_anc_dir = getopt.optarg;
break;
279 case 'f': d_anc_file = getopt.optarg;
break;
280 case 'r': d_cache_dir = getopt.optarg;
break;
281 case 'o': set_response(getopt.optarg);
break;
282 case 'u': set_URL(getopt.optarg);
break;
283 case 't': d_timeout = atoi(getopt.optarg);
break;
285 d_conditional_request =
true;
287 =
static_cast<time_t
>(strtol(getopt.optarg, NULL, 10));
289 case 'h': print_usage();
293 default: print_usage();
297 DBGN(cerr <<
"exiting." << endl);
299 return getopt.optind;
307 DODSFilter::is_conditional()
const
309 return d_conditional_request;
337 DODSFilter::get_cgi_version()
const
349 DODSFilter::get_ce()
const
355 DODSFilter::set_ce(
string _ce)
357 d_ce =
www2id(_ce,
"%",
"%20");
369 DODSFilter::get_dataset_name()
const
375 DODSFilter::set_dataset_name(
const string ds)
377 d_dataset =
www2id(ds,
"%",
"%20");
384 DODSFilter::get_URL()
const
392 DODSFilter::set_URL(
const string &url)
394 if (url.find(
'?') != url.npos)
408 DODSFilter::get_dataset_version()
const
419 void DODSFilter::set_response(
const string &r)
421 if (r ==
"DAS" || r ==
"das") {
422 d_response = DAS_Response;
425 else if (r ==
"DDS" || r ==
"dds") {
426 d_response = DDS_Response;
429 else if (r ==
"DataDDS" || r ==
"dods") {
430 d_response = DataDDS_Response;
433 else if (r ==
"DDX" || r ==
"ddx") {
434 d_response = DDX_Response;
437 else if (r ==
"DataDDX" || r ==
"dataddx") {
438 d_response = DataDDX_Response;
439 d_action =
"dataddx" ;
441 else if (r ==
"Version") {
442 d_response = Version_Response;
443 d_action =
"version" ;
451 DODSFilter::get_response()
const
457 string DODSFilter::get_action()
const
483 DODSFilter::get_dataset_last_modified_time()
const
498 DODSFilter::get_das_last_modified_time(
const string &anc_location)
const
500 DBG(cerr <<
"DODSFilter::get_das_last_modified_time(anc_location="
501 << anc_location <<
"call faf(das) d_dataset=" << d_dataset
502 <<
" d_anc_file=" << d_anc_file << endl);
505 = Ancillary::find_ancillary_file(d_dataset,
"das",
506 (anc_location ==
"") ? d_anc_dir : anc_location,
510 get_dataset_last_modified_time());
521 DODSFilter::get_dds_last_modified_time(
const string &anc_location)
const
523 DBG(cerr <<
"DODSFilter::get_das_last_modified_time(anc_location="
524 << anc_location <<
"call faf(dds) d_dataset=" << d_dataset
525 <<
" d_anc_file=" << d_anc_file << endl);
528 = Ancillary::find_ancillary_file(d_dataset,
"dds",
529 (anc_location ==
"") ? d_anc_dir : anc_location,
533 get_dataset_last_modified_time());
550 DODSFilter::get_data_last_modified_time(
const string &anc_location)
const
552 DBG(cerr <<
"DODSFilter::get_das_last_modified_time(anc_location="
553 << anc_location <<
"call faf(both) d_dataset=" << d_dataset
554 <<
" d_anc_file=" << d_anc_file << endl);
557 = Ancillary::find_ancillary_file(d_dataset,
"dds",
558 (anc_location ==
"") ? d_anc_dir : anc_location,
561 = Ancillary::find_ancillary_file(d_dataset,
"das",
562 (anc_location ==
"") ? d_anc_dir : anc_location,
568 time_t n = get_dataset_last_modified_time();
581 DODSFilter::get_request_if_modified_since()
const
583 return d_if_modified_since;
593 DODSFilter::get_cache_dir()
const
603 DODSFilter::set_timeout(
int t)
610 DODSFilter::get_timeout()
const
628 DODSFilter::establish_timeout(FILE *stream)
const
643 DODSFilter::establish_timeout(ostream &stream)
const
655 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.";
667 DODSFilter::print_usage()
const
672 throw Error(emessage);
681 DODSFilter::send_version_info()
const
699 DODSFilter::send_das(FILE *out,
DAS &das,
const string &anc_location,
700 bool with_mime_headers)
const
702 time_t das_lmt = get_das_last_modified_time(anc_location);
704 && das_lmt <= get_request_if_modified_since()
705 && with_mime_headers) {
709 if (with_mime_headers)
729 DODSFilter::send_das(ostream &out,
DAS &das,
const string &anc_location,
730 bool with_mime_headers)
const
732 time_t das_lmt = get_das_last_modified_time(anc_location);
734 && das_lmt <= get_request_if_modified_since()
735 && with_mime_headers) {
739 if (with_mime_headers)
747 DODSFilter::send_das(
DAS &das,
const string &anc_location,
748 bool with_mime_headers)
const
750 send_das(cout, das, anc_location, with_mime_headers);
773 const string &anc_location,
774 bool with_mime_headers)
const
781 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.");
783 time_t dds_lmt = get_dds_last_modified_time(anc_location);
785 && dds_lmt <= get_request_if_modified_since()
786 && with_mime_headers) {
790 if (with_mime_headers)
821 const string &anc_location,
822 bool with_mime_headers)
const
829 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.");
831 time_t dds_lmt = get_dds_last_modified_time(anc_location);
833 && dds_lmt <= get_request_if_modified_since()
834 && with_mime_headers) {
838 if (with_mime_headers)
851 bool constrained,
const string &anc_location,
852 bool with_mime_headers)
const
854 send_dds(cout, dds, eval, constrained, anc_location, with_mime_headers);
864 fprintf(out,
"Dataset {\n");
866 fprintf(out,
"} function_value;\n");
867 fprintf(out,
"Data:\n");
889 out <<
"Dataset {\n" ;
891 out <<
"} function_value;\n" ;
911 FILE * out,
bool ce_eval)
const
915 fprintf(out,
"Data:\n");
924 if ((*i)->send_p()) {
925 DBG(cerr <<
"Sending " << (*i)->name() << endl);
926 (*i)->serialize(eval, dds, m, ce_eval);
937 ostream &out,
bool ce_eval)
const
950 if ((*i)->send_p()) {
951 DBG(cerr <<
"Sending " << (*i)->name() << endl);
952 (*i)->serialize(eval, dds, m, ce_eval);
962 ostream &out,
const string &boundary,
963 const string &start,
bool ce_eval)
const
972 uuid_unparse(uu, &uuid[0]);
974 if (getdomainname(domain, 255) != 0 || strlen(domain) == 0)
975 strncpy(domain,
"opendap.org", 255);
977 string cid = string(&uuid[0]) +
"@" + string(&domain[0]);
991 if ((*i)->send_p()) {
992 DBG(cerr <<
"Sending " << (*i)->name() << endl);
993 (*i)->serialize(eval, dds, m, ce_eval);
1020 FILE * data_stream,
const string & anc_location,
1021 bool with_mime_headers)
const
1026 time_t data_lmt = get_data_last_modified_time(anc_location);
1027 if (is_conditional()
1028 && data_lmt <= get_request_if_modified_since()
1029 && with_mime_headers) {
1034 establish_timeout(data_stream);
1055 #if COMPRESSION_FOR_SERVER3
1056 if (with_mime_headers)
1059 fflush(data_stream);
1063 data_stream = compressor(data_stream, childpid);
1065 if (with_mime_headers)
1068 fflush(data_stream);
1070 functional_constraint(*var, dds, eval, data_stream);
1078 if (with_mime_headers)
1081 dataset_constraint(*fdds, eval, data_stream,
false);
1085 if (with_mime_headers)
1088 dataset_constraint(dds, eval, data_stream);
1091 fflush(data_stream);
1113 ostream & data_stream,
const string & anc_location,
1114 bool with_mime_headers)
const
1119 time_t data_lmt = get_data_last_modified_time(anc_location);
1120 if (is_conditional()
1121 && data_lmt <= get_request_if_modified_since()
1122 && with_mime_headers) {
1127 establish_timeout(data_stream);
1148 if (with_mime_headers)
1151 data_stream << flush ;
1153 functional_constraint(*var, dds, eval, data_stream);
1160 if (with_mime_headers)
1163 dataset_constraint(*fdds, eval, data_stream,
false);
1167 if (with_mime_headers)
1170 dataset_constraint(dds, eval, data_stream);
1173 data_stream << flush ;
1189 bool with_mime_headers)
const
1196 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.");
1198 time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
1203 if (is_conditional() && dds_lmt <= get_request_if_modified_since()
1204 && with_mime_headers) {
1209 if (with_mime_headers)
1228 bool with_mime_headers)
const
1235 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.");
1237 time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
1242 if (is_conditional() && dds_lmt <= get_request_if_modified_since()
1243 && with_mime_headers) {
1248 if (with_mime_headers)
1276 ostream & data_stream,
const string &start,
1277 const string &boundary,
const string & anc_location,
1278 bool with_mime_headers)
const
1283 time_t data_lmt = get_data_last_modified_time(anc_location);
1284 if (is_conditional()
1285 && data_lmt <= get_request_if_modified_since()
1286 && with_mime_headers) {
1291 establish_timeout(data_stream);
1308 if (with_mime_headers)
1310 d_cgi_ver,
x_plain, data_lmt);
1311 data_stream << flush ;
1313 DDS var_dds(&btf, var->
name());
1315 var_dds.add_var(var);
1316 dataset_constraint_ddx(var_dds, eval, data_stream, boundary, start);
1325 if (with_mime_headers)
1327 d_cgi_ver,
x_plain, data_lmt);
1328 data_stream << flush ;
1329 dataset_constraint(*fdds, eval, data_stream,
false);
1333 if (with_mime_headers)
1335 d_cgi_ver,
x_plain, data_lmt);
1336 data_stream << flush ;
1337 dataset_constraint_ddx(dds, eval, data_stream, boundary, start);
1340 data_stream << flush ;
1342 if (with_mime_headers)
1343 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)
BaseType * eval_function(DDS &dds, const string &dataset)
Evaluate a function-valued constraint expression.
Vars_iter var_begin()
Return an iterator to the first variable.
void parse_constraint(const string &constraint, DDS &dds)
Parse the constraint expression given the current DDS.
virtual bool serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval=true)=0
Move data to the net.
void print_xml(FILE *out, bool constrained, const string &blob="")
void set_mime_text(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
virtual void print(FILE *out, bool dereference=false)
#define unknown_error
Unknown error.
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)
marshaller that knows how to marshall/serialize dap data objects to a file using XDR ...
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.