41 #include "D4Connect.h" 42 #include "HTTPConnect.h" 47 #include "D4ParserSax2.h" 48 #include "chunked_stream.h" 49 #include "chunked_istream.h" 50 #include "D4StreamUnMarshaller.h" 53 #include "mime_util.h" 63 void 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: d_stream = " << rs << 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..");
91 parser.intern(*rs.get_cpp_stream(), &dmr,
false);
94 cerr <<
"Exception: " << e.get_error_message() << endl;
97 catch (std::exception &e) {
98 cerr <<
"Exception: " << e.what() << endl;
102 cerr <<
"Exception: unknown error" << endl;
110 throw Error(
"Unknown response type");
116 void D4Connect::process_data(DMR &data, Response &rs)
118 DBG(cerr <<
"Entering D4Connect::process_data" << endl);
120 assert(rs.get_cpp_stream());
122 data.set_dap_version(rs.get_protocol());
124 DBG(cerr <<
"Entering process_data: d_stream = " << rs << endl);
125 switch (rs.get_type()) {
129 if (!e.parse(rs.get_cpp_stream()))
130 throw InternalErr(__FILE__, __LINE__,
"Could not parse the Error object returned by the server!");
133 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors not processed yet: FIXME!");
139 throw InternalErr(__FILE__, __LINE__,
140 "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
143 #if BYTE_ORDER_PREFIX 146 *rs.get_cpp_stream() >> byte_order;
150 #if BYTE_ORDER_PREFIX 151 chunked_istream cis(*rs.get_cpp_stream(), 1024, byte_order);
153 chunked_istream cis(*(rs.get_cpp_stream()), CHUNK_SIZE);
159 int chunk_size = cis.read_next_chunk();
161 throw Error(
"Found an unexpected end of input (EOF) while reading a DAP4 data response. (1)");
164 char chunk[chunk_size];
165 cis.read(chunk, chunk_size);
169 parser.intern(chunk, chunk_size - 2, &data,
false);
172 cerr <<
"Exception: " << e.get_error_message() << endl;
175 catch (std::exception &e) {
176 cerr <<
"Exception: " << e.what() << endl;
180 cerr <<
"Exception: unknown error" << endl;
184 #if BYTE_ORDER_PREFIX 185 D4StreamUnMarshaller um(cis, byte_order);
187 D4StreamUnMarshaller um(cis, cis.twiddle_bytes());
189 data.root()->deserialize(um, data);
195 throw Error(
"Unknown response type");
207 void D4Connect::parse_mime(Response &rs)
209 rs.set_version(
"dods/0.0");
210 rs.set_protocol(
"2.0");
212 istream &data_source = *rs.get_cpp_stream();
214 while (!mime.empty()) {
215 string header, value;
219 if (header ==
"content-description") {
220 DBG(cout << header <<
": " << value << endl);
224 else if (header ==
"xdods-server" && rs.get_version() ==
"dods/0.0") {
225 DBG(cout << header <<
": " << value << endl);
226 rs.set_version(value);
229 else if (header ==
"xopendap-server") {
230 DBG(cout << header <<
": " << value << endl);
231 rs.set_version(value);
233 else if (header ==
"xdap") {
234 DBG(cout << header <<
": " << value << endl);
235 rs.set_protocol(value);
238 else if (rs.get_version() ==
"dods/0.0" && header ==
"server") {
239 DBG(cout << header <<
": " << value << endl);
240 rs.set_version(value);
255 D4Connect::D4Connect(
const string &url,
string uname,
string password) :
256 d_http(0), d_local(false), d_URL(
""), d_UrlQueryString(
""), d_server(
"unknown"), d_protocol(
"4.0")
262 if (name.find(
"http") == 0) {
263 DBG(cerr <<
"Connect: The identifier is an http URL" << endl);
265 d_http->set_use_cpp_streams(
true);
270 string::size_type dotpos = name.find(
'?');
271 if (dotpos != std::string::npos) {
272 d_URL = name.substr(0, dotpos);
274 d_UrlQueryString = name.substr(dotpos + 1);
276 if(d_UrlQueryString.find(DAP4_CE_QUERY_KEY) != std::string::npos){
277 std::stringstream msg;
279 msg <<
"WARNING: A DAP4 constraint expression key was found in the query string!" << endl;
280 msg <<
"The submitted dataset URL: " << name << endl;
281 msg <<
"Contains the query string: " << d_UrlQueryString << endl;
282 msg <<
"This will cause issues when making DAP4 requests that specify additional constraints. " << endl;
283 cerr << msg.str() << endl;
290 DBG(cerr <<
"Connect: The identifier is a local data source." << endl);
297 D4Connect::~D4Connect()
299 if (d_http)
delete d_http;
304 std::string D4Connect::build_dap4_ce(
const string requestSuffix,
const string dap4ce){
306 std::stringstream url;
307 bool needsAmpersand =
false;
309 url << d_URL << requestSuffix <<
"?";
311 if(d_UrlQueryString.length()> 0){
312 url << d_UrlQueryString;
313 needsAmpersand =
true;
316 if(dap4ce.length()> 0){
321 url << DAP4_CE_QUERY_KEY <<
"=" <<
id2www_ce(dap4ce);
326 cerr <<
"D4Connect::build_dap4_ce() - Source URL: " << d_URL << endl;
327 cerr <<
"D4Connect::build_dap4_ce() - Source URL Query String: " << d_UrlQueryString << endl;
328 cerr <<
"D4Connect::build_dap4_ce() - dap4ce: " << dap4ce << endl;
329 cerr <<
"D4Connect::build_dap4_ce() - request URL: " << url.str() << endl;
339 void D4Connect::request_dmr(
DMR &dmr,
const string expr)
341 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 cerr <<
"Response type unknown, assuming it's a DMR response." << endl;
357 parser.intern(*rs->get_cpp_stream(), &dmr,
false );
362 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors are not processed yet.");
367 throw InternalErr(__FILE__, __LINE__,
"Web error found where it should never be.");
371 throw InternalErr(__FILE__, __LINE__,
"Response type not handled (got " 372 + long_to_string(rs->get_type()) +
").");
383 void D4Connect::request_dap4_data(
DMR &dmr,
const string expr)
385 string url = build_dap4_ce(
".dap", expr);
391 d_server = rs->get_version();
392 d_protocol = rs->get_protocol();
394 switch (rs->get_type()) {
396 cerr <<
"Response type unknown, assuming it's a DAP4 Data response." << endl;
400 #if BYTE_ORDER_PREFIX 401 istream &in = *rs->get_cpp_stream();
408 #if BYTE_ORDER_PREFIX 418 int chunk_size = cis.read_next_chunk();
420 throw Error(
"Found an unexpected end of input (EOF) while reading a DAP4 data response. (2)");
423 char chunk[chunk_size];
424 cis.read(chunk, chunk_size);
428 parser.intern(chunk, chunk_size - 2, &dmr,
false );
431 #if BYTE_ORDER_PREFIX 442 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors are not processed yet.");
447 throw InternalErr(__FILE__, __LINE__,
"Web error found where it should never be.");
451 throw InternalErr(__FILE__, __LINE__,
"Response type not handled (got " 452 + long_to_string(rs->get_type()) +
").");
467 if (rs.get_type() == unknown_type)
468 throw Error(
"Unknown response type.");
470 read_dmr_no_mime(dmr, rs);
474 D4Connect::read_dmr_no_mime(
DMR &dmr,
Response &rs)
477 if (rs.get_type() == unknown_type)
478 rs.set_type(dap4_dmr);
480 switch (rs.get_type()) {
482 process_dmr(dmr, rs);
483 d_server = rs.get_version();
484 d_protocol = dmr.dap_version();
487 throw Error(
"Expected a DAP4 DMR response.");
495 if (rs.get_type() == unknown_type)
496 throw Error(
"Unknown response type.");
498 read_data_no_mime(data, rs);
501 void D4Connect::read_data_no_mime(
DMR &data,
Response &rs)
504 if (rs.get_type() == unknown_type)
505 rs.set_type(dap4_data);
507 switch (rs.get_type()) {
509 process_data(data, rs);
510 d_server = rs.get_version();
511 d_protocol = data.dap_version();
514 throw Error(
"Expected a DAP4 Data response.");
558 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)
Read data from the stream made by D4StreamMarshaller.
void set_xdap_protocol(int major, int minor)
void set_cache_enabled(bool enabled)
HTTPResponse * fetch_url(const string &url)
A class for software fault reporting.
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)
virtual void deserialize(D4StreamUnMarshaller &um, DMR &dmr)
void set_accept_deflate(bool defalte)
void set_xdap_protocol(int major, int minor)
bool twiddle_bytes() const
A class for error processing.