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 16760 2007-06-26 21:42:26Z 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     -h: This message.";
00091 
00092 #if 0
00093 // Removed the call to waitpid in send_data() because calling fflush
00094 // addresses the problem wait() was supposed to solve and calling wait() is
00095 // the root of ticket #335. jhrg 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     //  similar 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         case 'h': print_usage(); exit(1);
00285         default: print_usage(); // Throws Error
00286         }
00287     }
00288 
00289     DBGN(cerr << "exiting." << endl);
00290 
00291     return getopt.optind; // return the index of the next argument
00292 }
00293 
00298 bool
00299 DODSFilter::is_conditional() const
00300 {
00301     return d_conditional_request;
00302 }
00303 
00317 void
00318 DODSFilter::set_cgi_version(string version)
00319 {
00320     d_cgi_ver = version;
00321 }
00322 
00328 string
00329 DODSFilter::get_cgi_version() const
00330 {
00331     return d_cgi_ver;
00332 }
00333 
00340 string
00341 DODSFilter::get_ce() const
00342 {
00343     return d_ce;
00344 }
00345 
00346 void
00347 DODSFilter::set_ce(string _ce)
00348 {
00349     d_ce = www2id(_ce, "%", "%20");
00350 }
00351 
00360 string
00361 DODSFilter::get_dataset_name() const
00362 {
00363     return d_dataset;
00364 }
00365 
00366 void
00367 DODSFilter::set_dataset_name(const string ds)
00368 {
00369     d_dataset = www2id(ds, "%", "%20");
00370 }
00371 
00375 string
00376 DODSFilter::get_URL() const
00377 {
00378     return d_url;
00379 }
00380 
00383 void
00384 DODSFilter::set_URL(const string &url)
00385 {
00386     if (url.find('?') != url.npos)
00387         print_usage();  // Throws Error
00388 
00389     d_url = url;
00390 }
00391 
00399 string
00400 DODSFilter::get_dataset_version() const
00401 {
00402     return "";
00403 }
00404 
00411 void DODSFilter::set_response(const string &r)
00412 {
00413     if (r == "DAS" || r == "das") {
00414         d_response = DAS_Response;
00415         d_action = "das" ;
00416     }
00417     else if (r == "DDS" || r == "dds") {
00418         d_response = DDS_Response;
00419         d_action = "dds" ;
00420     }
00421     else if (r == "DataDDS" || r == "dods") {
00422         d_response = DataDDS_Response;
00423         d_action = "dods" ;
00424     }
00425     else if (r == "DDX" || r == "ddx") {
00426         d_response = DDX_Response;
00427         d_action = "ddx" ;
00428     }
00429     else if (r == "Version") {
00430         d_response = Version_Response;
00431         d_action = "version" ;
00432     }
00433     else
00434         print_usage();   // Throws Error
00435 }
00436 
00438 DODSFilter::Response
00439 DODSFilter::get_response() const
00440 {
00441     return d_response;
00442 }
00443 
00445 string DODSFilter::get_action() const
00446 {
00447     return d_action;
00448 }
00449 
00470 time_t
00471 DODSFilter::get_dataset_last_modified_time() const
00472 {
00473     return last_modified_time(d_dataset);
00474 }
00475 
00485 time_t
00486 DODSFilter::get_das_last_modified_time(const string &anc_location) const
00487 {
00488     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00489         << anc_location << "call faf(das) d_dataset=" << d_dataset
00490         << " d_anc_file=" << d_anc_file << endl);
00491 
00492     string name
00493     = find_ancillary_file(d_dataset, "das",
00494                           (anc_location == "") ? d_anc_dir : anc_location,
00495                           d_anc_file);
00496 
00497     return max((name != "") ? last_modified_time(name) : 0,
00498                get_dataset_last_modified_time());
00499 }
00500 
00508 time_t
00509 DODSFilter::get_dds_last_modified_time(const string &anc_location) const
00510 {
00511     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00512         << anc_location << "call faf(dds) d_dataset=" << d_dataset
00513         << " d_anc_file=" << d_anc_file << endl);
00514 
00515     string name
00516     = find_ancillary_file(d_dataset, "dds",
00517                           (anc_location == "") ? d_anc_dir : anc_location,
00518                           d_anc_file);
00519 
00520     return max((name != "") ? last_modified_time(name) : 0,
00521                get_dataset_last_modified_time());
00522 }
00523 
00537 time_t
00538 DODSFilter::get_data_last_modified_time(const string &anc_location) const
00539 {
00540     DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
00541         << anc_location << "call faf(both) d_dataset=" << d_dataset
00542         << " d_anc_file=" << d_anc_file << endl);
00543 
00544     string dds_name
00545     = find_ancillary_file(d_dataset, "dds",
00546                           (anc_location == "") ? d_anc_dir : anc_location,
00547                           d_anc_file);
00548     string das_name
00549     = find_ancillary_file(d_dataset, "das",
00550                           (anc_location == "") ? d_anc_dir : anc_location,
00551                           d_anc_file);
00552 
00553     time_t m = max((das_name != "") ? last_modified_time(das_name) : (time_t)0,
00554                    (dds_name != "") ? last_modified_time(dds_name) : (time_t)0);
00555     // Note that this is a call to get_dataset_... not get_data_...
00556     time_t n = get_dataset_last_modified_time();
00557 
00558     return max(m, n);
00559 }
00560 
00568 time_t
00569 DODSFilter::get_request_if_modified_since() const
00570 {
00571     return d_if_modified_since;
00572 }
00573 
00580 string
00581 DODSFilter::get_cache_dir() const
00582 {
00583     return d_cache_dir;
00584 }
00585 
00590 void
00591 DODSFilter::set_timeout(int t)
00592 {
00593     d_timeout = t;
00594 }
00595 
00597 int
00598 DODSFilter::get_timeout() const
00599 {
00600     return d_timeout;
00601 }
00602 
00614 void
00615 DODSFilter::establish_timeout(FILE *stream) const
00616 {
00617 #ifndef WIN32
00618     if (d_timeout > 0) {
00619         SignalHandler *sh = SignalHandler::instance();
00620         sh->register_handler(SIGALRM, new AlarmHandler(stream));
00621         alarm(d_timeout);
00622     }
00623 #endif
00624 }
00625 
00626 
00636 void
00637 DODSFilter::read_ancillary_das(DAS &das, const string &anc_location) const
00638 {
00639     string name = find_ancillary_file(d_dataset, "das",
00640                                       (anc_location == "") ? d_anc_dir : anc_location,
00641                                       d_anc_file);
00642 
00643     FILE *in = fopen(name.c_str(), "r");
00644     if (in) {
00645         das.parse(in);
00646         int res = fclose(in) ;
00647         if (res) {
00648             DBG(cerr << "DODSFilter::read_ancillary_das - Failed to close file " << (void *)in << endl ;) ;
00649         }
00650     }
00651 }
00652 
00662 void
00663 DODSFilter::read_ancillary_dds(DDS &dds, const string &anc_location) const
00664 {
00665     string name = find_ancillary_file(d_dataset, "dds",
00666                                       (anc_location == "") ? d_anc_dir : anc_location,
00667                                       d_anc_file);
00668     FILE *in = fopen(name.c_str(), "r");
00669     if (in) {
00670         dds.parse(in);
00671         int res = fclose(in) ;
00672         if (res) {
00673             DBG(cerr << "DODSFilter::read_ancillary_dds - Failed to close " << (void *)in << endl ;) ;
00674         }
00675     }
00676 }
00677 
00678 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.";
00679 
00689 void
00690 DODSFilter::print_usage() const
00691 {
00692     // Write a message to the WWW server error log file.
00693     ErrMsgT(usage.c_str());
00694 
00695     throw Error(unknown_error, emessage);
00696 }
00697 
00703 void
00704 DODSFilter::send_version_info() const
00705 {
00706     do_version(d_cgi_ver, get_dataset_version());
00707 }
00708 
00720 void
00721 DODSFilter::send_das(FILE *out, DAS &das, const string &anc_location,
00722                      bool with_mime_headers) const
00723 {
00724     time_t das_lmt = get_das_last_modified_time(anc_location);
00725     if (is_conditional()
00726         && das_lmt <= get_request_if_modified_since()
00727         && with_mime_headers) {
00728         set_mime_not_modified(out);
00729     }
00730     else {
00731         if (with_mime_headers)
00732             set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
00733         das.print(out);
00734     }
00735     fflush(out) ;
00736 }
00737 
00738 void
00739 DODSFilter::send_das(DAS &das, const string &anc_location,
00740                      bool with_mime_headers) const
00741 {
00742     send_das(stdout, das, anc_location, with_mime_headers);
00743 }
00744 
00761 void
00762 DODSFilter::send_dds(FILE *out, DDS &dds, ConstraintEvaluator &eval,
00763                      bool constrained,
00764                      const string &anc_location,
00765                      bool with_mime_headers) const
00766 {
00767     // If constrained, parse the constraint. Throws Error or InternalErr.
00768     if (constrained)
00769         eval.parse_constraint(d_ce, dds);
00770 
00771     if (eval.functional_expression())
00772         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.");
00773 
00774     time_t dds_lmt = get_dds_last_modified_time(anc_location);
00775     if (is_conditional()
00776         && dds_lmt <= get_request_if_modified_since()
00777         && with_mime_headers) {
00778         set_mime_not_modified(out);
00779     }
00780     else {
00781         if (with_mime_headers)
00782             set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt);
00783         if (constrained)
00784             dds.print_constrained(out);
00785         else
00786             dds.print(out);
00787     }
00788 
00789     fflush(out) ;
00790 }
00791 
00792 void
00793 DODSFilter::send_dds(DDS &dds, ConstraintEvaluator &eval,
00794                      bool constrained, const string &anc_location,
00795                      bool with_mime_headers) const
00796 {
00797     send_dds(stdout, dds, eval, constrained, anc_location, with_mime_headers);
00798 }
00799 
00800 // 'lmt' unused. Should it be used to supply a LMT or removed from the
00801 // method? jhrg 8/9/05
00802 void
00803 DODSFilter::functional_constraint(BaseType &var, DDS &dds,
00804                                   ConstraintEvaluator &eval, FILE *out)
00805 const
00806 {
00807     fprintf(out, "Dataset {\n");
00808     var.print_decl(out, "    ", true, false, true);
00809     fprintf(out, "} function_value;\n");
00810     fprintf(out, "Data:\n");
00811 
00812     fflush(out);
00813 
00814     // Grab a stream encodes using XDR.
00815     XDR *xdr_sink = new_xdrstdio(out, XDR_ENCODE);
00816 
00817     try {
00818         // In the following call to serialize, suppress CE evaluation.
00819         var.serialize(d_dataset, eval, dds, xdr_sink, false);
00820         delete_xdrstdio(xdr_sink);
00821     }
00822     catch (Error &e) {
00823         delete_xdrstdio(xdr_sink);
00824         throw;
00825     }
00826 }
00827 
00828 void
00829 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
00830                                FILE * out) const
00831 {
00832     // send constrained DDS
00833     dds.print_constrained(out);
00834     fprintf(out, "Data:\n");
00835     fflush(out);
00836 
00837     // Grab a stream that encodes using XDR.
00838     XDR *xdr_sink = new_xdrstdio(out, XDR_ENCODE);
00839 
00840     try {
00841         // Send all variables in the current projection (send_p())
00842         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
00843             if ((*i)->send_p()) {
00844                 DBG(cerr << "Sending " << (*i)->name() << endl);
00845                 (*i)->serialize(d_dataset, eval, dds, xdr_sink, true);
00846             }
00847 
00848         delete_xdrstdio(xdr_sink);
00849     }
00850     catch (Error & e) {
00851         delete_xdrstdio(xdr_sink);
00852         throw;
00853     }
00854 }
00855 
00872 void
00873 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
00874                       FILE * data_stream, const string & anc_location,
00875                       bool with_mime_headers) const
00876 {
00877     // If this is a conditional request and the server should send a 304
00878     // response, do that and exit. Otherwise, continue on and send the full
00879     // response.
00880     time_t data_lmt = get_data_last_modified_time(anc_location);
00881     if (is_conditional()
00882         && data_lmt <= get_request_if_modified_since()
00883         && with_mime_headers) {
00884         set_mime_not_modified(data_stream);
00885         return;
00886     }
00887     // Set up the alarm.
00888     establish_timeout(data_stream);
00889     dds.set_timeout(d_timeout);
00890 
00891     eval.parse_constraint(d_ce, dds);   // Throws Error if the ce doesn't
00892                                         // parse. 
00893 
00894     dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
00895 
00896     // Start sending the response...
00897 #if COMPRESSION_FOR_SERVER3
00898     bool compress = d_comp && deflate_exists();
00899 #endif
00900 
00901     // Handle *functional* constraint expressions specially
00902     if (eval.functional_expression()) {
00903         // Get the result and then start sending the headers. This provides a
00904         // way to send errors back to the client w/o colliding with the
00905         // normal response headers. There's some duplication of code with this
00906         // and the else-clause.
00907         BaseType *var = eval.eval_function(dds, d_dataset);
00908         if (!var)
00909             throw Error(unknown_error, "Error calling the CE function.");
00910 
00911 #if COMPRESSION_FOR_SERVER3
00912         if (with_mime_headers)
00913             set_mime_binary(data_stream, dods_data, d_cgi_ver,
00914                             (compress) ? deflate : x_plain, data_lmt);
00915         fflush(data_stream);
00916 
00917         int childpid;
00918         if (compress)
00919             data_stream = compressor(data_stream, childpid);
00920 #endif
00921         if (with_mime_headers)
00922             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
00923 
00924         fflush(data_stream);
00925 
00926         functional_constraint(*var, dds, eval, data_stream);
00927         delete var;
00928         var = 0;
00929     }
00930     else {
00931 #if COMPRESSION_FOR_SERVER3
00932         if (with_mime_headers)
00933             set_mime_binary(data_stream, dods_data, d_cgi_ver,
00934                             (compress) ? deflate : x_plain, data_lmt);
00935         fflush(data_stream);
00936 
00937         int childpid;
00938         if (compress)
00939             data_stream = compressor(data_stream, childpid);
00940 #endif
00941         if (with_mime_headers)
00942             set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
00943 
00944         dataset_constraint(dds, eval, data_stream);
00945     }
00946 
00947     fflush(data_stream);
00948 }
00949 
00960 void
00961 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out,
00962                      bool with_mime_headers) const
00963 {
00964     // If constrained, parse the constraint. Throws Error or InternalErr.
00965     if (!d_ce.empty())
00966         eval.parse_constraint(d_ce, dds);
00967 
00968     time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
00969 
00970     // If this is a conditional request and the server should send a 304
00971     // response, do that and exit. Otherwise, continue on and send the full
00972     // response.
00973     if (is_conditional() && dds_lmt <= get_request_if_modified_since()
00974         && with_mime_headers) {
00975         set_mime_not_modified(out);
00976         return;
00977     }
00978     else {
00979         if (with_mime_headers)
00980             set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
00981         dds.print_xml(out, !d_ce.empty(), d_url + ".blob?" + d_ce);
00982     }
00983 }
00984 
00989 void
00990 DODSFilter::send_blob(DDS &, FILE *, bool)
00991 {
00992 #if 0
00993     // Broken. jhrg 4/3/06
00994     bool compress = d_comp && deflate_exists();
00995     time_t data_lmt = get_data_last_modified_time(d_anc_dir);
00996 
00997     // If this is a conditional request and the server should send a 304
00998     // response, do that and exit. Otherwise, continue on and send the full
00999     // response.
01000     if (is_conditional() && data_lmt <= get_request_if_modified_since()
01001         && with_mime_headers) {
01002         set_mime_not_modified(out);
01003         return;
01004     }
01005 
01006     dds.parse_constraint(d_ce);
01007 
01008     // Handle *functional* constraint expressions specially
01009     if (dds.functional_expression()) {
01010         BaseType *var = dds.eval_function(d_dataset);
01011         if (!var)
01012             throw Error("Error calling the CE function.");
01013 
01014         if (with_mime_headers)
01015             set_mime_binary(out, dods_data, d_cgi_ver,
01016                             (compress) ? deflate : x_plain, data_lmt);
01017 
01018         FILE *comp_sink;
01019         XDR *xdr_sink;
01020         int childpid = get_sinks(out, compress, &comp_sink, &xdr_sink);
01021 
01022         // In the following call to serialize, suppress CE evaluation.
01023         if (!var->serialize(d_dataset, dds, xdr_sink, false))
01024             throw Error("Could not send the function result.");
01025 
01026         clean_sinks(childpid, compress, xdr_sink, comp_sink);
01027     }
01028     else {
01029         if (with_mime_headers)
01030             set_mime_binary(out, dods_data, d_cgi_ver,
01031                             (compress) ? deflate : x_plain, data_lmt);
01032 
01033         FILE *comp_sink;
01034         XDR *xdr_sink;
01035         int childpid = get_sinks(out, compress, &comp_sink, &xdr_sink);
01036 
01037         for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
01038             if ((*i)->send_p()) // only process projected variables
01039                 if (!(*i)->serialize(d_dataset, dds, xdr_sink, true))
01040                     throw Error(string("Could not serialize variable '")
01041                                 + (*i)->name() + string("'."));
01042 
01043         clean_sinks(childpid, compress, xdr_sink, comp_sink);
01044     }
01045 #endif
01046 }
01047 

Generated on Wed Jun 27 12:56:39 2007 for libdap++ by  doxygen 1.4.7