45#include "HTTPConnect.h"
48#include "D4ParserSax2.h"
49#include "D4StreamUnMarshaller.h"
50#include "chunked_istream.h"
51#include "chunked_stream.h"
63void D4Connect::process_dmr(
DMR &dmr,
Response &rs) {
64 DBG(cerr <<
"Entering D4Connect::process_dmr" << endl);
66 dmr.set_dap_version(rs.get_protocol());
68 DBG(cerr <<
"Entering process_data. Response.getVersion() = " << rs.get_version() << endl);
69 switch (rs.get_type()) {
73 if (!e.parse(rs.get_stream()))
74 throw InternalErr(__FILE__, __LINE__,
"Could not parse the Error object returned by the server!");
77 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors not processed yet: FIXME!");
83 throw InternalErr(__FILE__, __LINE__,
84 "An error was reported by the remote httpd; this should have been processed by HTTPConnect.");
94 parser.intern(*rs.get_cpp_stream(), &dmr);
96 cerr <<
"Exception: " << e.get_error_message() << endl;
98 }
catch (std::exception &e) {
99 cerr <<
"Exception: " << e.what() << endl;
102 cerr <<
"Exception: unknown error" << endl;
110 throw Error(
"Unknown response type");
116void D4Connect::process_data(
DMR &data,
Response &rs) {
117 DBG(cerr <<
"Entering D4Connect::process_data" << endl);
119 assert(rs.get_cpp_stream());
121 data.set_dap_version(rs.get_protocol());
123 DBG(cerr <<
"Entering process_data. Response.getVersion() = " << rs.get_version() << endl);
124 switch (rs.get_type()) {
126 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors not processed yet: FIXME!");
134 "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
137 chunked_istream cis(*(rs.get_cpp_stream()), CHUNK_SIZE);
142 int chunk_size = cis.read_next_chunk();
144 throw Error(
"Found an unexpected end of input (EOF) while reading a DAP4 data response. (1)");
147 char chunk[chunk_size];
148 cis.read(chunk, chunk_size);
153 parser.set_strict(
false);
156 parser.intern(chunk, chunk_size - 2, &data);
158 cerr <<
"Exception: " << e.get_error_message() << endl;
160 }
catch (std::exception &e) {
161 cerr <<
"Exception: " << e.what() << endl;
164 cerr <<
"Exception: unknown error" << endl;
168 D4StreamUnMarshaller um(cis, cis.twiddle_bytes());
169 data.root()->deserialize(um, data);
175 throw Error(
"Unknown response type");
187void D4Connect::parse_mime(
Response &rs) {
188 rs.set_version(
"dods/0.0");
189 rs.set_protocol(
"2.0");
191 istream &data_source = *rs.get_cpp_stream();
193 while (!mime.empty()) {
194 string header, value;
198 if (header ==
"content-description") {
199 DBG(cout << header <<
": " << value << endl);
203 else if (header ==
"xdods-server" && rs.get_version() ==
"dods/0.0") {
204 DBG(cout << header <<
": " << value << endl);
205 rs.set_version(value);
208 else if (header ==
"xopendap-server") {
209 DBG(cout << header <<
": " << value << endl);
210 rs.set_version(value);
211 }
else if (header ==
"xdap") {
212 DBG(cout << header <<
": " << value << endl);
213 rs.set_protocol(value);
216 else if (rs.get_version() ==
"dods/0.0" && header ==
"server") {
217 DBG(cout << header <<
": " << value << endl);
218 rs.set_version(value);
233D4Connect::D4Connect(
const string &url,
string uname,
string password)
234 : d_http(0), d_local(false), d_URL(
""), d_UrlQueryString(
""), d_server(
"unknown"), d_protocol(
"4.0") {
239 if (name.find(
"http") == 0) {
240 DBG(cerr <<
"Connect: The identifier is an http URL" << endl);
242 d_http->set_use_cpp_streams(
true);
247 string::size_type dotpos = name.find(
'?');
248 if (dotpos != std::string::npos) {
249 d_URL = name.substr(0, dotpos);
251 d_UrlQueryString = name.substr(dotpos + 1);
253 if (d_UrlQueryString.find(DAP4_CE_QUERY_KEY) != std::string::npos) {
254 std::stringstream msg;
256 msg <<
"WARNING: A DAP4 constraint expression key was found in the query string!" << endl;
257 msg <<
"The submitted dataset URL: " << name << endl;
258 msg <<
"Contains the query string: " << d_UrlQueryString << endl;
259 msg <<
"This will cause issues when making DAP4 requests that specify additional constraints. " << endl;
260 cerr << msg.str() << endl;
265 DBG(cerr <<
"Connect: The identifier is a local data source." << endl);
272D4Connect::~D4Connect() {
277std::string D4Connect::build_dap4_ce(
const string requestSuffix,
const string dap4ce) {
278 std::stringstream url;
279 bool needsAmpersand =
false;
281 url << d_URL << requestSuffix <<
"?";
283 if (d_UrlQueryString.length() > 0) {
284 url << d_UrlQueryString;
285 needsAmpersand =
true;
288 if (dap4ce.length() > 0) {
292 url << DAP4_CE_QUERY_KEY <<
"=" <<
id2www_ce(dap4ce);
295 DBG(cerr <<
"D4Connect::build_dap4_ce() - Source URL: " << d_URL << endl);
296 DBG(cerr <<
"D4Connect::build_dap4_ce() - Source URL Query String: " << d_UrlQueryString << endl);
297 DBG(cerr <<
"D4Connect::build_dap4_ce() - dap4ce: " << dap4ce << endl);
298 DBG(cerr <<
"D4Connect::build_dap4_ce() - request URL: " << url.str() << endl);
303void D4Connect::request_dmr(
DMR &dmr,
const string expr) {
304 string url = build_dap4_ce(
".dmr", expr);
308 rs = d_http->fetch_url(url);
310 d_server = rs->get_version();
311 d_protocol = rs->get_protocol();
313 switch (rs->get_type()) {
315 DBG(cerr <<
"Response type unknown, assuming it's a DMR response." << endl);
319 parser.intern(*rs->get_cpp_stream(), &dmr);
324 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors are not processed yet.");
329 throw InternalErr(__FILE__, __LINE__,
"Web error found where it should never be.");
332 throw InternalErr(__FILE__, __LINE__,
333 "Response type not handled (got " + long_to_string(rs->get_type()) +
").");
343void D4Connect::request_dap4_data(
DMR &dmr,
const string expr) {
344 string url = build_dap4_ce(
".dap", expr);
348 rs = d_http->fetch_url(url);
350 d_server = rs->get_version();
351 d_protocol = rs->get_protocol();
353 switch (rs->get_type()) {
355 DBG(cerr <<
"Response type unknown, assuming it's a DAP4 Data response." << endl);
359 chunked_istream cis(*(rs->get_cpp_stream()), CHUNK_SIZE);
365 int chunk_size = cis.read_next_chunk();
367 throw Error(
"Found an unexpected end of input (EOF) while reading a DAP4 data response. (2)");
370 char chunk[chunk_size];
371 cis.read(chunk, chunk_size);
375 parser.set_strict(
false);
377 parser.intern(chunk, chunk_size - 2, &dmr,
false );
380 D4StreamUnMarshaller um(cis, cis.twiddle_bytes());
381 dmr.root()->deserialize(um, dmr);
387 throw InternalErr(__FILE__, __LINE__,
"DAP4 errors are not processed yet.");
392 throw InternalErr(__FILE__, __LINE__,
"Web error found where it should never be.");
395 throw InternalErr(__FILE__, __LINE__,
396 "Response type not handled (got " + long_to_string(rs->get_type()) +
").");
408 if (rs.get_type() == unknown_type)
409 throw Error(
"Unknown response type.");
411 read_dmr_no_mime(dmr, rs);
414void D4Connect::read_dmr_no_mime(
DMR &dmr,
Response &rs) {
416 if (rs.get_type() == unknown_type)
417 rs.set_type(dap4_dmr);
419 switch (rs.get_type()) {
421 process_dmr(dmr, rs);
422 d_server = rs.get_version();
423 d_protocol = dmr.dap_version();
426 throw Error(
"Expected a DAP4 DMR response.");
430void D4Connect::read_data(
DMR &data,
Response &rs) {
432 if (rs.get_type() == unknown_type)
433 throw Error(
"Unknown response type.");
435 read_data_no_mime(data, rs);
438void D4Connect::read_data_no_mime(
DMR &data,
Response &rs) {
440 if (rs.get_type() == unknown_type)
441 rs.set_type(dap4_data);
443 switch (rs.get_type()) {
445 process_data(data, rs);
446 d_server = rs.get_version();
447 d_protocol = data.dap_version();
450 throw Error(
"Expected a DAP4 Data response.");
461 d_http->set_credentials(u, p);
469 d_http->set_accept_deflate(deflate);
479 d_http->set_xdap_protocol(major, minor);
487 d_http->set_cache_enabled(cache);
490bool 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.
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)