libdap++  Updated for version 3.8.2
DODSFilter.cc
Go to the documentation of this file.
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