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

Generated on Wed May 13 18:06:38 2009 for libdap++ by  doxygen 1.4.7