43#include "HTTPConnect.h"
48#include "D4ParserSax2.h"
49#include "chunked_stream.h"
50#include "chunked_istream.h"
51#include "D4StreamUnMarshaller.h"
63void D4Connect::process_dmr(DMR &dmr, Response &rs)
65 DBG(cerr <<
"Entering D4Connect::process_dmr" << endl);
67 dmr.set_dap_version(rs.get_protocol());
69 DBG(cerr <<
"Entering process_data. Response.getVersion() = " << rs.get_version() << endl);
70 switch (rs.get_type()) {
74 if (!e.parse(rs.get_stream()))
75 throw InternalErr(__FILE__, __LINE__,
"Could not parse the Error object returned by the server!");
78 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors not processed yet: FIXME!");
84 throw InternalErr(__FILE__, __LINE__,
85 "An error was reported by the remote httpd; this should have been processed by HTTPConnect.");
95 parser.intern(*rs.get_cpp_stream(), &dmr);
98 cerr <<
"Exception: " << e.get_error_message() << endl;
101 catch (std::exception &e) {
102 cerr <<
"Exception: " << e.what() << endl;
106 cerr <<
"Exception: unknown error" << endl;
114 throw Error(
"Unknown response type");
120void D4Connect::process_data(DMR &data, Response &rs)
122 DBG(cerr <<
"Entering D4Connect::process_data" << endl);
124 assert(rs.get_cpp_stream());
126 data.set_dap_version(rs.get_protocol());
128 DBG(cerr <<
"Entering process_data. Response.getVersion() = " << rs.get_version() << endl);
129 switch (rs.get_type()) {
131 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors not processed yet: FIXME!");
137 throw InternalErr(__FILE__, __LINE__,
138 "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
141 chunked_istream cis(*(rs.get_cpp_stream()), CHUNK_SIZE);
146 int chunk_size = cis.read_next_chunk();
148 throw Error(
"Found an unexpected end of input (EOF) while reading a DAP4 data response. (1)");
151 char chunk[chunk_size];
152 cis.read(chunk, chunk_size);
157 parser.set_strict(
false);
160 parser.intern(chunk, chunk_size - 2, &data);
163 cerr <<
"Exception: " << e.get_error_message() << endl;
166 catch (std::exception &e) {
167 cerr <<
"Exception: " << e.what() << endl;
171 cerr <<
"Exception: unknown error" << endl;
175 D4StreamUnMarshaller um(cis, cis.twiddle_bytes());
176 data.root()->deserialize(um, data);
182 throw Error(
"Unknown response type");
194void D4Connect::parse_mime(Response &rs)
196 rs.set_version(
"dods/0.0");
197 rs.set_protocol(
"2.0");
199 istream &data_source = *rs.get_cpp_stream();
201 while (!mime.empty()) {
202 string header, value;
206 if (header ==
"content-description") {
207 DBG(cout << header <<
": " << value << endl);
211 else if (header ==
"xdods-server" && rs.get_version() ==
"dods/0.0") {
212 DBG(cout << header <<
": " << value << endl);
213 rs.set_version(value);
216 else if (header ==
"xopendap-server") {
217 DBG(cout << header <<
": " << value << endl);
218 rs.set_version(value);
220 else if (header ==
"xdap") {
221 DBG(cout << header <<
": " << value << endl);
222 rs.set_protocol(value);
225 else if (rs.get_version() ==
"dods/0.0" && header ==
"server") {
226 DBG(cout << header <<
": " << value << endl);
227 rs.set_version(value);
242D4Connect::D4Connect(
const string &url,
string uname,
string password) :
243 d_http(0), d_local(false), d_URL(
""), d_UrlQueryString(
""), d_server(
"unknown"), d_protocol(
"4.0")
249 if (name.find(
"http") == 0) {
250 DBG(cerr <<
"Connect: The identifier is an http URL" << endl);
252 d_http->set_use_cpp_streams(
true);
257 string::size_type dotpos = name.find(
'?');
258 if (dotpos != std::string::npos) {
259 d_URL = name.substr(0, dotpos);
261 d_UrlQueryString = name.substr(dotpos + 1);
263 if (d_UrlQueryString.find(DAP4_CE_QUERY_KEY) != std::string::npos) {
264 std::stringstream msg;
266 msg <<
"WARNING: A DAP4 constraint expression key was found in the query string!" << endl;
267 msg <<
"The submitted dataset URL: " << name << endl;
268 msg <<
"Contains the query string: " << d_UrlQueryString << endl;
269 msg <<
"This will cause issues when making DAP4 requests that specify additional constraints. " << endl;
270 cerr << msg.str() << endl;
277 DBG(cerr <<
"Connect: The identifier is a local data source." << endl);
284D4Connect::~D4Connect()
286 if (d_http)
delete d_http;
289std::string D4Connect::build_dap4_ce(
const string requestSuffix,
const string dap4ce)
291 std::stringstream url;
292 bool needsAmpersand =
false;
294 url << d_URL << requestSuffix <<
"?";
296 if (d_UrlQueryString.length() > 0) {
297 url << d_UrlQueryString;
298 needsAmpersand =
true;
301 if (dap4ce.length() > 0) {
302 if (needsAmpersand) url <<
"&";
304 url << DAP4_CE_QUERY_KEY <<
"=" <<
id2www_ce(dap4ce);
307 DBG(cerr <<
"D4Connect::build_dap4_ce() - Source URL: " << d_URL << endl);
308 DBG(cerr <<
"D4Connect::build_dap4_ce() - Source URL Query String: " << d_UrlQueryString << endl);
309 DBG(cerr <<
"D4Connect::build_dap4_ce() - dap4ce: " << dap4ce << endl);
310 DBG(cerr <<
"D4Connect::build_dap4_ce() - request URL: " << url.str() << endl);
315void D4Connect::request_dmr(DMR &dmr,
const string expr)
317 string url = build_dap4_ce(
".dmr", expr);
323 d_server = rs->get_version();
324 d_protocol = rs->get_protocol();
326 switch (rs->get_type()) {
328 DBG(cerr <<
"Response type unknown, assuming it's a DMR response." << endl);
332 parser.intern(*rs->get_cpp_stream(), &dmr);
337 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors are not processed yet.");
342 throw InternalErr(__FILE__, __LINE__,
"Web error found where it should never be.");
345 throw InternalErr(__FILE__, __LINE__,
346 "Response type not handled (got " + long_to_string(rs->get_type()) +
").");
357void D4Connect::request_dap4_data(DMR &dmr,
const string expr)
359 string url = build_dap4_ce(
".dap", expr);
365 d_server = rs->get_version();
366 d_protocol = rs->get_protocol();
368 switch (rs->get_type()) {
370 DBG(cerr <<
"Response type unknown, assuming it's a DAP4 Data response." << endl);
374 chunked_istream cis(*(rs->get_cpp_stream()), CHUNK_SIZE);
380 int chunk_size = cis.read_next_chunk();
382 throw Error(
"Found an unexpected end of input (EOF) while reading a DAP4 data response. (2)");
385 char chunk[chunk_size];
386 cis.read(chunk, chunk_size);
390 parser.set_strict(
false);
392 parser.intern(chunk, chunk_size - 2, &dmr,
false );
395 D4StreamUnMarshaller um(cis, cis.twiddle_bytes());
396 dmr.root()->deserialize(um, dmr);
402 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors are not processed yet.");
407 throw InternalErr(__FILE__, __LINE__,
"Web error found where it should never be.");
410 throw InternalErr(__FILE__, __LINE__,
411 "Response type not handled (got " + long_to_string(rs->get_type()) +
").");
422void D4Connect::read_dmr(DMR &dmr, Response &rs)
425 if (rs.get_type() == unknown_type)
throw Error(
"Unknown response type.");
427 read_dmr_no_mime(dmr, rs);
430void D4Connect::read_dmr_no_mime(DMR &dmr, Response &rs)
433 if (rs.get_type() == unknown_type) rs.set_type(dap4_dmr);
435 switch (rs.get_type()) {
437 process_dmr(dmr, rs);
438 d_server = rs.get_version();
439 d_protocol = dmr.dap_version();
442 throw Error(
"Expected a DAP4 DMR response.");
446void D4Connect::read_data(DMR &data, Response &rs)
449 if (rs.get_type() == unknown_type)
throw Error(
"Unknown response type.");
451 read_data_no_mime(data, rs);
454void D4Connect::read_data_no_mime(DMR &data, Response &rs)
457 if (rs.get_type() == unknown_type) rs.set_type(dap4_data);
459 switch (rs.get_type()) {
461 process_data(data, rs);
462 d_server = rs.get_version();
463 d_protocol = data.dap_version();
466 throw Error(
"Expected a DAP4 Data response.");
506bool D4Connect::is_cache_enabled()
void set_accept_deflate(bool deflate)
void set_cache_enabled(bool enabled)
void set_xdap_protocol(int major, int minor)
void set_credentials(std::string u, std::string p)
Set the credentials for responding to challenges while dereferencing URLs.
void set_accept_deflate(bool defalte)
HTTPResponse * fetch_url(const string &url)
void set_credentials(const string &u, const string &p)
void set_cache_enabled(bool enabled)
void set_xdap_protocol(int major, int minor)
top level DAP object to house generic methods
ObjectType get_description_type(const string &value)
void parse_mime_header(const string &header, string &name, string &value)
string prune_spaces(const string &name)
string id2www_ce(string in, const string &allowable)
string get_next_mime_header(FILE *in)