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 19948 2008-12-03 23:51:12Z 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 00059 #include <GetOpt.h> 00060 00061 #include "DAS.h" 00062 #include "DDS.h" 00063 #include "debug.h" 00064 #include "cgi_util.h" 00065 #include "Ancillary.h" 00066 #include "util.h" 00067 #include "escaping.h" 00068 #include "DODSFilter.h" 00069 #include "XDRFileMarshaller.h" 00070 #include "XDRStreamMarshaller.h" 00071 #include "InternalErr.h" 00072 #ifndef WIN32 00073 #include "SignalHandler.h" 00074 #include "EventHandler.h" 00075 #include "AlarmHandler.h" 00076 #endif 00077 00078 using namespace std; 00079 00080 namespace libdap { 00081 00082 const string usage = 00083 "Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\ 00084 \n\ 00085 options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\ 00086 -u <url>: The complete URL minus the CE (required for DDX)\n\ 00087 -c: Compress the response using the deflate algorithm.\n\ 00088 -e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\ 00089 -v <version>: Use <version> as the version number\n\ 00090 -d <dir>: Look for ancillary file in <dir> (deprecated).\n\ 00091 -f <file>: Look for ancillary data in <file> (deprecated).\n\ 00092 -r <dir>: Use <dir> as a cache directory\n\ 00093 -l <time>: Conditional request; if data source is unchanged since\n\ 00094 <time>, return an HTTP 304 response.\n\ 00095 -t <seconds>: Timeout the handler after <seconds>.\n\ 00096 -h: This message."; 00097 00098 #if 0 00099 // Removed the call to waitpid in send_data() because calling fflush 00100 // addresses the problem wait() was supposed to solve and calling wait() is 00101 // the root of ticket #335. jhrg 3/10/06 00102 #ifdef WIN32 00103 #define WAITPID(pid) while(_cwait(NULL, pid, NULL) > 0) 00104 #else 00105 #define WAITPID(pid) while(waitpid(pid, 0, 0) > 0) 00106 #endif 00107 #endif 00108 00173 DODSFilter::DODSFilter(int argc, char *argv[]) throw(Error) 00174 { 00175 initialize(argc, argv); 00176 00177 DBG(cerr << "d_comp: " << d_comp << endl); 00178 DBG(cerr << "d_ce: " << d_ce << endl); 00179 DBG(cerr << "d_cgi_ver: " << d_cgi_ver << endl); 00180 DBG(cerr << "d_response: " << d_response << endl); 00181 DBG(cerr << "d_anc_dir: " << d_anc_dir << endl); 00182 DBG(cerr << "d_anc_file: " << d_anc_file << endl); 00183 DBG(cerr << "d_cache_dir: " << d_cache_dir << endl); 00184 DBG(cerr << "d_conditional_request: " << d_conditional_request << endl); 00185 DBG(cerr << "d_if_modified_since: " << d_if_modified_since << endl); 00186 DBG(cerr << "d_url: " << d_url << endl); 00187 DBG(cerr << "d_timeout: " << d_timeout << endl); 00188 } 00189 00190 DODSFilter::~DODSFilter() 00191 { 00192 } 00193 00196 void 00197 DODSFilter::initialize() 00198 { 00199 // Set default values. Don't use the C++ constructor initialization so 00200 // that a subclass can have more control over this process. 00201 d_comp = false; 00202 d_bad_options = false; 00203 d_conditional_request = false; 00204 d_dataset = ""; 00205 d_ce = ""; 00206 d_cgi_ver = ""; 00207 d_anc_dir = ""; 00208 d_anc_file = ""; 00209 d_cache_dir = ""; 00210 d_response = Unknown_Response;; 00211 d_anc_das_lmt = 0; 00212 d_anc_dds_lmt = 0; 00213 d_if_modified_since = -1; 00214 d_url = ""; 00215 d_program_name = "Unknown"; 00216 d_timeout = 0; 00217 00218 #ifdef WIN32 00219 // We want serving from win32 to behave in a manner 00220 // similar to the UNIX way - no CR->NL terminated lines 00221 // in files. Hence stdout goes to binary mode. 00222 _setmode(_fileno(stdout), _O_BINARY); 00223 #endif 00224 } 00225 00237 void 00238 DODSFilter::initialize(int argc, char *argv[]) 00239 { 00240 initialize(); 00241 00242 d_program_name = argv[0]; 00243 00244 // This should be specialized by a subclass. This may throw Error. 00245 int next_arg = process_options(argc, argv); 00246 00247 // Look at what's left after processing the command line options. Either 00248 // there MUST be a dataset name OR the caller is asking for version 00249 // information. If neither is true, then the options are bad. 00250 if (next_arg < argc) { 00251 d_dataset = argv[next_arg]; 00252 d_dataset = www2id(d_dataset, "%", "%20"); 00253 } 00254 else if (get_response() != Version_Response) 00255 print_usage(); // Throws Error 00256 } 00257 00266 int 00267 DODSFilter::process_options(int argc, char *argv[]) 00268 { 00269 DBG(cerr << "Entering process_options... "); 00270 00271 int option_char; 00272 GetOpt getopt (argc, argv, "ce: v: d: f: r: l: o: u: t: "); 00273 00274 while ((option_char = getopt()) != EOF) { 00275 switch (option_char) { 00276 case 'c': d_comp = true; break; 00277 case 'e': set_ce(getopt.optarg); break; 00278 case 'v': set_cgi_version(getopt.optarg); break; 00279 case 'd': d_anc_dir = getopt.optarg; break; 00280 case 'f': d_anc_file = getopt.optarg; break; 00281 case 'r': d_cache_dir = getopt.optarg; break; 00282 case 'o': set_response(getopt.optarg); break; 00283 case 'u': set_URL(getopt.optarg); break; 00284 case 't': d_timeout = atoi(getopt.optarg); break; 00285 case 'l': 00286 d_conditional_request = true; 00287 d_if_modified_since 00288 = static_cast<time_t>(strtol(getopt.optarg, NULL, 10)); 00289 break; 00290 case 'h': print_usage(); exit(1); 00291 default: print_usage(); // Throws Error 00292 } 00293 } 00294 00295 DBGN(cerr << "exiting." << endl); 00296 00297 return getopt.optind; // return the index of the next argument 00298 } 00299 00304 bool 00305 DODSFilter::is_conditional() const 00306 { 00307 return d_conditional_request; 00308 } 00309 00323 void 00324 DODSFilter::set_cgi_version(string version) 00325 { 00326 d_cgi_ver = version; 00327 } 00328 00334 string 00335 DODSFilter::get_cgi_version() const 00336 { 00337 return d_cgi_ver; 00338 } 00339 00346 string 00347 DODSFilter::get_ce() const 00348 { 00349 return d_ce; 00350 } 00351 00352 void 00353 DODSFilter::set_ce(string _ce) 00354 { 00355 d_ce = www2id(_ce, "%", "%20"); 00356 } 00357 00366 string 00367 DODSFilter::get_dataset_name() const 00368 { 00369 return d_dataset; 00370 } 00371 00372 void 00373 DODSFilter::set_dataset_name(const string ds) 00374 { 00375 d_dataset = www2id(ds, "%", "%20"); 00376 } 00377 00381 string 00382 DODSFilter::get_URL() const 00383 { 00384 return d_url; 00385 } 00386 00389 void 00390 DODSFilter::set_URL(const string &url) 00391 { 00392 if (url.find('?') != url.npos) 00393 print_usage(); // Throws Error 00394 00395 d_url = url; 00396 } 00397 00405 string 00406 DODSFilter::get_dataset_version() const 00407 { 00408 return ""; 00409 } 00410 00417 void DODSFilter::set_response(const string &r) 00418 { 00419 if (r == "DAS" || r == "das") { 00420 d_response = DAS_Response; 00421 d_action = "das" ; 00422 } 00423 else if (r == "DDS" || r == "dds") { 00424 d_response = DDS_Response; 00425 d_action = "dds" ; 00426 } 00427 else if (r == "DataDDS" || r == "dods") { 00428 d_response = DataDDS_Response; 00429 d_action = "dods" ; 00430 } 00431 else if (r == "DDX" || r == "ddx") { 00432 d_response = DDX_Response; 00433 d_action = "ddx" ; 00434 } 00435 else if (r == "Version") { 00436 d_response = Version_Response; 00437 d_action = "version" ; 00438 } 00439 else 00440 print_usage(); // Throws Error 00441 } 00442 00444 DODSFilter::Response 00445 DODSFilter::get_response() const 00446 { 00447 return d_response; 00448 } 00449 00451 string DODSFilter::get_action() const 00452 { 00453 return d_action; 00454 } 00455 00476 time_t 00477 DODSFilter::get_dataset_last_modified_time() const 00478 { 00479 return last_modified_time(d_dataset); 00480 } 00481 00491 time_t 00492 DODSFilter::get_das_last_modified_time(const string &anc_location) const 00493 { 00494 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location=" 00495 << anc_location << "call faf(das) d_dataset=" << d_dataset 00496 << " d_anc_file=" << d_anc_file << endl); 00497 00498 string name 00499 = Ancillary::find_ancillary_file(d_dataset, "das", 00500 (anc_location == "") ? d_anc_dir : anc_location, 00501 d_anc_file); 00502 00503 return max((name != "") ? last_modified_time(name) : 0, 00504 get_dataset_last_modified_time()); 00505 } 00506 00514 time_t 00515 DODSFilter::get_dds_last_modified_time(const string &anc_location) const 00516 { 00517 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location=" 00518 << anc_location << "call faf(dds) d_dataset=" << d_dataset 00519 << " d_anc_file=" << d_anc_file << endl); 00520 00521 string name 00522 = Ancillary::find_ancillary_file(d_dataset, "dds", 00523 (anc_location == "") ? d_anc_dir : anc_location, 00524 d_anc_file); 00525 00526 return max((name != "") ? last_modified_time(name) : 0, 00527 get_dataset_last_modified_time()); 00528 } 00529 00543 time_t 00544 DODSFilter::get_data_last_modified_time(const string &anc_location) const 00545 { 00546 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location=" 00547 << anc_location << "call faf(both) d_dataset=" << d_dataset 00548 << " d_anc_file=" << d_anc_file << endl); 00549 00550 string dds_name 00551 = Ancillary::find_ancillary_file(d_dataset, "dds", 00552 (anc_location == "") ? d_anc_dir : anc_location, 00553 d_anc_file); 00554 string das_name 00555 = Ancillary::find_ancillary_file(d_dataset, "das", 00556 (anc_location == "") ? d_anc_dir : anc_location, 00557 d_anc_file); 00558 00559 time_t m = max((das_name != "") ? last_modified_time(das_name) : (time_t)0, 00560 (dds_name != "") ? last_modified_time(dds_name) : (time_t)0); 00561 // Note that this is a call to get_dataset_... not get_data_... 00562 time_t n = get_dataset_last_modified_time(); 00563 00564 return max(m, n); 00565 } 00566 00574 time_t 00575 DODSFilter::get_request_if_modified_since() const 00576 { 00577 return d_if_modified_since; 00578 } 00579 00586 string 00587 DODSFilter::get_cache_dir() const 00588 { 00589 return d_cache_dir; 00590 } 00591 00596 void 00597 DODSFilter::set_timeout(int t) 00598 { 00599 d_timeout = t; 00600 } 00601 00603 int 00604 DODSFilter::get_timeout() const 00605 { 00606 return d_timeout; 00607 } 00608 00609 //#if FILE_METHODS 00621 void 00622 DODSFilter::establish_timeout(FILE *stream) const 00623 { 00624 #ifndef WIN32 00625 if (d_timeout > 0) { 00626 SignalHandler *sh = SignalHandler::instance(); 00627 EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream)); 00628 delete old_eh; 00629 alarm(d_timeout); 00630 } 00631 #endif 00632 } 00633 //#endif 00634 00635 // FIXME 00636 void 00637 DODSFilter::establish_timeout(ostream &stream) const 00638 { 00639 #ifndef WIN32 00640 if (d_timeout > 0) { 00641 SignalHandler *sh = SignalHandler::instance(); 00642 EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream)); 00643 delete old_eh; 00644 alarm(d_timeout); 00645 } 00646 #endif 00647 } 00648 00649 00659 void 00660 DODSFilter::read_ancillary_das(DAS &das, const string &anc_location) const 00661 { 00662 Ancillary::read_ancillary_das( das, d_dataset, 00663 (anc_location == "") ? d_anc_dir : anc_location, 00664 d_anc_file); 00665 } 00666 00676 void 00677 DODSFilter::read_ancillary_dds(DDS &dds, const string &anc_location) const 00678 { 00679 Ancillary::read_ancillary_dds( dds, d_dataset, 00680 (anc_location == "") ? d_anc_dir : anc_location, 00681 d_anc_file); 00682 } 00683 00684 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."; 00685 00695 void 00696 DODSFilter::print_usage() const 00697 { 00698 // Write a message to the WWW server error log file. 00699 ErrMsgT(usage.c_str()); 00700 00701 throw Error(unknown_error, emessage); 00702 } 00703 00709 void 00710 DODSFilter::send_version_info() const 00711 { 00712 do_version(d_cgi_ver, get_dataset_version()); 00713 } 00714 00715 //#if FILE_METHODS 00727 void 00728 DODSFilter::send_das(FILE *out, DAS &das, const string &anc_location, 00729 bool with_mime_headers) const 00730 { 00731 time_t das_lmt = get_das_last_modified_time(anc_location); 00732 if (is_conditional() 00733 && das_lmt <= get_request_if_modified_since() 00734 && with_mime_headers) { 00735 set_mime_not_modified(out); 00736 } 00737 else { 00738 if (with_mime_headers) 00739 set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt); 00740 das.print(out); 00741 } 00742 fflush(out) ; 00743 } 00744 //#endif 00756 void 00757 DODSFilter::send_das(ostream &out, DAS &das, const string &anc_location, 00758 bool with_mime_headers) const 00759 { 00760 time_t das_lmt = get_das_last_modified_time(anc_location); 00761 if (is_conditional() 00762 && das_lmt <= get_request_if_modified_since() 00763 && with_mime_headers) { 00764 set_mime_not_modified(out); 00765 } 00766 else { 00767 if (with_mime_headers) 00768 set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt); 00769 das.print(out); 00770 } 00771 out << flush ; 00772 } 00773 00774 void 00775 DODSFilter::send_das(DAS &das, const string &anc_location, 00776 bool with_mime_headers) const 00777 { 00778 send_das(cout, das, anc_location, with_mime_headers); 00779 } 00780 00781 //#if FILE_METHODS 00798 void 00799 DODSFilter::send_dds(FILE *out, DDS &dds, ConstraintEvaluator &eval, 00800 bool constrained, 00801 const string &anc_location, 00802 bool with_mime_headers) const 00803 { 00804 // If constrained, parse the constraint. Throws Error or InternalErr. 00805 if (constrained) 00806 eval.parse_constraint(d_ce, dds); 00807 00808 if (eval.functional_expression()) 00809 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."); 00810 00811 time_t dds_lmt = get_dds_last_modified_time(anc_location); 00812 if (is_conditional() 00813 && dds_lmt <= get_request_if_modified_since() 00814 && with_mime_headers) { 00815 set_mime_not_modified(out); 00816 } 00817 else { 00818 if (with_mime_headers) 00819 set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt); 00820 if (constrained) 00821 dds.print_constrained(out); 00822 else 00823 dds.print(out); 00824 } 00825 00826 fflush(out) ; 00827 } 00828 //#endif 00845 void 00846 DODSFilter::send_dds(ostream &out, DDS &dds, ConstraintEvaluator &eval, 00847 bool constrained, 00848 const string &anc_location, 00849 bool with_mime_headers) const 00850 { 00851 // If constrained, parse the constraint. Throws Error or InternalErr. 00852 if (constrained) 00853 eval.parse_constraint(d_ce, dds); 00854 00855 if (eval.functional_expression()) 00856 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."); 00857 00858 time_t dds_lmt = get_dds_last_modified_time(anc_location); 00859 if (is_conditional() 00860 && dds_lmt <= get_request_if_modified_since() 00861 && with_mime_headers) { 00862 set_mime_not_modified(out); 00863 } 00864 else { 00865 if (with_mime_headers) 00866 set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt); 00867 if (constrained) 00868 dds.print_constrained(out); 00869 else 00870 dds.print(out); 00871 } 00872 00873 out << flush ; 00874 } 00875 00876 void 00877 DODSFilter::send_dds(DDS &dds, ConstraintEvaluator &eval, 00878 bool constrained, const string &anc_location, 00879 bool with_mime_headers) const 00880 { 00881 send_dds(cout, dds, eval, constrained, anc_location, with_mime_headers); 00882 } 00883 00884 //#if FILE_METHODS 00885 // 'lmt' unused. Should it be used to supply a LMT or removed from the 00886 // method? jhrg 8/9/05 00887 void 00888 DODSFilter::functional_constraint(BaseType &var, DDS &dds, 00889 ConstraintEvaluator &eval, FILE *out) const 00890 { 00891 fprintf(out, "Dataset {\n"); 00892 var.print_decl(out, " ", true, false, true); 00893 fprintf(out, "} function_value;\n"); 00894 fprintf(out, "Data:\n"); 00895 00896 fflush(out); 00897 00898 // Grab a stream encodes using XDR. 00899 XDRFileMarshaller m( out ) ; 00900 00901 try { 00902 // In the following call to serialize, suppress CE evaluation. 00903 var.serialize(eval, dds, m, false); 00904 } 00905 catch (Error &e) { 00906 throw; 00907 } 00908 } 00909 //#endif 00910 // 'lmt' unused. Should it be used to supply a LMT or removed from the 00911 // method? jhrg 8/9/05 00912 void 00913 DODSFilter::functional_constraint(BaseType &var, DDS &dds, 00914 ConstraintEvaluator &eval, ostream &out) const 00915 { 00916 out << "Dataset {\n" ; 00917 var.print_decl(out, " ", true, false, true); 00918 out << "} function_value;\n" ; 00919 out << "Data:\n" ; 00920 00921 out << flush ; 00922 00923 // Grab a stream encodes using XDR. 00924 XDRStreamMarshaller m( out ) ; 00925 00926 try { 00927 // In the following call to serialize, suppress CE evaluation. 00928 var.serialize(eval, dds, m, false); 00929 } 00930 catch (Error &e) { 00931 throw; 00932 } 00933 } 00934 //#if FILE_METHODS 00935 void 00936 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval, 00937 FILE * out) const 00938 { 00939 // send constrained DDS 00940 dds.print_constrained(out); 00941 fprintf(out, "Data:\n"); 00942 fflush(out); 00943 00944 // Grab a stream that encodes using XDR. 00945 XDRFileMarshaller 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, true); 00953 } 00954 } 00955 catch (Error & e) { 00956 throw; 00957 } 00958 } 00959 //#endif 00960 00961 void 00962 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval, 00963 ostream &out) const 00964 { 00965 // send constrained DDS 00966 dds.print_constrained(out); 00967 out << "Data:\n" ; 00968 out << flush ; 00969 00970 // Grab a stream that encodes using XDR. 00971 XDRStreamMarshaller m( out ) ; 00972 00973 try { 00974 // Send all variables in the current projection (send_p()) 00975 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++) 00976 if ((*i)->send_p()) { 00977 DBG(cerr << "Sending " << (*i)->name() << endl); 00978 (*i)->serialize(eval, dds, m, true); 00979 } 00980 } 00981 catch (Error & e) { 00982 throw; 00983 } 00984 } 00985 //#if FILE_METHODS 01002 void 01003 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval, 01004 FILE * data_stream, const string & anc_location, 01005 bool with_mime_headers) const 01006 { 01007 // If this is a conditional request and the server should send a 304 01008 // response, do that and exit. Otherwise, continue on and send the full 01009 // response. 01010 time_t data_lmt = get_data_last_modified_time(anc_location); 01011 if (is_conditional() 01012 && data_lmt <= get_request_if_modified_since() 01013 && with_mime_headers) { 01014 set_mime_not_modified(data_stream); 01015 return; 01016 } 01017 // Set up the alarm. 01018 establish_timeout(data_stream); 01019 dds.set_timeout(d_timeout); 01020 01021 eval.parse_constraint(d_ce, dds); // Throws Error if the ce doesn't 01022 // parse. 01023 01024 dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node. 01025 01026 // Start sending the response... 01027 #if COMPRESSION_FOR_SERVER3 01028 bool compress = d_comp && deflate_exists(); 01029 #endif 01030 01031 // Handle *functional* constraint expressions specially 01032 if (eval.functional_expression()) { 01033 // Get the result and then start sending the headers. This provides a 01034 // way to send errors back to the client w/o colliding with the 01035 // normal response headers. There's some duplication of code with this 01036 // and the else-clause. 01037 BaseType *var = eval.eval_function(dds, d_dataset); 01038 if (!var) 01039 throw Error(unknown_error, "Error calling the CE function."); 01040 01041 #if COMPRESSION_FOR_SERVER3 01042 if (with_mime_headers) 01043 set_mime_binary(data_stream, dods_data, d_cgi_ver, 01044 (compress) ? deflate : x_plain, data_lmt); 01045 fflush(data_stream); 01046 01047 int childpid; 01048 if (compress) 01049 data_stream = compressor(data_stream, childpid); 01050 #endif 01051 if (with_mime_headers) 01052 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01053 01054 fflush(data_stream); 01055 01056 functional_constraint(*var, dds, eval, data_stream); 01057 delete var; 01058 var = 0; 01059 } 01060 else { 01061 #if COMPRESSION_FOR_SERVER3 01062 if (with_mime_headers) 01063 set_mime_binary(data_stream, dods_data, d_cgi_ver, 01064 (compress) ? deflate : x_plain, data_lmt); 01065 fflush(data_stream); 01066 01067 int childpid; 01068 if (compress) 01069 data_stream = compressor(data_stream, childpid); 01070 #endif 01071 if (with_mime_headers) 01072 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01073 01074 dataset_constraint(dds, eval, data_stream); 01075 } 01076 01077 fflush(data_stream); 01078 } 01079 //#endif 01096 void 01097 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval, 01098 ostream & data_stream, const string & anc_location, 01099 bool with_mime_headers) const 01100 { 01101 // If this is a conditional request and the server should send a 304 01102 // response, do that and exit. Otherwise, continue on and send the full 01103 // response. 01104 time_t data_lmt = get_data_last_modified_time(anc_location); 01105 if (is_conditional() 01106 && data_lmt <= get_request_if_modified_since() 01107 && with_mime_headers) { 01108 set_mime_not_modified(data_stream); 01109 return; 01110 } 01111 // Set up the alarm. 01112 establish_timeout(data_stream); 01113 dds.set_timeout(d_timeout); 01114 01115 eval.parse_constraint(d_ce, dds); // Throws Error if the ce doesn't 01116 // parse. 01117 01118 dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node. 01119 01120 // Start sending the response... 01121 #if COMPRESSION_FOR_SERVER3 01122 bool compress = d_comp && deflate_exists(); 01123 #endif 01124 01125 // Handle *functional* constraint expressions specially 01126 if (eval.functional_expression()) { 01127 // Get the result and then start sending the headers. This provides a 01128 // way to send errors back to the client w/o colliding with the 01129 // normal response headers. There's some duplication of code with this 01130 // and the else-clause. 01131 BaseType *var = eval.eval_function(dds, d_dataset); 01132 if (!var) 01133 throw Error(unknown_error, "Error calling the CE function."); 01134 01135 #if COMPRESSION_FOR_SERVER3 01136 if (with_mime_headers) 01137 set_mime_binary(data_stream, dods_data, d_cgi_ver, 01138 (compress) ? deflate : x_plain, data_lmt); 01139 data_stream << flush ; 01140 01141 int childpid; 01142 if (compress) 01143 data_stream = compressor(data_stream, childpid); 01144 #endif 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 else { 01155 #if COMPRESSION_FOR_SERVER3 01156 if (with_mime_headers) 01157 set_mime_binary(data_stream, dods_data, d_cgi_ver, 01158 (compress) ? deflate : x_plain, data_lmt); 01159 data_stream << flush ; 01160 01161 int childpid; 01162 if (compress) 01163 data_stream = compressor(data_stream, childpid); 01164 #endif 01165 if (with_mime_headers) 01166 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt); 01167 01168 dataset_constraint(dds, eval, data_stream); 01169 } 01170 01171 data_stream << flush ; 01172 } 01173 01174 //#if FILE_METHODS 01185 void 01186 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out, 01187 bool with_mime_headers) const 01188 { 01189 // If constrained, parse the constraint. Throws Error or InternalErr. 01190 if (!d_ce.empty()) 01191 eval.parse_constraint(d_ce, dds); 01192 01193 if (eval.functional_expression()) 01194 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."); 01195 01196 time_t dds_lmt = get_dds_last_modified_time(d_anc_dir); 01197 01198 // If this is a conditional request and the server should send a 304 01199 // response, do that and exit. Otherwise, continue on and send the full 01200 // response. 01201 if (is_conditional() && dds_lmt <= get_request_if_modified_since() 01202 && with_mime_headers) { 01203 set_mime_not_modified(out); 01204 return; 01205 } 01206 else { 01207 if (with_mime_headers) 01208 set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt); 01209 dds.print_xml(out, !d_ce.empty(), d_url + ".blob?" + d_ce); 01210 } 01211 } 01212 //#endif 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(), d_url + ".blob?" + d_ce); 01248 } 01249 } 01250 //#if FILE_METHODS 01255 void 01256 DODSFilter::send_blob(DDS &, FILE *, bool) 01257 { 01258 #if 0 01259 // Broken. jhrg 4/3/06 01260 bool compress = d_comp && deflate_exists(); 01261 time_t data_lmt = get_data_last_modified_time(d_anc_dir); 01262 01263 // If this is a conditional request and the server should send a 304 01264 // response, do that and exit. Otherwise, continue on and send the full 01265 // response. 01266 if (is_conditional() && data_lmt <= get_request_if_modified_since() 01267 && with_mime_headers) { 01268 set_mime_not_modified(out); 01269 return; 01270 } 01271 01272 dds.parse_constraint(d_ce); 01273 01274 // Handle *functional* constraint expressions specially 01275 if (dds.functional_expression()) { 01276 BaseType *var = dds.eval_function(d_dataset); 01277 if (!var) 01278 throw Error("Error calling the CE function."); 01279 01280 if (with_mime_headers) 01281 set_mime_binary(out, dods_data, d_cgi_ver, 01282 (compress) ? deflate : x_plain, data_lmt); 01283 01284 FILE *comp_sink; 01285 XDR *xdr_sink; 01286 int childpid = get_sinks(out, compress, &comp_sink, &xdr_sink); 01287 01288 // In the following call to serialize, suppress CE evaluation. 01289 if (!var->serialize(d_dataset, dds, xdr_sink, false)) 01290 throw Error("Could not send the function result."); 01291 01292 clean_sinks(childpid, compress, xdr_sink, comp_sink); 01293 } 01294 else { 01295 if (with_mime_headers) 01296 set_mime_binary(out, dods_data, d_cgi_ver, 01297 (compress) ? deflate : x_plain, data_lmt); 01298 01299 FILE *comp_sink; 01300 XDR *xdr_sink; 01301 int childpid = get_sinks(out, compress, &comp_sink, &xdr_sink); 01302 01303 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++) 01304 if ((*i)->send_p()) // only process projected variables 01305 if (!(*i)->serialize(d_dataset, dds, xdr_sink, true)) 01306 throw Error(string("Could not serialize variable '") 01307 + (*i)->name() + string("'.")); 01308 01309 clean_sinks(childpid, compress, xdr_sink, comp_sink); 01310 } 01311 #endif 01312 } 01313 //#endif 01314 } // namespace libdap 01315