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 16088 2007-03-28 21:42:19Z jimg $"
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 "InternalErr.h"
00068 #ifndef WIN32
00069 #include "SignalHandler.h"
00070 #include "EventHandler.h"
00071 #include "AlarmHandler.h"
00072 #endif
00073 
00074 using namespace std;
00075 
00076 const string usage =
00077     "Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\
00078     \n\
00079     options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\
00080     -u <url>: The complete URL minus the CE (required for DDX)\n\
00081     -c: Compress the response using the deflate algorithm.\n\
00082     -e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\
00083     -v <version>: Use <version> as the version number\n\
00084     -d <dir>: Look for ancillary file in <dir> (deprecated).\n\
00085     -f <file>: Look for ancillary data in <file> (deprecated).\n\
00086     -r <dir>: Use <dir> as a cache directory\n\
00087     -l <time>: Conditional request; if data source is unchanged since\n\
00088     <time>, return an HTTP 304 response.\n\
00089     -t <seconds>: Timeout the handler after <seconds>.\n\
00090     ";
00091 
00092 #if 0
00093 // Removed the call to waitpid in send_data() because I think calling fflush
00094 // addresses the problem wait() was supposed to solve and I think calling
00095 // wait() is the root of ticket #335. jheg 3/10/06
00096 #ifdef WIN32
00097 #define WAITPID(pid) while(_cwait(NULL, pid, NULL) > 0)
00098 #else
00099 #define WAITPID(pid) while(waitpid(pid, 0, 0) > 0)
00100 #endif
00101 #endif
00102 
00167 DODSFilter::DODSFilter(int argc, char *argv[]) throw(Error)
00168 {
00169     initialize(argc, argv);
00170 
00171     DBG(cerr << "d_comp: " << d_comp << endl);
00172     DBG(cerr << "d_ce: " << d_ce << endl);
00173     DBG(cerr << "d_cgi_ver: " << d_cgi_ver << endl);
00174     DBG(cerr << "d_response: " << d_response << endl);
00175     DBG(cerr << "d_anc_dir: " << d_anc_dir << endl);
00176     DBG(cerr << "d_anc_file: " << d_anc_file << endl);
00177     DBG(cerr << "d_cache_dir: " << d_cache_dir << endl);
00178     DBG(cerr << "d_conditional_request: " << d_conditional_request << endl);
00179     DBG(cerr << "d_if_modified_since: " << d_if_modified_since << endl);
00180     DBG(cerr << "d_url: " << d_url << endl);
00181     DBG(cerr << "d_timeout: " << d_timeout << endl);
00182 }
00183 
00184 DODSFilter::~DODSFilter()
00185 {
00186 }
00187 
00190 void
00191 DODSFilter::initialize()
00192 {
00193     // Set default values. Don't use the C++ constructor initialization so
00194     // that a subclass can have more control over this process.
00195     d_comp = false;
00196     d_bad_options = false;
00197     d_conditional_request = false;
00198     d_dataset = "";
00199     d_ce = "";
00200     d_cgi_ver = "";
00201     d_anc_dir = "";
00202     d_anc_file = "";
00203     d_cache_dir = "";
00204     d_response = Unknown_Response;;
00205     d_anc_das_lmt = 0;
00206     d_anc_dds_lmt = 0;
00207     d_if_modified_since = -1;
00208     d_url = "";
00209     d_program_name = "Unknown";
00210     d_timeout = 0;
00211 
00212 #ifdef WIN32
00213     //  We want serving from win32 to behave in a manner
00214     //  similiar to the UNIX way - no CR->NL terminated lines
00215     //  in files. Hence stdout goes to binary mode.
00216     _setmode(_fileno(stdout), _O_BINARY);
00217 #endif
00218 }
00219 
00231 void
00232 DODSFilter::initialize(int argc, char *argv[])
00233 {
00234     initialize();
00235 
00236     d_program_name = argv[0];
00237 
00238     // This should be specialized by a subclass. This may throw Error.
00239     int next_arg = process_options(argc, argv);
00240 
00241     // Look at what's left after processing the command line options. Either
00242     // there MUST be a dataset name OR the caller is asking for version
00243     // information. If neither is true, then the options are bad.
00244     if (next_arg < argc) {
00245         d_dataset = argv[next_arg];
00246         d_dataset = www2id(d_dataset, "%", "%20");
00247     }
00248     else if (get_response() != Version_Response)
00249         print_usage();   // Throws Error
00250 }
00251 
00260 int
00261 DODSFilter::process_options(int argc, char *argv[])
00262 {
00263     DBG(cerr << "Entering process_options... ");
00264 
00265     int option_char;
00266     GetOpt getopt (argc, argv, "ce: v: d: f: r: l: o: u: t: ");
00267 
00268     while ((option_char = getopt()) != EOF) {
00269         switch (option_char) {
00270         case 'c': d_comp = true; break;
00271         case 'e': set_ce(getopt.optarg); break;
00272         case 'v': set_cgi_version(getopt.optarg); break;
00273         case 'd': d_anc_dir = getopt.optarg; break;
00274         case 'f': d_anc_file = getopt.optarg; break;
00275         case 'r': d_cache_dir = getopt.optarg; break;
00276         case 'o': set_response(getopt.optarg); break;
00277         case 'u': set_URL(getopt.optarg); break;
00278         case 't': d_timeout = atoi(getopt.optarg); break;
00279         case 'l':
00280             d_conditional_request = true;
00281             d_if_modified_since
00282             = static_cast<time_t>(strtol(getopt.optarg, NULL, 10));
00283             break;
00284         default: print_usage(); // Throws Error
00285         }
00286     }
00287 
00288     DBGN(cerr << "exiting." << endl);
00289 
00290     return getopt.optind; // return the index of the next argument
00291 }
00292 
00297 bool
00298 DODSFilter::is_conditional() const
00299 {
00300     return d_conditional_request;
00301 }
00302 
00316 void
00317 DODSFilter::set_cgi_version(string version)
00318 {
00319     d_cgi_ver = version;
00320 }
00321 
00327 string
00328 DODSFilter::get_cgi_version() const
00329 {
00330     return d_cgi_ver;
00331 }
00332 
00339 string
00340 DODSFilter::get_ce() const
00341 {
00342     return d_ce;
00343 }
00344 
00345 void
00346 DODSFilter::set_ce(string _ce)
00347 {
00348     d_ce = www2id(_ce, "%", "%20");
00349 }
00350 
00359 string
00360 DODSFilter::get_dataset_name() const
00361 {
00362     return d_dataset;
00363 }
00364 
00365 void
00366 DODSFilter::set_dataset_name(const string ds)
00367 {
00368     d_dataset = www2id(ds, "%", "%20");
00369 }
00370 
00374 string
00375 DODSFilter::get_URL() const
00376 {
00377     return d_url;
00378 }
00379 
00382 void
00383 DODSFilter::set_URL(const string &url)
00384 {
00385     if (url.find('?') != url.npos)
00386         print_usage();  // Throws Error
00387 
00388     d_url = url;
00389 }
00390 
00398 string
00399 DODSFilter::get_dataset_version() const
00400 {
00401     return "";
00402 }
00403 
00410 void DODSFilter::set_response(const string &r)
00411 {
00412     if (r == "DAS" || r == "das") {
00413         d_response = DAS_Response;
00414         d_action = "das" ;
00415     }
00416     else if (r == "DDS" || r == "dds") {
00417         d_response = DDS_Response;
00418         d_action = "dds" ;
00419     }
00420     else if (r == "DataDDS" || r == "dods") {
00421         d_response = DataDDS_Response;
00422         d_action = "dods" ;
00423     }
00424     else if (r == "DDX" || r == "ddx") {
00425         d_response = DDX_Response;
00426         d_action = "ddx" ;
00427     }
00428     else if (r == "Version") {
00429         d_response = Version_Response;
00430         d_action = "version" ;
00431     }
00432     else
00433         print_usage();   // Throws Error
00434 }
00435 
00437 DODSFilter::Response
00438 DODSFilter::get_response() const
00439 {
00440     return d_response;
00441 }
00442 
00444 string DODSFilter::get_action() const
00445 {
00446     return d_action;
00447 }
00448 
00469 time_t
00470 DODSFilter::get_dataset_last_modified_time() const
00471 {
00472     return last_modified_time(d_dataset);
00473 }
00474 
00484 time_t
00485 DODSFilter::get_das_last_modified_time(const string &anc_location) const
00486 {
00487     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00488         << anc_location << "call faf(das) d_dataset=" << d_dataset
00489         << " d_anc_file=" << d_anc_file << endl);
00490 
00491     string name
00492     = find_ancillary_file(d_dataset, "das",
00493                           (anc_location == "") ? d_anc_dir : anc_location,
00494                           d_anc_file);
00495 
00496     return max((name != "") ? last_modified_time(name) : 0,
00497                get_dataset_last_modified_time());
00498 }
00499 
00507 time_t
00508 DODSFilter::get_dds_last_modified_time(const string &anc_location) const
00509 {
00510     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00511         << anc_location << "call faf(dds) d_dataset=" << d_dataset
00512         << " d_anc_file=" << d_anc_file << endl);
00513 
00514     string name
00515     = find_ancillary_file(d_dataset, "dds",
00516                           (anc_location == "") ? d_anc_dir : anc_location,
00517                           d_anc_file);
00518 
00519     return max((name != "") ? last_modified_time(name) : 0,
00520                get_dataset_last_modified_time());
00521 }
00522 
00536 time_t
00537 DODSFilter::get_data_last_modified_time(const string &anc_location) const
00538 {
00539     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00540         << anc_location << "call faf(both) d_dataset=" << d_dataset
00541         << " d_anc_file=" << d_anc_file << endl);
00542 
00543     string dds_name
00544     = find_ancillary_file(d_dataset, "dds",
00545                           (anc_location == "") ? d_anc_dir : anc_location,
00546                           d_anc_file);
00547     string das_name
00548     = find_ancillary_file(d_dataset, "das",
00549                           (anc_location == "") ? d_anc_dir : anc_location,
00550                           d_anc_file);
00551 
00552     time_t m = max((das_name != "") ? last_modified_time(das_name) : (time_t)0,
00553                    (dds_name != "") ? last_modified_time(dds_name) : (time_t)0);
00554     // Note that this is a call to get_dataset_... not get_data_...
00555     time_t n = get_dataset_last_modified_time();
00556 
00557     return max(m, n);
00558 }
00559 
00567 time_t
00568 DODSFilter::get_request_if_modified_since() const
00569 {
00570     return d_if_modified_since;
00571 }
00572 
00579 string
00580 DODSFilter::get_cache_dir() const
00581 {
00582     return d_cache_dir;
00583 }
00584 
00589 void
00590 DODSFilter::set_timeout(int t)
00591 {
00592     d_timeout = t;
00593 }
00594 
00596 int
00597 DODSFilter::get_timeout() const
00598 {
00599     return d_timeout;
00600 }
00601 
00613 void
00614 DODSFilter::establish_timeout(FILE *stream) const
00615 {
00616 #ifndef WIN32
00617     if (d_timeout > 0) {
00618         SignalHandler *sh = SignalHandler::instance();
00619         sh->register_handler(SIGALRM, new AlarmHandler(stream));
00620         alarm(d_timeout);
00621     }
00622 #endif
00623 }
00624 
00625 
00635 void
00636 DODSFilter::read_ancillary_das(DAS &das, const string &anc_location) const
00637 {
00638     string name = find_ancillary_file(d_dataset, "das",
00639                                       (anc_location == "") ? d_anc_dir : anc_location,
00640                                       d_anc_file);
00641 
00642     FILE *in = fopen(name.c_str(), "r");
00643     if (in) {
00644         das.parse(in);
00645         int res = fclose(in) ;
00646         if (res) {
00647             DBG(cerr << "DODSFilter::read_ancillary_das - Failed to close file " << (void *)in << endl ;) ;
00648         }
00649     }
00650 }
00651 
00661 void
00662 DODSFilter::read_ancillary_dds(DDS &dds, const string &anc_location) const
00663 {
00664     string name = find_ancillary_file(d_dataset, "dds",
00665                                       (anc_location == "") ? d_anc_dir : anc_location,
00666                                       d_anc_file);
00667     FILE *in = fopen(name.c_str(), "r");
00668     if (in) {
00669         dds.parse(in);
00670         int res = fclose(in) ;
00671         if (res) {
00672             DBG(cerr << "DODSFilter::read_ancillary_dds - Failed to close " << (void *)in << endl ;) ;
00673         }
00674     }
00675 }
00676 
00677 static const char *emessage = "DODS internal server error; usage error. Please report this to the dataset maintainer, or to support@unidata.ucar.edu.";
00678 
00688 void
00689 DODSFilter::print_usage() const
00690 {
00691     // Write a message to the WWW server error log file.
00692     ErrMsgT(usage.c_str());
00693 
00694     throw Error(unknown_error, emessage);
00695 }
00696 
00702 void
00703 DODSFilter::send_version_info() const
00704 {
00705     do_version(d_cgi_ver, get_dataset_version());
00706 }
00707 
00719 void
00720 DODSFilter::send_das(FILE *out, DAS &das, const string &anc_location,
00721                      bool with_mime_headers) const
00722 {
00723     time_t das_lmt = get_das_last_modified_time(anc_location);
00724     if (is_conditional()
00725         && das_lmt <= get_request_if_modified_since()
00726         && with_mime_headers) {
00727         set_mime_not_modified(out);
00728     }
00729     else {
00730         if (with_mime_headers)
00731             set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
00732         das.print(out);
00733     }
00734     fflush(out) ;
00735 }
00736 
00737 void
00738 DODSFilter::send_das(DAS &das, const string &anc_location,
00739                      bool with_mime_headers) const
00740 {
00741     send_das(stdout, das, anc_location, with_mime_headers);
00742 }
00743 
00760 void
00761 DODSFilter::send_dds(FILE *out, DDS &dds, ConstraintEvaluator &eval,
00762                      bool constrained,
00763                      const string &anc_location,
00764                      bool with_mime_headers) const
00765 {
00766     // If constrained, parse the constriant. Throws Error or InternalErr.
00767     if (constrained)
00768         eval.parse_constraint(d_ce, dds);
00769 
00770     if (eval.functional_expression())
00771         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.");
00772 
00773     time_t dds_lmt = get_dds_last_modified_time(anc_location);
00774     if (is_conditional()
00775         && dds_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_dds, d_cgi_ver, x_plain, dds_lmt);
00782         if (constrained)
00783             dds.print_constrained(out);
00784         else
00785             dds.print(out);
00786     }
00787 
00788     fflush(out) ;
00789 }
00790 
00791 void
00792 DODSFilter::send_dds(DDS &dds, ConstraintEvaluator &eval,
00793                      bool constrained, const string &anc_location,
00794                      bool with_mime_headers) const
00795 {
00796     send_dds(stdout, dds, eval, constrained, anc_location, with_mime_headers);
00797 }
00798 
00799 // 'lmt' unused. Should it be used to supply a LMT or removed from the
00800 // method? jhrg 8/9/05
00801 void
00802 DODSFilter::functional_constraint(BaseType &var, DDS &dds,
00803                                   ConstraintEvaluator &eval, FILE *out)
00804 const
00805 {
00806     fprintf(out, "Dataset {\n");
00807     var.print_decl(out, "    ", true, false, true);
00808     fprintf(out, "} function_value;\n");
00809     fprintf(out, "Data:\n");
00810 
00811     fflush(out);
00812 
00813     // Grab a stream encodes using XDR.
00814     XDR *xdr_sink = new_xdrstdio(out, XDR_ENCODE);
00815 
00816     try {
00817         // In the following call to serialize, suppress CE evaluation.
00818         var.serialize(d_dataset, eval, dds, xdr_sink, false);
00819         delete_xdrstdio(xdr_sink);
00820     }
00821     catch (Error &e) {
00822         delete_xdrstdio(xdr_sink);
00823         throw;
00824     }
00825 }
00826 
00827 void
00828 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
00829                                FILE * out) const
00830 {
00831     // send constrained DDS
00832     dds.print_constrained(out);
00833     fprintf(out, "Data:\n");
00834     fflush(out);
00835 
00836     // Grab a stream that encodes using XDR.
00837     XDR *xdr_sink = new_xdrstdio(out, XDR_ENCODE);
00838 
00839     try {
00840         // Send all variables in the current projection (send_p())
00841         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
00842             if ((*i)->send_p()) {
00843                 DBG(cerr << "Sending " << (*i)->name() << endl);
00844                 (*i)->serialize(d_dataset, eval, dds, xdr_sink, true);
00845             }
00846 
00847         delete_xdrstdio(xdr_sink);
00848     }
00849     catch (Error & e) {
00850         delete_xdrstdio(xdr_sink);
00851         throw;
00852     }
00853 }
00854 
00871 void
00872 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
00873                       FILE * data_stream, const string & anc_location,
00874                       bool with_mime_headers) const
00875 {
00876     // If this is a conditional request and the server should send a 304
00877     // response, do that and exit. Otherwise, continue on and send the full
00878     // response.
00879     time_t data_lmt = get_data_last_modified_time(anc_location);
00880     if (is_conditional()
00881         && data_lmt <= get_request_if_modified_since()
00882         && with_mime_headers) {
00883         set_mime_not_modified(data_stream);
00884         return;
00885     }
00886     // Set up the alarm.
00887     establish_timeout(data_stream);
00888     dds.set_timeout(d_timeout);
00889 
00890     eval.parse_constraint(d_ce, dds);   // Throws Error if the ce doesn't
00891                                         // parse. 
00892 
00893     dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
00894 
00895     // Start sending the response...
00896 #if COMPRESSION_FOR_SERVER3
00897     bool compress = d_comp && deflate_exists();
00898 #endif
00899 
00900     // Handle *functional* constraint expressions specially
00901     if (eval.functional_expression()) {
00902         // Get the result and then start sending the headers. This provides a
00903         // way to send errors back to the client w/o colliding with the
00904         // normal response headers. There's some duplication of code with this
00905         // and the else-clause.
00906         BaseType *var = eval.eval_function(dds, d_dataset);
00907         if (!var)
00908             throw Error(unknown_error, "Error calling the CE function.");
00909 
00910 #if COMPRESSION_FOR_SERVER3
00911         if (with_mime_headers)
00912             set_mime_binary(data_stream, dods_data, d_cgi_ver,
00913                             (compress) ? deflate : x_plain, data_lmt);
00914         fflush(data_stream);
00915 
00916         int childpid;
00917         if (compress)
00918             data_stream = compressor(data_stream, childpid);
00919 #endif
00920         if (with_mime_headers)
00921             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
00922 
00923         fflush(data_stream);
00924 
00925         functional_constraint(*var, dds, eval, data_stream);
00926         delete var;
00927         var = 0;
00928     }
00929     else {
00930 #if COMPRESSION_FOR_SERVER3
00931         if (with_mime_headers)
00932             set_mime_binary(data_stream, dods_data, d_cgi_ver,
00933                             (compress) ? deflate : x_plain, data_lmt);
00934         fflush(data_stream);
00935 
00936         int childpid;
00937         if (compress)
00938             data_stream = compressor(data_stream, childpid);
00939 #endif
00940         if (with_mime_headers)
00941             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
00942 
00943         dataset_constraint(dds, eval, data_stream);
00944     }
00945 
00946     fflush(data_stream);
00947 }
00948 
00959 void
00960 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out,
00961                      bool with_mime_headers) const
00962 {
00963     // If constrained, parse the constriant. Throws Error or InternalErr.
00964     if (!d_ce.empty())
00965         eval.parse_constraint(d_ce, dds);
00966 
00967     time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
00968 
00969     // If this is a conditional request and the server should send a 304
00970     // response, do that and exit. Otherwise, continue on and send the full
00971     // response.
00972     if (is_conditional() && dds_lmt <= get_request_if_modified_since()
00973         && with_mime_headers) {
00974         set_mime_not_modified(out);
00975         return;
00976     }
00977     else {
00978         if (with_mime_headers)
00979             set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
00980         dds.print_xml(out, !d_ce.empty(), d_url + ".blob?" + d_ce);
00981     }
00982 }
00983 
00988 void
00989 DODSFilter::send_blob(DDS &, FILE *, bool)
00990 {
00991 #if 0
00992     // Broken. jhrg 4/3/06
00993     bool compress = d_comp && deflate_exists();
00994     time_t data_lmt = get_data_last_modified_time(d_anc_dir);
00995 
00996     // If this is a conditional request and the server should send a 304
00997     // response, do that and exit. Otherwise, continue on and send the full
00998     // response.
00999     if (is_conditional() && data_lmt <= get_request_if_modified_since()
01000         && with_mime_headers) {
01001         set_mime_not_modified(out);
01002         return;
01003     }
01004 
01005     dds.parse_constraint(d_ce);
01006 
01007     // Handle *functional* constraint expressions specially
01008     if (dds.functional_expression()) {
01009         BaseType *var = dds.eval_function(d_dataset);
01010         if (!var)
01011             throw Error("Error calling the CE function.");
01012 
01013         if (with_mime_headers)
01014             set_mime_binary(out, dods_data, d_cgi_ver,
01015                             (compress) ? deflate : x_plain, data_lmt);
01016 
01017         FILE *comp_sink;
01018         XDR *xdr_sink;
01019         int childpid = get_sinks(out, compress, &comp_sink, &xdr_sink);
01020 
01021         // In the following call to serialize, suppress CE evaluation.
01022         if (!var->serialize(d_dataset, dds, xdr_sink, false))
01023             throw Error("Could not send the function result.");
01024 
01025         clean_sinks(childpid, compress, xdr_sink, comp_sink);
01026     }
01027     else {
01028         if (with_mime_headers)
01029             set_mime_binary(out, dods_data, d_cgi_ver,
01030                             (compress) ? deflate : x_plain, data_lmt);
01031 
01032         FILE *comp_sink;
01033         XDR *xdr_sink;
01034         int childpid = get_sinks(out, compress, &comp_sink, &xdr_sink);
01035 
01036         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
01037             if ((*i)->send_p()) // only process projected variables
01038                 if (!(*i)->serialize(d_dataset, dds, xdr_sink, true))
01039                     throw Error(string("Could not serialize variable '")
01040                                 + (*i)->name() + string("'."));
01041 
01042         clean_sinks(childpid, compress, xdr_sink, comp_sink);
01043     }
01044 #endif
01045 }
01046 

Generated on Fri Feb 8 05:14:02 2008 for libdap++ by  doxygen 1.5.4