00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "config.h"
00038
00039 static char rcsid[] not_used =
00040 {"$Id: DODSFilter.cc 21701 2009-11-06 00:35:54Z jimg $"
00041 };
00042
00043 #include <signal.h>
00044
00045 #ifndef WIN32
00046 #include <unistd.h>
00047 #include <sys/wait.h>
00048 #else
00049 #include <io.h>
00050 #include <fcntl.h>
00051 #include <process.h>
00052 #endif
00053
00054 #include <iostream>
00055 #include <string>
00056 #include <algorithm>
00057 #include <cstdlib>
00058 #include <cstring>
00059
00060 #include <uuid/uuid.h>
00061
00062 #include <GetOpt.h>
00063
00064 #include "DAS.h"
00065 #include "DDS.h"
00066 #include "debug.h"
00067 #include "mime_util.h"
00068 #include "Ancillary.h"
00069 #include "util.h"
00070 #include "escaping.h"
00071 #include "DODSFilter.h"
00072 #if FILE_METHODS
00073 #include "XDRFileMarshaller.h"
00074 #endif
00075 #include "XDRStreamMarshaller.h"
00076 #include "InternalErr.h"
00077
00078 #ifndef WIN32
00079 #include "SignalHandler.h"
00080 #include "EventHandler.h"
00081 #include "AlarmHandler.h"
00082 #endif
00083
00084 #define CRLF "\r\n" // Change here, expr-test.cc and DODSFilter.cc
00085
00086
00087
00088 using namespace std;
00089
00090 namespace libdap {
00091
00092 const string usage =
00093 "Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\
00094 \n\
00095 options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\
00096 -u <url>: The complete URL minus the CE (required for DDX)\n\
00097 -c: Compress the response using the deflate algorithm.\n\
00098 -e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\
00099 -v <version>: Use <version> as the version number\n\
00100 -d <dir>: Look for ancillary file in <dir> (deprecated).\n\
00101 -f <file>: Look for ancillary data in <file> (deprecated).\n\
00102 -r <dir>: Use <dir> as a cache directory\n\
00103 -l <time>: Conditional request; if data source is unchanged since\n\
00104 <time>, return an HTTP 304 response.\n\
00105 -t <seconds>: Timeout the handler after <seconds>.\n\
00106 -h: This message.";
00107
00172 DODSFilter::DODSFilter(int argc, char *argv[]) throw(Error)
00173 {
00174 initialize(argc, argv);
00175
00176 DBG(cerr << "d_comp: " << d_comp << endl);
00177 DBG(cerr << "d_ce: " << d_ce << endl);
00178 DBG(cerr << "d_cgi_ver: " << d_cgi_ver << endl);
00179 DBG(cerr << "d_response: " << d_response << endl);
00180 DBG(cerr << "d_anc_dir: " << d_anc_dir << endl);
00181 DBG(cerr << "d_anc_file: " << d_anc_file << endl);
00182 DBG(cerr << "d_cache_dir: " << d_cache_dir << endl);
00183 DBG(cerr << "d_conditional_request: " << d_conditional_request << endl);
00184 DBG(cerr << "d_if_modified_since: " << d_if_modified_since << endl);
00185 DBG(cerr << "d_url: " << d_url << endl);
00186 DBG(cerr << "d_timeout: " << d_timeout << endl);
00187 }
00188
00189 DODSFilter::~DODSFilter()
00190 {
00191 }
00192
00195 void
00196 DODSFilter::initialize()
00197 {
00198
00199
00200 d_comp = false;
00201 d_bad_options = false;
00202 d_conditional_request = false;
00203 d_dataset = "";
00204 d_ce = "";
00205 d_cgi_ver = "";
00206 d_anc_dir = "";
00207 d_anc_file = "";
00208 d_cache_dir = "";
00209 d_response = Unknown_Response;;
00210 d_anc_das_lmt = 0;
00211 d_anc_dds_lmt = 0;
00212 d_if_modified_since = -1;
00213 d_url = "";
00214 d_program_name = "Unknown";
00215 d_timeout = 0;
00216
00217 #ifdef WIN32
00218
00219
00220
00221 _setmode(_fileno(stdout), _O_BINARY);
00222 #endif
00223 }
00224
00236 void
00237 DODSFilter::initialize(int argc, char *argv[])
00238 {
00239 initialize();
00240
00241 d_program_name = argv[0];
00242
00243
00244 int next_arg = process_options(argc, argv);
00245
00246
00247
00248
00249 if (next_arg < argc) {
00250 d_dataset = argv[next_arg];
00251 d_dataset = www2id(d_dataset, "%", "%20");
00252 }
00253 else if (get_response() != Version_Response)
00254 print_usage();
00255 }
00256
00265 int
00266 DODSFilter::process_options(int argc, char *argv[])
00267 {
00268 DBG(cerr << "Entering process_options... ");
00269
00270 int option_char;
00271 GetOpt getopt (argc, argv, "ce: v: d: f: r: l: o: u: t: ");
00272
00273 while ((option_char = getopt()) != EOF) {
00274 switch (option_char) {
00275 case 'c': d_comp = true; break;
00276 case 'e': set_ce(getopt.optarg); break;
00277 case 'v': set_cgi_version(getopt.optarg); break;
00278 case 'd': d_anc_dir = getopt.optarg; break;
00279 case 'f': d_anc_file = getopt.optarg; break;
00280 case 'r': d_cache_dir = getopt.optarg; break;
00281 case 'o': set_response(getopt.optarg); break;
00282 case 'u': set_URL(getopt.optarg); break;
00283 case 't': d_timeout = atoi(getopt.optarg); break;
00284 case 'l':
00285 d_conditional_request = true;
00286 d_if_modified_since
00287 = static_cast<time_t>(strtol(getopt.optarg, NULL, 10));
00288 break;
00289 case 'h': print_usage(); exit(1);
00290 default: print_usage();
00291 }
00292 }
00293
00294 DBGN(cerr << "exiting." << endl);
00295
00296 return getopt.optind;
00297 }
00298
00303 bool
00304 DODSFilter::is_conditional() const
00305 {
00306 return d_conditional_request;
00307 }
00308
00322 void
00323 DODSFilter::set_cgi_version(string version)
00324 {
00325 d_cgi_ver = version;
00326 }
00327
00333 string
00334 DODSFilter::get_cgi_version() const
00335 {
00336 return d_cgi_ver;
00337 }
00338
00345 string
00346 DODSFilter::get_ce() const
00347 {
00348 return d_ce;
00349 }
00350
00351 void
00352 DODSFilter::set_ce(string _ce)
00353 {
00354 d_ce = www2id(_ce, "%", "%20");
00355 }
00356
00365 string
00366 DODSFilter::get_dataset_name() const
00367 {
00368 return d_dataset;
00369 }
00370
00371 void
00372 DODSFilter::set_dataset_name(const string ds)
00373 {
00374 d_dataset = www2id(ds, "%", "%20");
00375 }
00376
00380 string
00381 DODSFilter::get_URL() const
00382 {
00383 return d_url;
00384 }
00385
00388 void
00389 DODSFilter::set_URL(const string &url)
00390 {
00391 if (url.find('?') != url.npos)
00392 print_usage();
00393
00394 d_url = url;
00395 }
00396
00404 string
00405 DODSFilter::get_dataset_version() const
00406 {
00407 return "";
00408 }
00409
00416 void DODSFilter::set_response(const string &r)
00417 {
00418 if (r == "DAS" || r == "das") {
00419 d_response = DAS_Response;
00420 d_action = "das" ;
00421 }
00422 else if (r == "DDS" || r == "dds") {
00423 d_response = DDS_Response;
00424 d_action = "dds" ;
00425 }
00426 else if (r == "DataDDS" || r == "dods") {
00427 d_response = DataDDS_Response;
00428 d_action = "dods" ;
00429 }
00430 else if (r == "DDX" || r == "ddx") {
00431 d_response = DDX_Response;
00432 d_action = "ddx" ;
00433 }
00434 else if (r == "DataDDX" || r == "dataddx") {
00435 d_response = DataDDX_Response;
00436 d_action = "dataddx" ;
00437 }
00438 else if (r == "Version") {
00439 d_response = Version_Response;
00440 d_action = "version" ;
00441 }
00442 else
00443 print_usage();
00444 }
00445
00447 DODSFilter::Response
00448 DODSFilter::get_response() const
00449 {
00450 return d_response;
00451 }
00452
00454 string DODSFilter::get_action() const
00455 {
00456 return d_action;
00457 }
00458
00479 time_t
00480 DODSFilter::get_dataset_last_modified_time() const
00481 {
00482 return last_modified_time(d_dataset);
00483 }
00484
00494 time_t
00495 DODSFilter::get_das_last_modified_time(const string &anc_location) const
00496 {
00497 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00498 << anc_location << "call faf(das) d_dataset=" << d_dataset
00499 << " d_anc_file=" << d_anc_file << endl);
00500
00501 string name
00502 = Ancillary::find_ancillary_file(d_dataset, "das",
00503 (anc_location == "") ? d_anc_dir : anc_location,
00504 d_anc_file);
00505
00506 return max((name != "") ? last_modified_time(name) : 0,
00507 get_dataset_last_modified_time());
00508 }
00509
00517 time_t
00518 DODSFilter::get_dds_last_modified_time(const string &anc_location) const
00519 {
00520 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00521 << anc_location << "call faf(dds) d_dataset=" << d_dataset
00522 << " d_anc_file=" << d_anc_file << endl);
00523
00524 string name
00525 = Ancillary::find_ancillary_file(d_dataset, "dds",
00526 (anc_location == "") ? d_anc_dir : anc_location,
00527 d_anc_file);
00528
00529 return max((name != "") ? last_modified_time(name) : 0,
00530 get_dataset_last_modified_time());
00531 }
00532
00546 time_t
00547 DODSFilter::get_data_last_modified_time(const string &anc_location) const
00548 {
00549 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00550 << anc_location << "call faf(both) d_dataset=" << d_dataset
00551 << " d_anc_file=" << d_anc_file << endl);
00552
00553 string dds_name
00554 = Ancillary::find_ancillary_file(d_dataset, "dds",
00555 (anc_location == "") ? d_anc_dir : anc_location,
00556 d_anc_file);
00557 string das_name
00558 = Ancillary::find_ancillary_file(d_dataset, "das",
00559 (anc_location == "") ? d_anc_dir : anc_location,
00560 d_anc_file);
00561
00562 time_t m = max((das_name != "") ? last_modified_time(das_name) : (time_t)0,
00563 (dds_name != "") ? last_modified_time(dds_name) : (time_t)0);
00564
00565 time_t n = get_dataset_last_modified_time();
00566
00567 return max(m, n);
00568 }
00569
00577 time_t
00578 DODSFilter::get_request_if_modified_since() const
00579 {
00580 return d_if_modified_since;
00581 }
00582
00589 string
00590 DODSFilter::get_cache_dir() const
00591 {
00592 return d_cache_dir;
00593 }
00594
00599 void
00600 DODSFilter::set_timeout(int t)
00601 {
00602 d_timeout = t;
00603 }
00604
00606 int
00607 DODSFilter::get_timeout() const
00608 {
00609 return d_timeout;
00610 }
00611
00612 #if FILE_METHODS
00613
00624 void
00625 DODSFilter::establish_timeout(FILE *stream) const
00626 {
00627 #ifndef WIN32
00628 if (d_timeout > 0) {
00629 SignalHandler *sh = SignalHandler::instance();
00630 EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream));
00631 delete old_eh;
00632 alarm(d_timeout);
00633 }
00634 #endif
00635 }
00636 #endif
00637
00638
00639 void
00640 DODSFilter::establish_timeout(ostream &stream) const
00641 {
00642 #ifndef WIN32
00643 if (d_timeout > 0) {
00644 SignalHandler *sh = SignalHandler::instance();
00645 EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream));
00646 delete old_eh;
00647 alarm(d_timeout);
00648 }
00649 #endif
00650 }
00651
00652 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.";
00653
00663 void
00664 DODSFilter::print_usage() const
00665 {
00666
00667 ErrMsgT(usage.c_str());
00668
00669 throw Error(unknown_error, emessage);
00670 }
00671
00677 void
00678 DODSFilter::send_version_info() const
00679 {
00680 do_version(d_cgi_ver, get_dataset_version());
00681 }
00682
00683 #if FILE_METHODS
00684
00695 void
00696 DODSFilter::send_das(FILE *out, DAS &das, const string &anc_location,
00697 bool with_mime_headers) const
00698 {
00699 time_t das_lmt = get_das_last_modified_time(anc_location);
00700 if (is_conditional()
00701 && das_lmt <= get_request_if_modified_since()
00702 && with_mime_headers) {
00703 set_mime_not_modified(out);
00704 }
00705 else {
00706 if (with_mime_headers)
00707 set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
00708 das.print(out);
00709 }
00710 fflush(out) ;
00711 }
00712 #endif
00713
00725 void
00726 DODSFilter::send_das(ostream &out, DAS &das, const string &anc_location,
00727 bool with_mime_headers) const
00728 {
00729 time_t das_lmt = get_das_last_modified_time(anc_location);
00730 if (is_conditional()
00731 && das_lmt <= get_request_if_modified_since()
00732 && with_mime_headers) {
00733 set_mime_not_modified(out);
00734 }
00735 else {
00736 if (with_mime_headers)
00737 set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
00738 das.print(out);
00739 }
00740 out << flush ;
00741 }
00742
00743 void
00744 DODSFilter::send_das(DAS &das, const string &anc_location,
00745 bool with_mime_headers) const
00746 {
00747 send_das(cout, das, anc_location, with_mime_headers);
00748 }
00749
00750 #if FILE_METHODS
00751
00767 void
00768 DODSFilter::send_dds(FILE *out, DDS &dds, ConstraintEvaluator &eval,
00769 bool constrained,
00770 const string &anc_location,
00771 bool with_mime_headers) const
00772 {
00773
00774 if (constrained)
00775 eval.parse_constraint(d_ce, dds);
00776
00777 if (eval.functional_expression())
00778 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.");
00779
00780 time_t dds_lmt = get_dds_last_modified_time(anc_location);
00781 if (is_conditional()
00782 && dds_lmt <= get_request_if_modified_since()
00783 && with_mime_headers) {
00784 set_mime_not_modified(out);
00785 }
00786 else {
00787 if (with_mime_headers)
00788 set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt);
00789 if (constrained)
00790 dds.print_constrained(out);
00791 else
00792 dds.print(out);
00793 }
00794
00795 fflush(out) ;
00796 }
00797 #endif
00798
00815 void
00816 DODSFilter::send_dds(ostream &out, DDS &dds, ConstraintEvaluator &eval,
00817 bool constrained,
00818 const string &anc_location,
00819 bool with_mime_headers) const
00820 {
00821
00822 if (constrained)
00823 eval.parse_constraint(d_ce, dds);
00824
00825 if (eval.functional_expression())
00826 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.");
00827
00828 time_t dds_lmt = get_dds_last_modified_time(anc_location);
00829 if (is_conditional()
00830 && dds_lmt <= get_request_if_modified_since()
00831 && with_mime_headers) {
00832 set_mime_not_modified(out);
00833 }
00834 else {
00835 if (with_mime_headers)
00836 set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt);
00837 if (constrained)
00838 dds.print_constrained(out);
00839 else
00840 dds.print(out);
00841 }
00842
00843 out << flush ;
00844 }
00845
00846 void
00847 DODSFilter::send_dds(DDS &dds, ConstraintEvaluator &eval,
00848 bool constrained, const string &anc_location,
00849 bool with_mime_headers) const
00850 {
00851 send_dds(cout, dds, eval, constrained, anc_location, with_mime_headers);
00852 }
00853
00854 #if FILE_METHODS
00855
00856
00857 void
00858 DODSFilter::functional_constraint(BaseType &var, DDS &dds,
00859 ConstraintEvaluator &eval, FILE *out) const
00860 {
00861 fprintf(out, "Dataset {\n");
00862 var.print_decl(out, " ", true, false, true);
00863 fprintf(out, "} function_value;\n");
00864 fprintf(out, "Data:\n");
00865
00866 fflush(out);
00867
00868 XDRFileMarshaller m( out ) ;
00869
00870 try {
00871
00872 var.serialize(eval, dds, m, false);
00873 }
00874 catch (Error &e) {
00875 throw;
00876 }
00877 }
00878 #endif
00879
00880
00881
00882 void
00883 DODSFilter::functional_constraint(BaseType &var, DDS &dds,
00884 ConstraintEvaluator &eval, ostream &out) const
00885 {
00886 out << "Dataset {\n" ;
00887 var.print_decl(out, " ", true, false, true);
00888 out << "} function_value;\n" ;
00889 out << "Data:\n" ;
00890
00891 out << flush ;
00892
00893
00894 XDRStreamMarshaller m( out ) ;
00895
00896 try {
00897
00898 var.serialize(eval, dds, m, false);
00899 }
00900 catch (Error &e) {
00901 throw;
00902 }
00903 }
00904
00905 #if FILE_METHODS
00906 void
00907 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
00908 FILE * out) const
00909 {
00910
00911 dds.print_constrained(out);
00912 fprintf(out, "Data:\n");
00913 fflush(out);
00914
00915
00916 XDRFileMarshaller m( out ) ;
00917
00918 try {
00919
00920 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
00921 if ((*i)->send_p()) {
00922 DBG(cerr << "Sending " << (*i)->name() << endl);
00923 (*i)->serialize(eval, dds, m, true);
00924 }
00925 }
00926 catch (Error & e) {
00927 throw;
00928 }
00929 }
00930 #endif
00931
00932 void
00933 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
00934 ostream &out) const
00935 {
00936
00937 dds.print_constrained(out);
00938 out << "Data:\n" ;
00939 out << flush ;
00940
00941
00942 XDRStreamMarshaller m( out ) ;
00943
00944 try {
00945
00946 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
00947 if ((*i)->send_p()) {
00948 DBG(cerr << "Sending " << (*i)->name() << endl);
00949 (*i)->serialize(eval, dds, m, true);
00950 }
00951 }
00952 catch (Error & e) {
00953 throw;
00954 }
00955 }
00956
00957 void
00958 DODSFilter::dataset_constraint_ddx(DDS & dds, ConstraintEvaluator & eval,
00959 ostream &out, const string &boundary,
00960 const string &start) const
00961 {
00962
00963 set_mime_ddx_boundary(out, boundary, start, dap4_ddx);
00964
00965
00966 uuid_t uu;
00967 uuid_generate(uu);
00968 char uuid[37];
00969 uuid_unparse(uu, &uuid[0]);
00970 char domain[256];
00971 if (getdomainname(domain, 255) != 0 || strlen(domain) == 0)
00972 strncpy(domain, "opendap.org", 255);
00973
00974 string cid = string(&uuid[0]) + "@" + string(&domain[0]);
00975
00976
00977 dds.print_xml(out, true, cid);
00978
00979
00980 set_mime_data_boundary(out, boundary, cid, dap4_data, binary);
00981
00982
00983 XDRStreamMarshaller m( out ) ;
00984
00985 try {
00986
00987 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
00988 if ((*i)->send_p()) {
00989 DBG(cerr << "Sending " << (*i)->name() << endl);
00990 (*i)->serialize(eval, dds, m, true);
00991 }
00992 }
00993 catch (Error & e) {
00994 throw;
00995 }
00996 }
00997
00998 #if FILE_METHODS
00999
01015 void
01016 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
01017 FILE * data_stream, const string & anc_location,
01018 bool with_mime_headers) const
01019 {
01020
01021
01022
01023 time_t data_lmt = get_data_last_modified_time(anc_location);
01024 if (is_conditional()
01025 && data_lmt <= get_request_if_modified_since()
01026 && with_mime_headers) {
01027 set_mime_not_modified(data_stream);
01028 return;
01029 }
01030
01031 establish_timeout(data_stream);
01032 dds.set_timeout(d_timeout);
01033
01034 eval.parse_constraint(d_ce, dds);
01035
01036
01037 dds.tag_nested_sequences();
01038
01039
01040 #if COMPRESSION_FOR_SERVER3
01041 bool compress = d_comp && deflate_exists();
01042 #endif
01043
01044
01045 if (eval.functional_expression()) {
01046
01047
01048
01049
01050 BaseType *var = eval.eval_function(dds, d_dataset);
01051 if (!var)
01052 throw Error(unknown_error, "Error calling the CE function.");
01053
01054 #if COMPRESSION_FOR_SERVER3
01055 if (with_mime_headers)
01056 set_mime_binary(data_stream, dods_data, d_cgi_ver,
01057 (compress) ? deflate : x_plain, data_lmt);
01058 fflush(data_stream);
01059
01060 int childpid;
01061 if (compress)
01062 data_stream = compressor(data_stream, childpid);
01063 #endif
01064 if (with_mime_headers)
01065 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01066
01067 fflush(data_stream);
01068
01069 functional_constraint(*var, dds, eval, data_stream);
01070 delete var;
01071 var = 0;
01072 }
01073 else {
01074 #if COMPRESSION_FOR_SERVER3
01075 if (with_mime_headers)
01076 set_mime_binary(data_stream, dods_data, d_cgi_ver,
01077 (compress) ? deflate : x_plain, data_lmt);
01078 fflush(data_stream);
01079
01080 int childpid;
01081 if (compress)
01082 data_stream = compressor(data_stream, childpid);
01083 #endif
01084 if (with_mime_headers)
01085 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01086
01087 dataset_constraint(dds, eval, data_stream);
01088 }
01089
01090 fflush(data_stream);
01091 }
01092 #endif
01093
01110 void
01111 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
01112 ostream & data_stream, const string & anc_location,
01113 bool with_mime_headers) const
01114 {
01115
01116
01117
01118 time_t data_lmt = get_data_last_modified_time(anc_location);
01119 if (is_conditional()
01120 && data_lmt <= get_request_if_modified_since()
01121 && with_mime_headers) {
01122 set_mime_not_modified(data_stream);
01123 return;
01124 }
01125
01126 establish_timeout(data_stream);
01127 dds.set_timeout(d_timeout);
01128
01129 eval.parse_constraint(d_ce, dds);
01130
01131
01132 dds.tag_nested_sequences();
01133
01134
01135
01136
01137 if (eval.functional_expression()) {
01138
01139
01140
01141
01142 BaseType *var = eval.eval_function(dds, d_dataset);
01143 if (!var)
01144 throw Error(unknown_error, "Error calling the CE function.");
01145
01146 if (with_mime_headers)
01147 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01148
01149 data_stream << flush ;
01150
01151 functional_constraint(*var, dds, eval, data_stream);
01152 delete var;
01153 var = 0;
01154 }
01155 else {
01156 if (with_mime_headers)
01157 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01158
01159 dataset_constraint(dds, eval, data_stream);
01160 }
01161
01162 data_stream << flush ;
01163 }
01164
01165 #if FILE_METHODS
01166
01176 void
01177 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out,
01178 bool with_mime_headers) const
01179 {
01180
01181 if (!d_ce.empty())
01182 eval.parse_constraint(d_ce, dds);
01183
01184 if (eval.functional_expression())
01185 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.");
01186
01187 time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
01188
01189
01190
01191
01192 if (is_conditional() && dds_lmt <= get_request_if_modified_since()
01193 && with_mime_headers) {
01194 set_mime_not_modified(out);
01195 return;
01196 }
01197 else {
01198 if (with_mime_headers)
01199 set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
01200 dds.print_xml(out, !d_ce.empty(), "");
01201 }
01202 }
01203 #endif
01204
01215 void
01216 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, ostream &out,
01217 bool with_mime_headers) const
01218 {
01219
01220 if (!d_ce.empty())
01221 eval.parse_constraint(d_ce, dds);
01222
01223 if (eval.functional_expression())
01224 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.");
01225
01226 time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
01227
01228
01229
01230
01231 if (is_conditional() && dds_lmt <= get_request_if_modified_since()
01232 && with_mime_headers) {
01233 set_mime_not_modified(out);
01234 return;
01235 }
01236 else {
01237 if (with_mime_headers)
01238 set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
01239 dds.print_xml(out, !d_ce.empty(), "");
01240 }
01241 }
01242
01259 void
01260 DODSFilter::send_data_ddx(DDS & dds, ConstraintEvaluator & eval,
01261 ostream & data_stream, const string &start,
01262 const string &boundary, const string & anc_location,
01263 bool with_mime_headers) const
01264 {
01265
01266
01267
01268 time_t data_lmt = get_data_last_modified_time(anc_location);
01269 if (is_conditional()
01270 && data_lmt <= get_request_if_modified_since()
01271 && with_mime_headers) {
01272 set_mime_not_modified(data_stream);
01273 return;
01274 }
01275
01276 establish_timeout(data_stream);
01277 dds.set_timeout(d_timeout);
01278
01279 eval.parse_constraint(d_ce, dds);
01280
01281
01282 dds.tag_nested_sequences();
01283
01284
01285
01286
01287 if (eval.functional_expression()) {
01288 BaseType *var = eval.eval_function(dds, d_dataset);
01289 if (!var)
01290 throw Error(unknown_error, "Error calling the CE function.");
01291
01292 if (with_mime_headers)
01293 set_mime_multipart(data_stream, boundary, start, dap4_data_ddx,
01294 d_cgi_ver, x_plain, data_lmt);
01295 data_stream << flush ;
01296 BaseTypeFactory btf;
01297 DDS var_dds(&btf, var->name());
01298 var->set_send_p(true);
01299 var_dds.add_var(var);
01300 dataset_constraint_ddx(var_dds, eval, data_stream, boundary, start);
01301
01302
01303 delete var;
01304 var = 0;
01305 }
01306 else {
01307 if (with_mime_headers)
01308 set_mime_multipart(data_stream, boundary, start, dap4_data_ddx,
01309 d_cgi_ver, x_plain, data_lmt);
01310 data_stream << flush ;
01311 dataset_constraint_ddx(dds, eval, data_stream, boundary, start);
01312 }
01313
01314 data_stream << flush ;
01315
01316 if (with_mime_headers)
01317 data_stream << CRLF << "--" << boundary << "--" << CRLF;
01318 }
01319
01320 }
01321