44 #include "D4Connect.h" 45 #include "HTTPConnect.h" 50 #include "D4ParserSax2.h" 51 #include "chunked_stream.h" 52 #include "chunked_istream.h" 53 #include "D4StreamUnMarshaller.h" 56 #include "mime_util.h" 67 void D4Connect::process_dmr(DMR &dmr, Response &rs)
69 DBG(cerr <<
"Entering D4Connect::process_dmr" << endl);
71 dmr.set_dap_version(rs.get_protocol());
73 DBG(cerr <<
"Entering process_data. Response.getVersion() = " << rs.get_version() << endl);
74 switch (rs.get_type()) {
78 if (!e.parse(rs.get_stream()))
79 throw InternalErr(__FILE__, __LINE__,
"Could not parse the Error object returned by the server!");
82 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors not processed yet: FIXME!");
88 throw InternalErr(__FILE__, __LINE__,
89 "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
99 parser.intern(*rs.get_cpp_stream(), &dmr);
102 cerr <<
"Exception: " << e.get_error_message() << endl;
105 catch (std::exception &e) {
106 cerr <<
"Exception: " << e.what() << endl;
110 cerr <<
"Exception: unknown error" << endl;
118 throw Error(
"Unknown response type");
124 void D4Connect::process_data(DMR &data, Response &rs)
126 DBG(cerr <<
"Entering D4Connect::process_data" << endl);
128 assert(rs.get_cpp_stream());
130 data.set_dap_version(rs.get_protocol());
132 DBG(cerr <<
"Entering process_data. Response.getVersion() = " << rs.get_version() << endl);
133 switch (rs.get_type()) {
137 if (!e.parse(rs.get_cpp_stream()))
138 throw InternalErr(__FILE__, __LINE__,
"Could not parse the Error object returned by the server!");
141 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors not processed yet: FIXME!");
147 throw InternalErr(__FILE__, __LINE__,
148 "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
151 #if BYTE_ORDER_PREFIX 154 *rs.get_cpp_stream() >> byte_order;
158 #if BYTE_ORDER_PREFIX 159 chunked_istream cis(*rs.get_cpp_stream(), 1024, byte_order);
161 chunked_istream cis(*(rs.get_cpp_stream()), CHUNK_SIZE);
167 int chunk_size = cis.read_next_chunk();
169 throw Error(
"Found an unexpected end of input (EOF) while reading a DAP4 data response. (1)");
172 char chunk[chunk_size];
173 cis.read(chunk, chunk_size);
178 parser.set_strict(
false);
181 parser.intern(chunk, chunk_size - 2, &data);
184 cerr <<
"Exception: " << e.get_error_message() << endl;
187 catch (std::exception &e) {
188 cerr <<
"Exception: " << e.what() << endl;
192 cerr <<
"Exception: unknown error" << endl;
196 #if BYTE_ORDER_PREFIX 197 D4StreamUnMarshaller um(cis, byte_order);
199 D4StreamUnMarshaller um(cis, cis.twiddle_bytes());
201 data.root()->deserialize(um, data);
207 throw Error(
"Unknown response type");
219 void D4Connect::parse_mime(Response &rs)
221 rs.set_version(
"dods/0.0");
222 rs.set_protocol(
"2.0");
224 istream &data_source = *rs.get_cpp_stream();
226 while (!mime.empty()) {
227 string header, value;
231 if (header ==
"content-description") {
232 DBG(cout << header <<
": " << value << endl);
236 else if (header ==
"xdods-server" && rs.get_version() ==
"dods/0.0") {
237 DBG(cout << header <<
": " << value << endl);
238 rs.set_version(value);
241 else if (header ==
"xopendap-server") {
242 DBG(cout << header <<
": " << value << endl);
243 rs.set_version(value);
245 else if (header ==
"xdap") {
246 DBG(cout << header <<
": " << value << endl);
247 rs.set_protocol(value);
250 else if (rs.get_version() ==
"dods/0.0" && header ==
"server") {
251 DBG(cout << header <<
": " << value << endl);
252 rs.set_version(value);
267 D4Connect::D4Connect(
const string &url,
string uname,
string password) :
268 d_http(0), d_local(false), d_URL(
""), d_UrlQueryString(
""), d_server(
"unknown"), d_protocol(
"4.0")
274 if (name.find(
"http") == 0) {
275 DBG(cerr <<
"Connect: The identifier is an http URL" << endl);
277 d_http->set_use_cpp_streams(
true);
282 string::size_type dotpos = name.find(
'?');
283 if (dotpos != std::string::npos) {
284 d_URL = name.substr(0, dotpos);
286 d_UrlQueryString = name.substr(dotpos + 1);
288 if (d_UrlQueryString.find(DAP4_CE_QUERY_KEY) != std::string::npos) {
289 std::stringstream msg;
291 msg <<
"WARNING: A DAP4 constraint expression key was found in the query string!" << endl;
292 msg <<
"The submitted dataset URL: " << name << endl;
293 msg <<
"Contains the query string: " << d_UrlQueryString << endl;
294 msg <<
"This will cause issues when making DAP4 requests that specify additional constraints. " << endl;
295 cerr << msg.str() << endl;
302 DBG(cerr <<
"Connect: The identifier is a local data source." << endl);
309 D4Connect::~D4Connect()
311 if (d_http)
delete d_http;
314 std::string D4Connect::build_dap4_ce(
const string requestSuffix,
const string dap4ce)
316 std::stringstream url;
317 bool needsAmpersand =
false;
319 url << d_URL << requestSuffix <<
"?";
321 if (d_UrlQueryString.length() > 0) {
322 url << d_UrlQueryString;
323 needsAmpersand =
true;
326 if (dap4ce.length() > 0) {
327 if (needsAmpersand) url <<
"&";
329 url << DAP4_CE_QUERY_KEY <<
"=" <<
id2www_ce(dap4ce);
332 DBG(cerr <<
"D4Connect::build_dap4_ce() - Source URL: " << d_URL << endl);
333 DBG(cerr <<
"D4Connect::build_dap4_ce() - Source URL Query String: " << d_UrlQueryString << endl);
334 DBG(cerr <<
"D4Connect::build_dap4_ce() - dap4ce: " << dap4ce << endl);
335 DBG(cerr <<
"D4Connect::build_dap4_ce() - request URL: " << url.str() << endl);
340 void D4Connect::request_dmr(DMR &dmr,
const string expr)
342 string url = build_dap4_ce(
".dmr", expr);
348 d_server = rs->get_version();
349 d_protocol = rs->get_protocol();
351 switch (rs->get_type()) {
353 DBG(cerr <<
"Response type unknown, assuming it's a DMR response." << endl);
357 parser.intern(*rs->get_cpp_stream(), &dmr);
362 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors are not processed yet.");
367 throw InternalErr(__FILE__, __LINE__,
"Web error found where it should never be.");
370 throw InternalErr(__FILE__, __LINE__,
371 "Response type not handled (got " + long_to_string(rs->get_type()) +
").");
382 void D4Connect::request_dap4_data(DMR &dmr,
const string expr)
384 string url = build_dap4_ce(
".dap", expr);
390 d_server = rs->get_version();
391 d_protocol = rs->get_protocol();
393 switch (rs->get_type()) {
395 DBG(cerr <<
"Response type unknown, assuming it's a DAP4 Data response." << endl);
398 #if BYTE_ORDER_PREFIX 399 istream &in = *rs->get_cpp_stream();
406 #if BYTE_ORDER_PREFIX 407 chunked_istream cis(*(rs->get_cpp_stream()), 1024, byte_order);
409 chunked_istream cis(*(rs->get_cpp_stream()), CHUNK_SIZE);
416 int chunk_size = cis.read_next_chunk();
418 throw Error(
"Found an unexpected end of input (EOF) while reading a DAP4 data response. (2)");
421 char chunk[chunk_size];
422 cis.read(chunk, chunk_size);
426 parser.set_strict(
false);
428 parser.intern(chunk, chunk_size - 2, &dmr,
false );
431 #if BYTE_ORDER_PREFIX 432 D4StreamUnMarshaller um(cis, byte_order);
434 D4StreamUnMarshaller um(cis, cis.twiddle_bytes());
436 dmr.root()->deserialize(um, dmr);
442 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors are not processed yet.");
447 throw InternalErr(__FILE__, __LINE__,
"Web error found where it should never be.");
450 throw InternalErr(__FILE__, __LINE__,
451 "Response type not handled (got " + long_to_string(rs->get_type()) +
").");
462 void D4Connect::read_dmr(DMR &dmr, Response &rs)
465 if (rs.get_type() == unknown_type)
throw Error(
"Unknown response type.");
467 read_dmr_no_mime(dmr, rs);
470 void D4Connect::read_dmr_no_mime(DMR &dmr, Response &rs)
473 if (rs.get_type() == unknown_type) rs.set_type(dap4_dmr);
475 switch (rs.get_type()) {
477 process_dmr(dmr, rs);
478 d_server = rs.get_version();
479 d_protocol = dmr.dap_version();
482 throw Error(
"Expected a DAP4 DMR response.");
486 void D4Connect::read_data(DMR &data, Response &rs)
489 if (rs.get_type() == unknown_type)
throw Error(
"Unknown response type.");
491 read_data_no_mime(data, rs);
494 void D4Connect::read_data_no_mime(DMR &data, Response &rs)
497 if (rs.get_type() == unknown_type) rs.set_type(dap4_data);
499 switch (rs.get_type()) {
501 process_data(data, rs);
502 d_server = rs.get_version();
503 d_protocol = data.dap_version();
506 throw Error(
"Expected a DAP4 Data response.");
546 bool D4Connect::is_cache_enabled()
string get_next_mime_header(FILE *in)
void set_credentials(std::string u, std::string p)
Set the credentials for responding to challenges while dereferencing URLs.
string id2www_ce(string in, const string &allowable)
string prune_spaces(const string &name)
void set_credentials(const string &u, const string &p)
void set_xdap_protocol(int major, int minor)
void set_cache_enabled(bool enabled)
HTTPResponse * fetch_url(const string &url)
top level DAP object to house generic methods
void parse_mime_header(const string &header, string &name, string &value)
void set_accept_deflate(bool deflate)
ObjectType get_description_type(const string &value)
void set_cache_enabled(bool enabled)
void set_accept_deflate(bool defalte)
void set_xdap_protocol(int major, int minor)