• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

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 21701 2009-11-06 00:35: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         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 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) 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, true);
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) 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, true);
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) 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, true);
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 #if COMPRESSION_FOR_SERVER3
01041     bool compress = d_comp && deflate_exists();
01042 #endif
01043 
01044     // Handle *functional* constraint expressions specially
01045     if (eval.functional_expression()) {
01046         // Get the result and then start sending the headers. This provides a
01047         // way to send errors back to the client w/o colliding with the
01048         // normal response headers. There's some duplication of code with this
01049         // and the else-clause.
01050         BaseType *var = eval.eval_function(dds, d_dataset);
01051         if (!var)
01052             throw Error(unknown_error, "Error calling the CE function.");
01053 
01054 #if COMPRESSION_FOR_SERVER3
01055         if (with_mime_headers)
01056             set_mime_binary(data_stream, dods_data, d_cgi_ver,
01057                             (compress) ? deflate : x_plain, data_lmt);
01058         fflush(data_stream);
01059 
01060         int childpid;
01061         if (compress)
01062             data_stream = compressor(data_stream, childpid);
01063 #endif
01064         if (with_mime_headers)
01065             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01066 
01067         fflush(data_stream);
01068 
01069         functional_constraint(*var, dds, eval, data_stream);
01070         delete var;
01071         var = 0;
01072     }
01073     else {
01074 #if COMPRESSION_FOR_SERVER3
01075         if (with_mime_headers)
01076             set_mime_binary(data_stream, dods_data, d_cgi_ver,
01077                             (compress) ? deflate : x_plain, data_lmt);
01078         fflush(data_stream);
01079 
01080         int childpid;
01081         if (compress)
01082             data_stream = compressor(data_stream, childpid);
01083 #endif
01084         if (with_mime_headers)
01085             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01086 
01087         dataset_constraint(dds, eval, data_stream);
01088     }
01089 
01090     fflush(data_stream);
01091 }
01092 #endif
01093 
01110 void
01111 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
01112                       ostream & data_stream, const string & anc_location,
01113                       bool with_mime_headers) const
01114 {
01115     // If this is a conditional request and the server should send a 304
01116     // response, do that and exit. Otherwise, continue on and send the full
01117     // response.
01118     time_t data_lmt = get_data_last_modified_time(anc_location);
01119     if (is_conditional()
01120         && data_lmt <= get_request_if_modified_since()
01121         && with_mime_headers) {
01122         set_mime_not_modified(data_stream);
01123         return;
01124     }
01125     // Set up the alarm.
01126     establish_timeout(data_stream);
01127     dds.set_timeout(d_timeout);
01128 
01129     eval.parse_constraint(d_ce, dds);   // Throws Error if the ce doesn't
01130                                         // parse.
01131 
01132     dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
01133 
01134     // Start sending the response...
01135 
01136     // Handle *functional* constraint expressions specially
01137     if (eval.functional_expression()) {
01138         // Get the result and then start sending the headers. This provides a
01139         // way to send errors back to the client w/o colliding with the
01140         // normal response headers. There's some duplication of code with this
01141         // and the else-clause.
01142         BaseType *var = eval.eval_function(dds, d_dataset);
01143         if (!var)
01144             throw Error(unknown_error, "Error calling the CE function.");
01145 
01146        if (with_mime_headers)
01147             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01148 
01149         data_stream << flush ;
01150 
01151         functional_constraint(*var, dds, eval, data_stream);
01152         delete var;
01153         var = 0;
01154     }
01155     else {
01156         if (with_mime_headers)
01157             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01158 
01159         dataset_constraint(dds, eval, data_stream);
01160     }
01161 
01162     data_stream << flush ;
01163 }
01164 
01165 #if FILE_METHODS
01166 
01176 void
01177 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out,
01178                      bool with_mime_headers) const
01179 {
01180     // If constrained, parse the constraint. Throws Error or InternalErr.
01181     if (!d_ce.empty())
01182         eval.parse_constraint(d_ce, dds);
01183 
01184     if (eval.functional_expression())
01185         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.");
01186 
01187     time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
01188 
01189     // If this is a conditional request and the server should send a 304
01190     // response, do that and exit. Otherwise, continue on and send the full
01191     // response.
01192     if (is_conditional() && dds_lmt <= get_request_if_modified_since()
01193         && with_mime_headers) {
01194         set_mime_not_modified(out);
01195         return;
01196     }
01197     else {
01198         if (with_mime_headers)
01199             set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
01200         dds.print_xml(out, !d_ce.empty(), "");
01201     }
01202 }
01203 #endif
01204 
01215 void
01216 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, ostream &out,
01217                      bool with_mime_headers) const
01218 {
01219     // If constrained, parse the constraint. Throws Error or InternalErr.
01220     if (!d_ce.empty())
01221         eval.parse_constraint(d_ce, dds);
01222 
01223     if (eval.functional_expression())
01224         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.");
01225 
01226     time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
01227 
01228     // If this is a conditional request and the server should send a 304
01229     // response, do that and exit. Otherwise, continue on and send the full
01230     // response.
01231     if (is_conditional() && dds_lmt <= get_request_if_modified_since()
01232         && with_mime_headers) {
01233         set_mime_not_modified(out);
01234         return;
01235     }
01236     else {
01237         if (with_mime_headers)
01238             set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
01239         dds.print_xml(out, !d_ce.empty(), "");
01240     }
01241 }
01242 
01259 void
01260 DODSFilter::send_data_ddx(DDS & dds, ConstraintEvaluator & eval,
01261                       ostream & data_stream, const string &start,
01262                       const string &boundary, const string & anc_location,
01263                       bool with_mime_headers) const
01264 {
01265     // If this is a conditional request and the server should send a 304
01266     // response, do that and exit. Otherwise, continue on and send the full
01267     // response.
01268     time_t data_lmt = get_data_last_modified_time(anc_location);
01269     if (is_conditional()
01270         && data_lmt <= get_request_if_modified_since()
01271         && with_mime_headers) {
01272         set_mime_not_modified(data_stream);
01273         return;
01274     }
01275     // Set up the alarm.
01276     establish_timeout(data_stream);
01277     dds.set_timeout(d_timeout);
01278 
01279     eval.parse_constraint(d_ce, dds);   // Throws Error if the ce doesn't
01280                                         // parse.
01281 
01282     dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
01283 
01284     // Start sending the response...
01285 
01286     // Handle *functional* constraint expressions specially
01287     if (eval.functional_expression()) {
01288         BaseType *var = eval.eval_function(dds, d_dataset);
01289         if (!var)
01290             throw Error(unknown_error, "Error calling the CE function.");
01291 
01292         if (with_mime_headers)
01293             set_mime_multipart(data_stream, boundary, start, dap4_data_ddx,
01294                 d_cgi_ver, x_plain, data_lmt);
01295         data_stream << flush ;
01296         BaseTypeFactory btf;
01297         DDS var_dds(&btf, var->name());
01298         var->set_send_p(true);
01299         var_dds.add_var(var);
01300         dataset_constraint_ddx(var_dds, eval, data_stream, boundary, start);
01301 
01302         // functional_constraint_ddx(*var, dds, eval, data_stream, boundary);
01303         delete var;
01304         var = 0;
01305     }
01306     else {
01307         if (with_mime_headers)
01308             set_mime_multipart(data_stream, boundary, start, dap4_data_ddx,
01309                     d_cgi_ver, x_plain, data_lmt);
01310         data_stream << flush ;
01311         dataset_constraint_ddx(dds, eval, data_stream, boundary, start);
01312     }
01313 
01314     data_stream << flush ;
01315 
01316     if (with_mime_headers)
01317         data_stream << CRLF << "--" << boundary << "--" << CRLF;
01318 }
01319 
01320 } // namespace libdap
01321 

Generated on Mon Sep 6 2010 06:34:01 for libdap++ by  doxygen 1.7.1