libdap Updated for version 3.20.11
libdap4 is an implementation of OPeNDAP's DAP protocol.
DODSFilter.cc
1
2// -*- mode: c++; c-basic-offset:4 -*-
3
4// This file is part of libdap, A C++ implementation of the OPeNDAP Data
5// Access Protocol.
6
7// Copyright (c) 2002,2003 OPeNDAP, Inc.
8// Author: James Gallagher <jgallagher@opendap.org>
9//
10// This library is free software; you can redistribute it and/or
11// modify it under the terms of the GNU Lesser General Public
12// License as published by the Free Software Foundation; either
13// version 2.1 of the License, or (at your option) any later version.
14//
15// This library is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18// Lesser General Public License for more details.
19//
20// You should have received a copy of the GNU Lesser General Public
21// License along with this library; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23//
24// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25
26// (c) COPYRIGHT URI/MIT 1997-1999
27// Please read the full copyright statement in the file COPYRIGHT_URI.
28//
29// Authors:
30// jhrg,jimg James Gallagher <jgallagher@gso.uri.edu>
31
32// Implementation of the DODSFilter class. This class is used to build dods
33// filter programs which, along with a CGI program, comprise OPeNDAP servers.
34// jhrg 8/26/97
35
36
37#include "config.h"
38
39#include <signal.h>
40
41#ifndef WIN32
42#include <unistd.h> // for getopt
43#include <sys/wait.h>
44#else
45#include <io.h>
46#include <fcntl.h>
47#include <process.h>
48#endif
49
50#include <iostream>
51#include <sstream>
52#include <string>
53#include <algorithm>
54#include <cstdlib>
55#include <cstring>
56
57#ifdef HAVE_UUID_UUID_H
58#include <uuid/uuid.h> // used to build CID header value for data ddx
59#elif defined(HAVE_UUID_H)
60#include <uuid.h>
61#else
62#error "Could not find UUID library header"
63#endif
64
65#include <GetOpt.h>
66
67#include "DAS.h"
68#include "DDS.h"
69#include "debug.h"
70#include "mime_util.h"
71#include "Ancillary.h"
72#include "util.h"
73#include "escaping.h"
74#include "DODSFilter.h"
75#include "XDRStreamMarshaller.h"
76#include "InternalErr.h"
77
78#ifndef WIN32
79#include "SignalHandler.h"
80#include "EventHandler.h"
81#include "AlarmHandler.h"
82#endif
83
84#define CRLF "\r\n" // Change here, expr-test.cc and DODSFilter.cc
85
86using namespace std;
87
88namespace libdap {
89
90const string usage =
91 "Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\
92 \n\
93 options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\
94 -u <url>: The complete URL minus the CE (required for DDX)\n\
95 -c: Compress the response using the deflate algorithm.\n\
96 -e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\
97 -v <version>: Use <version> as the version number\n\
98 -d <dir>: Look for ancillary file in <dir> (deprecated).\n\
99 -f <file>: Look for ancillary data in <file> (deprecated).\n\
100 -r <dir>: Use <dir> as a cache directory\n\
101 -l <time>: Conditional request; if data source is unchanged since\n\
102 <time>, return an HTTP 304 response.\n\
103 -t <seconds>: Timeout the handler after <seconds>.\n\
104 -h: This message.";
105
170DODSFilter::DODSFilter(int argc, char *argv[]) throw(Error)
171{
172 initialize(argc, argv);
173
174 DBG(cerr << "d_comp: " << d_comp << endl);
175 DBG(cerr << "d_dap2ce: " << d_dap2ce << endl);
176 DBG(cerr << "d_cgi_ver: " << d_cgi_ver << endl);
177 DBG(cerr << "d_response: " << d_response << endl);
178 DBG(cerr << "d_anc_dir: " << d_anc_dir << endl);
179 DBG(cerr << "d_anc_file: " << d_anc_file << endl);
180 DBG(cerr << "d_cache_dir: " << d_cache_dir << endl);
181 DBG(cerr << "d_conditional_request: " << d_conditional_request << endl);
182 DBG(cerr << "d_if_modified_since: " << d_if_modified_since << endl);
183 DBG(cerr << "d_url: " << d_url << endl);
184 DBG(cerr << "d_timeout: " << d_timeout << endl);
185}
186
187DODSFilter::~DODSFilter()
188{
189}
190
193void
195{
196 // Set default values. Don't use the C++ constructor initialization so
197 // that a subclass can have more control over this process.
198 d_comp = false;
199 d_bad_options = false;
200 d_conditional_request = false;
201 d_dataset = "";
202 d_dap2ce = "";
203 d_cgi_ver = "";
204 d_anc_dir = "";
205 d_anc_file = "";
206 d_cache_dir = "";
207 d_response = Unknown_Response;;
208 d_anc_das_lmt = 0;
209 d_anc_dds_lmt = 0;
210 d_if_modified_since = -1;
211 d_url = "";
212 d_program_name = "Unknown";
213 d_timeout = 0;
214
215#ifdef WIN32
216 // We want serving from win32 to behave in a manner
217 // similar to the UNIX way - no CR->NL terminated lines
218 // in files. Hence stdout goes to binary mode.
219 _setmode(_fileno(stdout), _O_BINARY);
220#endif
221}
222
234void
235DODSFilter::initialize(int argc, char *argv[])
236{
237 initialize();
238
239 d_program_name = argv[0];
240
241 // This should be specialized by a subclass. This may throw Error.
242 int next_arg = process_options(argc, argv);
243
244 // Look at what's left after processing the command line options. Either
245 // there MUST be a dataset name OR the caller is asking for version
246 // information. If neither is true, then the options are bad.
247 if (next_arg < argc) {
248 d_dataset = argv[next_arg];
249 d_dataset = www2id(d_dataset, "%", "%20");
250 }
251 else if (get_response() != Version_Response)
252 print_usage(); // Throws Error
253}
254
263int
264DODSFilter::process_options(int argc, char *argv[])
265{
266 DBG(cerr << "Entering process_options... ");
267
268 int option_char;
269 GetOpt getopt (argc, argv, "ce: v: d: f: r: l: o: u: t: ");
270
271 while ((option_char = getopt()) != -1) {
272 switch (option_char) {
273 case 'c': d_comp = true; break;
274 case 'e': set_ce(getopt.optarg); break;
275 case 'v': set_cgi_version(getopt.optarg); break;
276 case 'd': d_anc_dir = getopt.optarg; break;
277 case 'f': d_anc_file = getopt.optarg; break;
278 case 'r': d_cache_dir = getopt.optarg; break;
279 case 'o': set_response(getopt.optarg); break;
280 case 'u': set_URL(getopt.optarg); break;
281 case 't': d_timeout = atoi(getopt.optarg); break;
282 case 'l':
283 d_conditional_request = true;
284 d_if_modified_since
285 = static_cast<time_t>(strtol(getopt.optarg, NULL, 10));
286 break;
287 case 'h': print_usage();
288 break;
289 // exit(1);
290 // Removed 12/29/2011; exit should
291 // not be called by a library. NB:
292 // print_usage() throws Error.
293 default: print_usage(); // Throws Error
294 break;
295 }
296 }
297
298 DBGN(cerr << "exiting." << endl);
299
300 return getopt.optind; // return the index of the next argument
301}
302
307bool
309{
310 return d_conditional_request;
311}
312
326void
328{
329 d_cgi_ver = version;
330}
331
337string
339{
340 return d_cgi_ver;
341}
342
349string
351{
352 return d_dap2ce;
353}
354
355void
356DODSFilter::set_ce(string _ce)
357{
358 d_dap2ce = www2id(_ce, "%", "%20");
359}
360
369string
371{
372 return d_dataset;
373}
374
375void
376DODSFilter::set_dataset_name(const string ds)
377{
378 d_dataset = www2id(ds, "%", "%20");
379}
380
384string
386{
387 return d_url;
388}
389
392void
393DODSFilter::set_URL(const string &url)
394{
395 if (url.find('?') != url.npos)
396 print_usage(); // Throws Error
397
398 d_url = url;
399}
400
408string
410{
411 return "";
412}
413
420void DODSFilter::set_response(const string &r)
421{
422 if (r == "DAS" || r == "das") {
423 d_response = DAS_Response;
424 d_action = "das" ;
425 }
426 else if (r == "DDS" || r == "dds") {
427 d_response = DDS_Response;
428 d_action = "dds" ;
429 }
430 else if (r == "DataDDS" || r == "dods") {
431 d_response = DataDDS_Response;
432 d_action = "dods" ;
433 }
434 else if (r == "DDX" || r == "ddx") {
435 d_response = DDX_Response;
436 d_action = "ddx" ;
437 }
438 else if (r == "DataDDX" || r == "dataddx") {
439 d_response = DataDDX_Response;
440 d_action = "dataddx" ;
441 }
442 else if (r == "Version") {
443 d_response = Version_Response;
444 d_action = "version" ;
445 }
446 else
447 print_usage(); // Throws Error
448}
449
453{
454 return d_response;
455}
456
459{
460 return d_action;
461}
462
483time_t
485{
486 return last_modified_time(d_dataset);
487}
488
498time_t
499DODSFilter::get_das_last_modified_time(const string &anc_location) const
500{
501 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
502 << anc_location << "call faf(das) d_dataset=" << d_dataset
503 << " d_anc_file=" << d_anc_file << endl);
504
505 string name
506 = Ancillary::find_ancillary_file(d_dataset, "das",
507 (anc_location == "") ? d_anc_dir : anc_location,
508 d_anc_file);
509
510 return max((name != "") ? last_modified_time(name) : 0,
512}
513
521time_t
522DODSFilter::get_dds_last_modified_time(const string &anc_location) const
523{
524 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
525 << anc_location << "call faf(dds) d_dataset=" << d_dataset
526 << " d_anc_file=" << d_anc_file << endl);
527
528 string name
529 = Ancillary::find_ancillary_file(d_dataset, "dds",
530 (anc_location == "") ? d_anc_dir : anc_location,
531 d_anc_file);
532
533 return max((name != "") ? last_modified_time(name) : 0,
535}
536
550time_t
551DODSFilter::get_data_last_modified_time(const string &anc_location) const
552{
553 DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
554 << anc_location << "call faf(both) d_dataset=" << d_dataset
555 << " d_anc_file=" << d_anc_file << endl);
556
557 string dds_name
558 = Ancillary::find_ancillary_file(d_dataset, "dds",
559 (anc_location == "") ? d_anc_dir : anc_location,
560 d_anc_file);
561 string das_name
562 = Ancillary::find_ancillary_file(d_dataset, "das",
563 (anc_location == "") ? d_anc_dir : anc_location,
564 d_anc_file);
565
566 time_t m = max((das_name != "") ? last_modified_time(das_name) : (time_t)0,
567 (dds_name != "") ? last_modified_time(dds_name) : (time_t)0);
568 // Note that this is a call to get_dataset_... not get_data_...
570
571 return max(m, n);
572}
573
581time_t
583{
584 return d_if_modified_since;
585}
586
593string
595{
596 return d_cache_dir;
597}
598
603void
605{
606 d_timeout = t;
607}
608
610int
612{
613 return d_timeout;
614}
615
627void
628DODSFilter::establish_timeout(FILE *stream) const
629{
630#ifndef WIN32
631 if (d_timeout > 0) {
633 EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream));
634 delete old_eh;
635 alarm(d_timeout);
636 }
637#endif
638}
639
640void
641DODSFilter::establish_timeout(ostream &stream) const
642{
643#ifndef WIN32
644 if (d_timeout > 0) {
646 EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream));
647 delete old_eh;
648 alarm(d_timeout);
649 }
650#endif
651}
652
653static 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.";
654
664void
666{
667 // Write a message to the WWW server error log file.
668 ErrMsgT(usage.c_str());
669
670 throw Error(emessage);
671}
672
678void
680{
681 do_version(d_cgi_ver, get_dataset_version());
682}
683
695void
696DODSFilter::send_das(FILE *out, DAS &das, const string &anc_location,
697 bool with_mime_headers) const
698{
699 ostringstream oss;
700 send_das(oss, das, anc_location, with_mime_headers);
701 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
702}
703
715void
716DODSFilter::send_das(ostream &out, DAS &das, const string &anc_location,
717 bool with_mime_headers) const
718{
719 time_t das_lmt = get_das_last_modified_time(anc_location);
720 if (is_conditional()
721 && das_lmt <= get_request_if_modified_since()
722 && with_mime_headers) {
724 }
725 else {
726 if (with_mime_headers)
727 set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
728 das.print(out);
729 }
730 out << flush ;
731}
732
733void
734DODSFilter::send_das(DAS &das, const string &anc_location,
735 bool with_mime_headers) const
736{
737 send_das(cout, das, anc_location, with_mime_headers);
738}
739
756void
757DODSFilter::send_dds(FILE *out, DDS &dds, ConstraintEvaluator &eval,
758 bool constrained,
759 const string &anc_location,
760 bool with_mime_headers) const
761{
762 ostringstream oss;
763 send_dds(oss, dds, eval, constrained, anc_location, with_mime_headers);
764 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
765}
766
783void
784DODSFilter::send_dds(ostream &out, DDS &dds, ConstraintEvaluator &eval,
785 bool constrained,
786 const string &anc_location,
787 bool with_mime_headers) const
788{
789 // If constrained, parse the constraint. Throws Error or InternalErr.
790 if (constrained)
791 eval.parse_constraint(d_dap2ce, dds);
792
793 if (eval.functional_expression())
794 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.");
795
796 time_t dds_lmt = get_dds_last_modified_time(anc_location);
797 if (is_conditional()
798 && dds_lmt <= get_request_if_modified_since()
799 && with_mime_headers) {
801 }
802 else {
803 if (with_mime_headers)
804 set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt);
805 if (constrained)
806 dds.print_constrained(out);
807 else
808 dds.print(out);
809 }
810
811 out << flush ;
812}
813
814void
815DODSFilter::send_dds(DDS &dds, ConstraintEvaluator &eval,
816 bool constrained, const string &anc_location,
817 bool with_mime_headers) const
818{
819 send_dds(cout, dds, eval, constrained, anc_location, with_mime_headers);
820}
821
822// 'lmt' unused. Should it be used to supply a LMT or removed from the
823// method? jhrg 8/9/05
824void
825DODSFilter::functional_constraint(BaseType &var, DDS &dds,
826 ConstraintEvaluator &eval, FILE *out) const
827{
828 ostringstream oss;
829 functional_constraint(var, dds, eval, oss);
830 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
831}
832
833// 'lmt' unused. Should it be used to supply a LMT or removed from the
834// method? jhrg 8/9/05
835void
836DODSFilter::functional_constraint(BaseType &var, DDS &dds,
837 ConstraintEvaluator &eval, ostream &out) const
838{
839 out << "Dataset {\n" ;
840 var.print_decl(out, " ", true, false, true);
841 out << "} function_value;\n" ;
842 out << "Data:\n" ;
843
844 out << flush ;
845
846 // Grab a stream that encodes using XDR.
847 XDRStreamMarshaller m( out ) ;
848
849 try {
850 // In the following call to serialize, suppress CE evaluation.
851 var.serialize(eval, dds, m, false);
852 }
853 catch (Error &e) {
854 throw;
855 }
856}
857
858void
859DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
860 FILE * out, bool ce_eval) const
861{
862 ostringstream oss;
863 dataset_constraint(dds, eval, oss, ce_eval);
864 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
865}
866
867void
868DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
869 ostream &out, bool ce_eval) const
870{
871 // send constrained DDS
872 dds.print_constrained(out);
873 out << "Data:\n" ;
874 out << flush ;
875
876 // Grab a stream that encodes using XDR.
877 XDRStreamMarshaller m( out ) ;
878
879 try {
880 // Send all variables in the current projection (send_p())
881 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
882 if ((*i)->send_p()) {
883 DBG(cerr << "Sending " << (*i)->name() << endl);
884 (*i)->serialize(eval, dds, m, ce_eval);
885 }
886 }
887 catch (Error & e) {
888 throw;
889 }
890}
891
892void
893DODSFilter::dataset_constraint_ddx(DDS & dds, ConstraintEvaluator & eval,
894 ostream &out, const string &boundary,
895 const string &start, bool ce_eval) const
896{
897 // Write the MPM headers for the DDX (text/xml) part of the response
898 set_mime_ddx_boundary(out, boundary, start, dods_ddx);
899
900 // Make cid
901 uuid_t uu;
902 uuid_generate(uu);
903 char uuid[37];
904 uuid_unparse(uu, uuid);
905 char domain[256];
906 if (getdomainname(domain, 255) != 0 || strlen(domain) == 0)
907 strncpy(domain, "opendap.org", 255);
908
909 string cid = string(uuid) + "@" + string(domain);
910
911 // Send constrained DDX with a data blob reference
912 dds.print_xml_writer(out, true, cid);
913
914 // Write the MPM headers for the data part of the response.
915 set_mime_data_boundary(out, boundary, cid, dap4_data, binary);
916
917 // Grab a stream that encodes using XDR.
918 XDRStreamMarshaller m( out ) ;
919
920 try {
921 // Send all variables in the current projection (send_p())
922 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
923 if ((*i)->send_p()) {
924 DBG(cerr << "Sending " << (*i)->name() << endl);
925 (*i)->serialize(eval, dds, m, ce_eval);
926 }
927 }
928 catch (Error & e) {
929 throw;
930 }
931}
932
949void
951 FILE * data_stream, const string & anc_location,
952 bool with_mime_headers) const
953{
954 ostringstream oss;
955 send_data(dds, eval, oss, anc_location, with_mime_headers);
956 fwrite(oss.str().data(), sizeof(char), oss.str().length(), data_stream);
957}
958
975void
977 ostream & data_stream, const string & anc_location,
978 bool with_mime_headers) const
979{
980 // If this is a conditional request and the server should send a 304
981 // response, do that and exit. Otherwise, continue on and send the full
982 // response.
983 time_t data_lmt = get_data_last_modified_time(anc_location);
984 if (is_conditional()
985 && data_lmt <= get_request_if_modified_since()
986 && with_mime_headers) {
987 set_mime_not_modified(data_stream);
988 return;
989 }
990 // Set up the alarm.
991 establish_timeout(data_stream);
992 dds.set_timeout(d_timeout);
993
994 eval.parse_constraint(d_dap2ce, dds); // Throws Error if the ce doesn't
995 // parse.
996
997 dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
998
999 // Start sending the response...
1000
1001 // Handle *functional* constraint expressions specially
1002#if 0
1003 if (eval.functional_expression()) {
1004 // Get the result and then start sending the headers. This provides a
1005 // way to send errors back to the client w/o colliding with the
1006 // normal response headers. There's some duplication of code with this
1007 // and the else-clause.
1008 BaseType *var = eval.eval_function(dds, d_dataset);
1009 if (!var)
1010 throw Error(unknown_error, "Error calling the CE function.");
1011
1012 if (with_mime_headers)
1013 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
1014
1015 data_stream << flush ;
1016
1017 functional_constraint(*var, dds, eval, data_stream);
1018 delete var;
1019 var = 0;
1020 }
1021#endif
1022 if (eval.function_clauses()) {
1023 DDS *fdds = eval.eval_function_clauses(dds);
1024 if (with_mime_headers)
1025 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
1026
1027 dataset_constraint(*fdds, eval, data_stream, false);
1028 delete fdds;
1029 }
1030 else {
1031 if (with_mime_headers)
1032 set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
1033
1034 dataset_constraint(dds, eval, data_stream);
1035 }
1036
1037 data_stream << flush ;
1038}
1039
1050void
1052 bool with_mime_headers) const
1053{
1054 ostringstream oss;
1055 send_ddx(dds, eval, oss, with_mime_headers);
1056 fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1057}
1058
1069void
1071 bool with_mime_headers) const
1072{
1073 // If constrained, parse the constraint. Throws Error or InternalErr.
1074 if (!d_dap2ce.empty())
1075 eval.parse_constraint(d_dap2ce, dds);
1076
1077 if (eval.functional_expression())
1078 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.");
1079
1080 time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
1081
1082 // If this is a conditional request and the server should send a 304
1083 // response, do that and exit. Otherwise, continue on and send the full
1084 // response.
1085 if (is_conditional() && dds_lmt <= get_request_if_modified_since()
1086 && with_mime_headers) {
1088 return;
1089 }
1090 else {
1091 if (with_mime_headers)
1092 set_mime_text(out, dods_ddx, d_cgi_ver, x_plain, dds_lmt);
1093 dds.print_xml_writer(out, !d_dap2ce.empty(), "");
1094 }
1095}
1096
1117void
1119 ostream & data_stream, const string &start,
1120 const string &boundary, const string & anc_location,
1121 bool with_mime_headers) const
1122{
1123 // If this is a conditional request and the server should send a 304
1124 // response, do that and exit. Otherwise, continue on and send the full
1125 // response.
1126 time_t data_lmt = get_data_last_modified_time(anc_location);
1127 if (is_conditional()
1128 && data_lmt <= get_request_if_modified_since()
1129 && with_mime_headers) {
1130 set_mime_not_modified(data_stream);
1131 return;
1132 }
1133 // Set up the alarm.
1134 establish_timeout(data_stream);
1135 dds.set_timeout(d_timeout);
1136
1137 eval.parse_constraint(d_dap2ce, dds); // Throws Error if the ce doesn't
1138 // parse.
1139
1140 dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
1141
1142 // Start sending the response...
1143
1144 // Handle *functional* constraint expressions specially
1145#if 0
1146 if (eval.functional_expression()) {
1147 BaseType *var = eval.eval_function(dds, d_dataset);
1148 if (!var)
1149 throw Error(unknown_error, "Error calling the CE function.");
1150
1151 if (with_mime_headers)
1152 set_mime_multipart(data_stream, boundary, start, dods_data_ddx,
1153 d_cgi_ver, x_plain, data_lmt);
1154 data_stream << flush ;
1155 BaseTypeFactory btf;
1156 DDS var_dds(&btf, var->name());
1157 var->set_send_p(true);
1158 var_dds.add_var(var);
1159 serialize_dap2_data_ddx(var_dds, eval, data_stream, boundary, start);
1160
1161 // functional_constraint_ddx(*var, dds, eval, data_stream, boundary);
1162 delete var;
1163 var = 0;
1164 }
1165#endif
1166 if (eval.function_clauses()) {
1167 DDS *fdds = eval.eval_function_clauses(dds);
1168 if (with_mime_headers)
1169 set_mime_multipart(data_stream, boundary, start, dods_data_ddx,
1170 d_cgi_ver, x_plain, data_lmt);
1171 data_stream << flush ;
1172 dataset_constraint(*fdds, eval, data_stream, false);
1173 delete fdds;
1174 }
1175 else {
1176 if (with_mime_headers)
1177 set_mime_multipart(data_stream, boundary, start, dods_data_ddx,
1178 d_cgi_ver, x_plain, data_lmt);
1179 data_stream << flush ;
1180 dataset_constraint_ddx(dds, eval, data_stream, boundary, start);
1181 }
1182
1183 data_stream << flush ;
1184
1185 if (with_mime_headers)
1186 data_stream << CRLF << "--" << boundary << "--" << CRLF;
1187}
1188
1189} // namespace libdap
1190
Definition: GetOpt.h:39
static string find_ancillary_file(const string &pathname, const string &ext, const string &dir, const string &file)
Find a file with ancillary data.
Definition: Ancillary.cc:69
The basic data type for the DODS DAP types.
Definition: BaseType.h:118
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:316
virtual void set_send_p(bool state)
Definition: BaseType.cc:564
Evaluate a constraint expression.
void parse_constraint(const std::string &constraint, DDS &dds)
Parse the constraint expression given the current DDS.
BaseType * eval_function(DDS &dds, const std::string &dataset)
Evaluate a function-valued constraint expression.
bool function_clauses()
Does the current constraint expression contain function clauses.
DDS * eval_function_clauses(DDS &dds)
Evaluate a function-valued constraint expression that contains several function calls.
bool functional_expression()
Does the current constraint expression return a BaseType pointer? This method does not evaluate the c...
Hold attribute data for a DAP2 dataset.
Definition: DAS.h:122
virtual void print(FILE *out, bool dereference=false)
Definition: DAS.cc:329
void print(FILE *out)
Print the entire DDS to the specified file.
Definition: DDS.cc:924
void tag_nested_sequences()
Traverse DDS, set Sequence leaf nodes.
Definition: DDS.cc:831
void print_constrained(FILE *out)
Print a constrained DDS to the specified file.
Definition: DDS.cc:1203
void add_var(BaseType *bt)
Adds a copy of the variable to the DDS. Using the ptr_duplicate() method, perform a deep copy on the ...
Definition: DDS.cc:543
void print_xml_writer(ostream &out, bool constrained, const string &blob="")
Definition: DDS.cc:1304
virtual string get_ce() const
Get the constraint expression.
Definition: DODSFilter.cc:350
virtual void send_data(DDS &dds, ConstraintEvaluator &eval, ostream &data_stream, const string &anc_location="", bool with_mime_headers=true) const
Transmit data.
Definition: DODSFilter.cc:976
virtual time_t get_dds_last_modified_time(const string &anc_location="") const
Definition: DODSFilter.cc:522
virtual Response get_response() const
Definition: DODSFilter.cc:452
virtual time_t get_dataset_last_modified_time() const
Definition: DODSFilter.cc:484
virtual int process_options(int argc, char *argv[])
Definition: DODSFilter.cc:264
virtual void set_URL(const string &url)
Definition: DODSFilter.cc:393
virtual string get_action() const
Definition: DODSFilter.cc:458
void set_timeout(int timeout=0)
Definition: DODSFilter.cc:604
virtual void print_usage() const
Print usage information for a filter program.
Definition: DODSFilter.cc:665
virtual string get_dataset_version() const
Get the version information for the dataset.
Definition: DODSFilter.cc:409
virtual bool is_conditional() const
Is this request conditional?
Definition: DODSFilter.cc:308
virtual string get_dataset_name() const
Get the dataset name.
Definition: DODSFilter.cc:370
virtual void send_ddx(DDS &dds, ConstraintEvaluator &eval, ostream &out, bool with_mime_headers=true) const
Definition: DODSFilter.cc:1070
virtual string get_cgi_version() const
Definition: DODSFilter.cc:338
virtual void send_version_info() const
Send version information back to the client program.
Definition: DODSFilter.cc:679
virtual void send_data_ddx(DDS &dds, ConstraintEvaluator &eval, ostream &data_stream, const string &start, const string &boundary, const string &anc_location="", bool with_mime_headers=true) const
Transmit data.
Definition: DODSFilter.cc:1118
virtual void set_response(const string &r)
Definition: DODSFilter.cc:420
virtual string get_URL() const
Definition: DODSFilter.cc:385
virtual void set_cgi_version(string version)
Definition: DODSFilter.cc:327
int get_timeout() const
Definition: DODSFilter.cc:611
virtual string get_cache_dir() const
Get the cache directory.
Definition: DODSFilter.cc:594
virtual time_t get_das_last_modified_time(const string &anc_location="") const
Definition: DODSFilter.cc:499
virtual time_t get_request_if_modified_since() const
Definition: DODSFilter.cc:582
virtual time_t get_data_last_modified_time(const string &anc_location="") const
Definition: DODSFilter.cc:551
A class for error processing.
Definition: Error.h:94
EventHandler * register_handler(int signum, EventHandler *eh, bool ignore_by_default=false)
static SignalHandler * instance()
top level DAP object to house generic methods
Definition: AlarmHandler.h:36
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:220
time_t last_modified_time(const string &name)
Definition: mime_util.cc:95
void set_mime_not_modified(FILE *out)
Send a ‘Not Modified’ response.
Definition: mime_util.cc:1143
void set_mime_binary(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
Definition: mime_util.cc:621
bool do_version(const string &script_ver, const string &dataset_ver)
Send a version number.
Definition: mime_util.cc:190
void ErrMsgT(const string &Msgt)
Logs an error message.
Definition: mime_util.cc:223
void set_mime_text(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
Definition: mime_util.cc:379