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 25112 2011-12-29 21:44:54Z 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 // 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 } 00295 } 00296 00297 DBGN(cerr << "exiting." << endl); 00298 00299 return getopt.optind; // return the index of the next argument 00300 } 00301 00306 bool 00307 DODSFilter::is_conditional() const 00308 { 00309 return d_conditional_request; 00310 } 00311 00325 void 00326 DODSFilter::set_cgi_version(string version) 00327 { 00328 d_cgi_ver = version; 00329 } 00330 00336 string 00337 DODSFilter::get_cgi_version() const 00338 { 00339 return d_cgi_ver; 00340 } 00341 00348 string 00349 DODSFilter::get_ce() const 00350 { 00351 return d_ce; 00352 } 00353 00354 void 00355 DODSFilter::set_ce(string _ce) 00356 { 00357 d_ce = www2id(_ce, "%", "%20"); 00358 } 00359 00368 string 00369 DODSFilter::get_dataset_name() const 00370 { 00371 return d_dataset; 00372 } 00373 00374 void 00375 DODSFilter::set_dataset_name(const string ds) 00376 { 00377 d_dataset = www2id(ds, "%", "%20"); 00378 } 00379 00383 string 00384 DODSFilter::get_URL() const 00385 { 00386 return d_url; 00387 } 00388 00391 void 00392 DODSFilter::set_URL(const string &url) 00393 { 00394 if (url.find('?') != url.npos) 00395 print_usage(); // Throws Error 00396 00397 d_url = url; 00398 } 00399 00407 string 00408 DODSFilter::get_dataset_version() const 00409 { 00410 return ""; 00411 } 00412 00419 void DODSFilter::set_response(const string &r) 00420 { 00421 if (r == "DAS" || r == "das") { 00422 d_response = DAS_Response; 00423 d_action = "das" ; 00424 } 00425 else if (r == "DDS" || r == "dds") { 00426 d_response = DDS_Response; 00427 d_action = "dds" ; 00428 } 00429 else if (r == "DataDDS" || r == "dods") { 00430 d_response = DataDDS_Response; 00431 d_action = "dods" ; 00432 } 00433 else if (r == "DDX" || r == "ddx") { 00434 d_response = DDX_Response; 00435 d_action = "ddx" ; 00436 } 00437 else if (r == "DataDDX" || r == "dataddx") { 00438 d_response = DataDDX_Response; 00439 d_action = "dataddx" ; 00440 } 00441 else if (r == "Version") { 00442 d_response = Version_Response; 00443 d_action = "version" ; 00444 } 00445 else 00446 print_usage(); // Throws Error 00447 } 00448 00450 DODSFilter::Response 00451 DODSFilter::get_response() const 00452 { 00453 return d_response; 00454 } 00455 00457 string DODSFilter::get_action() const 00458 { 00459 return d_action; 00460 } 00461 00482 time_t 00483 DODSFilter::get_dataset_last_modified_time() const 00484 { 00485 return last_modified_time(d_dataset); 00486 } 00487 00497 time_t 00498 DODSFilter::get_das_last_modified_time(const string &anc_location) const 00499 { 00500 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location=" 00501 << anc_location << "call faf(das) d_dataset=" << d_dataset 00502 << " d_anc_file=" << d_anc_file << endl); 00503 00504 string name 00505 = Ancillary::find_ancillary_file(d_dataset, "das", 00506 (anc_location == "") ? d_anc_dir : anc_location, 00507 d_anc_file); 00508 00509 return max((name != "") ? last_modified_time(name) : 0, 00510 get_dataset_last_modified_time()); 00511 } 00512 00520 time_t 00521 DODSFilter::get_dds_last_modified_time(const string &anc_location) const 00522 { 00523 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location=" 00524 << anc_location << "call faf(dds) d_dataset=" << d_dataset 00525 << " d_anc_file=" << d_anc_file << endl); 00526 00527 string name 00528 = Ancillary::find_ancillary_file(d_dataset, "dds", 00529 (anc_location == "") ? d_anc_dir : anc_location, 00530 d_anc_file); 00531 00532 return max((name != "") ? last_modified_time(name) : 0, 00533 get_dataset_last_modified_time()); 00534 } 00535 00549 time_t 00550 DODSFilter::get_data_last_modified_time(const string &anc_location) const 00551 { 00552 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location=" 00553 << anc_location << "call faf(both) d_dataset=" << d_dataset 00554 << " d_anc_file=" << d_anc_file << endl); 00555 00556 string dds_name 00557 = Ancillary::find_ancillary_file(d_dataset, "dds", 00558 (anc_location == "") ? d_anc_dir : anc_location, 00559 d_anc_file); 00560 string das_name 00561 = Ancillary::find_ancillary_file(d_dataset, "das", 00562 (anc_location == "") ? d_anc_dir : anc_location, 00563 d_anc_file); 00564 00565 time_t m = max((das_name != "") ? last_modified_time(das_name) : (time_t)0, 00566 (dds_name != "") ? last_modified_time(dds_name) : (time_t)0); 00567 // Note that this is a call to get_dataset_... not get_data_... 00568 time_t n = get_dataset_last_modified_time(); 00569 00570 return max(m, n); 00571 } 00572 00580 time_t 00581 DODSFilter::get_request_if_modified_since() const 00582 { 00583 return d_if_modified_since; 00584 } 00585 00592 string 00593 DODSFilter::get_cache_dir() const 00594 { 00595 return d_cache_dir; 00596 } 00597 00602 void 00603 DODSFilter::set_timeout(int t) 00604 { 00605 d_timeout = t; 00606 } 00607 00609 int 00610 DODSFilter::get_timeout() const 00611 { 00612 return d_timeout; 00613 } 00614 00615 #if FILE_METHODS 00616 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 #endif 00640 00641 // FIXME 00642 void 00643 DODSFilter::establish_timeout(ostream &stream) const 00644 { 00645 #ifndef WIN32 00646 if (d_timeout > 0) { 00647 SignalHandler *sh = SignalHandler::instance(); 00648 EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream)); 00649 delete old_eh; 00650 alarm(d_timeout); 00651 } 00652 #endif 00653 } 00654 00655 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."; 00656 00666 void 00667 DODSFilter::print_usage() const 00668 { 00669 // Write a message to the WWW server error log file. 00670 ErrMsgT(usage.c_str()); 00671 00672 throw Error(emessage); 00673 } 00674 00680 void 00681 DODSFilter::send_version_info() const 00682 { 00683 do_version(d_cgi_ver, get_dataset_version()); 00684 } 00685 00686 #if FILE_METHODS 00687 00698 void 00699 DODSFilter::send_das(FILE *out, DAS &das, const string &anc_location, 00700 bool with_mime_headers) const 00701 { 00702 time_t das_lmt = get_das_last_modified_time(anc_location); 00703 if (is_conditional() 00704 && das_lmt <= get_request_if_modified_since() 00705 && with_mime_headers) { 00706 set_mime_not_modified(out); 00707 } 00708 else { 00709 if (with_mime_headers) 00710 set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt); 00711 das.print(out); 00712 } 00713 fflush(out) ; 00714 } 00715 #endif 00716 00728 void 00729 DODSFilter::send_das(ostream &out, DAS &das, const string &anc_location, 00730 bool with_mime_headers) const 00731 { 00732 time_t das_lmt = get_das_last_modified_time(anc_location); 00733 if (is_conditional() 00734 && das_lmt <= get_request_if_modified_since() 00735 && with_mime_headers) { 00736 set_mime_not_modified(out); 00737 } 00738 else { 00739 if (with_mime_headers) 00740 set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt); 00741 das.print(out); 00742 } 00743 out << flush ; 00744 } 00745 00746 void 00747 DODSFilter::send_das(DAS &das, const string &anc_location, 00748 bool with_mime_headers) const 00749 { 00750 send_das(cout, das, anc_location, with_mime_headers); 00751 } 00752 00753 #if FILE_METHODS 00754 00770 void 00771 DODSFilter::send_dds(FILE *out, DDS &dds, ConstraintEvaluator &eval, 00772 bool constrained, 00773 const string &anc_location, 00774 bool with_mime_headers) const 00775 { 00776 // If constrained, parse the constraint. Throws Error or InternalErr. 00777 if (constrained) 00778 eval.parse_constraint(d_ce, dds); 00779 00780 if (eval.functional_expression()) 00781 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."); 00782 00783 time_t dds_lmt = get_dds_last_modified_time(anc_location); 00784 if (is_conditional() 00785 && dds_lmt <= get_request_if_modified_since() 00786 && with_mime_headers) { 00787 set_mime_not_modified(out); 00788 } 00789 else { 00790 if (with_mime_headers) 00791 set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt); 00792 if (constrained) 00793 dds.print_constrained(out); 00794 else 00795 dds.print(out); 00796 } 00797 00798 fflush(out) ; 00799 } 00800 #endif 00801 00818 void 00819 DODSFilter::send_dds(ostream &out, DDS &dds, ConstraintEvaluator &eval, 00820 bool constrained, 00821 const string &anc_location, 00822 bool with_mime_headers) const 00823 { 00824 // If constrained, parse the constraint. Throws Error or InternalErr. 00825 if (constrained) 00826 eval.parse_constraint(d_ce, dds); 00827 00828 if (eval.functional_expression()) 00829 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."); 00830 00831 time_t dds_lmt = get_dds_last_modified_time(anc_location); 00832 if (is_conditional() 00833 && dds_lmt <= get_request_if_modified_since() 00834 && with_mime_headers) { 00835 set_mime_not_modified(out); 00836 } 00837 else { 00838 if (with_mime_headers) 00839 set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt); 00840 if (constrained) 00841 dds.print_constrained(out); 00842 else 00843 dds.print(out); 00844 } 00845 00846 out << flush ; 00847 } 00848 00849 void 00850 DODSFilter::send_dds(DDS &dds, ConstraintEvaluator &eval, 00851 bool constrained, const string &anc_location, 00852 bool with_mime_headers) const 00853 { 00854 send_dds(cout, dds, eval, constrained, anc_location, with_mime_headers); 00855 } 00856 00857 #if FILE_METHODS 00858 // 'lmt' unused. Should it be used to supply a LMT or removed from the 00859 // method? jhrg 8/9/05 00860 void 00861 DODSFilter::functional_constraint(BaseType &var, DDS &dds, 00862 ConstraintEvaluator &eval, FILE *out) const 00863 { 00864 fprintf(out, "Dataset {\n"); 00865 var.print_decl(out, " ", true, false, true); 00866 fprintf(out, "} function_value;\n"); 00867 fprintf(out, "Data:\n"); 00868 00869 fflush(out); 00870 00871 XDRFileMarshaller m( out ) ; 00872 00873 try { 00874 // In the following call to serialize, suppress CE evaluation. 00875 var.serialize(eval, dds, m, false); 00876 } 00877 catch (Error &e) { 00878 throw; 00879 } 00880 } 00881 #endif 00882 00883 // 'lmt' unused. Should it be used to supply a LMT or removed from the 00884 // method? jhrg 8/9/05 00885 void 00886 DODSFilter::functional_constraint(BaseType &var, DDS &dds, 00887 ConstraintEvaluator &eval, ostream &out) const 00888 { 00889 out << "Dataset {\n" ; 00890 var.print_decl(out, " ", true, false, true); 00891 out << "} function_value;\n" ; 00892 out << "Data:\n" ; 00893 00894 out << flush ; 00895 00896 // Grab a stream that encodes using XDR. 00897 XDRStreamMarshaller m( out ) ; 00898 00899 try { 00900 // In the following call to serialize, suppress CE evaluation. 00901 var.serialize(eval, dds, m, false); 00902 } 00903 catch (Error &e) { 00904 throw; 00905 } 00906 } 00907 00908 #if FILE_METHODS 00909 void 00910 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval, 00911 FILE * out, bool ce_eval) const 00912 { 00913 // send constrained DDS 00914 dds.print_constrained(out); 00915 fprintf(out, "Data:\n"); 00916 fflush(out); 00917 00918 // Grab a stream that encodes using XDR. 00919 XDRFileMarshaller m( out ) ; 00920 00921 try { 00922 // Send all variables in the current projection (send_p()) 00923 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++) 00924 if ((*i)->send_p()) { 00925 DBG(cerr << "Sending " << (*i)->name() << endl); 00926 (*i)->serialize(eval, dds, m, ce_eval); 00927 } 00928 } 00929 catch (Error & e) { 00930 throw; 00931 } 00932 } 00933 #endif 00934 00935 void 00936 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval, 00937 ostream &out, bool ce_eval) const 00938 { 00939 // send constrained DDS 00940 dds.print_constrained(out); 00941 out << "Data:\n" ; 00942 out << flush ; 00943 00944 // Grab a stream that encodes using XDR. 00945 XDRStreamMarshaller m( out ) ; 00946 00947 try { 00948 // Send all variables in the current projection (send_p()) 00949 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++) 00950 if ((*i)->send_p()) { 00951 DBG(cerr << "Sending " << (*i)->name() << endl); 00952 (*i)->serialize(eval, dds, m, ce_eval); 00953 } 00954 } 00955 catch (Error & e) { 00956 throw; 00957 } 00958 } 00959 00960 void 00961 DODSFilter::dataset_constraint_ddx(DDS & dds, ConstraintEvaluator & eval, 00962 ostream &out, const string &boundary, 00963 const string &start, bool ce_eval) const 00964 { 00965 // Write the MPM headers for the DDX (text/xml) part of the response 00966 set_mime_ddx_boundary(out, boundary, start, dap4_ddx); 00967 00968 // Make cid 00969 uuid_t uu; 00970 uuid_generate(uu); 00971 char uuid[37]; 00972 uuid_unparse(uu, &uuid[0]); 00973 char domain[256]; 00974 if (getdomainname(domain, 255) != 0 || strlen(domain) == 0) 00975 strncpy(domain, "opendap.org", 255); 00976 00977 string cid = string(&uuid[0]) + "@" + string(&domain[0]); 00978 00979 // Send constrained DDX with a data blob reference 00980 dds.print_xml(out, true, cid); 00981 00982 // Write the MPM headers for the data part of the response. 00983 set_mime_data_boundary(out, boundary, cid, dap4_data, binary); 00984 00985 // Grab a stream that encodes using XDR. 00986 XDRStreamMarshaller m( out ) ; 00987 00988 try { 00989 // Send all variables in the current projection (send_p()) 00990 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++) 00991 if ((*i)->send_p()) { 00992 DBG(cerr << "Sending " << (*i)->name() << endl); 00993 (*i)->serialize(eval, dds, m, ce_eval); 00994 } 00995 } 00996 catch (Error & e) { 00997 throw; 00998 } 00999 } 01000 01001 #if FILE_METHODS 01002 01018 void 01019 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval, 01020 FILE * data_stream, const string & anc_location, 01021 bool with_mime_headers) const 01022 { 01023 // If this is a conditional request and the server should send a 304 01024 // response, do that and exit. Otherwise, continue on and send the full 01025 // response. 01026 time_t data_lmt = get_data_last_modified_time(anc_location); 01027 if (is_conditional() 01028 && data_lmt <= get_request_if_modified_since() 01029 && with_mime_headers) { 01030 set_mime_not_modified(data_stream); 01031 return; 01032 } 01033 // Set up the alarm. 01034 establish_timeout(data_stream); 01035 dds.set_timeout(d_timeout); 01036 01037 eval.parse_constraint(d_ce, dds); // Throws Error if the ce doesn't 01038 // parse. 01039 01040 dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node. 01041 01042 // Start sending the response... 01043 01044 // Handle *functional* constraint expressions specially 01045 #if 0 01046 if (eval.functional_expression()) { 01047 // Get the result and then start sending the headers. This provides a 01048 // way to send errors back to the client w/o colliding with the 01049 // normal response headers. There's some duplication of code with this 01050 // and the else-clause. 01051 BaseType *var = eval.eval_function(dds, d_dataset); 01052 if (!var) 01053 throw Error(unknown_error, "Error calling the CE function."); 01054 01055 #if COMPRESSION_FOR_SERVER3 01056 if (with_mime_headers) 01057 set_mime_binary(data_stream, dods_data, d_cgi_ver, 01058 (compress) ? deflate : x_plain, data_lmt); 01059 fflush(data_stream); 01060 01061 int childpid; 01062 if (compress) 01063 data_stream = compressor(data_stream, childpid); 01064 #endif 01065 if (with_mime_headers) 01066 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01067 01068 fflush(data_stream); 01069 01070 functional_constraint(*var, dds, eval, data_stream); 01071 delete var; 01072 var = 0; 01073 } 01074 #endif 01075 if (eval.function_clauses()) { 01076 DDS *fdds = eval.eval_function_clauses(dds); 01077 01078 if (with_mime_headers) 01079 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01080 01081 dataset_constraint(*fdds, eval, data_stream, false); 01082 delete fdds; 01083 } 01084 else { 01085 if (with_mime_headers) 01086 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01087 01088 dataset_constraint(dds, eval, data_stream); 01089 } 01090 01091 fflush(data_stream); 01092 } 01093 #endif 01094 01111 void 01112 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval, 01113 ostream & data_stream, const string & anc_location, 01114 bool with_mime_headers) const 01115 { 01116 // If this is a conditional request and the server should send a 304 01117 // response, do that and exit. Otherwise, continue on and send the full 01118 // response. 01119 time_t data_lmt = get_data_last_modified_time(anc_location); 01120 if (is_conditional() 01121 && data_lmt <= get_request_if_modified_since() 01122 && with_mime_headers) { 01123 set_mime_not_modified(data_stream); 01124 return; 01125 } 01126 // Set up the alarm. 01127 establish_timeout(data_stream); 01128 dds.set_timeout(d_timeout); 01129 01130 eval.parse_constraint(d_ce, dds); // Throws Error if the ce doesn't 01131 // parse. 01132 01133 dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node. 01134 01135 // Start sending the response... 01136 01137 // Handle *functional* constraint expressions specially 01138 #if 0 01139 if (eval.functional_expression()) { 01140 // Get the result and then start sending the headers. This provides a 01141 // way to send errors back to the client w/o colliding with the 01142 // normal response headers. There's some duplication of code with this 01143 // and the else-clause. 01144 BaseType *var = eval.eval_function(dds, d_dataset); 01145 if (!var) 01146 throw Error(unknown_error, "Error calling the CE function."); 01147 01148 if (with_mime_headers) 01149 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01150 01151 data_stream << flush ; 01152 01153 functional_constraint(*var, dds, eval, data_stream); 01154 delete var; 01155 var = 0; 01156 } 01157 #endif 01158 if (eval.function_clauses()) { 01159 DDS *fdds = eval.eval_function_clauses(dds); 01160 if (with_mime_headers) 01161 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01162 01163 dataset_constraint(*fdds, eval, data_stream, false); 01164 delete fdds; 01165 } 01166 else { 01167 if (with_mime_headers) 01168 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01169 01170 dataset_constraint(dds, eval, data_stream); 01171 } 01172 01173 data_stream << flush ; 01174 } 01175 01176 #if FILE_METHODS 01177 01187 void 01188 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out, 01189 bool with_mime_headers) const 01190 { 01191 // If constrained, parse the constraint. Throws Error or InternalErr. 01192 if (!d_ce.empty()) 01193 eval.parse_constraint(d_ce, dds); 01194 01195 if (eval.functional_expression()) 01196 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."); 01197 01198 time_t dds_lmt = get_dds_last_modified_time(d_anc_dir); 01199 01200 // If this is a conditional request and the server should send a 304 01201 // response, do that and exit. Otherwise, continue on and send the full 01202 // response. 01203 if (is_conditional() && dds_lmt <= get_request_if_modified_since() 01204 && with_mime_headers) { 01205 set_mime_not_modified(out); 01206 return; 01207 } 01208 else { 01209 if (with_mime_headers) 01210 set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt); 01211 dds.print_xml(out, !d_ce.empty(), ""); 01212 } 01213 } 01214 #endif 01215 01226 void 01227 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, ostream &out, 01228 bool with_mime_headers) const 01229 { 01230 // If constrained, parse the constraint. Throws Error or InternalErr. 01231 if (!d_ce.empty()) 01232 eval.parse_constraint(d_ce, dds); 01233 01234 if (eval.functional_expression()) 01235 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."); 01236 01237 time_t dds_lmt = get_dds_last_modified_time(d_anc_dir); 01238 01239 // If this is a conditional request and the server should send a 304 01240 // response, do that and exit. Otherwise, continue on and send the full 01241 // response. 01242 if (is_conditional() && dds_lmt <= get_request_if_modified_since() 01243 && with_mime_headers) { 01244 set_mime_not_modified(out); 01245 return; 01246 } 01247 else { 01248 if (with_mime_headers) 01249 set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt); 01250 dds.print_xml(out, !d_ce.empty(), ""); 01251 } 01252 } 01253 01274 void 01275 DODSFilter::send_data_ddx(DDS & dds, ConstraintEvaluator & eval, 01276 ostream & data_stream, const string &start, 01277 const string &boundary, const string & anc_location, 01278 bool with_mime_headers) const 01279 { 01280 // If this is a conditional request and the server should send a 304 01281 // response, do that and exit. Otherwise, continue on and send the full 01282 // response. 01283 time_t data_lmt = get_data_last_modified_time(anc_location); 01284 if (is_conditional() 01285 && data_lmt <= get_request_if_modified_since() 01286 && with_mime_headers) { 01287 set_mime_not_modified(data_stream); 01288 return; 01289 } 01290 // Set up the alarm. 01291 establish_timeout(data_stream); 01292 dds.set_timeout(d_timeout); 01293 01294 eval.parse_constraint(d_ce, dds); // Throws Error if the ce doesn't 01295 // parse. 01296 01297 dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node. 01298 01299 // Start sending the response... 01300 01301 // Handle *functional* constraint expressions specially 01302 #if 0 01303 if (eval.functional_expression()) { 01304 BaseType *var = eval.eval_function(dds, d_dataset); 01305 if (!var) 01306 throw Error(unknown_error, "Error calling the CE function."); 01307 01308 if (with_mime_headers) 01309 set_mime_multipart(data_stream, boundary, start, dap4_data_ddx, 01310 d_cgi_ver, x_plain, data_lmt); 01311 data_stream << flush ; 01312 BaseTypeFactory btf; 01313 DDS var_dds(&btf, var->name()); 01314 var->set_send_p(true); 01315 var_dds.add_var(var); 01316 dataset_constraint_ddx(var_dds, eval, data_stream, boundary, start); 01317 01318 // functional_constraint_ddx(*var, dds, eval, data_stream, boundary); 01319 delete var; 01320 var = 0; 01321 } 01322 #endif 01323 if (eval.function_clauses()) { 01324 DDS *fdds = eval.eval_function_clauses(dds); 01325 if (with_mime_headers) 01326 set_mime_multipart(data_stream, boundary, start, dap4_data_ddx, 01327 d_cgi_ver, x_plain, data_lmt); 01328 data_stream << flush ; 01329 dataset_constraint(*fdds, eval, data_stream, false); 01330 delete fdds; 01331 } 01332 else { 01333 if (with_mime_headers) 01334 set_mime_multipart(data_stream, boundary, start, dap4_data_ddx, 01335 d_cgi_ver, x_plain, data_lmt); 01336 data_stream << flush ; 01337 dataset_constraint_ddx(dds, eval, data_stream, boundary, start); 01338 } 01339 01340 data_stream << flush ; 01341 01342 if (with_mime_headers) 01343 data_stream << CRLF << "--" << boundary << "--" << CRLF; 01344 } 01345 01346 } // namespace libdap 01347