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 23477 2010-09-02 21:02:59Z jimg $"
00041     };
00042 
00043 #include <signal.h>
00044 
00045 #ifndef WIN32
00046 #include <unistd.h>   // for getopt
00047 #include <sys/wait.h>
00048 #else
00049 #include <io.h>
00050 #include <fcntl.h>
00051 #include <process.h>
00052 #endif
00053 
00054 #include <iostream>
00055 #include <string>
00056 #include <algorithm>
00057 #include <cstdlib>
00058 #include <cstring>
00059 
00060 #include <uuid/uuid.h>  // used to build CID header value for data ddx
00061 
00062 #include <GetOpt.h>
00063 
00064 #include "DAS.h"
00065 #include "DDS.h"
00066 #include "debug.h"
00067 #include "mime_util.h"
00068 #include "Ancillary.h"
00069 #include "util.h"
00070 #include "escaping.h"
00071 #include "DODSFilter.h"
00072 #if FILE_METHODS
00073 #include "XDRFileMarshaller.h"
00074 #endif
00075 #include "XDRStreamMarshaller.h"
00076 #include "InternalErr.h"
00077 
00078 #ifndef WIN32
00079 #include "SignalHandler.h"
00080 #include "EventHandler.h"
00081 #include "AlarmHandler.h"
00082 #endif
00083 
00084 #define CRLF "\r\n"             // Change here, expr-test.cc and DODSFilter.cc
00085 
00086 //#undef FILE_METHODS
00087 
00088 using namespace std;
00089 
00090 namespace libdap {
00091 
00092 const string usage =
00093     "Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\
00094     \n\
00095     options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\
00096     -u <url>: The complete URL minus the CE (required for DDX)\n\
00097     -c: Compress the response using the deflate algorithm.\n\
00098     -e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\
00099     -v <version>: Use <version> as the version number\n\
00100     -d <dir>: Look for ancillary file in <dir> (deprecated).\n\
00101     -f <file>: Look for ancillary data in <file> (deprecated).\n\
00102     -r <dir>: Use <dir> as a cache directory\n\
00103     -l <time>: Conditional request; if data source is unchanged since\n\
00104     <time>, return an HTTP 304 response.\n\
00105     -t <seconds>: Timeout the handler after <seconds>.\n\
00106     -h: This message.";
00107 
00172 DODSFilter::DODSFilter(int argc, char *argv[]) throw(Error)
00173 {
00174     initialize(argc, argv);
00175 
00176     DBG(cerr << "d_comp: " << d_comp << endl);
00177     DBG(cerr << "d_ce: " << d_ce << endl);
00178     DBG(cerr << "d_cgi_ver: " << d_cgi_ver << endl);
00179     DBG(cerr << "d_response: " << d_response << endl);
00180     DBG(cerr << "d_anc_dir: " << d_anc_dir << endl);
00181     DBG(cerr << "d_anc_file: " << d_anc_file << endl);
00182     DBG(cerr << "d_cache_dir: " << d_cache_dir << endl);
00183     DBG(cerr << "d_conditional_request: " << d_conditional_request << endl);
00184     DBG(cerr << "d_if_modified_since: " << d_if_modified_since << endl);
00185     DBG(cerr << "d_url: " << d_url << endl);
00186     DBG(cerr << "d_timeout: " << d_timeout << endl);
00187 }
00188 
00189 DODSFilter::~DODSFilter()
00190 {
00191 }
00192 
00195 void
00196 DODSFilter::initialize()
00197 {
00198     // Set default values. Don't use the C++ constructor initialization so
00199     // that a subclass can have more control over this process.
00200     d_comp = false;
00201     d_bad_options = false;
00202     d_conditional_request = false;
00203     d_dataset = "";
00204     d_ce = "";
00205     d_cgi_ver = "";
00206     d_anc_dir = "";
00207     d_anc_file = "";
00208     d_cache_dir = "";
00209     d_response = Unknown_Response;;
00210     d_anc_das_lmt = 0;
00211     d_anc_dds_lmt = 0;
00212     d_if_modified_since = -1;
00213     d_url = "";
00214     d_program_name = "Unknown";
00215     d_timeout = 0;
00216 
00217 #ifdef WIN32
00218     //  We want serving from win32 to behave in a manner
00219     //  similar to the UNIX way - no CR->NL terminated lines
00220     //  in files. Hence stdout goes to binary mode.
00221     _setmode(_fileno(stdout), _O_BINARY);
00222 #endif
00223 }
00224 
00236 void
00237 DODSFilter::initialize(int argc, char *argv[])
00238 {
00239     initialize();
00240 
00241     d_program_name = argv[0];
00242 
00243     // This should be specialized by a subclass. This may throw Error.
00244     int next_arg = process_options(argc, argv);
00245 
00246     // Look at what's left after processing the command line options. Either
00247     // there MUST be a dataset name OR the caller is asking for version
00248     // information. If neither is true, then the options are bad.
00249     if (next_arg < argc) {
00250         d_dataset = argv[next_arg];
00251         d_dataset = www2id(d_dataset, "%", "%20");
00252     }
00253     else if (get_response() != Version_Response)
00254         print_usage();   // Throws Error
00255 }
00256 
00265 int
00266 DODSFilter::process_options(int argc, char *argv[])
00267 {
00268     DBG(cerr << "Entering process_options... ");
00269 
00270     int option_char;
00271     GetOpt getopt (argc, argv, "ce: v: d: f: r: l: o: u: t: ");
00272 
00273     while ((option_char = getopt()) != EOF) {
00274         switch (option_char) {
00275         case 'c': d_comp = true; break;
00276         case 'e': set_ce(getopt.optarg); break;
00277         case 'v': set_cgi_version(getopt.optarg); break;
00278         case 'd': d_anc_dir = getopt.optarg; break;
00279         case 'f': d_anc_file = getopt.optarg; break;
00280         case 'r': d_cache_dir = getopt.optarg; break;
00281         case 'o': set_response(getopt.optarg); break;
00282         case 'u': set_URL(getopt.optarg); break;
00283         case 't': d_timeout = atoi(getopt.optarg); break;
00284         case 'l':
00285             d_conditional_request = true;
00286             d_if_modified_since
00287             = static_cast<time_t>(strtol(getopt.optarg, NULL, 10));
00288             break;
00289         case 'h': print_usage(); exit(1);
00290         default: print_usage(); // Throws Error
00291         }
00292     }
00293 
00294     DBGN(cerr << "exiting." << endl);
00295 
00296     return getopt.optind; // return the index of the next argument
00297 }
00298 
00303 bool
00304 DODSFilter::is_conditional() const
00305 {
00306     return d_conditional_request;
00307 }
00308 
00322 void
00323 DODSFilter::set_cgi_version(string version)
00324 {
00325     d_cgi_ver = version;
00326 }
00327 
00333 string
00334 DODSFilter::get_cgi_version() const
00335 {
00336     return d_cgi_ver;
00337 }
00338 
00345 string
00346 DODSFilter::get_ce() const
00347 {
00348     return d_ce;
00349 }
00350 
00351 void
00352 DODSFilter::set_ce(string _ce)
00353 {
00354     d_ce = www2id(_ce, "%", "%20");
00355 }
00356 
00365 string
00366 DODSFilter::get_dataset_name() const
00367 {
00368     return d_dataset;
00369 }
00370 
00371 void
00372 DODSFilter::set_dataset_name(const string ds)
00373 {
00374     d_dataset = www2id(ds, "%", "%20");
00375 }
00376 
00380 string
00381 DODSFilter::get_URL() const
00382 {
00383     return d_url;
00384 }
00385 
00388 void
00389 DODSFilter::set_URL(const string &url)
00390 {
00391     if (url.find('?') != url.npos)
00392         print_usage();  // Throws Error
00393 
00394     d_url = url;
00395 }
00396 
00404 string
00405 DODSFilter::get_dataset_version() const
00406 {
00407     return "";
00408 }
00409 
00416 void DODSFilter::set_response(const string &r)
00417 {
00418     if (r == "DAS" || r == "das") {
00419         d_response = DAS_Response;
00420         d_action = "das" ;
00421     }
00422     else if (r == "DDS" || r == "dds") {
00423         d_response = DDS_Response;
00424         d_action = "dds" ;
00425     }
00426     else if (r == "DataDDS" || r == "dods") {
00427         d_response = DataDDS_Response;
00428         d_action = "dods" ;
00429     }
00430     else if (r == "DDX" || r == "ddx") {
00431         d_response = DDX_Response;
00432         d_action = "ddx" ;
00433     }
00434     else if (r == "DataDDX" || r == "dataddx") {
00435         d_response = DataDDX_Response;
00436         d_action = "dataddx" ;
00437     }
00438     else if (r == "Version") {
00439         d_response = Version_Response;
00440         d_action = "version" ;
00441     }
00442     else
00443         print_usage();   // Throws Error
00444 }
00445 
00447 DODSFilter::Response
00448 DODSFilter::get_response() const
00449 {
00450     return d_response;
00451 }
00452 
00454 string DODSFilter::get_action() const
00455 {
00456     return d_action;
00457 }
00458 
00479 time_t
00480 DODSFilter::get_dataset_last_modified_time() const
00481 {
00482     return last_modified_time(d_dataset);
00483 }
00484 
00494 time_t
00495 DODSFilter::get_das_last_modified_time(const string &anc_location) const
00496 {
00497     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00498         << anc_location << "call faf(das) d_dataset=" << d_dataset
00499         << " d_anc_file=" << d_anc_file << endl);
00500 
00501     string name
00502     = Ancillary::find_ancillary_file(d_dataset, "das",
00503                           (anc_location == "") ? d_anc_dir : anc_location,
00504                           d_anc_file);
00505 
00506     return max((name != "") ? last_modified_time(name) : 0,
00507                get_dataset_last_modified_time());
00508 }
00509 
00517 time_t
00518 DODSFilter::get_dds_last_modified_time(const string &anc_location) const
00519 {
00520     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00521         << anc_location << "call faf(dds) d_dataset=" << d_dataset
00522         << " d_anc_file=" << d_anc_file << endl);
00523 
00524     string name
00525     = Ancillary::find_ancillary_file(d_dataset, "dds",
00526                           (anc_location == "") ? d_anc_dir : anc_location,
00527                           d_anc_file);
00528 
00529     return max((name != "") ? last_modified_time(name) : 0,
00530                get_dataset_last_modified_time());
00531 }
00532 
00546 time_t
00547 DODSFilter::get_data_last_modified_time(const string &anc_location) const
00548 {
00549     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00550         << anc_location << "call faf(both) d_dataset=" << d_dataset
00551         << " d_anc_file=" << d_anc_file << endl);
00552 
00553     string dds_name
00554     = Ancillary::find_ancillary_file(d_dataset, "dds",
00555                           (anc_location == "") ? d_anc_dir : anc_location,
00556                           d_anc_file);
00557     string das_name
00558     = Ancillary::find_ancillary_file(d_dataset, "das",
00559                           (anc_location == "") ? d_anc_dir : anc_location,
00560                           d_anc_file);
00561 
00562     time_t m = max((das_name != "") ? last_modified_time(das_name) : (time_t)0,
00563                    (dds_name != "") ? last_modified_time(dds_name) : (time_t)0);
00564     // Note that this is a call to get_dataset_... not get_data_...
00565     time_t n = get_dataset_last_modified_time();
00566 
00567     return max(m, n);
00568 }
00569 
00577 time_t
00578 DODSFilter::get_request_if_modified_since() const
00579 {
00580     return d_if_modified_since;
00581 }
00582 
00589 string
00590 DODSFilter::get_cache_dir() const
00591 {
00592     return d_cache_dir;
00593 }
00594 
00599 void
00600 DODSFilter::set_timeout(int t)
00601 {
00602     d_timeout = t;
00603 }
00604 
00606 int
00607 DODSFilter::get_timeout() const
00608 {
00609     return d_timeout;
00610 }
00611 
00612 #if FILE_METHODS
00613 
00624 void
00625 DODSFilter::establish_timeout(FILE *stream) const
00626 {
00627 #ifndef WIN32
00628     if (d_timeout > 0) {
00629         SignalHandler *sh = SignalHandler::instance();
00630         EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream));
00631         delete old_eh;
00632         alarm(d_timeout);
00633     }
00634 #endif
00635 }
00636 #endif
00637 
00638 // FIXME
00639 void
00640 DODSFilter::establish_timeout(ostream &stream) const
00641 {
00642 #ifndef WIN32
00643     if (d_timeout > 0) {
00644         SignalHandler *sh = SignalHandler::instance();
00645         EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream));
00646         delete old_eh;
00647         alarm(d_timeout);
00648     }
00649 #endif
00650 }
00651 
00652 static const char *emessage = "DODS internal server error; usage error. Please report this to the dataset maintainer, or to the opendap-tech@opendap.org mailing list.";
00653 
00663 void
00664 DODSFilter::print_usage() const
00665 {
00666     // Write a message to the WWW server error log file.
00667     ErrMsgT(usage.c_str());
00668 
00669     throw Error(unknown_error, emessage);
00670 }
00671 
00677 void
00678 DODSFilter::send_version_info() const
00679 {
00680     do_version(d_cgi_ver, get_dataset_version());
00681 }
00682 
00683 #if FILE_METHODS
00684 
00695 void
00696 DODSFilter::send_das(FILE *out, DAS &das, const string &anc_location,
00697                      bool with_mime_headers) const
00698 {
00699     time_t das_lmt = get_das_last_modified_time(anc_location);
00700     if (is_conditional()
00701         && das_lmt <= get_request_if_modified_since()
00702         && with_mime_headers) {
00703         set_mime_not_modified(out);
00704     }
00705     else {
00706         if (with_mime_headers)
00707             set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
00708         das.print(out);
00709     }
00710     fflush(out) ;
00711 }
00712 #endif
00713 
00725 void
00726 DODSFilter::send_das(ostream &out, DAS &das, const string &anc_location,
00727                      bool with_mime_headers) const
00728 {
00729     time_t das_lmt = get_das_last_modified_time(anc_location);
00730     if (is_conditional()
00731         && das_lmt <= get_request_if_modified_since()
00732         && with_mime_headers) {
00733         set_mime_not_modified(out);
00734     }
00735     else {
00736         if (with_mime_headers)
00737             set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
00738         das.print(out);
00739     }
00740     out << flush ;
00741 }
00742 
00743 void
00744 DODSFilter::send_das(DAS &das, const string &anc_location,
00745                      bool with_mime_headers) const
00746 {
00747     send_das(cout, das, anc_location, with_mime_headers);
00748 }
00749 
00750 #if FILE_METHODS
00751 
00767 void
00768 DODSFilter::send_dds(FILE *out, DDS &dds, ConstraintEvaluator &eval,
00769                      bool constrained,
00770                      const string &anc_location,
00771                      bool with_mime_headers) const
00772 {
00773     // If constrained, parse the constraint. Throws Error or InternalErr.
00774     if (constrained)
00775         eval.parse_constraint(d_ce, dds);
00776 
00777     if (eval.functional_expression())
00778         throw Error("Function calls can only be used with data requests. To see the structure of the underlying data source, reissue the URL without the function.");
00779 
00780     time_t dds_lmt = get_dds_last_modified_time(anc_location);
00781     if (is_conditional()
00782         && dds_lmt <= get_request_if_modified_since()
00783         && with_mime_headers) {
00784         set_mime_not_modified(out);
00785     }
00786     else {
00787         if (with_mime_headers)
00788             set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt);
00789         if (constrained)
00790             dds.print_constrained(out);
00791         else
00792             dds.print(out);
00793     }
00794 
00795     fflush(out) ;
00796 }
00797 #endif
00798 
00815 void
00816 DODSFilter::send_dds(ostream &out, DDS &dds, ConstraintEvaluator &eval,
00817                      bool constrained,
00818                      const string &anc_location,
00819                      bool with_mime_headers) const
00820 {
00821     // If constrained, parse the constraint. Throws Error or InternalErr.
00822     if (constrained)
00823         eval.parse_constraint(d_ce, dds);
00824 
00825     if (eval.functional_expression())
00826         throw Error("Function calls can only be used with data requests. To see the structure of the underlying data source, reissue the URL without the function.");
00827 
00828     time_t dds_lmt = get_dds_last_modified_time(anc_location);
00829     if (is_conditional()
00830         && dds_lmt <= get_request_if_modified_since()
00831         && with_mime_headers) {
00832         set_mime_not_modified(out);
00833     }
00834     else {
00835         if (with_mime_headers)
00836             set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt);
00837         if (constrained)
00838             dds.print_constrained(out);
00839         else
00840             dds.print(out);
00841     }
00842 
00843     out << flush ;
00844 }
00845 
00846 void
00847 DODSFilter::send_dds(DDS &dds, ConstraintEvaluator &eval,
00848                      bool constrained, const string &anc_location,
00849                      bool with_mime_headers) const
00850 {
00851     send_dds(cout, dds, eval, constrained, anc_location, with_mime_headers);
00852 }
00853 
00854 #if FILE_METHODS
00855 // 'lmt' unused. Should it be used to supply a LMT or removed from the
00856 // method? jhrg 8/9/05
00857 void
00858 DODSFilter::functional_constraint(BaseType &var, DDS &dds,
00859                                   ConstraintEvaluator &eval, FILE *out) const
00860 {
00861     fprintf(out, "Dataset {\n");
00862     var.print_decl(out, "    ", true, false, true);
00863     fprintf(out, "} function_value;\n");
00864     fprintf(out, "Data:\n");
00865 
00866     fflush(out);
00867 
00868     XDRFileMarshaller m( out ) ;
00869 
00870     try {
00871         // In the following call to serialize, suppress CE evaluation.
00872         var.serialize(eval, dds, m, false);
00873     }
00874     catch (Error &e) {
00875         throw;
00876     }
00877 }
00878 #endif
00879 
00880 // 'lmt' unused. Should it be used to supply a LMT or removed from the
00881 // method? jhrg 8/9/05
00882 void
00883 DODSFilter::functional_constraint(BaseType &var, DDS &dds,
00884                                   ConstraintEvaluator &eval, ostream &out) const
00885 {
00886     out << "Dataset {\n" ;
00887     var.print_decl(out, "    ", true, false, true);
00888     out << "} function_value;\n" ;
00889     out << "Data:\n" ;
00890 
00891     out << flush ;
00892 
00893     // Grab a stream that encodes using XDR.
00894     XDRStreamMarshaller m( out ) ;
00895 
00896     try {
00897         // In the following call to serialize, suppress CE evaluation.
00898         var.serialize(eval, dds, m, false);
00899     }
00900     catch (Error &e) {
00901         throw;
00902     }
00903 }
00904 
00905 #if FILE_METHODS
00906 void
00907 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
00908                                FILE * out, bool ce_eval) const
00909 {
00910     // send constrained DDS
00911     dds.print_constrained(out);
00912     fprintf(out, "Data:\n");
00913     fflush(out);
00914 
00915     // Grab a stream that encodes using XDR.
00916     XDRFileMarshaller m( out ) ;
00917 
00918     try {
00919         // Send all variables in the current projection (send_p())
00920         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
00921             if ((*i)->send_p()) {
00922                 DBG(cerr << "Sending " << (*i)->name() << endl);
00923                 (*i)->serialize(eval, dds, m, ce_eval);
00924             }
00925     }
00926     catch (Error & e) {
00927         throw;
00928     }
00929 }
00930 #endif
00931 
00932 void
00933 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
00934                                ostream &out, bool ce_eval) const
00935 {
00936     // send constrained DDS
00937     dds.print_constrained(out);
00938     out << "Data:\n" ;
00939     out << flush ;
00940 
00941     // Grab a stream that encodes using XDR.
00942     XDRStreamMarshaller m( out ) ;
00943 
00944     try {
00945         // Send all variables in the current projection (send_p())
00946         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
00947             if ((*i)->send_p()) {
00948                 DBG(cerr << "Sending " << (*i)->name() << endl);
00949                 (*i)->serialize(eval, dds, m, ce_eval);
00950             }
00951     }
00952     catch (Error & e) {
00953         throw;
00954     }
00955 }
00956 
00957 void
00958 DODSFilter::dataset_constraint_ddx(DDS & dds, ConstraintEvaluator & eval,
00959                                ostream &out, const string &boundary,
00960                                const string &start, bool ce_eval) const
00961 {
00962     // Write the MPM headers for the DDX (text/xml) part of the response
00963     set_mime_ddx_boundary(out, boundary, start, dap4_ddx);
00964 
00965     // Make cid
00966     uuid_t uu;
00967     uuid_generate(uu);
00968     char uuid[37];
00969     uuid_unparse(uu, &uuid[0]);
00970     char domain[256];
00971     if (getdomainname(domain, 255) != 0 || strlen(domain) == 0)
00972         strncpy(domain, "opendap.org", 255);
00973 
00974     string cid = string(&uuid[0]) + "@" + string(&domain[0]);
00975 
00976     // Send constrained DDX with a data blob reference
00977     dds.print_xml(out, true, cid);
00978 
00979     // Write the MPM headers for the data part of the response.
00980     set_mime_data_boundary(out, boundary, cid, dap4_data, binary);
00981 
00982     // Grab a stream that encodes using XDR.
00983     XDRStreamMarshaller m( out ) ;
00984 
00985     try {
00986         // Send all variables in the current projection (send_p())
00987         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
00988             if ((*i)->send_p()) {
00989                 DBG(cerr << "Sending " << (*i)->name() << endl);
00990                 (*i)->serialize(eval, dds, m, ce_eval);
00991             }
00992     }
00993     catch (Error & e) {
00994         throw;
00995     }
00996 }
00997 
00998 #if FILE_METHODS
00999 
01015 void
01016 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
01017                       FILE * data_stream, const string & anc_location,
01018                       bool with_mime_headers) const
01019 {
01020     // If this is a conditional request and the server should send a 304
01021     // response, do that and exit. Otherwise, continue on and send the full
01022     // response.
01023     time_t data_lmt = get_data_last_modified_time(anc_location);
01024     if (is_conditional()
01025         && data_lmt <= get_request_if_modified_since()
01026         && with_mime_headers) {
01027         set_mime_not_modified(data_stream);
01028         return;
01029     }
01030     // Set up the alarm.
01031     establish_timeout(data_stream);
01032     dds.set_timeout(d_timeout);
01033 
01034     eval.parse_constraint(d_ce, dds);   // Throws Error if the ce doesn't
01035                                         // parse.
01036 
01037     dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
01038 
01039     // Start sending the response...
01040 
01041     // Handle *functional* constraint expressions specially
01042 #if 0
01043     if (eval.functional_expression()) {
01044         // Get the result and then start sending the headers. This provides a
01045         // way to send errors back to the client w/o colliding with the
01046         // normal response headers. There's some duplication of code with this
01047         // and the else-clause.
01048         BaseType *var = eval.eval_function(dds, d_dataset);
01049         if (!var)
01050             throw Error(unknown_error, "Error calling the CE function.");
01051 
01052 #if COMPRESSION_FOR_SERVER3
01053         if (with_mime_headers)
01054             set_mime_binary(data_stream, dods_data, d_cgi_ver,
01055                             (compress) ? deflate : x_plain, data_lmt);
01056         fflush(data_stream);
01057 
01058         int childpid;
01059         if (compress)
01060             data_stream = compressor(data_stream, childpid);
01061 #endif
01062         if (with_mime_headers)
01063             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01064 
01065         fflush(data_stream);
01066 
01067         functional_constraint(*var, dds, eval, data_stream);
01068         delete var;
01069         var = 0;
01070     }
01071 #endif
01072     if (eval.function_clauses()) {
01073         DDS *fdds = eval.eval_function_clauses(dds);
01074 
01075         if (with_mime_headers)
01076             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01077 
01078         dataset_constraint(*fdds, eval, data_stream, false);
01079         delete fdds;
01080     }
01081     else {
01082         if (with_mime_headers)
01083             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01084 
01085         dataset_constraint(dds, eval, data_stream);
01086     }
01087 
01088     fflush(data_stream);
01089 }
01090 #endif
01091 
01108 void
01109 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
01110                       ostream & data_stream, const string & anc_location,
01111                       bool with_mime_headers) const
01112 {
01113     // If this is a conditional request and the server should send a 304
01114     // response, do that and exit. Otherwise, continue on and send the full
01115     // response.
01116     time_t data_lmt = get_data_last_modified_time(anc_location);
01117     if (is_conditional()
01118         && data_lmt <= get_request_if_modified_since()
01119         && with_mime_headers) {
01120         set_mime_not_modified(data_stream);
01121         return;
01122     }
01123     // Set up the alarm.
01124     establish_timeout(data_stream);
01125     dds.set_timeout(d_timeout);
01126 
01127     eval.parse_constraint(d_ce, dds);   // Throws Error if the ce doesn't
01128                                         // parse.
01129 
01130     dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
01131 
01132     // Start sending the response...
01133 
01134     // Handle *functional* constraint expressions specially
01135 #if 0
01136     if (eval.functional_expression()) {
01137         // Get the result and then start sending the headers. This provides a
01138         // way to send errors back to the client w/o colliding with the
01139         // normal response headers. There's some duplication of code with this
01140         // and the else-clause.
01141         BaseType *var = eval.eval_function(dds, d_dataset);
01142         if (!var)
01143             throw Error(unknown_error, "Error calling the CE function.");
01144 
01145        if (with_mime_headers)
01146             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01147 
01148         data_stream << flush ;
01149 
01150         functional_constraint(*var, dds, eval, data_stream);
01151         delete var;
01152         var = 0;
01153     }
01154 #endif
01155     if (eval.function_clauses()) {
01156         DDS *fdds = eval.eval_function_clauses(dds);
01157         if (with_mime_headers)
01158             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01159 
01160         dataset_constraint(*fdds, eval, data_stream, false);
01161         delete fdds;
01162     }
01163     else {
01164         if (with_mime_headers)
01165             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01166 
01167         dataset_constraint(dds, eval, data_stream);
01168     }
01169 
01170     data_stream << flush ;
01171 }
01172 
01173 #if FILE_METHODS
01174 
01184 void
01185 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out,
01186                      bool with_mime_headers) const
01187 {
01188     // If constrained, parse the constraint. Throws Error or InternalErr.
01189     if (!d_ce.empty())
01190         eval.parse_constraint(d_ce, dds);
01191 
01192     if (eval.functional_expression())
01193         throw Error("Function calls can only be used with data requests. To see the structure of the underlying data source, reissue the URL without the function.");
01194 
01195     time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
01196 
01197     // If this is a conditional request and the server should send a 304
01198     // response, do that and exit. Otherwise, continue on and send the full
01199     // response.
01200     if (is_conditional() && dds_lmt <= get_request_if_modified_since()
01201         && with_mime_headers) {
01202         set_mime_not_modified(out);
01203         return;
01204     }
01205     else {
01206         if (with_mime_headers)
01207             set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
01208         dds.print_xml(out, !d_ce.empty(), "");
01209     }
01210 }
01211 #endif
01212 
01223 void
01224 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, ostream &out,
01225                      bool with_mime_headers) const
01226 {
01227     // If constrained, parse the constraint. Throws Error or InternalErr.
01228     if (!d_ce.empty())
01229         eval.parse_constraint(d_ce, dds);
01230 
01231     if (eval.functional_expression())
01232         throw Error("Function calls can only be used with data requests. To see the structure of the underlying data source, reissue the URL without the function.");
01233 
01234     time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
01235 
01236     // If this is a conditional request and the server should send a 304
01237     // response, do that and exit. Otherwise, continue on and send the full
01238     // response.
01239     if (is_conditional() && dds_lmt <= get_request_if_modified_since()
01240         && with_mime_headers) {
01241         set_mime_not_modified(out);
01242         return;
01243     }
01244     else {
01245         if (with_mime_headers)
01246             set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
01247         dds.print_xml(out, !d_ce.empty(), "");
01248     }
01249 }
01250 
01267 void
01268 DODSFilter::send_data_ddx(DDS & dds, ConstraintEvaluator & eval,
01269                       ostream & data_stream, const string &start,
01270                       const string &boundary, const string & anc_location,
01271                       bool with_mime_headers) const
01272 {
01273     // If this is a conditional request and the server should send a 304
01274     // response, do that and exit. Otherwise, continue on and send the full
01275     // response.
01276     time_t data_lmt = get_data_last_modified_time(anc_location);
01277     if (is_conditional()
01278         && data_lmt <= get_request_if_modified_since()
01279         && with_mime_headers) {
01280         set_mime_not_modified(data_stream);
01281         return;
01282     }
01283     // Set up the alarm.
01284     establish_timeout(data_stream);
01285     dds.set_timeout(d_timeout);
01286 
01287     eval.parse_constraint(d_ce, dds);   // Throws Error if the ce doesn't
01288                                         // parse.
01289 
01290     dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
01291 
01292     // Start sending the response...
01293 
01294     // Handle *functional* constraint expressions specially
01295 #if 0
01296     if (eval.functional_expression()) {
01297         BaseType *var = eval.eval_function(dds, d_dataset);
01298         if (!var)
01299             throw Error(unknown_error, "Error calling the CE function.");
01300 
01301         if (with_mime_headers)
01302             set_mime_multipart(data_stream, boundary, start, dap4_data_ddx,
01303                 d_cgi_ver, x_plain, data_lmt);
01304         data_stream << flush ;
01305         BaseTypeFactory btf;
01306         DDS var_dds(&btf, var->name());
01307         var->set_send_p(true);
01308         var_dds.add_var(var);
01309         dataset_constraint_ddx(var_dds, eval, data_stream, boundary, start);
01310 
01311         // functional_constraint_ddx(*var, dds, eval, data_stream, boundary);
01312         delete var;
01313         var = 0;
01314     }
01315 #endif
01316     if (eval.function_clauses()) {
01317         DDS *fdds = eval.eval_function_clauses(dds);
01318         if (with_mime_headers)
01319             set_mime_multipart(data_stream, boundary, start, dap4_data_ddx,
01320                     d_cgi_ver, x_plain, data_lmt);
01321         data_stream << flush ;
01322         dataset_constraint(*fdds, eval, data_stream, false);
01323         delete fdds;
01324     }
01325     else {
01326         if (with_mime_headers)
01327             set_mime_multipart(data_stream, boundary, start, dap4_data_ddx,
01328                     d_cgi_ver, x_plain, data_lmt);
01329         data_stream << flush ;
01330         dataset_constraint_ddx(dds, eval, data_stream, boundary, start);
01331     }
01332 
01333     data_stream << flush ;
01334 
01335     if (with_mime_headers)
01336         data_stream << CRLF << "--" << boundary << "--" << CRLF;
01337 }
01338 
01339 } // namespace libdap
01340