libdap++  Updated for version 3.13.1
DODSFilter.cc
Go to the documentation of this file.
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 #include <uuid/uuid.h> // used to build CID header value for data ddx
58 
59 #include <GetOpt.h>
60 
61 #include "DAS.h"
62 #include "DDS.h"
63 #include "debug.h"
64 #include "mime_util.h"
65 #include "Ancillary.h"
66 #include "util.h"
67 #include "escaping.h"
68 #include "DODSFilter.h"
69 #include "XDRStreamMarshaller.h"
70 #include "InternalErr.h"
71 
72 #ifndef WIN32
73 #include "SignalHandler.h"
74 #include "EventHandler.h"
75 #include "AlarmHandler.h"
76 #endif
77 
78 #define CRLF "\r\n" // Change here, expr-test.cc and DODSFilter.cc
79 
80 using namespace std;
81 
82 namespace libdap {
83 
84 const string usage =
85  "Usage: <handler name> -o <response> -u <url> [options ...] [data set]\n\
86  \n\
87  options: -o <response>: DAS, DDS, DataDDS, DDX, BLOB or Version (Required)\n\
88  -u <url>: The complete URL minus the CE (required for DDX)\n\
89  -c: Compress the response using the deflate algorithm.\n\
90  -e <expr>: When returning a DataDDS, use <expr> as the constraint.\n\
91  -v <version>: Use <version> as the version number\n\
92  -d <dir>: Look for ancillary file in <dir> (deprecated).\n\
93  -f <file>: Look for ancillary data in <file> (deprecated).\n\
94  -r <dir>: Use <dir> as a cache directory\n\
95  -l <time>: Conditional request; if data source is unchanged since\n\
96  <time>, return an HTTP 304 response.\n\
97  -t <seconds>: Timeout the handler after <seconds>.\n\
98  -h: This message.";
99 
164 DODSFilter::DODSFilter(int argc, char *argv[]) throw(Error)
165 {
166  initialize(argc, argv);
167 
168  DBG(cerr << "d_comp: " << d_comp << endl);
169  DBG(cerr << "d_ce: " << d_ce << endl);
170  DBG(cerr << "d_cgi_ver: " << d_cgi_ver << endl);
171  DBG(cerr << "d_response: " << d_response << endl);
172  DBG(cerr << "d_anc_dir: " << d_anc_dir << endl);
173  DBG(cerr << "d_anc_file: " << d_anc_file << endl);
174  DBG(cerr << "d_cache_dir: " << d_cache_dir << endl);
175  DBG(cerr << "d_conditional_request: " << d_conditional_request << endl);
176  DBG(cerr << "d_if_modified_since: " << d_if_modified_since << endl);
177  DBG(cerr << "d_url: " << d_url << endl);
178  DBG(cerr << "d_timeout: " << d_timeout << endl);
179 }
180 
181 DODSFilter::~DODSFilter()
182 {
183 }
184 
187 void
188 DODSFilter::initialize()
189 {
190  // Set default values. Don't use the C++ constructor initialization so
191  // that a subclass can have more control over this process.
192  d_comp = false;
193  d_bad_options = false;
194  d_conditional_request = false;
195  d_dataset = "";
196  d_ce = "";
197  d_cgi_ver = "";
198  d_anc_dir = "";
199  d_anc_file = "";
200  d_cache_dir = "";
201  d_response = Unknown_Response;;
202  d_anc_das_lmt = 0;
203  d_anc_dds_lmt = 0;
204  d_if_modified_since = -1;
205  d_url = "";
206  d_program_name = "Unknown";
207  d_timeout = 0;
208 
209 #ifdef WIN32
210  // We want serving from win32 to behave in a manner
211  // similar to the UNIX way - no CR->NL terminated lines
212  // in files. Hence stdout goes to binary mode.
213  _setmode(_fileno(stdout), _O_BINARY);
214 #endif
215 }
216 
228 void
229 DODSFilter::initialize(int argc, char *argv[])
230 {
231  initialize();
232 
233  d_program_name = argv[0];
234 
235  // This should be specialized by a subclass. This may throw Error.
236  int next_arg = process_options(argc, argv);
237 
238  // Look at what's left after processing the command line options. Either
239  // there MUST be a dataset name OR the caller is asking for version
240  // information. If neither is true, then the options are bad.
241  if (next_arg < argc) {
242  d_dataset = argv[next_arg];
243  d_dataset = www2id(d_dataset, "%", "%20");
244  }
245  else if (get_response() != Version_Response)
246  print_usage(); // Throws Error
247 }
248 
257 int
258 DODSFilter::process_options(int argc, char *argv[])
259 {
260  DBG(cerr << "Entering process_options... ");
261 
262  int option_char;
263  GetOpt getopt (argc, argv, "ce: v: d: f: r: l: o: u: t: ");
264 
265  while ((option_char = getopt()) != EOF) {
266  switch (option_char) {
267  case 'c': d_comp = true; break;
268  case 'e': set_ce(getopt.optarg); break;
269  case 'v': set_cgi_version(getopt.optarg); break;
270  case 'd': d_anc_dir = getopt.optarg; break;
271  case 'f': d_anc_file = getopt.optarg; break;
272  case 'r': d_cache_dir = getopt.optarg; break;
273  case 'o': set_response(getopt.optarg); break;
274  case 'u': set_URL(getopt.optarg); break;
275  case 't': d_timeout = atoi(getopt.optarg); break;
276  case 'l':
277  d_conditional_request = true;
278  d_if_modified_since
279  = static_cast<time_t>(strtol(getopt.optarg, NULL, 10));
280  break;
281  case 'h': print_usage();
282  break;
283  // exit(1);
284  // Removed 12/29/2011; exit should
285  // not be called by a library. NB:
286  // print_usage() throws Error.
287  default: print_usage(); // Throws Error
288  break;
289  }
290  }
291 
292  DBGN(cerr << "exiting." << endl);
293 
294  return getopt.optind; // return the index of the next argument
295 }
296 
301 bool
302 DODSFilter::is_conditional() const
303 {
304  return d_conditional_request;
305 }
306 
320 void
321 DODSFilter::set_cgi_version(string version)
322 {
323  d_cgi_ver = version;
324 }
325 
331 string
332 DODSFilter::get_cgi_version() const
333 {
334  return d_cgi_ver;
335 }
336 
343 string
344 DODSFilter::get_ce() const
345 {
346  return d_ce;
347 }
348 
349 void
350 DODSFilter::set_ce(string _ce)
351 {
352  d_ce = www2id(_ce, "%", "%20");
353 }
354 
363 string
364 DODSFilter::get_dataset_name() const
365 {
366  return d_dataset;
367 }
368 
369 void
370 DODSFilter::set_dataset_name(const string ds)
371 {
372  d_dataset = www2id(ds, "%", "%20");
373 }
374 
378 string
379 DODSFilter::get_URL() const
380 {
381  return d_url;
382 }
383 
386 void
387 DODSFilter::set_URL(const string &url)
388 {
389  if (url.find('?') != url.npos)
390  print_usage(); // Throws Error
391 
392  d_url = url;
393 }
394 
402 string
403 DODSFilter::get_dataset_version() const
404 {
405  return "";
406 }
407 
414 void DODSFilter::set_response(const string &r)
415 {
416  if (r == "DAS" || r == "das") {
417  d_response = DAS_Response;
418  d_action = "das" ;
419  }
420  else if (r == "DDS" || r == "dds") {
421  d_response = DDS_Response;
422  d_action = "dds" ;
423  }
424  else if (r == "DataDDS" || r == "dods") {
425  d_response = DataDDS_Response;
426  d_action = "dods" ;
427  }
428  else if (r == "DDX" || r == "ddx") {
429  d_response = DDX_Response;
430  d_action = "ddx" ;
431  }
432  else if (r == "DataDDX" || r == "dataddx") {
433  d_response = DataDDX_Response;
434  d_action = "dataddx" ;
435  }
436  else if (r == "Version") {
437  d_response = Version_Response;
438  d_action = "version" ;
439  }
440  else
441  print_usage(); // Throws Error
442 }
443 
446 DODSFilter::get_response() const
447 {
448  return d_response;
449 }
450 
452 string DODSFilter::get_action() const
453 {
454  return d_action;
455 }
456 
477 time_t
478 DODSFilter::get_dataset_last_modified_time() const
479 {
480  return last_modified_time(d_dataset);
481 }
482 
492 time_t
493 DODSFilter::get_das_last_modified_time(const string &anc_location) const
494 {
495  DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
496  << anc_location << "call faf(das) d_dataset=" << d_dataset
497  << " d_anc_file=" << d_anc_file << endl);
498 
499  string name
500  = Ancillary::find_ancillary_file(d_dataset, "das",
501  (anc_location == "") ? d_anc_dir : anc_location,
502  d_anc_file);
503 
504  return max((name != "") ? last_modified_time(name) : 0,
505  get_dataset_last_modified_time());
506 }
507 
515 time_t
516 DODSFilter::get_dds_last_modified_time(const string &anc_location) const
517 {
518  DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
519  << anc_location << "call faf(dds) d_dataset=" << d_dataset
520  << " d_anc_file=" << d_anc_file << endl);
521 
522  string name
523  = Ancillary::find_ancillary_file(d_dataset, "dds",
524  (anc_location == "") ? d_anc_dir : anc_location,
525  d_anc_file);
526 
527  return max((name != "") ? last_modified_time(name) : 0,
528  get_dataset_last_modified_time());
529 }
530 
544 time_t
545 DODSFilter::get_data_last_modified_time(const string &anc_location) const
546 {
547  DBG(cerr << "DODSFilter::get_das_last_modified_time(anc_location="
548  << anc_location << "call faf(both) d_dataset=" << d_dataset
549  << " d_anc_file=" << d_anc_file << endl);
550 
551  string dds_name
552  = Ancillary::find_ancillary_file(d_dataset, "dds",
553  (anc_location == "") ? d_anc_dir : anc_location,
554  d_anc_file);
555  string das_name
556  = Ancillary::find_ancillary_file(d_dataset, "das",
557  (anc_location == "") ? d_anc_dir : anc_location,
558  d_anc_file);
559 
560  time_t m = max((das_name != "") ? last_modified_time(das_name) : (time_t)0,
561  (dds_name != "") ? last_modified_time(dds_name) : (time_t)0);
562  // Note that this is a call to get_dataset_... not get_data_...
563  time_t n = get_dataset_last_modified_time();
564 
565  return max(m, n);
566 }
567 
575 time_t
576 DODSFilter::get_request_if_modified_since() const
577 {
578  return d_if_modified_since;
579 }
580 
587 string
588 DODSFilter::get_cache_dir() const
589 {
590  return d_cache_dir;
591 }
592 
597 void
598 DODSFilter::set_timeout(int t)
599 {
600  d_timeout = t;
601 }
602 
604 int
605 DODSFilter::get_timeout() const
606 {
607  return d_timeout;
608 }
609 
621 void
622 DODSFilter::establish_timeout(FILE *stream) const
623 {
624 #ifndef WIN32
625  if (d_timeout > 0) {
626  SignalHandler *sh = SignalHandler::instance();
627  EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream));
628  delete old_eh;
629  alarm(d_timeout);
630  }
631 #endif
632 }
633 
634 void
635 DODSFilter::establish_timeout(ostream &stream) const
636 {
637 #ifndef WIN32
638  if (d_timeout > 0) {
639  SignalHandler *sh = SignalHandler::instance();
640  EventHandler *old_eh = sh->register_handler(SIGALRM, new AlarmHandler(stream));
641  delete old_eh;
642  alarm(d_timeout);
643  }
644 #endif
645 }
646 
647 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.";
648 
658 void
659 DODSFilter::print_usage() const
660 {
661  // Write a message to the WWW server error log file.
662  ErrMsgT(usage.c_str());
663 
664  throw Error(emessage);
665 }
666 
672 void
673 DODSFilter::send_version_info() const
674 {
675  do_version(d_cgi_ver, get_dataset_version());
676 }
677 
689 void
690 DODSFilter::send_das(FILE *out, DAS &das, const string &anc_location,
691  bool with_mime_headers) const
692 {
693  ostringstream oss;
694  send_das(oss, das, anc_location, with_mime_headers);
695  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
696 }
697 
709 void
710 DODSFilter::send_das(ostream &out, DAS &das, const string &anc_location,
711  bool with_mime_headers) const
712 {
713  time_t das_lmt = get_das_last_modified_time(anc_location);
714  if (is_conditional()
715  && das_lmt <= get_request_if_modified_since()
716  && with_mime_headers) {
718  }
719  else {
720  if (with_mime_headers)
721  set_mime_text(out, dods_das, d_cgi_ver, x_plain, das_lmt);
722  das.print(out);
723  }
724  out << flush ;
725 }
726 
727 void
728 DODSFilter::send_das(DAS &das, const string &anc_location,
729  bool with_mime_headers) const
730 {
731  send_das(cout, das, anc_location, with_mime_headers);
732 }
733 
750 void
751 DODSFilter::send_dds(FILE *out, DDS &dds, ConstraintEvaluator &eval,
752  bool constrained,
753  const string &anc_location,
754  bool with_mime_headers) const
755 {
756  ostringstream oss;
757  send_dds(oss, dds, eval, constrained, anc_location, with_mime_headers);
758  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
759 }
760 
777 void
778 DODSFilter::send_dds(ostream &out, DDS &dds, ConstraintEvaluator &eval,
779  bool constrained,
780  const string &anc_location,
781  bool with_mime_headers) const
782 {
783  // If constrained, parse the constraint. Throws Error or InternalErr.
784  if (constrained)
785  eval.parse_constraint(d_ce, dds);
786 
787  if (eval.functional_expression())
788  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.");
789 
790  time_t dds_lmt = get_dds_last_modified_time(anc_location);
791  if (is_conditional()
792  && dds_lmt <= get_request_if_modified_since()
793  && with_mime_headers) {
795  }
796  else {
797  if (with_mime_headers)
798  set_mime_text(out, dods_dds, d_cgi_ver, x_plain, dds_lmt);
799  if (constrained)
800  dds.print_constrained(out);
801  else
802  dds.print(out);
803  }
804 
805  out << flush ;
806 }
807 
808 void
809 DODSFilter::send_dds(DDS &dds, ConstraintEvaluator &eval,
810  bool constrained, const string &anc_location,
811  bool with_mime_headers) const
812 {
813  send_dds(cout, dds, eval, constrained, anc_location, with_mime_headers);
814 }
815 
816 // 'lmt' unused. Should it be used to supply a LMT or removed from the
817 // method? jhrg 8/9/05
818 void
819 DODSFilter::functional_constraint(BaseType &var, DDS &dds,
820  ConstraintEvaluator &eval, FILE *out) const
821 {
822  ostringstream oss;
823  functional_constraint(var, dds, eval, oss);
824  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
825 }
826 
827 // 'lmt' unused. Should it be used to supply a LMT or removed from the
828 // method? jhrg 8/9/05
829 void
830 DODSFilter::functional_constraint(BaseType &var, DDS &dds,
831  ConstraintEvaluator &eval, ostream &out) const
832 {
833  out << "Dataset {\n" ;
834  var.print_decl(out, " ", true, false, true);
835  out << "} function_value;\n" ;
836  out << "Data:\n" ;
837 
838  out << flush ;
839 
840  // Grab a stream that encodes using XDR.
841  XDRStreamMarshaller m( out ) ;
842 
843  try {
844  // In the following call to serialize, suppress CE evaluation.
845  var.serialize(eval, dds, m, false);
846  }
847  catch (Error &e) {
848  throw;
849  }
850 }
851 
852 void
853 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
854  FILE * out, bool ce_eval) const
855 {
856  ostringstream oss;
857  dataset_constraint(dds, eval, oss, ce_eval);
858  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
859 }
860 
861 void
862 DODSFilter::dataset_constraint(DDS & dds, ConstraintEvaluator & eval,
863  ostream &out, bool ce_eval) const
864 {
865  // send constrained DDS
866  dds.print_constrained(out);
867  out << "Data:\n" ;
868  out << flush ;
869 
870  // Grab a stream that encodes using XDR.
871  XDRStreamMarshaller m( out ) ;
872 
873  try {
874  // Send all variables in the current projection (send_p())
875  for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
876  if ((*i)->send_p()) {
877  DBG(cerr << "Sending " << (*i)->name() << endl);
878  (*i)->serialize(eval, dds, m, ce_eval);
879  }
880  }
881  catch (Error & e) {
882  throw;
883  }
884 }
885 
886 void
887 DODSFilter::dataset_constraint_ddx(DDS & dds, ConstraintEvaluator & eval,
888  ostream &out, const string &boundary,
889  const string &start, bool ce_eval) const
890 {
891  // Write the MPM headers for the DDX (text/xml) part of the response
892  set_mime_ddx_boundary(out, boundary, start, dap4_ddx);
893 
894  // Make cid
895  uuid_t uu;
896  uuid_generate(uu);
897  char uuid[37];
898  uuid_unparse(uu, &uuid[0]);
899  char domain[256];
900  if (getdomainname(domain, 255) != 0 || strlen(domain) == 0)
901  strncpy(domain, "opendap.org", 255);
902 
903  string cid = string(&uuid[0]) + "@" + string(&domain[0]);
904 
905  // Send constrained DDX with a data blob reference
906  dds.print_xml_writer(out, true, cid);
907 
908  // Write the MPM headers for the data part of the response.
909  set_mime_data_boundary(out, boundary, cid, dap4_data, binary);
910 
911  // Grab a stream that encodes using XDR.
912  XDRStreamMarshaller m( out ) ;
913 
914  try {
915  // Send all variables in the current projection (send_p())
916  for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
917  if ((*i)->send_p()) {
918  DBG(cerr << "Sending " << (*i)->name() << endl);
919  (*i)->serialize(eval, dds, m, ce_eval);
920  }
921  }
922  catch (Error & e) {
923  throw;
924  }
925 }
926 
943 void
944 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
945  FILE * data_stream, const string & anc_location,
946  bool with_mime_headers) const
947 {
948  ostringstream oss;
949  send_data(dds, eval, oss, anc_location, with_mime_headers);
950  fwrite(oss.str().data(), sizeof(char), oss.str().length(), data_stream);
951 }
952 
969 void
970 DODSFilter::send_data(DDS & dds, ConstraintEvaluator & eval,
971  ostream & data_stream, const string & anc_location,
972  bool with_mime_headers) const
973 {
974  // If this is a conditional request and the server should send a 304
975  // response, do that and exit. Otherwise, continue on and send the full
976  // response.
977  time_t data_lmt = get_data_last_modified_time(anc_location);
978  if (is_conditional()
979  && data_lmt <= get_request_if_modified_since()
980  && with_mime_headers) {
981  set_mime_not_modified(data_stream);
982  return;
983  }
984  // Set up the alarm.
985  establish_timeout(data_stream);
986  dds.set_timeout(d_timeout);
987 
988  eval.parse_constraint(d_ce, dds); // Throws Error if the ce doesn't
989  // parse.
990 
991  dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
992 
993  // Start sending the response...
994 
995  // Handle *functional* constraint expressions specially
996 #if 0
997  if (eval.functional_expression()) {
998  // Get the result and then start sending the headers. This provides a
999  // way to send errors back to the client w/o colliding with the
1000  // normal response headers. There's some duplication of code with this
1001  // and the else-clause.
1002  BaseType *var = eval.eval_function(dds, d_dataset);
1003  if (!var)
1004  throw Error(unknown_error, "Error calling the CE function.");
1005 
1006  if (with_mime_headers)
1007  set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
1008 
1009  data_stream << flush ;
1010 
1011  functional_constraint(*var, dds, eval, data_stream);
1012  delete var;
1013  var = 0;
1014  }
1015 #endif
1016  if (eval.function_clauses()) {
1017  DDS *fdds = eval.eval_function_clauses(dds);
1018  if (with_mime_headers)
1019  set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
1020 
1021  dataset_constraint(*fdds, eval, data_stream, false);
1022  delete fdds;
1023  }
1024  else {
1025  if (with_mime_headers)
1026  set_mime_binary(data_stream, dods_data, d_cgi_ver, x_plain, data_lmt);
1027 
1028  dataset_constraint(dds, eval, data_stream);
1029  }
1030 
1031  data_stream << flush ;
1032 }
1033 
1044 void
1045 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, FILE *out,
1046  bool with_mime_headers) const
1047 {
1048  ostringstream oss;
1049  send_ddx(dds, eval, oss, with_mime_headers);
1050  fwrite(oss.str().data(), sizeof(char), oss.str().length(), out);
1051 }
1052 
1063 void
1064 DODSFilter::send_ddx(DDS &dds, ConstraintEvaluator &eval, ostream &out,
1065  bool with_mime_headers) const
1066 {
1067  // If constrained, parse the constraint. Throws Error or InternalErr.
1068  if (!d_ce.empty())
1069  eval.parse_constraint(d_ce, dds);
1070 
1071  if (eval.functional_expression())
1072  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.");
1073 
1074  time_t dds_lmt = get_dds_last_modified_time(d_anc_dir);
1075 
1076  // If this is a conditional request and the server should send a 304
1077  // response, do that and exit. Otherwise, continue on and send the full
1078  // response.
1079  if (is_conditional() && dds_lmt <= get_request_if_modified_since()
1080  && with_mime_headers) {
1081  set_mime_not_modified(out);
1082  return;
1083  }
1084  else {
1085  if (with_mime_headers)
1086  set_mime_text(out, dap4_ddx, d_cgi_ver, x_plain, dds_lmt);
1087  dds.print_xml_writer(out, !d_ce.empty(), "");
1088  }
1089 }
1090 
1111 void
1112 DODSFilter::send_data_ddx(DDS & dds, ConstraintEvaluator & eval,
1113  ostream & data_stream, const string &start,
1114  const string &boundary, const string & anc_location,
1115  bool with_mime_headers) const
1116 {
1117  // If this is a conditional request and the server should send a 304
1118  // response, do that and exit. Otherwise, continue on and send the full
1119  // response.
1120  time_t data_lmt = get_data_last_modified_time(anc_location);
1121  if (is_conditional()
1122  && data_lmt <= get_request_if_modified_since()
1123  && with_mime_headers) {
1124  set_mime_not_modified(data_stream);
1125  return;
1126  }
1127  // Set up the alarm.
1128  establish_timeout(data_stream);
1129  dds.set_timeout(d_timeout);
1130 
1131  eval.parse_constraint(d_ce, dds); // Throws Error if the ce doesn't
1132  // parse.
1133 
1134  dds.tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
1135 
1136  // Start sending the response...
1137 
1138  // Handle *functional* constraint expressions specially
1139 #if 0
1140  if (eval.functional_expression()) {
1141  BaseType *var = eval.eval_function(dds, d_dataset);
1142  if (!var)
1143  throw Error(unknown_error, "Error calling the CE function.");
1144 
1145  if (with_mime_headers)
1146  set_mime_multipart(data_stream, boundary, start, dap4_data_ddx,
1147  d_cgi_ver, x_plain, data_lmt);
1148  data_stream << flush ;
1149  BaseTypeFactory btf;
1150  DDS var_dds(&btf, var->name());
1151  var->set_send_p(true);
1152  var_dds.add_var(var);
1153  dataset_constraint_ddx(var_dds, eval, data_stream, boundary, start);
1154 
1155  // functional_constraint_ddx(*var, dds, eval, data_stream, boundary);
1156  delete var;
1157  var = 0;
1158  }
1159 #endif
1160  if (eval.function_clauses()) {
1161  DDS *fdds = eval.eval_function_clauses(dds);
1162  if (with_mime_headers)
1163  set_mime_multipart(data_stream, boundary, start, dap4_data_ddx,
1164  d_cgi_ver, x_plain, data_lmt);
1165  data_stream << flush ;
1166  dataset_constraint(*fdds, eval, data_stream, false);
1167  delete fdds;
1168  }
1169  else {
1170  if (with_mime_headers)
1171  set_mime_multipart(data_stream, boundary, start, dap4_data_ddx,
1172  d_cgi_ver, x_plain, data_lmt);
1173  data_stream << flush ;
1174  dataset_constraint_ddx(dds, eval, data_stream, boundary, start);
1175  }
1176 
1177  data_stream << flush ;
1178 
1179  if (with_mime_headers)
1180  data_stream << CRLF << "--" << boundary << "--" << CRLF;
1181 }
1182 
1183 } // namespace libdap
1184 
virtual void print_decl(FILE *out, string space=" ", bool print_semi=true, bool constraint_info=false, bool constrained=false)
Print an ASCII representation of the variable structure.
Definition: BaseType.cc:985
void ErrMsgT(const string &Msgt)
Logs an error message.
Definition: mime_util.cc:220
void print(FILE *out)
Print the entire DDS to the specified file.
Definition: DDS.cc:974
void set_mime_data_boundary(ostream &strm, const string &boundary, const string &cid, ObjectType type, EncodingType enc)
Definition: mime_util.cc:808
time_t last_modified_time(const string &name)
Definition: mime_util.cc:93
BaseType * eval_function(DDS &dds, const string &dataset)
Evaluate a function-valued constraint expression.
Vars_iter var_begin()
Return an iterator to the first variable.
Definition: DDS.cc:774
#define DBGN(x)
Definition: debug.h:59
void parse_constraint(const string &constraint, DDS &dds)
Parse the constraint expression given the current DDS.
virtual bool serialize(ConstraintEvaluator &eval, DDS &dds, Marshaller &m, bool ce_eval=true)=0
Move data to the net.
void set_timeout(int t)
Definition: DDS.cc:870
void set_mime_text(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
Definition: mime_util.cc:382
void print_xml_writer(ostream &out, bool constrained, const string &blob="")
Definition: DDS.cc:1130
virtual void print(FILE *out, bool dereference=false)
Definition: DAS.cc:344
const char * version
Definition: getdap.cc:60
#define unknown_error
Unknown error.
Definition: Error.h:60
#define DBG(x)
Definition: debug.h:58
virtual void set_send_p(bool state)
Definition: BaseType.cc:652
DDS * eval_function_clauses(DDS &dds)
Evaluate a function-valued constraint expression that contains several function calls.
void set_mime_ddx_boundary(ostream &strm, const string &boundary, const string &cid, ObjectType type, EncodingType enc)
Definition: mime_util.cc:795
std::vector< BaseType * >::iterator Vars_iter
Definition: DDS.h:219
#define CRLF
Definition: DODSFilter.cc:78
void set_mime_binary(FILE *out, ObjectType type, const string &ver, EncodingType enc, const time_t last_modified)
Definition: mime_util.cc:624
string name() const
Returns the name of the class instance.
Definition: BaseType.cc:254
void set_mime_not_modified(FILE *out)
Send a `Not Modified&#39; response.
Definition: mime_util.cc:1132
string www2id(const string &in, const string &escape, const string &except)
Definition: escaping.cc:220
Vars_iter var_end()
Return an iterator.
Definition: DDS.cc:786
Evaluate a constraint expression.
void tag_nested_sequences()
Traverse DDS, set Sequence leaf nodes.
Definition: DDS.cc:885
bool functional_expression()
Does the current constraint expression return a BaseType pointer? This method does not evaluate the c...
The basic data type for the DODS DAP types.
Definition: BaseType.h:199
Hold attribute data for a DAP2 dataset.
Definition: DAS.h:121
void set_mime_multipart(ostream &strm, const string &boundary, const string &start, ObjectType type, const string &version, EncodingType enc, const time_t last_modified)
Definition: mime_util.cc:721
bool function_clauses()
Does the current constraint expression contain function clauses.
A class for error processing.
Definition: Error.h:90
EventHandler * register_handler(int signum, EventHandler *eh, bool override=false)
marshaller that knows how to marshal/serialize dap data objects to a C++ iostream using XDR ...
bool do_version(const string &script_ver, const string &dataset_ver)
Send a version number.
Definition: mime_util.cc:187
void print_constrained(FILE *out)
Print a constrained DDS to the specified file.
Definition: DDS.cc:1029
void usage(string name)
Definition: getdap.cc:65