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 17002 2007-08-27 19:16:51Z pwest $"
00041     };
00042 
00043 #include <signal.h>
00044 
00045 #ifndef WIN32
00046 #include <unistd.h>
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 
00058 #include <GetOpt.h>
00059 
00060 #include "DAS.h"
00061 #include "DDS.h"
00062 #include "debug.h"
00063 #include "cgi_util.h"
00064 #include "util.h"
00065 #include "escaping.h"
00066 #include "DODSFilter.h"
00067 #include "XDRFileMarshaller.h"
00068 #include "XDRStreamMarshaller.h"
00069 #include "InternalErr.h"
00070 #ifndef WIN32
00071 #include "SignalHandler.h"
00072 #include "EventHandler.h"
00073 #include "AlarmHandler.h"
00074 #endif
00075 
00076 using namespace std;
00077 
00078 const string usage =
00079     "Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\
00080     \n\
00081     options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\
00082     -u <url>: The complete URL minus the CE (required for DDX)\n\
00083     -c: Compress the response using the deflate algorithm.\n\
00084     -e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\
00085     -v <version>: Use <version> as the version number\n\
00086     -d <dir>: Look for ancillary file in <dir> (deprecated).\n\
00087     -f <file>: Look for ancillary data in <file> (deprecated).\n\
00088     -r <dir>: Use <dir> as a cache directory\n\
00089     -l <time>: Conditional request; if data source is unchanged since\n\
00090     <time>, return an HTTP 304 response.\n\
00091     -t <seconds>: Timeout the handler after <seconds>.\n\
00092     -h: This message.";
00093 
00094 #if 0
00095 // Removed the call to waitpid in send_data() because calling fflush
00096 // addresses the problem wait() was supposed to solve and calling wait() is
00097 // the root of ticket #335. jhrg 3/10/06
00098 #ifdef WIN32
00099 #define WAITPID(pid) while(_cwait(NULL, pid, NULL) > 0)
00100 #else
00101 #define WAITPID(pid) while(waitpid(pid, 0, 0) > 0)
00102 #endif
00103 #endif
00104 
00169 DODSFilter::DODSFilter(int argc, char *argv[]) throw(Error)
00170 {
00171     initialize(argc, argv);
00172 
00173     DBG(cerr << "d_comp: " << d_comp << endl);
00174     DBG(cerr << "d_ce: " << d_ce << endl);
00175     DBG(cerr << "d_cgi_ver: " << d_cgi_ver << endl);
00176     DBG(cerr << "d_response: " << d_response << endl);
00177     DBG(cerr << "d_anc_dir: " << d_anc_dir << endl);
00178     DBG(cerr << "d_anc_file: " << d_anc_file << endl);
00179     DBG(cerr << "d_cache_dir: " << d_cache_dir << endl);
00180     DBG(cerr << "d_conditional_request: " << d_conditional_request << endl);
00181     DBG(cerr << "d_if_modified_since: " << d_if_modified_since << endl);
00182     DBG(cerr << "d_url: " << d_url << endl);
00183     DBG(cerr << "d_timeout: " << d_timeout << endl);
00184 }
00185 
00186 DODSFilter::~DODSFilter()
00187 {
00188 }
00189 
00192 void
00193 DODSFilter::initialize()
00194 {
00195     // Set default values. Don't use the C++ constructor initialization so
00196     // that a subclass can have more control over this process.
00197     d_comp = false;
00198     d_bad_options = false;
00199     d_conditional_request = false;
00200     d_dataset = "";
00201     d_ce = "";
00202     d_cgi_ver = "";
00203     d_anc_dir = "";
00204     d_anc_file = "";
00205     d_cache_dir = "";
00206     d_response = Unknown_Response;;
00207     d_anc_das_lmt = 0;
00208     d_anc_dds_lmt = 0;
00209     d_if_modified_since = -1;
00210     d_url = "";
00211     d_program_name = "Unknown";
00212     d_timeout = 0;
00213 
00214 #ifdef WIN32
00215     //  We want serving from win32 to behave in a manner
00216     //  similar to the UNIX way - no CR->NL terminated lines
00217     //  in files. Hence stdout goes to binary mode.
00218     _setmode(_fileno(stdout), _O_BINARY);
00219 #endif
00220 }
00221 
00233 void
00234 DODSFilter::initialize(int argc, char *argv[])
00235 {
00236     initialize();
00237 
00238     d_program_name = argv[0];
00239 
00240     // This should be specialized by a subclass. This may throw Error.
00241     int next_arg = process_options(argc, argv);
00242 
00243     // Look at what's left after processing the command line options. Either
00244     // there MUST be a dataset name OR the caller is asking for version
00245     // information. If neither is true, then the options are bad.
00246     if (next_arg < argc) {
00247         d_dataset = argv[next_arg];
00248         d_dataset = www2id(d_dataset, "%", "%20");
00249     }
00250     else if (get_response() != Version_Response)
00251         print_usage();   // Throws Error
00252 }
00253 
00262 int
00263 DODSFilter::process_options(int argc, char *argv[])
00264 {
00265     DBG(cerr << "Entering process_options... ");
00266 
00267     int option_char;
00268     GetOpt getopt (argc, argv, "ce: v: d: f: r: l: o: u: t: ");
00269 
00270     while ((option_char = getopt()) != EOF) {
00271         switch (option_char) {
00272         case 'c': d_comp = true; break;
00273         case 'e': set_ce(getopt.optarg); break;
00274         case 'v': set_cgi_version(getopt.optarg); break;
00275         case 'd': d_anc_dir = getopt.optarg; break;
00276         case 'f': d_anc_file = getopt.optarg; break;
00277         case 'r': d_cache_dir = getopt.optarg; break;
00278         case 'o': set_response(getopt.optarg); break;
00279         case 'u': set_URL(getopt.optarg); break;
00280         case 't': d_timeout = atoi(getopt.optarg); break;
00281         case 'l':
00282             d_conditional_request = true;
00283             d_if_modified_since
00284             = static_cast<time_t>(strtol(getopt.optarg, NULL, 10));
00285             break;
00286         case 'h': print_usage(); exit(1);
00287         default: print_usage(); // Throws Error
00288         }
00289     }
00290 
00291     DBGN(cerr << "exiting." << endl);
00292 
00293     return getopt.optind; // return the index of the next argument
00294 }
00295 
00300 bool
00301 DODSFilter::is_conditional() const
00302 {
00303     return d_conditional_request;
00304 }
00305 
00319 void
00320 DODSFilter::set_cgi_version(string version)
00321 {
00322     d_cgi_ver = version;
00323 }
00324 
00330 string
00331 DODSFilter::get_cgi_version() const
00332 {
00333     return d_cgi_ver;
00334 }
00335 
00342 string
00343 DODSFilter::get_ce() const
00344 {
00345     return d_ce;
00346 }
00347 
00348 void
00349 DODSFilter::set_ce(string _ce)
00350 {
00351     d_ce = www2id(_ce, "%", "%20");
00352 }
00353 
00362 string
00363 DODSFilter::get_dataset_name() const
00364 {
00365     return d_dataset;
00366 }
00367 
00368 void
00369 DODSFilter::set_dataset_name(const string ds)
00370 {
00371     d_dataset = www2id(ds, "%", "%20");
00372 }
00373 
00377 string
00378 DODSFilter::get_URL() const
00379 {
00380     return d_url;
00381 }
00382 
00385 void
00386 DODSFilter::set_URL(const string &url)
00387 {
00388     if (url.find('?') != url.npos)
00389         print_usage();  // Throws Error
00390 
00391     d_url = url;
00392 }
00393 
00401 string
00402 DODSFilter::get_dataset_version() const
00403 {
00404     return "";
00405 }
00406 
00413 void DODSFilter::set_response(const string &r)
00414 {
00415     if (r == "DAS" || r == "das") {
00416         d_response = DAS_Response;
00417         d_action = "das" ;
00418     }
00419     else if (r == "DDS" || r == "dds") {
00420         d_response = DDS_Response;
00421         d_action = "dds" ;
00422     }
00423     else if (r == "DataDDS" || r == "dods") {
00424         d_response = DataDDS_Response;
00425         d_action = "dods" ;
00426     }
00427     else if (r == "DDX" || r == "ddx") {
00428         d_response = DDX_Response;
00429         d_action = "ddx" ;
00430     }
00431     else if (r == "Version") {
00432         d_response = Version_Response;
00433         d_action = "version" ;
00434     }
00435     else
00436         print_usage();   // Throws Error
00437 }
00438 
00440 DODSFilter::Response
00441 DODSFilter::get_response() const
00442 {
00443     return d_response;
00444 }
00445 
00447 string DODSFilter::get_action() const
00448 {
00449     return d_action;
00450 }
00451 
00472 time_t
00473 DODSFilter::get_dataset_last_modified_time() const
00474 {
00475     return last_modified_time(d_dataset);
00476 }
00477 
00487 time_t
00488 DODSFilter::get_das_last_modified_time(const string &anc_location) const
00489 {
00490     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00491         << anc_location << "call faf(das) d_dataset=" << d_dataset
00492         << " d_anc_file=" << d_anc_file << endl);
00493 
00494     string name
00495     = find_ancillary_file(d_dataset, "das",
00496                           (anc_location == "") ? d_anc_dir : anc_location,
00497                           d_anc_file);
00498 
00499     return max((name != "") ? last_modified_time(name) : 0,
00500                get_dataset_last_modified_time());
00501 }
00502 
00510 time_t
00511 DODSFilter::get_dds_last_modified_time(const string &anc_location) const
00512 {
00513     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00514         << anc_location << "call faf(dds) d_dataset=" << d_dataset
00515         << " d_anc_file=" << d_anc_file << endl);
00516 
00517     string name
00518     = find_ancillary_file(d_dataset, "dds",
00519                           (anc_location == "") ? d_anc_dir : anc_location,
00520                           d_anc_file);
00521 
00522     return max((name != "") ? last_modified_time(name) : 0,
00523                get_dataset_last_modified_time());
00524 }
00525 
00539 time_t
00540 DODSFilter::get_data_last_modified_time(const string &anc_location) const
00541 {
00542     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00543         << anc_location << "call faf(both) d_dataset=" << d_dataset
00544         << " d_anc_file=" << d_anc_file << endl);
00545 
00546     string dds_name
00547     = find_ancillary_file(d_dataset, "dds",
00548                           (anc_location == "") ? d_anc_dir : anc_location,
00549                           d_anc_file);
00550     string das_name
00551     = find_ancillary_file(d_dataset, "das",
00552                           (anc_location == "") ? d_anc_dir : anc_location,
00553                           d_anc_file);
00554 
00555     time_t m = max((das_name != "") ? last_modified_time(das_name) : (time_t)0,
00556                    (dds_name != "") ? last_modified_time(dds_name) : (time_t)0);
00557     // Note that this is a call to get_dataset_... not get_data_...
00558     time_t n = get_dataset_last_modified_time();
00559 
00560     return max(m, n);
00561 }
00562 
00570 time_t
00571 DODSFilter::get_request_if_modified_since() const
00572 {
00573     return d_if_modified_since;
00574 }
00575 
00582 string
00583 DODSFilter::get_cache_dir() const
00584 {
00585     return d_cache_dir;
00586 }
00587 
00592 void
00593 DODSFilter::set_timeout(int t)
00594 {
00595     d_timeout = t;
00596 }
00597 
00599 int
00600 DODSFilter::get_timeout() const
00601 {
00602     return d_timeout;
00603 }
00604 
00616 void
00617 DODSFilter::establish_timeout(FILE *stream) const
00618 {
00619 #ifndef WIN32
00620     if (d_timeout > 0) {
00621         SignalHandler *sh = SignalHandler::instance();
00622         sh->register_handler(SIGALRM, new AlarmHandler(stream));
00623         alarm(d_timeout);
00624     }
00625 #endif
00626 }
00627 
00628 // FIXME
00629 void
00630 DODSFilter::establish_timeout(ostream &stream) const
00631 {
00632 #ifndef WIN32
00633     if (d_timeout > 0) {
00634         SignalHandler *sh = SignalHandler::instance();
00635         sh->register_handler(SIGALRM, new AlarmHandler(stream));
00636         alarm(d_timeout);
00637     }
00638 #endif
00639 }
00640 
00641 
00651 void
00652 DODSFilter::read_ancillary_das(DAS &das, const string &anc_location) const
00653 {
00654     string name = find_ancillary_file(d_dataset, "das",
00655                                       (anc_location == "") ? d_anc_dir : anc_location,
00656                                       d_anc_file);
00657 
00658     FILE *in = fopen(name.c_str(), "r");
00659     if (in) {
00660         das.parse(in);
00661         int res = fclose(in) ;
00662         if (res) {
00663             DBG(cerr << "DODSFilter::read_ancillary_das - Failed to close file " << (void *)in << endl ;) ;
00664         }
00665     }
00666 }
00667 
00677 void
00678 DODSFilter::read_ancillary_dds(DDS &dds, const string &anc_location) const
00679 {
00680     string name = find_ancillary_file(d_dataset, "dds",
00681                                       (anc_location == "") ? d_anc_dir : anc_location,
00682                                       d_anc_file);
00683     FILE *in = fopen(name.c_str(), "r");
00684     if (in) {
00685         dds.parse(in);
00686         int res = fclose(in) ;
00687         if (res) {
00688             DBG(cerr << "DODSFilter::read_ancillary_dds - Failed to close " << (void *)in << endl ;) ;
00689         }
00690     }
00691 }
00692 
00693 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.";
00694 
00704 void
00705 DODSFilter::print_usage() const
00706 {
00707     // Write a message to the WWW server error log file.
00708     ErrMsgT(usage.c_str());
00709 
00710     throw Error(unknown_error, emessage);
00711 }
00712 
00718 void
00719 DODSFilter::send_version_info() const
00720 {
00721     do_version(d_cgi_ver, get_dataset_version());
00722 }
00723 
00735 void
00736 DODSFilter::send_das(FILE *out, DAS &das, const string &anc_location,
00737                      bool with_mime_headers) const
00738 {
00739     time_t das_lmt = get_das_last_modified_time(anc_location);
00740     if (is_conditional()
00741         && das_lmt <= get_request_if_modified_since()
00742         && with_mime_headers) {
00743         set_mime_not_modified(out);
00744     }
00745     else {
00746         if (with_mime_headers)
00747             set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
00748         das.print(out);
00749     }
00750     fflush(out) ;
00751 }
00752 
00764 void
00765 DODSFilter::send_das(ostream &out, DAS &das, const string &anc_location,
00766                      bool with_mime_headers) const
00767 {
00768     time_t das_lmt = get_das_last_modified_time(anc_location);
00769     if (is_conditional()
00770         && das_lmt <= get_request_if_modified_since()
00771         && with_mime_headers) {
00772         set_mime_not_modified(out);
00773     }
00774     else {
00775         if (with_mime_headers)
00776             set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
00777         das.print(out);
00778     }
00779     out << flush ;
00780 }
00781 
00782 void
00783 DODSFilter::send_das(DAS &das, const string &anc_location,
00784                      bool with_mime_headers) const
00785 {
00786     send_das(stdout, das, anc_location, with_mime_headers);
00787 }
00788 
00805 void
00806 DODSFilter::send_dds(FILE *out, DDS &dds, ConstraintEvaluator &eval,
00807                      bool constrained,
00808                      const string &anc_location,
00809                      bool with_mime_headers) const
00810 {
00811     // If constrained, parse the constraint. Throws Error or InternalErr.
00812     if (constrained)
00813         eval.parse_constraint(d_ce, dds);
00814 
00815     if (eval.functional_expression())
00816         throw Error("Function calls can only be used with data requests. To see the structure\nof the underlying data source, reissue the URL without the function.");
00817 
00818     time_t dds_lmt = get_dds_last_modified_time(anc_location);
00819     if (is_conditional()
00820         && dds_lmt <= get_request_if_modified_since()
00821         && with_mime_headers) {
00822         set_mime_not_modified(out);
00823     }
00824     else {
00825         if (with_mime_headers)
00826             set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt);
00827         if (constrained)
00828             dds.print_constrained(out);
00829         else
00830             dds.print(out);
00831     }
00832 
00833     fflush(out) ;
00834 }
00835 
00852 void
00853 DODSFilter::send_dds(ostream &out, DDS &dds, ConstraintEvaluator &eval,
00854                      bool constrained,
00855                      const string &anc_location,
00856                      bool with_mime_headers) const
00857 {
00858     // If constrained, parse the constraint. Throws Error or InternalErr.
00859     if (constrained)
00860         eval.parse_constraint(d_ce, dds);
00861 
00862     if (eval.functional_expression())
00863         throw Error("Function calls can only be used with data requests. To see the structure\nof the underlying data source, reissue the URL without the function.");
00864 
00865     time_t dds_lmt = get_dds_last_modified_time(anc_location);
00866     if (is_conditional()
00867         && dds_lmt <= get_request_if_modified_since()
00868         && with_mime_headers) {
00869         set_mime_not_modified(out);
00870     }
00871     else {
00872         if (with_mime_headers)
00873             set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt);
00874         if (constrained)
00875             dds.print_constrained(out);
00876         else
00877             dds.print(out);
00878     }
00879 
00880     out << flush ;
00881 }
00882 
00883 void
00884 DODSFilter::send_dds(DDS &dds, ConstraintEvaluator &eval,
00885                      bool constrained, const string &anc_location,
00886                      bool with_mime_headers) const
00887 {
00888     send_dds(stdout, dds, eval, constrained, anc_location, with_mime_headers);
00889 }
00890 
00891 // 'lmt' unused. Should it be used to supply a LMT or removed from the
00892 // method? jhrg 8/9/05
00893 void
00894 DODSFilter::functional_constraint(BaseType &var, DDS &dds,
00895                                   ConstraintEvaluator &eval, FILE *out) const
00896 {
00897     fprintf(out, "Dataset {\n");
00898     var.print_decl(out, "    ", true, false, true);
00899     fprintf(out, "} function_value;\n");
00900     fprintf(out, "Data:\n");
00901 
00902     fflush(out);
00903 
00904     // Grab a stream encodes using XDR.
00905     XDRFileMarshaller m( out ) ;
00906 
00907     try {
00908         // In the following call to serialize, suppress CE evaluation.
00909         var.serialize(d_dataset, eval, dds, m, false);
00910     }
00911     catch (Error &e) {
00912         throw;
00913     }
00914 }
00915 
00916 // 'lmt' unused. Should it be used to supply a LMT or removed from the
00917 // method? jhrg 8/9/05
00918 void
00919 DODSFilter::functional_constraint(BaseType &var, DDS &dds,
00920                                   ConstraintEvaluator &eval, ostream &out) const
00921 {
00922     out << "Dataset {\n" ;
00923     var.print_decl(out, "    ", true, false, true);
00924     out << "} function_value;\n" ;
00925     out << "Data:\n" ;
00926 
00927     out << flush ;
00928 
00929     // Grab a stream encodes using XDR.
00930     XDRStreamMarshaller m( out ) ;
00931 
00932     try {
00933         // In the following call to serialize, suppress CE evaluation.
00934         var.serialize(d_dataset, eval, dds, m, false);
00935     }
00936     catch (Error &e) {
00937         throw;
00938     }
00939 }
00940 
00941 void
00942 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
00943                                FILE * out) const
00944 {
00945     // send constrained DDS
00946     dds.print_constrained(out);
00947     fprintf(out, "Data:\n");
00948     fflush(out);
00949 
00950     // Grab a stream that encodes using XDR.
00951     XDRFileMarshaller m( out ) ;
00952 
00953     try {
00954         // Send all variables in the current projection (send_p())
00955         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
00956             if ((*i)->send_p()) {
00957                 DBG(cerr << "Sending " << (*i)->name() << endl);
00958                 (*i)->serialize(d_dataset, eval, dds, m, true);
00959             }
00960     }
00961     catch (Error & e) {
00962         throw;
00963     }
00964 }
00965 
00966 void
00967 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
00968                                ostream &out) const
00969 {
00970     // send constrained DDS
00971     dds.print_constrained(out);
00972     out << "Data:\n" ;
00973     out << flush ;
00974 
00975     // Grab a stream that encodes using XDR.
00976     XDRStreamMarshaller m( out ) ;
00977 
00978     try {
00979         // Send all variables in the current projection (send_p())
00980         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
00981             if ((*i)->send_p()) {
00982                 DBG(cerr << "Sending " << (*i)->name() << endl);
00983                 (*i)->serialize(d_dataset, eval, dds, m, true);
00984             }
00985     }
00986     catch (Error & e) {
00987         throw;
00988     }
00989 }
00990 
01007 void
01008 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
01009                       FILE * data_stream, const string & anc_location,
01010                       bool with_mime_headers) const
01011 {
01012     // If this is a conditional request and the server should send a 304
01013     // response, do that and exit. Otherwise, continue on and send the full
01014     // response.
01015     time_t data_lmt = get_data_last_modified_time(anc_location);
01016     if (is_conditional()
01017         && data_lmt <= get_request_if_modified_since()
01018         && with_mime_headers) {
01019         set_mime_not_modified(data_stream);
01020         return;
01021     }
01022     // Set up the alarm.
01023     establish_timeout(data_stream);
01024     dds.set_timeout(d_timeout);
01025 
01026     eval.parse_constraint(d_ce, dds);   // Throws Error if the ce doesn't
01027                                         // parse. 
01028 
01029     dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
01030 
01031     // Start sending the response...
01032 #if COMPRESSION_FOR_SERVER3
01033     bool compress = d_comp && deflate_exists();
01034 #endif
01035 
01036     // Handle *functional* constraint expressions specially
01037     if (eval.functional_expression()) {
01038         // Get the result and then start sending the headers. This provides a
01039         // way to send errors back to the client w/o colliding with the
01040         // normal response headers. There's some duplication of code with this
01041         // and the else-clause.
01042         BaseType *var = eval.eval_function(dds, d_dataset);
01043         if (!var)
01044             throw Error(unknown_error, "Error calling the CE function.");
01045 
01046 #if COMPRESSION_FOR_SERVER3
01047         if (with_mime_headers)
01048             set_mime_binary(data_stream, dods_data, d_cgi_ver,
01049                             (compress) ? deflate : x_plain, data_lmt);
01050         fflush(data_stream);
01051 
01052         int childpid;
01053         if (compress)
01054             data_stream = compressor(data_stream, childpid);
01055 #endif
01056         if (with_mime_headers)
01057             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01058 
01059         fflush(data_stream);
01060 
01061         functional_constraint(*var, dds, eval, data_stream);
01062         delete var;
01063         var = 0;
01064     }
01065     else {
01066 #if COMPRESSION_FOR_SERVER3
01067         if (with_mime_headers)
01068             set_mime_binary(data_stream, dods_data, d_cgi_ver,
01069                             (compress) ? deflate : x_plain, data_lmt);
01070         fflush(data_stream);
01071 
01072         int childpid;
01073         if (compress)
01074             data_stream = compressor(data_stream, childpid);
01075 #endif
01076         if (with_mime_headers)
01077             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01078 
01079         dataset_constraint(dds, eval, data_stream);
01080     }
01081 
01082     fflush(data_stream);
01083 }
01084 
01101 void
01102 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
01103                       ostream & data_stream, const string & anc_location,
01104                       bool with_mime_headers) const
01105 {
01106     // If this is a conditional request and the server should send a 304
01107     // response, do that and exit. Otherwise, continue on and send the full
01108     // response.
01109     time_t data_lmt = get_data_last_modified_time(anc_location);
01110     if (is_conditional()
01111         && data_lmt <= get_request_if_modified_since()
01112         && with_mime_headers) {
01113         set_mime_not_modified(data_stream);
01114         return;
01115     }
01116     // Set up the alarm.
01117     establish_timeout(data_stream);
01118     dds.set_timeout(d_timeout);
01119 
01120     eval.parse_constraint(d_ce, dds);   // Throws Error if the ce doesn't
01121                                         // parse. 
01122 
01123     dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
01124 
01125     // Start sending the response...
01126 #if COMPRESSION_FOR_SERVER3
01127     bool compress = d_comp && deflate_exists();
01128 #endif
01129 
01130     // Handle *functional* constraint expressions specially
01131     if (eval.functional_expression()) {
01132         // Get the result and then start sending the headers. This provides a
01133         // way to send errors back to the client w/o colliding with the
01134         // normal response headers. There's some duplication of code with this
01135         // and the else-clause.
01136         BaseType *var = eval.eval_function(dds, d_dataset);
01137         if (!var)
01138             throw Error(unknown_error, "Error calling the CE function.");
01139 
01140 #if COMPRESSION_FOR_SERVER3
01141         if (with_mime_headers)
01142             set_mime_binary(data_stream, dods_data, d_cgi_ver,
01143                             (compress) ? deflate : x_plain, data_lmt);
01144         data_stream << flush ;
01145 
01146         int childpid;
01147         if (compress)
01148             data_stream = compressor(data_stream, childpid);
01149 #endif
01150         if (with_mime_headers)
01151             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01152 
01153         data_stream << flush ;
01154 
01155         functional_constraint(*var, dds, eval, data_stream);
01156         delete var;
01157         var = 0;
01158     }
01159     else {
01160 #if COMPRESSION_FOR_SERVER3
01161         if (with_mime_headers)
01162             set_mime_binary(data_stream, dods_data, d_cgi_ver,
01163                             (compress) ? deflate : x_plain, data_lmt);
01164         data_stream << flush ;
01165 
01166         int childpid;
01167         if (compress)
01168             data_stream = compressor(data_stream, childpid);
01169 #endif
01170         if (with_mime_headers)
01171             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01172 
01173         dataset_constraint(dds, eval, data_stream);
01174     }
01175 
01176     data_stream << flush ;
01177 }
01178 
01189 void
01190 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out,
01191                      bool with_mime_headers) const
01192 {
01193     // If constrained, parse the constraint. Throws Error or InternalErr.
01194     if (!d_ce.empty())
01195         eval.parse_constraint(d_ce, dds);
01196 
01197     time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
01198 
01199     // If this is a conditional request and the server should send a 304
01200     // response, do that and exit. Otherwise, continue on and send the full
01201     // response.
01202     if (is_conditional() && dds_lmt <= get_request_if_modified_since()
01203         && with_mime_headers) {
01204         set_mime_not_modified(out);
01205         return;
01206     }
01207     else {
01208         if (with_mime_headers)
01209             set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
01210         dds.print_xml(out, !d_ce.empty(), d_url + ".blob?" + d_ce);
01211     }
01212 }
01213 
01224 void
01225 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, ostream &out,
01226                      bool with_mime_headers) const
01227 {
01228     // If constrained, parse the constraint. Throws Error or InternalErr.
01229     if (!d_ce.empty())
01230         eval.parse_constraint(d_ce, dds);
01231 
01232     time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
01233 
01234     // If this is a conditional request and the server should send a 304
01235     // response, do that and exit. Otherwise, continue on and send the full
01236     // response.
01237     if (is_conditional() && dds_lmt <= get_request_if_modified_since()
01238         && with_mime_headers) {
01239         set_mime_not_modified(out);
01240         return;
01241     }
01242     else {
01243         if (with_mime_headers)
01244             set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
01245         dds.print_xml(out, !d_ce.empty(), d_url + ".blob?" + d_ce);
01246     }
01247 }
01248 
01253 void
01254 DODSFilter::send_blob(DDS &, FILE *, bool)
01255 {
01256 #if 0
01257     // Broken. jhrg 4/3/06
01258     bool compress = d_comp && deflate_exists();
01259     time_t data_lmt = get_data_last_modified_time(d_anc_dir);
01260 
01261     // If this is a conditional request and the server should send a 304
01262     // response, do that and exit. Otherwise, continue on and send the full
01263     // response.
01264     if (is_conditional() && data_lmt <= get_request_if_modified_since()
01265         && with_mime_headers) {
01266         set_mime_not_modified(out);
01267         return;
01268     }
01269 
01270     dds.parse_constraint(d_ce);
01271 
01272     // Handle *functional* constraint expressions specially
01273     if (dds.functional_expression()) {
01274         BaseType *var = dds.eval_function(d_dataset);
01275         if (!var)
01276             throw Error("Error calling the CE function.");
01277 
01278         if (with_mime_headers)
01279             set_mime_binary(out, dods_data, d_cgi_ver,
01280                             (compress) ? deflate : x_plain, data_lmt);
01281 
01282         FILE *comp_sink;
01283         XDR *xdr_sink;
01284         int childpid = get_sinks(out, compress, &comp_sink, &xdr_sink);
01285 
01286         // In the following call to serialize, suppress CE evaluation.
01287         if (!var->serialize(d_dataset, dds, xdr_sink, false))
01288             throw Error("Could not send the function result.");
01289 
01290         clean_sinks(childpid, compress, xdr_sink, comp_sink);
01291     }
01292     else {
01293         if (with_mime_headers)
01294             set_mime_binary(out, dods_data, d_cgi_ver,
01295                             (compress) ? deflate : x_plain, data_lmt);
01296 
01297         FILE *comp_sink;
01298         XDR *xdr_sink;
01299         int childpid = get_sinks(out, compress, &comp_sink, &xdr_sink);
01300 
01301         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
01302             if ((*i)->send_p()) // only process projected variables
01303                 if (!(*i)->serialize(d_dataset, dds, xdr_sink, true))
01304                     throw Error(string("Could not serialize variable '")
01305                                 + (*i)->name() + string("'."));
01306 
01307         clean_sinks(childpid, compress, xdr_sink, comp_sink);
01308     }
01309 #endif
01310 }
01311 

Generated on Wed Jan 2 04:11:02 2008 for libdap++ by  doxygen 1.5.4