libdap
Updated for version 3.17.0
|
00001 00002 // -*- mode: c++; c-basic-offset:4 -*- 00003 00004 // This file is part of libdap, A C++ implementation of the OPeNDAP Data 00005 // Access Protocol. 00006 00007 // Copyright (c) 2002,2003 OPeNDAP, Inc. 00008 // Author: James Gallagher <jgallagher@opendap.org> 00009 // 00010 // This library is free software; you can redistribute it and/or 00011 // modify it under the terms of the GNU Lesser General Public 00012 // License as published by the Free Software Foundation; either 00013 // version 2.1 of the License, or (at your option) any later version. 00014 // 00015 // This library is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 // Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public 00021 // License along with this library; if not, write to the Free Software 00022 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00023 // 00024 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112. 00025 00026 // (c) COPYRIGHT URI/MIT 1997-1999 00027 // Please read the full copyright statement in the file COPYRIGHT_URI. 00028 // 00029 // Authors: 00030 // jhrg,jimg James Gallagher <jgallagher@gso.uri.edu> 00031 00032 // Implementation of the DODSFilter class. This class is used to build dods 00033 // filter programs which, along with a CGI program, comprise OPeNDAP servers. 00034 // jhrg 8/26/97 00035 00036 00037 #include "config.h" 00038 00039 #include <signal.h> 00040 00041 #ifndef WIN32 00042 #include <unistd.h> // for getopt 00043 #include <sys/wait.h> 00044 #else 00045 #include <io.h> 00046 #include <fcntl.h> 00047 #include <process.h> 00048 #endif 00049 00050 #include <iostream> 00051 #include <sstream> 00052 #include <string> 00053 #include <algorithm> 00054 #include <cstdlib> 00055 #include <cstring> 00056 00057 #ifdef HAVE_UUID_UUID_H 00058 #include <uuid/uuid.h> // used to build CID header value for data ddx 00059 #elif defined(HAVE_UUID_H) 00060 #include <uuid.h> 00061 #else 00062 #error "Could not find UUID library header" 00063 #endif 00064 00065 #include <GetOpt.h> 00066 00067 #include "DAS.h" 00068 #include "DDS.h" 00069 #include "debug.h" 00070 #include "mime_util.h" 00071 #include "Ancillary.h" 00072 #include "util.h" 00073 #include "escaping.h" 00074 #include "DODSFilter.h" 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 using namespace std; 00087 00088 namespace libdap { 00089 00090 const string usage = 00091 "Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\ 00092 \n\ 00093 options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\ 00094 -u <url>: The complete URL minus the CE (required for DDX)\n\ 00095 -c: Compress the response using the deflate algorithm.\n\ 00096 -e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\ 00097 -v <version>: Use <version> as the version number\n\ 00098 -d <dir>: Look for ancillary file in <dir> (deprecated).\n\ 00099 -f <file>: Look for ancillary data in <file> (deprecated).\n\ 00100 -r <dir>: Use <dir> as a cache directory\n\ 00101 -l <time>: Conditional request; if data source is unchanged since\n\ 00102 <time>, return an HTTP 304 response.\n\ 00103 -t <seconds>: Timeout the handler after <seconds>.\n\ 00104 -h: This message."; 00105 00170 DODSFilter::DODSFilter(int argc, char *argv[]) throw(Error) 00171 { 00172 initialize(argc, argv); 00173 00174 DBG(cerr << "d_comp: " << d_comp << endl); 00175 DBG(cerr << "d_dap2ce: " << d_dap2ce << endl); 00176 DBG(cerr << "d_cgi_ver: " << d_cgi_ver << endl); 00177 DBG(cerr << "d_response: " << d_response << endl); 00178 DBG(cerr << "d_anc_dir: " << d_anc_dir << endl); 00179 DBG(cerr << "d_anc_file: " << d_anc_file << endl); 00180 DBG(cerr << "d_cache_dir: " << d_cache_dir << endl); 00181 DBG(cerr << "d_conditional_request: " << d_conditional_request << endl); 00182 DBG(cerr << "d_if_modified_since: " << d_if_modified_since << endl); 00183 DBG(cerr << "d_url: " << d_url << endl); 00184 DBG(cerr << "d_timeout: " << d_timeout << endl); 00185 } 00186 00187 DODSFilter::~DODSFilter() 00188 { 00189 } 00190 00193 void 00194 DODSFilter::initialize() 00195 { 00196 // Set default values. Don't use the C++ constructor initialization so 00197 // that a subclass can have more control over this process. 00198 d_comp = false; 00199 d_bad_options = false; 00200 d_conditional_request = false; 00201 d_dataset = ""; 00202 d_dap2ce = ""; 00203 d_cgi_ver = ""; 00204 d_anc_dir = ""; 00205 d_anc_file = ""; 00206 d_cache_dir = ""; 00207 d_response = Unknown_Response;; 00208 d_anc_das_lmt = 0; 00209 d_anc_dds_lmt = 0; 00210 d_if_modified_since = -1; 00211 d_url = ""; 00212 d_program_name = "Unknown"; 00213 d_timeout = 0; 00214 00215 #ifdef WIN32 00216 // We want serving from win32 to behave in a manner 00217 // similar to the UNIX way - no CR->NL terminated lines 00218 // in files. Hence stdout goes to binary mode. 00219 _setmode(_fileno(stdout), _O_BINARY); 00220 #endif 00221 } 00222 00234 void 00235 DODSFilter::initialize(int argc, char *argv[]) 00236 { 00237 initialize(); 00238 00239 d_program_name = argv[0]; 00240 00241 // This should be specialized by a subclass. This may throw Error. 00242 int next_arg = process_options(argc, argv); 00243 00244 // Look at what's left after processing the command line options. Either 00245 // there MUST be a dataset name OR the caller is asking for version 00246 // information. If neither is true, then the options are bad. 00247 if (next_arg < argc) { 00248 d_dataset = argv[next_arg]; 00249 d_dataset = www2id(d_dataset, "%", "%20"); 00250 } 00251 else if (get_response() != Version_Response) 00252 print_usage(); // Throws Error 00253 } 00254 00263 int 00264 DODSFilter::process_options(int argc, char *argv[]) 00265 { 00266 DBG(cerr << "Entering process_options... "); 00267 00268 int option_char; 00269 GetOpt getopt (argc, argv, "ce: v: d: f: r: l: o: u: t: "); 00270 00271 while ((option_char = getopt()) != -1) { 00272 switch (option_char) { 00273 case 'c': d_comp = true; break; 00274 case 'e': set_ce(getopt.optarg); break; 00275 case 'v': set_cgi_version(getopt.optarg); break; 00276 case 'd': d_anc_dir = getopt.optarg; break; 00277 case 'f': d_anc_file = getopt.optarg; break; 00278 case 'r': d_cache_dir = getopt.optarg; break; 00279 case 'o': set_response(getopt.optarg); break; 00280 case 'u': set_URL(getopt.optarg); break; 00281 case 't': d_timeout = atoi(getopt.optarg); break; 00282 case 'l': 00283 d_conditional_request = true; 00284 d_if_modified_since 00285 = static_cast<time_t>(strtol(getopt.optarg, NULL, 10)); 00286 break; 00287 case 'h': print_usage(); 00288 break; 00289 // exit(1); 00290 // Removed 12/29/2011; exit should 00291 // not be called by a library. NB: 00292 // print_usage() throws Error. 00293 default: print_usage(); // Throws Error 00294 break; 00295 } 00296 } 00297 00298 DBGN(cerr << "exiting." << endl); 00299 00300 return getopt.optind; // return the index of the next argument 00301 } 00302 00307 bool 00308 DODSFilter::is_conditional() const 00309 { 00310 return d_conditional_request; 00311 } 00312 00326 void 00327 DODSFilter::set_cgi_version(string version) 00328 { 00329 d_cgi_ver = version; 00330 } 00331 00337 string 00338 DODSFilter::get_cgi_version() const 00339 { 00340 return d_cgi_ver; 00341 } 00342 00349 string 00350 DODSFilter::get_ce() const 00351 { 00352 return d_dap2ce; 00353 } 00354 00355 void 00356 DODSFilter::set_ce(string _ce) 00357 { 00358 d_dap2ce = www2id(_ce, "%", "%20"); 00359 } 00360 00369 string 00370 DODSFilter::get_dataset_name() const 00371 { 00372 return d_dataset; 00373 } 00374 00375 void 00376 DODSFilter::set_dataset_name(const string ds) 00377 { 00378 d_dataset = www2id(ds, "%", "%20"); 00379 } 00380 00384 string 00385 DODSFilter::get_URL() const 00386 { 00387 return d_url; 00388 } 00389 00392 void 00393 DODSFilter::set_URL(const string &url) 00394 { 00395 if (url.find('?') != url.npos) 00396 print_usage(); // Throws Error 00397 00398 d_url = url; 00399 } 00400 00408 string 00409 DODSFilter::get_dataset_version() const 00410 { 00411 return ""; 00412 } 00413 00420 void DODSFilter::set_response(const string &r) 00421 { 00422 if (r == "DAS" || r == "das") { 00423 d_response = DAS_Response; 00424 d_action = "das" ; 00425 } 00426 else if (r == "DDS" || r == "dds") { 00427 d_response = DDS_Response; 00428 d_action = "dds" ; 00429 } 00430 else if (r == "DataDDS" || r == "dods") { 00431 d_response = DataDDS_Response; 00432 d_action = "dods" ; 00433 } 00434 else if (r == "DDX" || r == "ddx") { 00435 d_response = DDX_Response; 00436 d_action = "ddx" ; 00437 } 00438 else if (r == "DataDDX" || r == "dataddx") { 00439 d_response = DataDDX_Response; 00440 d_action = "dataddx" ; 00441 } 00442 else if (r == "Version") { 00443 d_response = Version_Response; 00444 d_action = "version" ; 00445 } 00446 else 00447 print_usage(); // Throws Error 00448 } 00449 00451 DODSFilter::Response 00452 DODSFilter::get_response() const 00453 { 00454 return d_response; 00455 } 00456 00458 string DODSFilter::get_action() const 00459 { 00460 return d_action; 00461 } 00462 00483 time_t 00484 DODSFilter::get_dataset_last_modified_time() const 00485 { 00486 return last_modified_time(d_dataset); 00487 } 00488 00498 time_t 00499 DODSFilter::get_das_last_modified_time(const string &anc_location) const 00500 { 00501 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location=" 00502 << anc_location << "call faf(das) d_dataset=" << d_dataset 00503 << " d_anc_file=" << d_anc_file << endl); 00504 00505 string name 00506 = Ancillary::find_ancillary_file(d_dataset, "das", 00507 (anc_location == "") ? d_anc_dir : anc_location, 00508 d_anc_file); 00509 00510 return max((name != "") ? last_modified_time(name) : 0, 00511 get_dataset_last_modified_time()); 00512 } 00513 00521 time_t 00522 DODSFilter::get_dds_last_modified_time(const string &anc_location) const 00523 { 00524 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location=" 00525 << anc_location << "call faf(dds) d_dataset=" << d_dataset 00526 << " d_anc_file=" << d_anc_file << endl); 00527 00528 string name 00529 = Ancillary::find_ancillary_file(d_dataset, "dds", 00530 (anc_location == "") ? d_anc_dir : anc_location, 00531 d_anc_file); 00532 00533 return max((name != "") ? last_modified_time(name) : 0, 00534 get_dataset_last_modified_time()); 00535 } 00536 00550 time_t 00551 DODSFilter::get_data_last_modified_time(const string &anc_location) const 00552 { 00553 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location=" 00554 << anc_location << "call faf(both) d_dataset=" << d_dataset 00555 << " d_anc_file=" << d_anc_file << endl); 00556 00557 string dds_name 00558 = Ancillary::find_ancillary_file(d_dataset, "dds", 00559 (anc_location == "") ? d_anc_dir : anc_location, 00560 d_anc_file); 00561 string das_name 00562 = Ancillary::find_ancillary_file(d_dataset, "das", 00563 (anc_location == "") ? d_anc_dir : anc_location, 00564 d_anc_file); 00565 00566 time_t m = max((das_name != "") ? last_modified_time(das_name) : (time_t)0, 00567 (dds_name != "") ? last_modified_time(dds_name) : (time_t)0); 00568 // Note that this is a call to get_dataset_... not get_data_... 00569 time_t n = get_dataset_last_modified_time(); 00570 00571 return max(m, n); 00572 } 00573 00581 time_t 00582 DODSFilter::get_request_if_modified_since() const 00583 { 00584 return d_if_modified_since; 00585 } 00586 00593 string 00594 DODSFilter::get_cache_dir() const 00595 { 00596 return d_cache_dir; 00597 } 00598 00603 void 00604 DODSFilter::set_timeout(int t) 00605 { 00606 d_timeout = t; 00607 } 00608 00610 int 00611 DODSFilter::get_timeout() const 00612 { 00613 return d_timeout; 00614 } 00615 00627 void 00628 DODSFilter::establish_timeout(FILE *stream) const 00629 { 00630 #ifndef WIN32 00631 if (d_timeout > 0) { 00632 SignalHandler *sh = SignalHandler::instance(); 00633 EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream)); 00634 delete old_eh; 00635 alarm(d_timeout); 00636 } 00637 #endif 00638 } 00639 00640 void 00641 DODSFilter::establish_timeout(ostream &stream) const 00642 { 00643 #ifndef WIN32 00644 if (d_timeout > 0) { 00645 SignalHandler *sh = SignalHandler::instance(); 00646 EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream)); 00647 delete old_eh; 00648 alarm(d_timeout); 00649 } 00650 #endif 00651 } 00652 00653 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."; 00654 00664 void 00665 DODSFilter::print_usage() const 00666 { 00667 // Write a message to the WWW server error log file. 00668 ErrMsgT(usage.c_str()); 00669 00670 throw Error(emessage); 00671 } 00672 00678 void 00679 DODSFilter::send_version_info() const 00680 { 00681 do_version(d_cgi_ver, get_dataset_version()); 00682 } 00683 00695 void 00696 DODSFilter::send_das(FILE *out, DAS &das, const string &anc_location, 00697 bool with_mime_headers) const 00698 { 00699 ostringstream oss; 00700 send_das(oss, das, anc_location, with_mime_headers); 00701 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out); 00702 } 00703 00715 void 00716 DODSFilter::send_das(ostream &out, DAS &das, const string &anc_location, 00717 bool with_mime_headers) const 00718 { 00719 time_t das_lmt = get_das_last_modified_time(anc_location); 00720 if (is_conditional() 00721 && das_lmt <= get_request_if_modified_since() 00722 && with_mime_headers) { 00723 set_mime_not_modified(out); 00724 } 00725 else { 00726 if (with_mime_headers) 00727 set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt); 00728 das.print(out); 00729 } 00730 out << flush ; 00731 } 00732 00733 void 00734 DODSFilter::send_das(DAS &das, const string &anc_location, 00735 bool with_mime_headers) const 00736 { 00737 send_das(cout, das, anc_location, with_mime_headers); 00738 } 00739 00756 void 00757 DODSFilter::send_dds(FILE *out, DDS &dds, ConstraintEvaluator &eval, 00758 bool constrained, 00759 const string &anc_location, 00760 bool with_mime_headers) const 00761 { 00762 ostringstream oss; 00763 send_dds(oss, dds, eval, constrained, anc_location, with_mime_headers); 00764 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out); 00765 } 00766 00783 void 00784 DODSFilter::send_dds(ostream &out, DDS &dds, ConstraintEvaluator &eval, 00785 bool constrained, 00786 const string &anc_location, 00787 bool with_mime_headers) const 00788 { 00789 // If constrained, parse the constraint. Throws Error or InternalErr. 00790 if (constrained) 00791 eval.parse_constraint(d_dap2ce, dds); 00792 00793 if (eval.functional_expression()) 00794 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."); 00795 00796 time_t dds_lmt = get_dds_last_modified_time(anc_location); 00797 if (is_conditional() 00798 && dds_lmt <= get_request_if_modified_since() 00799 && with_mime_headers) { 00800 set_mime_not_modified(out); 00801 } 00802 else { 00803 if (with_mime_headers) 00804 set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt); 00805 if (constrained) 00806 dds.print_constrained(out); 00807 else 00808 dds.print(out); 00809 } 00810 00811 out << flush ; 00812 } 00813 00814 void 00815 DODSFilter::send_dds(DDS &dds, ConstraintEvaluator &eval, 00816 bool constrained, const string &anc_location, 00817 bool with_mime_headers) const 00818 { 00819 send_dds(cout, dds, eval, constrained, anc_location, with_mime_headers); 00820 } 00821 00822 // 'lmt' unused. Should it be used to supply a LMT or removed from the 00823 // method? jhrg 8/9/05 00824 void 00825 DODSFilter::functional_constraint(BaseType &var, DDS &dds, 00826 ConstraintEvaluator &eval, FILE *out) const 00827 { 00828 ostringstream oss; 00829 functional_constraint(var, dds, eval, oss); 00830 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out); 00831 } 00832 00833 // 'lmt' unused. Should it be used to supply a LMT or removed from the 00834 // method? jhrg 8/9/05 00835 void 00836 DODSFilter::functional_constraint(BaseType &var, DDS &dds, 00837 ConstraintEvaluator &eval, ostream &out) const 00838 { 00839 out << "Dataset {\n" ; 00840 var.print_decl(out, " ", true, false, true); 00841 out << "} function_value;\n" ; 00842 out << "Data:\n" ; 00843 00844 out << flush ; 00845 00846 // Grab a stream that encodes using XDR. 00847 XDRStreamMarshaller m( out ) ; 00848 00849 try { 00850 // In the following call to serialize, suppress CE evaluation. 00851 var.serialize(eval, dds, m, false); 00852 } 00853 catch (Error &e) { 00854 throw; 00855 } 00856 } 00857 00858 void 00859 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval, 00860 FILE * out, bool ce_eval) const 00861 { 00862 ostringstream oss; 00863 dataset_constraint(dds, eval, oss, ce_eval); 00864 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out); 00865 } 00866 00867 void 00868 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval, 00869 ostream &out, bool ce_eval) const 00870 { 00871 // send constrained DDS 00872 dds.print_constrained(out); 00873 out << "Data:\n" ; 00874 out << flush ; 00875 00876 // Grab a stream that encodes using XDR. 00877 XDRStreamMarshaller m( out ) ; 00878 00879 try { 00880 // Send all variables in the current projection (send_p()) 00881 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++) 00882 if ((*i)->send_p()) { 00883 DBG(cerr << "Sending " << (*i)->name() << endl); 00884 (*i)->serialize(eval, dds, m, ce_eval); 00885 } 00886 } 00887 catch (Error & e) { 00888 throw; 00889 } 00890 } 00891 00892 void 00893 DODSFilter::dataset_constraint_ddx(DDS & dds, ConstraintEvaluator & eval, 00894 ostream &out, const string &boundary, 00895 const string &start, bool ce_eval) const 00896 { 00897 // Write the MPM headers for the DDX (text/xml) part of the response 00898 set_mime_ddx_boundary(out, boundary, start, dods_ddx); 00899 00900 // Make cid 00901 uuid_t uu; 00902 uuid_generate(uu); 00903 char uuid[37]; 00904 uuid_unparse(uu, &uuid[0]); 00905 char domain[256]; 00906 if (getdomainname(domain, 255) != 0 || strlen(domain) == 0) 00907 strncpy(domain, "opendap.org", 255); 00908 00909 string cid = string(&uuid[0]) + "@" + string(&domain[0]); 00910 00911 // Send constrained DDX with a data blob reference 00912 dds.print_xml_writer(out, true, cid); 00913 00914 // Write the MPM headers for the data part of the response. 00915 set_mime_data_boundary(out, boundary, cid, dap4_data, binary); 00916 00917 // Grab a stream that encodes using XDR. 00918 XDRStreamMarshaller m( out ) ; 00919 00920 try { 00921 // Send all variables in the current projection (send_p()) 00922 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++) 00923 if ((*i)->send_p()) { 00924 DBG(cerr << "Sending " << (*i)->name() << endl); 00925 (*i)->serialize(eval, dds, m, ce_eval); 00926 } 00927 } 00928 catch (Error & e) { 00929 throw; 00930 } 00931 } 00932 00949 void 00950 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval, 00951 FILE * data_stream, const string & anc_location, 00952 bool with_mime_headers) const 00953 { 00954 ostringstream oss; 00955 send_data(dds, eval, oss, anc_location, with_mime_headers); 00956 fwrite(oss.str().data(), sizeof(char), oss.str().length(), data_stream); 00957 } 00958 00975 void 00976 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval, 00977 ostream & data_stream, const string & anc_location, 00978 bool with_mime_headers) const 00979 { 00980 // If this is a conditional request and the server should send a 304 00981 // response, do that and exit. Otherwise, continue on and send the full 00982 // response. 00983 time_t data_lmt = get_data_last_modified_time(anc_location); 00984 if (is_conditional() 00985 && data_lmt <= get_request_if_modified_since() 00986 && with_mime_headers) { 00987 set_mime_not_modified(data_stream); 00988 return; 00989 } 00990 // Set up the alarm. 00991 establish_timeout(data_stream); 00992 dds.set_timeout(d_timeout); 00993 00994 eval.parse_constraint(d_dap2ce, dds); // Throws Error if the ce doesn't 00995 // parse. 00996 00997 dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node. 00998 00999 // Start sending the response... 01000 01001 // Handle *functional* constraint expressions specially 01002 #if 0 01003 if (eval.functional_expression()) { 01004 // Get the result and then start sending the headers. This provides a 01005 // way to send errors back to the client w/o colliding with the 01006 // normal response headers. There's some duplication of code with this 01007 // and the else-clause. 01008 BaseType *var = eval.eval_function(dds, d_dataset); 01009 if (!var) 01010 throw Error(unknown_error, "Error calling the CE function."); 01011 01012 if (with_mime_headers) 01013 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01014 01015 data_stream << flush ; 01016 01017 functional_constraint(*var, dds, eval, data_stream); 01018 delete var; 01019 var = 0; 01020 } 01021 #endif 01022 if (eval.function_clauses()) { 01023 DDS *fdds = eval.eval_function_clauses(dds); 01024 if (with_mime_headers) 01025 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01026 01027 dataset_constraint(*fdds, eval, data_stream, false); 01028 delete fdds; 01029 } 01030 else { 01031 if (with_mime_headers) 01032 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01033 01034 dataset_constraint(dds, eval, data_stream); 01035 } 01036 01037 data_stream << flush ; 01038 } 01039 01050 void 01051 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out, 01052 bool with_mime_headers) const 01053 { 01054 ostringstream oss; 01055 send_ddx(dds, eval, oss, with_mime_headers); 01056 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out); 01057 } 01058 01069 void 01070 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, ostream &out, 01071 bool with_mime_headers) const 01072 { 01073 // If constrained, parse the constraint. Throws Error or InternalErr. 01074 if (!d_dap2ce.empty()) 01075 eval.parse_constraint(d_dap2ce, dds); 01076 01077 if (eval.functional_expression()) 01078 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."); 01079 01080 time_t dds_lmt = get_dds_last_modified_time(d_anc_dir); 01081 01082 // If this is a conditional request and the server should send a 304 01083 // response, do that and exit. Otherwise, continue on and send the full 01084 // response. 01085 if (is_conditional() && dds_lmt <= get_request_if_modified_since() 01086 && with_mime_headers) { 01087 set_mime_not_modified(out); 01088 return; 01089 } 01090 else { 01091 if (with_mime_headers) 01092 set_mime_text(out, dods_ddx, d_cgi_ver, x_plain, dds_lmt); 01093 dds.print_xml_writer(out, !d_dap2ce.empty(), ""); 01094 } 01095 } 01096 01117 void 01118 DODSFilter::send_data_ddx(DDS & dds, ConstraintEvaluator & eval, 01119 ostream & data_stream, const string &start, 01120 const string &boundary, const string & anc_location, 01121 bool with_mime_headers) const 01122 { 01123 // If this is a conditional request and the server should send a 304 01124 // response, do that and exit. Otherwise, continue on and send the full 01125 // response. 01126 time_t data_lmt = get_data_last_modified_time(anc_location); 01127 if (is_conditional() 01128 && data_lmt <= get_request_if_modified_since() 01129 && with_mime_headers) { 01130 set_mime_not_modified(data_stream); 01131 return; 01132 } 01133 // Set up the alarm. 01134 establish_timeout(data_stream); 01135 dds.set_timeout(d_timeout); 01136 01137 eval.parse_constraint(d_dap2ce, dds); // Throws Error if the ce doesn't 01138 // parse. 01139 01140 dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node. 01141 01142 // Start sending the response... 01143 01144 // Handle *functional* constraint expressions specially 01145 #if 0 01146 if (eval.functional_expression()) { 01147 BaseType *var = eval.eval_function(dds, d_dataset); 01148 if (!var) 01149 throw Error(unknown_error, "Error calling the CE function."); 01150 01151 if (with_mime_headers) 01152 set_mime_multipart(data_stream, boundary, start, dods_data_ddx, 01153 d_cgi_ver, x_plain, data_lmt); 01154 data_stream << flush ; 01155 BaseTypeFactory btf; 01156 DDS var_dds(&btf, var->name()); 01157 var->set_send_p(true); 01158 var_dds.add_var(var); 01159 serialize_dap2_data_ddx(var_dds, eval, data_stream, boundary, start); 01160 01161 // functional_constraint_ddx(*var, dds, eval, data_stream, boundary); 01162 delete var; 01163 var = 0; 01164 } 01165 #endif 01166 if (eval.function_clauses()) { 01167 DDS *fdds = eval.eval_function_clauses(dds); 01168 if (with_mime_headers) 01169 set_mime_multipart(data_stream, boundary, start, dods_data_ddx, 01170 d_cgi_ver, x_plain, data_lmt); 01171 data_stream << flush ; 01172 dataset_constraint(*fdds, eval, data_stream, false); 01173 delete fdds; 01174 } 01175 else { 01176 if (with_mime_headers) 01177 set_mime_multipart(data_stream, boundary, start, dods_data_ddx, 01178 d_cgi_ver, x_plain, data_lmt); 01179 data_stream << flush ; 01180 dataset_constraint_ddx(dds, eval, data_stream, boundary, start); 01181 } 01182 01183 data_stream << flush ; 01184 01185 if (with_mime_headers) 01186 data_stream << CRLF << "--" << boundary << "--" << CRLF; 01187 } 01188 01189 } // namespace libdap 01190