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 18315 2008-03-03 20:14:44Z 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 "util.h"
00066 #include "escaping.h"
00067 #include "DODSFilter.h"
00068 #include "XDRFileMarshaller.h"
00069 #include "XDRStreamMarshaller.h"
00070 #include "InternalErr.h"
00071 #ifndef WIN32
00072 #include "SignalHandler.h"
00073 #include "EventHandler.h"
00074 #include "AlarmHandler.h"
00075 #endif
00076 
00077 using namespace std;
00078 
00079 namespace libdap {
00080 
00081 const string usage =
00082     "Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\
00083     \n\
00084     options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\
00085     -u <url>: The complete URL minus the CE (required for DDX)\n\
00086     -c: Compress the response using the deflate algorithm.\n\
00087     -e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\
00088     -v <version>: Use <version> as the version number\n\
00089     -d <dir>: Look for ancillary file in <dir> (deprecated).\n\
00090     -f <file>: Look for ancillary data in <file> (deprecated).\n\
00091     -r <dir>: Use <dir> as a cache directory\n\
00092     -l <time>: Conditional request; if data source is unchanged since\n\
00093     <time>, return an HTTP 304 response.\n\
00094     -t <seconds>: Timeout the handler after <seconds>.\n\
00095     -h: This message.";
00096 
00097 #if 0
00098 // Removed the call to waitpid in send_data() because calling fflush
00099 // addresses the problem wait() was supposed to solve and calling wait() is
00100 // the root of ticket #335. jhrg 3/10/06
00101 #ifdef WIN32
00102 #define WAITPID(pid) while(_cwait(NULL, pid, NULL) > 0)
00103 #else
00104 #define WAITPID(pid) while(waitpid(pid, 0, 0) > 0)
00105 #endif
00106 #endif
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 == "Version") {
00435         d_response = Version_Response;
00436         d_action = "version" ;
00437     }
00438     else
00439         print_usage();   // Throws Error
00440 }
00441 
00443 DODSFilter::Response
00444 DODSFilter::get_response() const
00445 {
00446     return d_response;
00447 }
00448 
00450 string DODSFilter::get_action() const
00451 {
00452     return d_action;
00453 }
00454 
00475 time_t
00476 DODSFilter::get_dataset_last_modified_time() const
00477 {
00478     return last_modified_time(d_dataset);
00479 }
00480 
00490 time_t
00491 DODSFilter::get_das_last_modified_time(const string &anc_location) const
00492 {
00493     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00494         << anc_location << "call faf(das) d_dataset=" << d_dataset
00495         << " d_anc_file=" << d_anc_file << endl);
00496 
00497     string name
00498     = find_ancillary_file(d_dataset, "das",
00499                           (anc_location == "") ? d_anc_dir : anc_location,
00500                           d_anc_file);
00501 
00502     return max((name != "") ? last_modified_time(name) : 0,
00503                get_dataset_last_modified_time());
00504 }
00505 
00513 time_t
00514 DODSFilter::get_dds_last_modified_time(const string &anc_location) const
00515 {
00516     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00517         << anc_location << "call faf(dds) d_dataset=" << d_dataset
00518         << " d_anc_file=" << d_anc_file << endl);
00519 
00520     string name
00521     = find_ancillary_file(d_dataset, "dds",
00522                           (anc_location == "") ? d_anc_dir : anc_location,
00523                           d_anc_file);
00524 
00525     return max((name != "") ? last_modified_time(name) : 0,
00526                get_dataset_last_modified_time());
00527 }
00528 
00542 time_t
00543 DODSFilter::get_data_last_modified_time(const string &anc_location) const
00544 {
00545     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00546         << anc_location << "call faf(both) d_dataset=" << d_dataset
00547         << " d_anc_file=" << d_anc_file << endl);
00548 
00549     string dds_name
00550     = find_ancillary_file(d_dataset, "dds",
00551                           (anc_location == "") ? d_anc_dir : anc_location,
00552                           d_anc_file);
00553     string das_name
00554     = find_ancillary_file(d_dataset, "das",
00555                           (anc_location == "") ? d_anc_dir : anc_location,
00556                           d_anc_file);
00557 
00558     time_t m = max((das_name != "") ? last_modified_time(das_name) : (time_t)0,
00559                    (dds_name != "") ? last_modified_time(dds_name) : (time_t)0);
00560     // Note that this is a call to get_dataset_... not get_data_...
00561     time_t n = get_dataset_last_modified_time();
00562 
00563     return max(m, n);
00564 }
00565 
00573 time_t
00574 DODSFilter::get_request_if_modified_since() const
00575 {
00576     return d_if_modified_since;
00577 }
00578 
00585 string
00586 DODSFilter::get_cache_dir() const
00587 {
00588     return d_cache_dir;
00589 }
00590 
00595 void
00596 DODSFilter::set_timeout(int t)
00597 {
00598     d_timeout = t;
00599 }
00600 
00602 int
00603 DODSFilter::get_timeout() const
00604 {
00605     return d_timeout;
00606 }
00607 
00619 void
00620 DODSFilter::establish_timeout(FILE *stream) const
00621 {
00622 #ifndef WIN32
00623     if (d_timeout > 0) {
00624         SignalHandler *sh = SignalHandler::instance();
00625         EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream));
00626         delete old_eh;
00627         alarm(d_timeout);
00628     }
00629 #endif
00630 }
00631 
00632 // FIXME
00633 void
00634 DODSFilter::establish_timeout(ostream &stream) const
00635 {
00636 #ifndef WIN32
00637     if (d_timeout > 0) {
00638         SignalHandler *sh = SignalHandler::instance();
00639         EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream));
00640         delete old_eh;
00641         alarm(d_timeout);
00642     }
00643 #endif
00644 }
00645 
00646 
00656 void
00657 DODSFilter::read_ancillary_das(DAS &das, const string &anc_location) const
00658 {
00659     string name = find_ancillary_file(d_dataset, "das",
00660                                       (anc_location == "") ? d_anc_dir : anc_location,
00661                                       d_anc_file);
00662 
00663     FILE *in = fopen(name.c_str(), "r");
00664     if (in) {
00665         das.parse(in);
00666         int res = fclose(in) ;
00667         if (res) {
00668             DBG(cerr << "DODSFilter::read_ancillary_das - Failed to close file " << (void *)in << endl ;) ;
00669         }
00670     }
00671 }
00672 
00682 void
00683 DODSFilter::read_ancillary_dds(DDS &dds, const string &anc_location) const
00684 {
00685     string name = find_ancillary_file(d_dataset, "dds",
00686                                       (anc_location == "") ? d_anc_dir : anc_location,
00687                                       d_anc_file);
00688     FILE *in = fopen(name.c_str(), "r");
00689     if (in) {
00690         dds.parse(in);
00691         int res = fclose(in) ;
00692         if (res) {
00693             DBG(cerr << "DODSFilter::read_ancillary_dds - Failed to close " << (void *)in << endl ;) ;
00694         }
00695     }
00696 }
00697 
00698 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.";
00699 
00709 void
00710 DODSFilter::print_usage() const
00711 {
00712     // Write a message to the WWW server error log file.
00713     ErrMsgT(usage.c_str());
00714 
00715     throw Error(unknown_error, emessage);
00716 }
00717 
00723 void
00724 DODSFilter::send_version_info() const
00725 {
00726     do_version(d_cgi_ver, get_dataset_version());
00727 }
00728 
00740 void
00741 DODSFilter::send_das(FILE *out, DAS &das, const string &anc_location,
00742                      bool with_mime_headers) const
00743 {
00744     time_t das_lmt = get_das_last_modified_time(anc_location);
00745     if (is_conditional()
00746         && das_lmt <= get_request_if_modified_since()
00747         && with_mime_headers) {
00748         set_mime_not_modified(out);
00749     }
00750     else {
00751         if (with_mime_headers)
00752             set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
00753         das.print(out);
00754     }
00755     fflush(out) ;
00756 }
00757 
00769 void
00770 DODSFilter::send_das(ostream &out, DAS &das, const string &anc_location,
00771                      bool with_mime_headers) const
00772 {
00773     time_t das_lmt = get_das_last_modified_time(anc_location);
00774     if (is_conditional()
00775         && das_lmt <= get_request_if_modified_since()
00776         && with_mime_headers) {
00777         set_mime_not_modified(out);
00778     }
00779     else {
00780         if (with_mime_headers)
00781             set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
00782         das.print(out);
00783     }
00784     out << flush ;
00785 }
00786 
00787 void
00788 DODSFilter::send_das(DAS &das, const string &anc_location,
00789                      bool with_mime_headers) const
00790 {
00791     send_das(stdout, das, anc_location, with_mime_headers);
00792 }
00793 
00810 void
00811 DODSFilter::send_dds(FILE *out, DDS &dds, ConstraintEvaluator &eval,
00812                      bool constrained,
00813                      const string &anc_location,
00814                      bool with_mime_headers) const
00815 {
00816     // If constrained, parse the constraint. Throws Error or InternalErr.
00817     if (constrained)
00818         eval.parse_constraint(d_ce, dds);
00819 
00820     if (eval.functional_expression())
00821         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.");
00822 
00823     time_t dds_lmt = get_dds_last_modified_time(anc_location);
00824     if (is_conditional()
00825         && dds_lmt <= get_request_if_modified_since()
00826         && with_mime_headers) {
00827         set_mime_not_modified(out);
00828     }
00829     else {
00830         if (with_mime_headers)
00831             set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt);
00832         if (constrained)
00833             dds.print_constrained(out);
00834         else
00835             dds.print(out);
00836     }
00837 
00838     fflush(out) ;
00839 }
00840 
00857 void
00858 DODSFilter::send_dds(ostream &out, DDS &dds, ConstraintEvaluator &eval,
00859                      bool constrained,
00860                      const string &anc_location,
00861                      bool with_mime_headers) const
00862 {
00863     // If constrained, parse the constraint. Throws Error or InternalErr.
00864     if (constrained)
00865         eval.parse_constraint(d_ce, dds);
00866 
00867     if (eval.functional_expression())
00868         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.");
00869 
00870     time_t dds_lmt = get_dds_last_modified_time(anc_location);
00871     if (is_conditional()
00872         && dds_lmt <= get_request_if_modified_since()
00873         && with_mime_headers) {
00874         set_mime_not_modified(out);
00875     }
00876     else {
00877         if (with_mime_headers)
00878             set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt);
00879         if (constrained)
00880             dds.print_constrained(out);
00881         else
00882             dds.print(out);
00883     }
00884 
00885     out << flush ;
00886 }
00887 
00888 void
00889 DODSFilter::send_dds(DDS &dds, ConstraintEvaluator &eval,
00890                      bool constrained, const string &anc_location,
00891                      bool with_mime_headers) const
00892 {
00893     send_dds(stdout, dds, eval, constrained, anc_location, with_mime_headers);
00894 }
00895 
00896 // 'lmt' unused. Should it be used to supply a LMT or removed from the
00897 // method? jhrg 8/9/05
00898 void
00899 DODSFilter::functional_constraint(BaseType &var, DDS &dds,
00900                                   ConstraintEvaluator &eval, FILE *out) const
00901 {
00902     fprintf(out, "Dataset {\n");
00903     var.print_decl(out, "    ", true, false, true);
00904     fprintf(out, "} function_value;\n");
00905     fprintf(out, "Data:\n");
00906 
00907     fflush(out);
00908 
00909     // Grab a stream encodes using XDR.
00910     XDRFileMarshaller m( out ) ;
00911 
00912     try {
00913         // In the following call to serialize, suppress CE evaluation.
00914         var.serialize(d_dataset, eval, dds, m, false);
00915     }
00916     catch (Error &e) {
00917         throw;
00918     }
00919 }
00920 
00921 // 'lmt' unused. Should it be used to supply a LMT or removed from the
00922 // method? jhrg 8/9/05
00923 void
00924 DODSFilter::functional_constraint(BaseType &var, DDS &dds,
00925                                   ConstraintEvaluator &eval, ostream &out) const
00926 {
00927     out << "Dataset {\n" ;
00928     var.print_decl(out, "    ", true, false, true);
00929     out << "} function_value;\n" ;
00930     out << "Data:\n" ;
00931 
00932     out << flush ;
00933 
00934     // Grab a stream encodes using XDR.
00935     XDRStreamMarshaller m( out ) ;
00936 
00937     try {
00938         // In the following call to serialize, suppress CE evaluation.
00939         var.serialize(d_dataset, eval, dds, m, false);
00940     }
00941     catch (Error &e) {
00942         throw;
00943     }
00944 }
00945 
00946 void
00947 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
00948                                FILE * out) const
00949 {
00950     // send constrained DDS
00951     dds.print_constrained(out);
00952     fprintf(out, "Data:\n");
00953     fflush(out);
00954 
00955     // Grab a stream that encodes using XDR.
00956     XDRFileMarshaller m( out ) ;
00957 
00958     try {
00959         // Send all variables in the current projection (send_p())
00960         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
00961             if ((*i)->send_p()) {
00962                 DBG(cerr << "Sending " << (*i)->name() << endl);
00963                 (*i)->serialize(d_dataset, eval, dds, m, true);
00964             }
00965     }
00966     catch (Error & e) {
00967         throw;
00968     }
00969 }
00970 
00971 void
00972 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
00973                                ostream &out) const
00974 {
00975     // send constrained DDS
00976     dds.print_constrained(out);
00977     out << "Data:\n" ;
00978     out << flush ;
00979 
00980     // Grab a stream that encodes using XDR.
00981     XDRStreamMarshaller m( out ) ;
00982 
00983     try {
00984         // Send all variables in the current projection (send_p())
00985         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
00986             if ((*i)->send_p()) {
00987                 DBG(cerr << "Sending " << (*i)->name() << endl);
00988                 (*i)->serialize(d_dataset, eval, dds, m, true);
00989             }
00990     }
00991     catch (Error & e) {
00992         throw;
00993     }
00994 }
00995 
01012 void
01013 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
01014                       FILE * data_stream, const string & anc_location,
01015                       bool with_mime_headers) const
01016 {
01017     // If this is a conditional request and the server should send a 304
01018     // response, do that and exit. Otherwise, continue on and send the full
01019     // response.
01020     time_t data_lmt = get_data_last_modified_time(anc_location);
01021     if (is_conditional()
01022         && data_lmt <= get_request_if_modified_since()
01023         && with_mime_headers) {
01024         set_mime_not_modified(data_stream);
01025         return;
01026     }
01027     // Set up the alarm.
01028     establish_timeout(data_stream);
01029     dds.set_timeout(d_timeout);
01030 
01031     eval.parse_constraint(d_ce, dds);   // Throws Error if the ce doesn't
01032                                         // parse. 
01033 
01034     dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
01035 
01036     // Start sending the response...
01037 #if COMPRESSION_FOR_SERVER3
01038     bool compress = d_comp && deflate_exists();
01039 #endif
01040 
01041     // Handle *functional* constraint expressions specially
01042     if (eval.functional_expression()) {
01043         // Get the result and then start sending the headers. This provides a
01044         // way to send errors back to the client w/o colliding with the
01045         // normal response headers. There's some duplication of code with this
01046         // and the else-clause.
01047         BaseType *var = eval.eval_function(dds, d_dataset);
01048         if (!var)
01049             throw Error(unknown_error, "Error calling the CE function.");
01050 
01051 #if COMPRESSION_FOR_SERVER3
01052         if (with_mime_headers)
01053             set_mime_binary(data_stream, dods_data, d_cgi_ver,
01054                             (compress) ? deflate : x_plain, data_lmt);
01055         fflush(data_stream);
01056 
01057         int childpid;
01058         if (compress)
01059             data_stream = compressor(data_stream, childpid);
01060 #endif
01061         if (with_mime_headers)
01062             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01063 
01064         fflush(data_stream);
01065 
01066         functional_constraint(*var, dds, eval, data_stream);
01067         delete var;
01068         var = 0;
01069     }
01070     else {
01071 #if COMPRESSION_FOR_SERVER3
01072         if (with_mime_headers)
01073             set_mime_binary(data_stream, dods_data, d_cgi_ver,
01074                             (compress) ? deflate : x_plain, data_lmt);
01075         fflush(data_stream);
01076 
01077         int childpid;
01078         if (compress)
01079             data_stream = compressor(data_stream, childpid);
01080 #endif
01081         if (with_mime_headers)
01082             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01083 
01084         dataset_constraint(dds, eval, data_stream);
01085     }
01086 
01087     fflush(data_stream);
01088 }
01089 
01106 void
01107 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
01108                       ostream & data_stream, const string & anc_location,
01109                       bool with_mime_headers) const
01110 {
01111     // If this is a conditional request and the server should send a 304
01112     // response, do that and exit. Otherwise, continue on and send the full
01113     // response.
01114     time_t data_lmt = get_data_last_modified_time(anc_location);
01115     if (is_conditional()
01116         && data_lmt <= get_request_if_modified_since()
01117         && with_mime_headers) {
01118         set_mime_not_modified(data_stream);
01119         return;
01120     }
01121     // Set up the alarm.
01122     establish_timeout(data_stream);
01123     dds.set_timeout(d_timeout);
01124 
01125     eval.parse_constraint(d_ce, dds);   // Throws Error if the ce doesn't
01126                                         // parse. 
01127 
01128     dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
01129 
01130     // Start sending the response...
01131 #if COMPRESSION_FOR_SERVER3
01132     bool compress = d_comp && deflate_exists();
01133 #endif
01134 
01135     // Handle *functional* constraint expressions specially
01136     if (eval.functional_expression()) {
01137         // Get the result and then start sending the headers. This provides a
01138         // way to send errors back to the client w/o colliding with the
01139         // normal response headers. There's some duplication of code with this
01140         // and the else-clause.
01141         BaseType *var = eval.eval_function(dds, d_dataset);
01142         if (!var)
01143             throw Error(unknown_error, "Error calling the CE function.");
01144 
01145 #if COMPRESSION_FOR_SERVER3
01146         if (with_mime_headers)
01147             set_mime_binary(data_stream, dods_data, d_cgi_ver,
01148                             (compress) ? deflate : x_plain, data_lmt);
01149         data_stream << flush ;
01150 
01151         int childpid;
01152         if (compress)
01153             data_stream = compressor(data_stream, childpid);
01154 #endif
01155         if (with_mime_headers)
01156             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01157 
01158         data_stream << flush ;
01159 
01160         functional_constraint(*var, dds, eval, data_stream);
01161         delete var;
01162         var = 0;
01163     }
01164     else {
01165 #if COMPRESSION_FOR_SERVER3
01166         if (with_mime_headers)
01167             set_mime_binary(data_stream, dods_data, d_cgi_ver,
01168                             (compress) ? deflate : x_plain, data_lmt);
01169         data_stream << flush ;
01170 
01171         int childpid;
01172         if (compress)
01173             data_stream = compressor(data_stream, childpid);
01174 #endif
01175         if (with_mime_headers)
01176             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
01177 
01178         dataset_constraint(dds, eval, data_stream);
01179     }
01180 
01181     data_stream << flush ;
01182 }
01183 
01194 void
01195 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out,
01196                      bool with_mime_headers) const
01197 {
01198     // If constrained, parse the constraint. Throws Error or InternalErr.
01199     if (!d_ce.empty())
01200         eval.parse_constraint(d_ce, dds);
01201 
01202     if (eval.functional_expression())
01203         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.");
01204 
01205     time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
01206 
01207     // If this is a conditional request and the server should send a 304
01208     // response, do that and exit. Otherwise, continue on and send the full
01209     // response.
01210     if (is_conditional() && dds_lmt <= get_request_if_modified_since()
01211         && with_mime_headers) {
01212         set_mime_not_modified(out);
01213         return;
01214     }
01215     else {
01216         if (with_mime_headers)
01217             set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
01218         dds.print_xml(out, !d_ce.empty(), d_url + ".blob?" + d_ce);
01219     }
01220 }
01221 
01232 void
01233 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, ostream &out,
01234                      bool with_mime_headers) const
01235 {
01236     // If constrained, parse the constraint. Throws Error or InternalErr.
01237     if (!d_ce.empty())
01238         eval.parse_constraint(d_ce, dds);
01239 
01240     if (eval.functional_expression())
01241         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.");
01242 
01243     time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
01244 
01245     // If this is a conditional request and the server should send a 304
01246     // response, do that and exit. Otherwise, continue on and send the full
01247     // response.
01248     if (is_conditional() && dds_lmt <= get_request_if_modified_since()
01249         && with_mime_headers) {
01250         set_mime_not_modified(out);
01251         return;
01252     }
01253     else {
01254         if (with_mime_headers)
01255             set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
01256         dds.print_xml(out, !d_ce.empty(), d_url + ".blob?" + d_ce);
01257     }
01258 }
01259 
01264 void
01265 DODSFilter::send_blob(DDS &, FILE *, bool)
01266 {
01267 #if 0
01268     // Broken. jhrg 4/3/06
01269     bool compress = d_comp && deflate_exists();
01270     time_t data_lmt = get_data_last_modified_time(d_anc_dir);
01271 
01272     // If this is a conditional request and the server should send a 304
01273     // response, do that and exit. Otherwise, continue on and send the full
01274     // response.
01275     if (is_conditional() && data_lmt <= get_request_if_modified_since()
01276         && with_mime_headers) {
01277         set_mime_not_modified(out);
01278         return;
01279     }
01280 
01281     dds.parse_constraint(d_ce);
01282 
01283     // Handle *functional* constraint expressions specially
01284     if (dds.functional_expression()) {
01285         BaseType *var = dds.eval_function(d_dataset);
01286         if (!var)
01287             throw Error("Error calling the CE function.");
01288 
01289         if (with_mime_headers)
01290             set_mime_binary(out, dods_data, d_cgi_ver,
01291                             (compress) ? deflate : x_plain, data_lmt);
01292 
01293         FILE *comp_sink;
01294         XDR *xdr_sink;
01295         int childpid = get_sinks(out, compress, &comp_sink, &xdr_sink);
01296 
01297         // In the following call to serialize, suppress CE evaluation.
01298         if (!var->serialize(d_dataset, dds, xdr_sink, false))
01299             throw Error("Could not send the function result.");
01300 
01301         clean_sinks(childpid, compress, xdr_sink, comp_sink);
01302     }
01303     else {
01304         if (with_mime_headers)
01305             set_mime_binary(out, dods_data, d_cgi_ver,
01306                             (compress) ? deflate : x_plain, data_lmt);
01307 
01308         FILE *comp_sink;
01309         XDR *xdr_sink;
01310         int childpid = get_sinks(out, compress, &comp_sink, &xdr_sink);
01311 
01312         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
01313             if ((*i)->send_p()) // only process projected variables
01314                 if (!(*i)->serialize(d_dataset, dds, xdr_sink, true))
01315                     throw Error(string("Could not serialize variable '")
01316                                 + (*i)->name() + string("'."));
01317 
01318         clean_sinks(childpid, compress, xdr_sink, comp_sink);
01319     }
01320 #endif
01321 }
01322 
01323 } // namespace libdap
01324 

Generated on Tue Mar 4 18:01:54 2008 for libdap++ by  doxygen 1.5.1