30 #include <uuid/uuid.h>
52 #include <ConstraintEvaluator.h>
53 #include <DDXParserSAX2.h>
54 #include <Ancillary.h>
55 #include <XDRStreamMarshaller.h>
56 #include <XDRFileUnMarshaller.h>
62 #include <mime_util.h>
66 #include <SignalHandler.h>
67 #include <EventHandler.h>
68 #include <AlarmHandler.h>
75 #define CRLF "\r\n" // Change here, expr-test.cc
76 #define DAP_PROTOCOL_VERSION "3.2"
79 using namespace libdap;
101 if (!d_response_cache)
104 return d_response_cache;
109 if (d_response_cache)
delete d_response_cache;
114 delete dynamic_cast<AlarmHandler*
>(SignalHandler::instance()->remove_handler(SIGALRM));
140 d_ce = www2id(_ce,
"%",
"%20");
168 d_dataset = www2id(ds,
"%",
"%20");
194 SignalHandler *sh = SignalHandler::instance();
195 EventHandler *old_eh = sh->register_handler(SIGALRM,
new AlarmHandler(stream));
202 static string::size_type
203 find_closing_paren(
const string &ce, string::size_type pos)
210 pos = ce.find_first_of(
"()", pos + 1);
211 if (pos == string::npos)
212 throw Error(malformed_expr,
"Expected to find a matching closing parenthesis in " + ce);
233 DBG(cerr <<
"Entering ResponseBuilder::split_ce" << endl);
240 string btp_function_ce =
"";
241 string::size_type pos = 0;
242 DBG(cerr <<
"ce: " << ce << endl);
246 string::size_type first_paren = ce.find(
"(", pos);
247 string::size_type closing_paren = string::npos;
248 if (first_paren != string::npos)
249 closing_paren = find_closing_paren(ce, first_paren);
252 while (first_paren != string::npos && closing_paren != string::npos) {
254 string name = ce.substr(pos, first_paren-pos);
255 DBG(cerr <<
"name: " << name << endl);
258 if (eval.find_function(name, &f)) {
260 if (!btp_function_ce.empty())
261 btp_function_ce +=
",";
262 btp_function_ce += ce.substr(pos, closing_paren+1-pos);
263 ce.erase(pos, closing_paren+1-pos);
268 pos = closing_paren + 1;
270 if (pos < ce.length() && ce.at(pos) ==
',')
274 first_paren = ce.find(
"(", pos);
275 closing_paren = ce.find(
")", pos);
278 DBG(cerr <<
"Modified constraint: " << ce << endl);
279 DBG(cerr <<
"BTP Function part: " << btp_function_ce << endl);
282 d_btp_func_ce = btp_function_ce;
301 if (with_mime_headers)
302 set_mime_text(out, dods_das, x_plain, last_modified_time(d_dataset),
"2.0");
329 establish_timeout(out);
330 dds.set_timeout(d_timeout);
333 if (with_mime_headers)
334 set_mime_text(out, dods_das, x_plain, last_modified_time(d_dataset),
"2.0");
347 if (!d_btp_func_ce.empty()) {
349 string cache_token =
"";
351 if (responseCache()) {
352 DBG(cerr <<
"Using the cache for the server function CE" << endl);
353 fdds = responseCache()->cache_dataset(dds, d_btp_func_ce,
this, &eval, cache_token);
356 DBG(cerr <<
"Cache not found; (re)calculating" << endl);
357 eval.parse_constraint(d_btp_func_ce, dds);
358 fdds = eval.eval_function_clauses(dds);
361 if (with_mime_headers)
362 set_mime_text(out, dods_das, x_plain, last_modified_time(d_dataset), dds.get_dap_version());
364 fdds->print_das(out);
367 responseCache()->unlock_and_close(cache_token);
372 DBG(cerr <<
"Simple constraint" << endl);
374 eval.parse_constraint(d_ce, dds);
376 if (with_mime_headers)
377 set_mime_text(out, dods_das, x_plain, last_modified_time(d_dataset), dds.get_dap_version());
404 bool with_mime_headers)
407 if (with_mime_headers)
408 set_mime_text(out, dods_dds, x_plain, last_modified_time(d_dataset), dds.get_dap_version());
416 establish_timeout(out);
417 dds.set_timeout(d_timeout);
425 if (!d_btp_func_ce.empty()) {
426 string cache_token =
"";
429 if (responseCache()) {
430 DBG(cerr <<
"Using the cache for the server function CE" << endl);
431 fdds = responseCache()->cache_dataset(dds, d_btp_func_ce,
this, &eval, cache_token);
434 DBG(cerr <<
"Cache not found; (re)calculating" << endl);
435 eval.parse_constraint(d_btp_func_ce, dds);
436 fdds = eval.eval_function_clauses(dds);
444 fdds->mark_all(
false);
446 eval.parse_constraint(d_ce, *fdds);
448 if (with_mime_headers)
449 set_mime_text(out, dods_dds, x_plain, last_modified_time(d_dataset), dds.get_dap_version());
451 fdds->print_constrained(out);
454 responseCache()->unlock_and_close(cache_token);
459 DBG(cerr <<
"Simple constraint" << endl);
461 eval.parse_constraint(d_ce, dds);
463 if (with_mime_headers)
464 set_mime_text(out, dods_dds, x_plain, last_modified_time(d_dataset), dds.get_dap_version());
466 dds.print_constrained(out);
478 DBG(cerr <<
"Inside dataset_constraint" << endl);
480 dds.print_constrained(out);
484 XDRStreamMarshaller m(out);
488 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++)
489 if ((*i)->send_p()) {
490 (*i)->serialize(eval, dds, m, ce_eval);
505 const string &boundary,
const string &start,
bool ce_eval)
508 libdap::set_mime_ddx_boundary(out, boundary, start, dap4_ddx, x_plain);
514 uuid_unparse(uu, &uuid[0]);
516 if (getdomainname(domain, 255) != 0 || strlen(domain) == 0)
517 strncpy(domain,
"opendap.org", 255);
519 string cid = string(&uuid[0]) +
"@" + string(&domain[0]);
521 dds.print_xml_writer(out,
true, cid);
524 set_mime_data_boundary(out, boundary, cid, dap4_data, x_plain);
526 XDRStreamMarshaller m(out);
531 for (DDS::Vars_iter i = dds.var_begin(); i != dds.var_end(); i++) {
532 if ((*i)->send_p()) {
533 (*i)->serialize(eval, dds, m, ce_eval);
559 establish_timeout(data_stream);
560 dds.set_timeout(d_timeout);
568 if (!d_btp_func_ce.empty()) {
569 BESDEBUG(
"dap",
"Found function(s) in CE: " << d_btp_func_ce << endl);
570 string cache_token =
"";
573 if (responseCache()) {
574 BESDEBUG(
"dap",
"Using the cache for the server function CE" << endl);
575 fdds = responseCache()->cache_dataset(dds, d_btp_func_ce,
this, &eval, cache_token);
578 BESDEBUG(
"dap",
"Cache not found; (re)calculating" << endl);
579 eval.parse_constraint(d_btp_func_ce, dds);
580 fdds = eval.eval_function_clauses(dds);
583 DBG(fdds->print_constrained(cerr));
590 fdds->mark_all(
false);
592 eval.parse_constraint(d_ce, *fdds);
594 fdds->tag_nested_sequences();
596 if (fdds->get_response_limit() != 0 && fdds->get_request_size(
true) > fdds->get_response_limit()) {
597 string msg =
"The Request for " + long_to_string(dds.get_request_size(
true) / 1024)
598 +
"KB is too large; requests for this user are limited to "
599 + long_to_string(dds.get_response_limit() / 1024) +
"KB.";
603 if (with_mime_headers)
604 set_mime_binary(data_stream, dods_data, x_plain, last_modified_time(d_dataset), dds.get_dap_version());
606 DBG(cerr <<
"About to call dataset_constraint" << endl);
607 dataset_constraint(data_stream, *fdds, eval,
false);
610 responseCache()->unlock_and_close(cache_token);
615 BESDEBUG(
"dap",
"Simple constraint" << endl);
617 eval.parse_constraint(d_ce, dds);
619 dds.tag_nested_sequences();
621 if (dds.get_response_limit() != 0 && dds.get_request_size(
true) > dds.get_response_limit()) {
622 string msg =
"The Request for " + long_to_string(dds.get_request_size(
true) / 1024)
623 +
"KB is too large; requests for this user are limited to "
624 + long_to_string(dds.get_response_limit() / 1024) +
"KB.";
628 if (with_mime_headers)
629 set_mime_binary(data_stream, dods_data, x_plain, last_modified_time(d_dataset), dds.get_dap_version());
631 dataset_constraint(data_stream, dds, eval);
634 data_stream << flush;
655 if (with_mime_headers)
656 set_mime_text(out, dap4_ddx, x_plain, last_modified_time(d_dataset), dds.get_dap_version());
658 dds.print_xml_writer(out,
false ,
"");
665 establish_timeout(out);
666 dds.set_timeout(d_timeout);
674 if (!d_btp_func_ce.empty()) {
675 string cache_token =
"";
678 if (responseCache()) {
679 DBG(cerr <<
"Using the cache for the server function CE" << endl);
680 fdds = responseCache()->cache_dataset(dds, d_btp_func_ce,
this, &eval, cache_token);
683 DBG(cerr <<
"Cache not found; (re)calculating" << endl);
684 eval.parse_constraint(d_btp_func_ce, dds);
685 fdds = eval.eval_function_clauses(dds);
693 fdds->mark_all(
false);
695 eval.parse_constraint(d_ce, *fdds);
697 if (with_mime_headers)
698 set_mime_text(out, dap4_ddx, x_plain, last_modified_time(d_dataset), dds.get_dap_version());
700 fdds->print_constrained(out);
703 responseCache()->unlock_and_close(cache_token);
708 DBG(cerr <<
"Simple constraint" << endl);
710 eval.parse_constraint(d_ce, dds);
712 if (with_mime_headers)
713 set_mime_text(out, dap4_ddx, x_plain, last_modified_time(d_dataset), dds.get_dap_version());
716 dds.print_xml_writer(out,
true,
"");
723 void BESDapResponseBuilder::send_dmr(ostream &out, DMR &dmr, ConstraintEvaluator &,
bool constrained,
724 bool with_mime_headers)
727 if (with_mime_headers)
728 set_mime_text(out, dap4_dmr, x_plain, last_modified_time(d_dataset), dmr.dap_version());
731 dmr.print_dap4(xml, constrained);
732 out << xml.get_doc();
740 establish_timeout(out);
749 if (!d_btp_func_ce.empty()) {
750 string cache_token =
"";
753 if (responseCache()) {
754 DBG(cerr <<
"Using the cache for the server function CE" << endl);
755 fdmr = responseCache()->cache_dataset(dmr, d_btp_func_ce,
this, &eval, cache_token);
758 DBG(cerr <<
"Cache not found; (re)calculating" << endl);
759 eval.parse_constraint(d_btp_func_ce, dmr);
760 fdmr = eval.eval_function_clauses(dmr);
768 fdmr->mark_all(
false);
770 eval.parse_constraint(d_ce, *fdmr);
772 if (with_mime_headers)
773 set_mime_text(out, dap4_dmr, x_plain, last_modified_time(d_dataset), dds.get_dap_version());
775 fdmr->print_constrained(out);
778 responseCache()->unlock_and_close(cache_token);
783 DBG(cerr <<
"Simple constraint" << endl);
785 eval.parse_constraint(d_ce, dmr);
787 if (with_mime_headers)
788 set_mime_text(out, dap4_dmr, x_plain, last_modified_time(d_dataset), dmr.dap_version());
790 dmr.print_constrained(out);
797 void BESDapResponseBuilder::send_dap4_data(ostream & data_stream, DMR & dmr, ConstraintEvaluator & eval,
bool with_mime_headers)
803 establish_timeout(data_stream);
806 eval.parse_constraint(d_ce, dmr);
808 if (dds.get_response_limit() != 0 && dds.get_request_size(
true) > dds.get_response_limit()) {
809 string msg =
"The Request for " + long_to_string(dds.get_request_size(
true) / 1024)
810 +
"KB is too large; requests for this user are limited to "
811 + long_to_string(dds.get_response_limit() / 1024) +
"KB.";
820 if (eval.function_clauses()) {
823 DDS *fdds = eval.eval_function_clauses(dds);
825 if (with_mime_headers)
826 set_mime_multipart(data_stream, boundary, start, dap4_data_ddx, x_plain, last_modified_time(d_dataset));
827 data_stream << flush;
828 dataset_constraint_ddx(data_stream, *fdds, eval, boundary, start);
837 if (with_mime_headers)
838 set_mime_multipart(data_stream, boundary, start, dap4_data_ddx, x_plain, last_modified_time(d_dataset));
839 data_stream << flush;
840 dataset_constraint_ddx(data_stream, dds, eval, boundary, start);
843 data_stream << flush;
845 if (with_mime_headers)
846 data_stream <<
CRLF <<
"--" << boundary <<
"--" <<
CRLF;
869 const string &boundary,
bool with_mime_headers)
872 establish_timeout(data_stream);
873 dds.set_timeout(d_timeout);
875 eval.parse_constraint(d_ce, dds);
877 if (dds.get_response_limit() != 0 && dds.get_request_size(
true) > dds.get_response_limit()) {
878 string msg =
"The Request for " + long_to_string(dds.get_request_size(
true) / 1024)
879 +
"KB is too large; requests for this user are limited to "
880 + long_to_string(dds.get_response_limit() / 1024) +
"KB.";
884 dds.tag_nested_sequences();
889 if (eval.function_clauses()) {
892 DDS *fdds = eval.eval_function_clauses(dds);
894 if (with_mime_headers)
895 set_mime_multipart(data_stream, boundary, start, dap4_data_ddx, x_plain, last_modified_time(d_dataset));
896 data_stream << flush;
897 dataset_constraint_ddx(data_stream, *fdds, eval, boundary, start);
906 if (with_mime_headers)
907 set_mime_multipart(data_stream, boundary, start, dap4_data_ddx, x_plain, last_modified_time(d_dataset));
908 data_stream << flush;
909 dataset_constraint_ddx(data_stream, dds, eval, boundary, start);
912 data_stream << flush;
914 if (with_mime_headers)
915 data_stream <<
CRLF <<
"--" << boundary <<
"--" <<
CRLF;
virtual void dataset_constraint(std::ostream &out, libdap::DDS &dds, libdap::ConstraintEvaluator &eval, bool ce_eval=true)
Build/return the BLOB part of the DAP2 data response.
virtual std::string get_ce() const
Return the entire constraint expression in a string.
static BESDapResponseCache * get_instance()
Get the default instance of the BESDapResponseCache object.
This class is used to cache DAP2 response objects.
virtual void send_das(std::ostream &out, libdap::DAS &das, bool with_mime_headers=true) const
virtual void send_data(std::ostream &data_stream, libdap::DDS &dds, libdap::ConstraintEvaluator &eval, bool with_mime_headers=true)
Send the data in the DDS object back to the client program.
virtual BESDapResponseCache * responseCache()
Lazy getter for the ResponseCache.
void initialize()
Called when initializing a ResponseBuilder that's not going to be passed command line arguments...
virtual void split_ce(libdap::ConstraintEvaluator &eval, const std::string &expr="")
Split the CE so that the server functions that compute new values are separated into their own string...
#define DAP_PROTOCOL_VERSION
void set_timeout(int timeout=0)
Set the server's timeout value.
virtual void set_dataset_name(const std::string _dataset)
Set the dataset name, which is a string used to access the dataset on the machine running the server...
virtual void send_ddx(std::ostream &out, libdap::DDS &dds, libdap::ConstraintEvaluator &eval, bool with_mime_headers=true)
Send the DDX response.
virtual void send_data_ddx(std::ostream &data_stream, libdap::DDS &dds, libdap::ConstraintEvaluator &eval, const std::string &start, const std::string &boundary, bool with_mime_headers=true)
Send the data in the DDS object back to the client program.
int get_timeout() const
Get the server's timeout value.
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
virtual void dataset_constraint_ddx(std::ostream &out, libdap::DDS &dds, libdap::ConstraintEvaluator &eval, const std::string &boundary, const std::string &start, bool ce_eval=true)
Build/return the DDX and the BLOB part of the DAP3.x data response.
virtual ~BESDapResponseBuilder()
virtual void set_ce(std::string _ce)
Set the constraint expression.
virtual void establish_timeout(std::ostream &stream) const
Use values of this instance to establish a timeout alarm for the server.
virtual std::string get_dataset_name() const
The ``dataset name'' is the filename or other string that the filter program will use to access the d...
virtual void send_dds(std::ostream &out, libdap::DDS &dds, libdap::ConstraintEvaluator &eval, bool constrained=false, bool with_mime_headers=true)
This function formats and prints an ASCII representation of a DDS on stdout.