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