00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "config.h"
00038
00039
00040
00041 static char rcsid[] not_used =
00042 { "$Id: Connect.cc 21699 2009-11-05 00:06:01Z jimg $"
00043 };
00044
00045 #include <cstring>
00046 #include <fstream>
00047 #include <algorithm>
00048
00049 #include "debug.h"
00050 #include "DataDDS.h"
00051 #include "Connect.h"
00052 #include "escaping.h"
00053 #include "RCReader.h"
00054 #include "DDXParserSAX2.h"
00055 #if FILE_METHODS
00056 #include "XDRFileUnMarshaller.h"
00057 #endif
00058 #include "fdiostream.h"
00059 #include "XDRStreamUnMarshaller.h"
00060
00061 #include "mime_util.h"
00062
00063 using std::cerr;
00064 using std::endl;
00065 using std::ifstream;
00066 using std::ofstream;
00067 using std::min;
00068
00069 namespace libdap {
00070
00073 void
00074 Connect::process_data(DataDDS &data, Response *rs)
00075 {
00076 DBG(cerr << "Entering Connect::process_data" << endl);
00077
00078 data.set_version(rs->get_version());
00079 data.set_protocol(rs->get_protocol());
00080
00081 DBG(cerr << "Entering process_data: d_stream = " << rs << endl);
00082 switch (rs->get_type()) {
00083 case dods_error: {
00084 Error e;
00085 if (!e.parse(rs->get_stream()))
00086 throw InternalErr(__FILE__, __LINE__,
00087 "Could not parse the Error object returned by the server!");
00088 throw e;
00089 }
00090
00091 case web_error:
00092
00093
00094 throw InternalErr(__FILE__, __LINE__, "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
00095
00096 case dap4_data_ddx: {
00097
00098 DDXParser ddx_parser(data.get_factory());
00099
00100
00101 string boundary = read_multipart_boundary(rs->get_stream());
00102 DBG(cerr << "MPM Boundary: " << boundary << endl);
00103 read_multipart_headers(rs->get_stream(), "text/xml", dap4_ddx);
00104
00105
00106
00107 string data_cid;
00108 ddx_parser.intern_stream(rs->get_stream(), &data, data_cid, boundary);
00109
00110
00111 data_cid = cid_to_header_value(data_cid);
00112 DBG(cerr << "Data CID: " << data_cid << endl);
00113
00114
00115
00116 read_multipart_headers(rs->get_stream(),
00117 "application/octet-stream", dap4_data, data_cid);
00118
00119
00120 #if FILE_METHODS
00121 XDRFileUnMarshaller um( rs->get_stream() ) ;
00122 #else
00123 fpistream in ( rs->get_stream() );
00124 XDRStreamUnMarshaller um( in ) ;
00125 #endif
00126 try {
00127 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end();
00128 i++) {
00129 (*i)->deserialize(um, &data);
00130 }
00131 }
00132 catch (Error &e) {
00133 throw e;
00134 }
00135
00136 return;
00137 }
00138
00139 case dods_data:
00140 default: {
00141
00142 data.parse(rs->get_stream());
00143 #if FILE_METHODS
00144 XDRFileUnMarshaller um( rs->get_stream() ) ;
00145 #else
00146 fpistream in ( rs->get_stream() );
00147 XDRStreamUnMarshaller um( in ) ;
00148 #endif
00149
00150 try {
00151 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end();
00152 i++) {
00153 (*i)->deserialize(um, &data);
00154 }
00155 }
00156 catch (Error &e) {
00157 throw e;
00158 }
00159
00160 return;
00161 }
00162 }
00163 }
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00186 void
00187 Connect::parse_mime(Response *rs)
00188 {
00189 rs->set_version("dods/0.0");
00190 rs->set_protocol("2.0");
00191
00192 FILE *data_source = rs->get_stream();
00193 string mime = get_next_mime_header(data_source);
00194 while (!mime.empty()) {
00195 string header, value;
00196 parse_mime_header(mime, header, value);
00197
00198
00199 if (header == "content-description:") {
00200 DBG(cout << header << ": " << value << endl);
00201 rs->set_type(get_description_type(value));
00202 }
00203
00204 else if (header == "xdods-server:"
00205 && rs->get_version() == "dods/0.0") {
00206 DBG(cout << header << ": " << value << endl);
00207 rs->set_version(value);
00208 }
00209
00210 else if (header == "xopendap-server:") {
00211 DBG(cout << header << ": " << value << endl);
00212 rs->set_version(value);
00213 }
00214 else if (header == "xdap:") {
00215 DBG(cout << header << ": " << value << endl);
00216 rs->set_protocol(value);
00217 }
00218
00219 else if (rs->get_version() == "dods/0.0" && header == "server:") {
00220 DBG(cout << header << ": " << value << endl);
00221 rs->set_version(value);
00222 }
00223
00224 mime = get_next_mime_header(data_source);
00225 }
00226 }
00227
00228
00229
00237 Connect::Connect(const string &n, string uname, string password)
00238 throw(Error, InternalErr)
00239 : d_http(0), d_version("unknown"), d_protocol("2.0")
00240 {
00241 string name = prune_spaces(n);
00242
00243
00244
00245 if (name.find("http") == 0) {
00246 DBG(cerr << "Connect: The identifier is an http URL" << endl);
00247 d_http = new HTTPConnect(RCReader::instance());
00248
00249
00250 string::size_type dotpos = name.find('?');
00251 if (dotpos != name.npos) {
00252 _URL = name.substr(0, dotpos);
00253 string expr = name.substr(dotpos + 1);
00254
00255 dotpos = expr.find('&');
00256 if (dotpos != expr.npos) {
00257 _proj = expr.substr(0, dotpos);
00258 _sel = expr.substr(dotpos);
00259 }
00260 else {
00261 _proj = expr;
00262 _sel = "";
00263 }
00264 }
00265 else {
00266 _URL = name;
00267 _proj = "";
00268 _sel = "";
00269 }
00270
00271 _local = false;
00272 }
00273 else {
00274 DBG(cerr << "Connect: The identifier is a local data source." << endl);
00275
00276 d_http = 0;
00277 _URL = "";
00278 _local = true;
00279 }
00280
00281 set_credentials(uname, password);
00282 }
00283
00284 Connect::~Connect()
00285 {
00286 DBG2(cerr << "Entering the Connect dtor" << endl);
00287
00288 if (d_http)
00289 delete d_http; d_http = 0;
00290
00291 DBG2(cerr << "Leaving the Connect dtor" << endl);
00292 }
00293
00301 string
00302 Connect::request_version()
00303 {
00304 string version_url = _URL + ".ver";
00305 if (_proj.length() + _sel.length())
00306 version_url = version_url + "?" + id2www_ce(_proj + _sel);
00307
00308 Response *rs = 0;
00309 try {
00310 rs = d_http->fetch_url(version_url);
00311 }
00312 catch (Error &e) {
00313 delete rs; rs = 0;
00314 throw e;
00315 }
00316
00317 d_version = rs->get_version();
00318 d_protocol = rs->get_protocol();
00319
00320 delete rs; rs = 0;
00321
00322 return d_version;
00323 }
00324
00336 string
00337 Connect::request_protocol()
00338 {
00339 string version_url = _URL + ".ver";
00340 if (_proj.length() + _sel.length())
00341 version_url = version_url + "?" + id2www_ce(_proj + _sel);
00342
00343 Response *rs = 0;
00344 try {
00345 rs = d_http->fetch_url(version_url);
00346 }
00347 catch (Error &e) {
00348 delete rs; rs = 0;
00349 throw e;
00350 }
00351
00352 d_version = rs->get_version();
00353 d_protocol = rs->get_protocol();
00354
00355 delete rs; rs = 0;
00356
00357 return d_protocol;
00358 }
00359
00367 void
00368 Connect::request_das(DAS &das)
00369 {
00370 string das_url = _URL + ".das";
00371 if (_proj.length() + _sel.length())
00372 das_url = das_url + "?" + id2www_ce(_proj + _sel);
00373
00374 Response *rs = 0;
00375 try {
00376 rs = d_http->fetch_url(das_url);
00377 }
00378 catch (Error &e) {
00379 delete rs; rs = 0;
00380 throw e;
00381 }
00382
00383 d_version = rs->get_version();
00384 d_protocol = rs->get_protocol();
00385
00386 switch (rs->get_type()) {
00387 case dods_error: {
00388 Error e;
00389 if (!e.parse(rs->get_stream())) {
00390 throw InternalErr(__FILE__, __LINE__,
00391 "Could not parse error returned from server.");
00392 break;
00393 }
00394 throw e;
00395 break;
00396 }
00397
00398 case web_error:
00399
00400
00401 break;
00402
00403 case dods_das:
00404 default:
00405
00406 try {
00407 das.parse(rs->get_stream());
00408 }
00409 catch (Error &e) {
00410 delete rs; rs = 0;
00411 throw e;
00412 }
00413
00414 break;
00415 }
00416
00417 delete rs; rs = 0;
00418 }
00419
00430 void
00431 Connect::request_das_url(DAS &das)
00432 {
00433 string use_url = _URL + "?" + _proj + _sel ;
00434 Response *rs = 0;
00435 try {
00436 rs = d_http->fetch_url(use_url);
00437 }
00438 catch (Error &e) {
00439 delete rs; rs = 0;
00440 throw e;
00441 }
00442
00443 d_version = rs->get_version();
00444 d_protocol = rs->get_protocol();
00445
00446 switch (rs->get_type()) {
00447 case dods_error: {
00448 Error e;
00449 if (!e.parse(rs->get_stream())) {
00450 throw InternalErr(__FILE__, __LINE__,
00451 "Could not parse error returned from server.");
00452 break;
00453 }
00454 throw e;
00455 break;
00456 }
00457
00458 case web_error:
00459
00460
00461 break;
00462
00463 case dods_das:
00464 default:
00465
00466 try {
00467 das.parse(rs->get_stream());
00468 }
00469 catch (Error &e) {
00470 delete rs; rs = 0;
00471 throw e;
00472 }
00473
00474 break;
00475 }
00476
00477 delete rs; rs = 0;
00478 }
00479
00493 void
00494 Connect::request_dds(DDS &dds, string expr)
00495 {
00496 string proj, sel;
00497 string::size_type dotpos = expr.find('&');
00498 if (dotpos != expr.npos) {
00499 proj = expr.substr(0, dotpos);
00500 sel = expr.substr(dotpos);
00501 }
00502 else {
00503 proj = expr;
00504 sel = "";
00505 }
00506
00507 string dds_url = _URL + ".dds" + "?"
00508 + id2www_ce(_proj + proj + _sel + sel);
00509
00510 Response *rs = 0;
00511 try {
00512 rs = d_http->fetch_url(dds_url);
00513 }
00514 catch (Error &e) {
00515 delete rs; rs = 0;
00516 throw e;
00517 }
00518
00519 d_version = rs->get_version();
00520 d_protocol = rs->get_protocol();
00521
00522 switch (rs->get_type()) {
00523 case dods_error: {
00524 Error e;
00525 if (!e.parse(rs->get_stream())) {
00526 throw InternalErr(__FILE__, __LINE__,
00527 "Could not parse error returned from server.");
00528 break;
00529 }
00530 throw e;
00531 break;
00532 }
00533
00534 case web_error:
00535
00536
00537 break;
00538
00539 case dods_dds:
00540 default:
00541
00542 try {
00543 dds.parse(rs->get_stream());
00544 }
00545 catch (Error &e) {
00546 delete rs; rs = 0;
00547 throw e;
00548 }
00549 break;
00550 }
00551
00552 delete rs; rs = 0;
00553 }
00554
00571 void
00572 Connect::request_dds_url(DDS &dds)
00573 {
00574 string use_url = _URL + "?" + _proj + _sel ;
00575 Response *rs = 0;
00576 try {
00577 rs = d_http->fetch_url(use_url);
00578 }
00579 catch (Error &e) {
00580 delete rs; rs = 0;
00581 throw e;
00582 }
00583
00584 d_version = rs->get_version();
00585 d_protocol = rs->get_protocol();
00586
00587 switch (rs->get_type()) {
00588 case dods_error: {
00589 Error e;
00590 if (!e.parse(rs->get_stream())) {
00591 throw InternalErr(__FILE__, __LINE__,
00592 "Could not parse error returned from server.");
00593 break;
00594 }
00595 throw e;
00596 break;
00597 }
00598
00599 case web_error:
00600
00601
00602 break;
00603
00604 case dods_dds:
00605 default:
00606
00607 try {
00608 dds.parse(rs->get_stream());
00609 }
00610 catch (Error &e) {
00611 delete rs; rs = 0;
00612 throw e;
00613 }
00614 break;
00615 }
00616
00617 delete rs; rs = 0;
00618 }
00619
00631 void
00632 Connect::request_ddx(DDS &dds, string expr)
00633 {
00634 string proj, sel;
00635 string::size_type dotpos = expr.find('&');
00636 if (dotpos != expr.npos) {
00637 proj = expr.substr(0, dotpos);
00638 sel = expr.substr(dotpos);
00639 }
00640 else {
00641 proj = expr;
00642 sel = "";
00643 }
00644
00645 string ddx_url = _URL + ".ddx" + "?"
00646 + id2www_ce(_proj + proj + _sel + sel);
00647
00648 Response *rs = 0;
00649 try {
00650 rs = d_http->fetch_url(ddx_url);
00651 }
00652 catch (Error &e) {
00653 delete rs; rs = 0;
00654 throw e;
00655 }
00656
00657 d_version = rs->get_version();
00658 d_protocol = rs->get_protocol();
00659
00660 switch (rs->get_type()) {
00661 case dods_error: {
00662 Error e;
00663 if (!e.parse(rs->get_stream())) {
00664 throw InternalErr(__FILE__, __LINE__,
00665 "Could not parse error returned from server.");
00666 break;
00667 }
00668 throw e;
00669 break;
00670 }
00671
00672 case web_error:
00673
00674
00675 break;
00676
00677 case dap4_ddx:
00678 case dods_ddx:
00679 try {
00680 string blob;
00681
00682 DDXParser ddxp(dds.get_factory());
00683 ddxp.intern_stream(rs->get_stream(), &dds, blob);
00684 }
00685 catch (Error &e) {
00686 delete rs; rs = 0;
00687 throw e;
00688 }
00689 break;
00690
00691 default:
00692 throw Error("The site did not return a valid response (it lacked the\n\
00693 expected content description header value of 'dap4-ddx' and\n\
00694 instead returned '" + long_to_string(rs->get_type()) + "').\n\
00695 This may indicate that the server at the site is not correctly\n\
00696 configured, or that the URL has changed.");
00697 }
00698
00699 delete rs; rs = 0;
00700 }
00701
00704 void
00705 Connect::request_ddx_url(DDS &dds)
00706 {
00707 string use_url = _URL + "?" + _proj + _sel ;
00708
00709 Response *rs = 0;
00710 try {
00711 rs = d_http->fetch_url(use_url);
00712 }
00713 catch (Error &e) {
00714 delete rs; rs = 0;
00715 throw e;
00716 }
00717
00718 d_version = rs->get_version();
00719 d_protocol = rs->get_protocol();
00720
00721 switch (rs->get_type()) {
00722 case dods_error: {
00723 Error e;
00724 if (!e.parse(rs->get_stream())) {
00725 throw InternalErr(__FILE__, __LINE__,
00726 "Could not parse error returned from server.");
00727 break;
00728 }
00729 throw e;
00730 break;
00731 }
00732
00733 case web_error:
00734
00735
00736 break;
00737
00738 case dap4_ddx:
00739 case dods_ddx:
00740 try {
00741 string blob;
00742
00743 DDXParser ddxp(dds.get_factory());
00744 ddxp.intern_stream(rs->get_stream(), &dds, blob);
00745 }
00746 catch (Error &e) {
00747 delete rs; rs = 0;
00748 throw e;
00749 }
00750 break;
00751
00752 default:
00753 throw Error("The site did not return a valid response (it lacked the\n\
00754 expected content description header value of 'dap4-ddx' and\n\
00755 instead returned '" + long_to_string(rs->get_type()) + "').\n\
00756 This may indicate that the server at the site is not correctly\n\
00757 configured, or that the URL has changed.");
00758 }
00759
00760 delete rs; rs = 0;
00761 }
00762
00778 void
00779 Connect::request_data(DataDDS &data, string expr)
00780 {
00781 string proj, sel;
00782 string::size_type dotpos = expr.find('&');
00783 if (dotpos != expr.npos) {
00784 proj = expr.substr(0, dotpos);
00785 sel = expr.substr(dotpos);
00786 }
00787 else {
00788 proj = expr;
00789 sel = "";
00790 }
00791
00792 string data_url = _URL + ".dods?"
00793 + id2www_ce(_proj + proj + _sel + sel);
00794
00795 Response *rs = 0;
00796
00797 try {
00798 rs = d_http->fetch_url(data_url);
00799
00800 d_version = rs->get_version();
00801 d_protocol = rs->get_protocol();
00802
00803 process_data(data, rs);
00804 delete rs; rs = 0;
00805 }
00806 catch (Error &e) {
00807 delete rs; rs = 0;
00808 throw e;
00809 }
00810 }
00811
00829 void
00830 Connect::request_data_url(DataDDS &data)
00831 {
00832 string use_url = _URL + "?" + _proj + _sel ;
00833 Response *rs = 0;
00834
00835 try {
00836 rs = d_http->fetch_url(use_url);
00837
00838 d_version = rs->get_version();
00839 d_protocol = rs->get_protocol();
00840
00841 process_data(data, rs);
00842 delete rs; rs = 0;
00843 }
00844 catch (Error &e) {
00845 delete rs; rs = 0;
00846 throw e;
00847 }
00848 }
00849
00850 void
00851 Connect::request_data_ddx(DataDDS &data, string expr)
00852 {
00853 string proj, sel;
00854 string::size_type dotpos = expr.find('&');
00855 if (dotpos != expr.npos) {
00856 proj = expr.substr(0, dotpos);
00857 sel = expr.substr(dotpos);
00858 }
00859 else {
00860 proj = expr;
00861 sel = "";
00862 }
00863
00864 string data_url = _URL + ".dap?"
00865 + id2www_ce(_proj + proj + _sel + sel);
00866
00867 Response *rs = 0;
00868
00869 try {
00870 rs = d_http->fetch_url(data_url);
00871
00872 d_version = rs->get_version();
00873 d_protocol = rs->get_protocol();
00874
00875 process_data(data, rs);
00876 delete rs; rs = 0;
00877 }
00878 catch (Error &e) {
00879 delete rs; rs = 0;
00880 throw e;
00881 }
00882 }
00883
00884 void
00885 Connect::request_data_ddx_url(DataDDS &data)
00886 {
00887 string use_url = _URL + "?" + _proj + _sel ;
00888 Response *rs = 0;
00889
00890 try {
00891 rs = d_http->fetch_url(use_url);
00892
00893 d_version = rs->get_version();
00894 d_protocol = rs->get_protocol();
00895
00896 process_data(data, rs);
00897 delete rs; rs = 0;
00898 }
00899 catch (Error &e) {
00900 delete rs; rs = 0;
00901 throw e;
00902 }
00903 }
00904
00918 void
00919 Connect::read_data(DataDDS &data, Response *rs)
00920 {
00921 if (!rs)
00922 throw InternalErr(__FILE__, __LINE__, "Response object is null.");
00923
00924
00925 parse_mime(rs);
00926
00927 read_data_no_mime(data, rs);
00928 }
00929
00930
00931
00932
00933
00934
00935 static void
00936 divine_type_information(Response *rs)
00937 {
00938
00939 char c = getc(rs->get_stream());
00940 while (isspace(c)) {
00941 c = getc(rs->get_stream());
00942 }
00943
00944
00945
00946
00947
00948
00949 switch (c) {
00950 case '-':
00951 rs->set_type(dap4_data_ddx);
00952 break;
00953 case 'D':
00954 case 'd':
00955 rs->set_type(dods_data);
00956 break;
00957 default:
00958 throw InternalErr(__FILE__, __LINE__, "Could not determine type of response object in stream.");
00959 }
00960
00961 ungetc(c, rs->get_stream());
00962 }
00963
00976 void
00977 Connect::read_data_no_mime(DataDDS &data, Response *rs)
00978 {
00979 if (rs->get_type() == unknown_type)
00980 divine_type_information(rs);
00981
00982 switch (rs->get_type()) {
00983 case dods_data:
00984 d_version = rs->get_version();
00985 d_protocol = rs->get_protocol();
00986 process_data(data, rs);
00987 break;
00988 case dap4_data_ddx:
00989 process_data(data, rs);
00990 d_version = rs->get_version();
00991 d_protocol = data.get_protocol();
00992 break;
00993 default:
00994 throw InternalErr(__FILE__, __LINE__, "Should have been a DataDDS or DataDDX.");
00995 }
00996 }
00997
00998 bool
00999 Connect::is_local()
01000 {
01001 return _local;
01002 }
01003
01020 string
01021 Connect::URL(bool ce)
01022 {
01023 if (_local)
01024 throw InternalErr(__FILE__, __LINE__,
01025 "URL(): This call is only valid for a DAP data source.");
01026
01027 if (ce)
01028 return _URL + "?" + _proj + _sel;
01029 else
01030 return _URL;
01031 }
01032
01041 string
01042 Connect::CE()
01043 {
01044 if (_local)
01045 throw InternalErr(__FILE__, __LINE__,
01046 "CE(): This call is only valid for a DAP data source.");
01047
01048 return _proj + _sel;
01049 }
01050
01056 void
01057 Connect::set_credentials(string u, string p)
01058 {
01059 if (d_http)
01060 d_http->set_credentials(u, p);
01061 }
01062
01066 void
01067 Connect::set_accept_deflate(bool deflate)
01068 {
01069 if (d_http)
01070 d_http->set_accept_deflate(deflate);
01071 }
01072
01078 void
01079 Connect::set_xdap_protocol(int major, int minor)
01080 {
01081 if (d_http)
01082 d_http->set_xdap_protocol(major, minor);
01083 }
01084
01088 void
01089 Connect::set_cache_enabled(bool cache)
01090 {
01091 if (d_http)
01092 d_http->set_cache_enabled(cache);
01093 }
01094
01095 bool
01096 Connect::is_cache_enabled()
01097 {
01098 bool status;
01099 DBG(cerr << "Entering is_cache_enabled (" << hex << d_http << dec
01100 << ")... ");
01101 if (d_http)
01102 status = d_http->is_cache_enabled();
01103 else
01104 status = false;
01105 DBGN(cerr << "exiting" << endl);
01106 return status;
01107 }
01108
01109 }