libdap++ Updated for version 3.8.2
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 static char rcsid[] not_used = 00040 {"$Id: DODSFilter.cc 23477 2010-09-02 21:02:59Z jimg $" 00041 }; 00042 00043 #include <signal.h> 00044 00045 #ifndef WIN32 00046 #include <unistd.h> // for getopt 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> // used to build CID header value for data ddx 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 //#undef FILE_METHODS 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 // Set default values. Don't use the C++ constructor initialization so 00199 // that a subclass can have more control over this process. 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 // We want serving from win32 to behave in a manner 00219 // similar to the UNIX way - no CR->NL terminated lines 00220 // in files. Hence stdout goes to binary mode. 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 // This should be specialized by a subclass. This may throw Error. 00244 int next_arg = process_options(argc, argv); 00245 00246 // Look at what's left after processing the command line options. Either 00247 // there MUST be a dataset name OR the caller is asking for version 00248 // information. If neither is true, then the options are bad. 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(); // Throws Error 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(); // Throws Error 00291 } 00292 } 00293 00294 DBGN(cerr << "exiting." << endl); 00295 00296 return getopt.optind; // return the index of the next argument 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(); // Throws Error 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(); // Throws Error 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 // Note that this is a call to get_dataset_... not get_data_... 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 // FIXME 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 // Write a message to the WWW server error log file. 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 // If constrained, parse the constraint. Throws Error or InternalErr. 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 // If constrained, parse the constraint. Throws Error or InternalErr. 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 // 'lmt' unused. Should it be used to supply a LMT or removed from the 00856 // method? jhrg 8/9/05 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 // In the following call to serialize, suppress CE evaluation. 00872 var.serialize(eval, dds, m, false); 00873 } 00874 catch (Error &e) { 00875 throw; 00876 } 00877 } 00878 #endif 00879 00880 // 'lmt' unused. Should it be used to supply a LMT or removed from the 00881 // method? jhrg 8/9/05 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 // Grab a stream that encodes using XDR. 00894 XDRStreamMarshaller m( out ) ; 00895 00896 try { 00897 // In the following call to serialize, suppress CE evaluation. 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, bool ce_eval) const 00909 { 00910 // send constrained DDS 00911 dds.print_constrained(out); 00912 fprintf(out, "Data:\n"); 00913 fflush(out); 00914 00915 // Grab a stream that encodes using XDR. 00916 XDRFileMarshaller m( out ) ; 00917 00918 try { 00919 // Send all variables in the current projection (send_p()) 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, ce_eval); 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, bool ce_eval) const 00935 { 00936 // send constrained DDS 00937 dds.print_constrained(out); 00938 out << "Data:\n" ; 00939 out << flush ; 00940 00941 // Grab a stream that encodes using XDR. 00942 XDRStreamMarshaller m( out ) ; 00943 00944 try { 00945 // Send all variables in the current projection (send_p()) 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, ce_eval); 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, bool ce_eval) const 00961 { 00962 // Write the MPM headers for the DDX (text/xml) part of the response 00963 set_mime_ddx_boundary(out, boundary, start, dap4_ddx); 00964 00965 // Make cid 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 // Send constrained DDX with a data blob reference 00977 dds.print_xml(out, true, cid); 00978 00979 // Write the MPM headers for the data part of the response. 00980 set_mime_data_boundary(out, boundary, cid, dap4_data, binary); 00981 00982 // Grab a stream that encodes using XDR. 00983 XDRStreamMarshaller m( out ) ; 00984 00985 try { 00986 // Send all variables in the current projection (send_p()) 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, ce_eval); 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 // If this is a conditional request and the server should send a 304 01021 // response, do that and exit. Otherwise, continue on and send the full 01022 // response. 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 // Set up the alarm. 01031 establish_timeout(data_stream); 01032 dds.set_timeout(d_timeout); 01033 01034 eval.parse_constraint(d_ce, dds); // Throws Error if the ce doesn't 01035 // parse. 01036 01037 dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node. 01038 01039 // Start sending the response... 01040 01041 // Handle *functional* constraint expressions specially 01042 #if 0 01043 if (eval.functional_expression()) { 01044 // Get the result and then start sending the headers. This provides a 01045 // way to send errors back to the client w/o colliding with the 01046 // normal response headers. There's some duplication of code with this 01047 // and the else-clause. 01048 BaseType *var = eval.eval_function(dds, d_dataset); 01049 if (!var) 01050 throw Error(unknown_error, "Error calling the CE function."); 01051 01052 #if COMPRESSION_FOR_SERVER3 01053 if (with_mime_headers) 01054 set_mime_binary(data_stream, dods_data, d_cgi_ver, 01055 (compress) ? deflate : x_plain, data_lmt); 01056 fflush(data_stream); 01057 01058 int childpid; 01059 if (compress) 01060 data_stream = compressor(data_stream, childpid); 01061 #endif 01062 if (with_mime_headers) 01063 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01064 01065 fflush(data_stream); 01066 01067 functional_constraint(*var, dds, eval, data_stream); 01068 delete var; 01069 var = 0; 01070 } 01071 #endif 01072 if (eval.function_clauses()) { 01073 DDS *fdds = eval.eval_function_clauses(dds); 01074 01075 if (with_mime_headers) 01076 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01077 01078 dataset_constraint(*fdds, eval, data_stream, false); 01079 delete fdds; 01080 } 01081 else { 01082 if (with_mime_headers) 01083 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01084 01085 dataset_constraint(dds, eval, data_stream); 01086 } 01087 01088 fflush(data_stream); 01089 } 01090 #endif 01091 01108 void 01109 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval, 01110 ostream & data_stream, const string & anc_location, 01111 bool with_mime_headers) const 01112 { 01113 // If this is a conditional request and the server should send a 304 01114 // response, do that and exit. Otherwise, continue on and send the full 01115 // response. 01116 time_t data_lmt = get_data_last_modified_time(anc_location); 01117 if (is_conditional() 01118 && data_lmt <= get_request_if_modified_since() 01119 && with_mime_headers) { 01120 set_mime_not_modified(data_stream); 01121 return; 01122 } 01123 // Set up the alarm. 01124 establish_timeout(data_stream); 01125 dds.set_timeout(d_timeout); 01126 01127 eval.parse_constraint(d_ce, dds); // Throws Error if the ce doesn't 01128 // parse. 01129 01130 dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node. 01131 01132 // Start sending the response... 01133 01134 // Handle *functional* constraint expressions specially 01135 #if 0 01136 if (eval.functional_expression()) { 01137 // Get the result and then start sending the headers. This provides a 01138 // way to send errors back to the client w/o colliding with the 01139 // normal response headers. There's some duplication of code with this 01140 // and the else-clause. 01141 BaseType *var = eval.eval_function(dds, d_dataset); 01142 if (!var) 01143 throw Error(unknown_error, "Error calling the CE function."); 01144 01145 if (with_mime_headers) 01146 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01147 01148 data_stream << flush ; 01149 01150 functional_constraint(*var, dds, eval, data_stream); 01151 delete var; 01152 var = 0; 01153 } 01154 #endif 01155 if (eval.function_clauses()) { 01156 DDS *fdds = eval.eval_function_clauses(dds); 01157 if (with_mime_headers) 01158 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01159 01160 dataset_constraint(*fdds, eval, data_stream, false); 01161 delete fdds; 01162 } 01163 else { 01164 if (with_mime_headers) 01165 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01166 01167 dataset_constraint(dds, eval, data_stream); 01168 } 01169 01170 data_stream << flush ; 01171 } 01172 01173 #if FILE_METHODS 01174 01184 void 01185 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out, 01186 bool with_mime_headers) const 01187 { 01188 // If constrained, parse the constraint. Throws Error or InternalErr. 01189 if (!d_ce.empty()) 01190 eval.parse_constraint(d_ce, dds); 01191 01192 if (eval.functional_expression()) 01193 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."); 01194 01195 time_t dds_lmt = get_dds_last_modified_time(d_anc_dir); 01196 01197 // If this is a conditional request and the server should send a 304 01198 // response, do that and exit. Otherwise, continue on and send the full 01199 // response. 01200 if (is_conditional() && dds_lmt <= get_request_if_modified_since() 01201 && with_mime_headers) { 01202 set_mime_not_modified(out); 01203 return; 01204 } 01205 else { 01206 if (with_mime_headers) 01207 set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt); 01208 dds.print_xml(out, !d_ce.empty(), ""); 01209 } 01210 } 01211 #endif 01212 01223 void 01224 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, ostream &out, 01225 bool with_mime_headers) const 01226 { 01227 // If constrained, parse the constraint. Throws Error or InternalErr. 01228 if (!d_ce.empty()) 01229 eval.parse_constraint(d_ce, dds); 01230 01231 if (eval.functional_expression()) 01232 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."); 01233 01234 time_t dds_lmt = get_dds_last_modified_time(d_anc_dir); 01235 01236 // If this is a conditional request and the server should send a 304 01237 // response, do that and exit. Otherwise, continue on and send the full 01238 // response. 01239 if (is_conditional() && dds_lmt <= get_request_if_modified_since() 01240 && with_mime_headers) { 01241 set_mime_not_modified(out); 01242 return; 01243 } 01244 else { 01245 if (with_mime_headers) 01246 set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt); 01247 dds.print_xml(out, !d_ce.empty(), ""); 01248 } 01249 } 01250 01267 void 01268 DODSFilter::send_data_ddx(DDS & dds, ConstraintEvaluator & eval, 01269 ostream & data_stream, const string &start, 01270 const string &boundary, const string & anc_location, 01271 bool with_mime_headers) const 01272 { 01273 // If this is a conditional request and the server should send a 304 01274 // response, do that and exit. Otherwise, continue on and send the full 01275 // response. 01276 time_t data_lmt = get_data_last_modified_time(anc_location); 01277 if (is_conditional() 01278 && data_lmt <= get_request_if_modified_since() 01279 && with_mime_headers) { 01280 set_mime_not_modified(data_stream); 01281 return; 01282 } 01283 // Set up the alarm. 01284 establish_timeout(data_stream); 01285 dds.set_timeout(d_timeout); 01286 01287 eval.parse_constraint(d_ce, dds); // Throws Error if the ce doesn't 01288 // parse. 01289 01290 dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node. 01291 01292 // Start sending the response... 01293 01294 // Handle *functional* constraint expressions specially 01295 #if 0 01296 if (eval.functional_expression()) { 01297 BaseType *var = eval.eval_function(dds, d_dataset); 01298 if (!var) 01299 throw Error(unknown_error, "Error calling the CE function."); 01300 01301 if (with_mime_headers) 01302 set_mime_multipart(data_stream, boundary, start, dap4_data_ddx, 01303 d_cgi_ver, x_plain, data_lmt); 01304 data_stream << flush ; 01305 BaseTypeFactory btf; 01306 DDS var_dds(&btf, var->name()); 01307 var->set_send_p(true); 01308 var_dds.add_var(var); 01309 dataset_constraint_ddx(var_dds, eval, data_stream, boundary, start); 01310 01311 // functional_constraint_ddx(*var, dds, eval, data_stream, boundary); 01312 delete var; 01313 var = 0; 01314 } 01315 #endif 01316 if (eval.function_clauses()) { 01317 DDS *fdds = eval.eval_function_clauses(dds); 01318 if (with_mime_headers) 01319 set_mime_multipart(data_stream, boundary, start, dap4_data_ddx, 01320 d_cgi_ver, x_plain, data_lmt); 01321 data_stream << flush ; 01322 dataset_constraint(*fdds, eval, data_stream, false); 01323 delete fdds; 01324 } 01325 else { 01326 if (with_mime_headers) 01327 set_mime_multipart(data_stream, boundary, start, dap4_data_ddx, 01328 d_cgi_ver, x_plain, data_lmt); 01329 data_stream << flush ; 01330 dataset_constraint_ddx(dds, eval, data_stream, boundary, start); 01331 } 01332 01333 data_stream << flush ; 01334 01335 if (with_mime_headers) 01336 data_stream << CRLF << "--" << boundary << "--" << CRLF; 01337 } 01338 01339 } // namespace libdap 01340