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 17002 2007-08-27 19:16:51Z pwest $"
00043 };
00044
00045 #include <stdio.h>
00046 #ifndef WIN32
00047 #include <unistd.h>
00048 #endif
00049
00050 #include <fstream>
00051 #include <algorithm>
00052
00053 #include "debug.h"
00054 #include "DataDDS.h"
00055 #include "Connect.h"
00056 #include "escaping.h"
00057 #include "RCReader.h"
00058 #include "DDXParser.h"
00059 #include "XDRFileUnMarshaller.h"
00060
00061 using std::cerr;
00062 using std::endl;
00063 using std::ifstream;
00064 using std::ofstream;
00065 using std::min;
00066
00067 extern ObjectType get_type(const string &value);
00068
00071 void
00072 Connect::process_data(DataDDS &data, Response *rs)
00073 {
00074 DBG(cerr << "Entering Connect::process_data" << endl);
00075
00076
00077
00078
00079
00080
00081 data.set_version(rs->get_version());
00082 data.set_protocol(rs->get_protocol());
00083
00084 DBG(cerr << "Entering process_data: d_stream = " << rs << endl);
00085 switch (rs->get_type()) {
00086 case dods_error: {
00087 Error e;
00088 if (!e.parse(rs->get_stream()))
00089 throw InternalErr(__FILE__, __LINE__,
00090 "Could not parse the Error object returned by the server!");
00091 throw e;
00092 }
00093
00094 case web_error:
00095
00096
00097 throw InternalErr(__FILE__, __LINE__, "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
00098
00099 case dods_data:
00100 default: {
00101
00102 data.parse(rs->get_stream());
00103 XDRFileUnMarshaller um( rs->get_stream() ) ;
00104
00105
00106 try {
00107 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end();
00108 i++) {
00109 (*i)->deserialize(um, &data);
00110 }
00111 }
00112 catch (Error &e) {
00113 throw e;
00114 }
00115
00116 return;
00117 }
00118
00119 #if 0
00120
00121
00122
00123
00124 default:
00125 throw Error("The site did not return a valid response (it lacked the\nexpected content description header value of 'dods_data').\nThis may indicate that the server at the site is not correctly\nconfigured, or that the URL has changed.");
00126 #endif
00127 }
00128 }
00129
00130
00131 ObjectType
00132 get_type(const string &value)
00133 {
00134 if (value == "dods_das")
00135 return dods_das;
00136 else if (value == "dods_dds")
00137 return dods_dds;
00138 else if (value == "dods_data")
00139 return dods_data;
00140 else if (value == "dods_error")
00141 return dods_error;
00142 else if (value == "web_error")
00143 return web_error;
00144 else
00145 return unknown_type;
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00169 void
00170 Connect::parse_mime(Response *rs)
00171 {
00172 rs->set_version("dods/0.0");
00173 rs->set_protocol("2.0");
00174
00175
00176
00177 FILE *data_source = rs->get_stream();
00178
00179 char line[256];
00180 fgets(line, 255, data_source);
00181
00182 int slen = strlen(line);
00183 slen = min(slen, 256);
00184 line[slen - 1] = '\0';
00185 if (line[slen - 2] == '\r')
00186 line[slen - 2] = '\0';
00187
00188 while (line[0] != '\0') {
00189 char h[256], v[256];
00190 sscanf(line, "%s %s\n", h, v);
00191 string header = h;
00192 string value = v;
00193 downcase(header);
00194 downcase(value);
00195
00196 if (header == "content-description:") {
00197 DBG(cout << header << ": " << value << endl);
00198 rs->set_type(get_type(value));
00199 }
00200 else if (header == "xdods-server:"
00201 && rs->get_version() == "dods/0.0") {
00202 DBG(cout << header << ": " << value << endl);
00203 rs->set_version(value);
00204 }
00205 else if (header == "xopendap-server:") {
00206 DBG(cout << header << ": " << value << endl);
00207 rs->set_version(value);
00208 }
00209 else if (header == "xdap:") {
00210 DBG(cout << header << ": " << value << endl);
00211 rs->set_protocol(value);
00212 }
00213 else if (rs->get_version() == "dods/0.0" && header == "server:") {
00214 DBG(cout << header << ": " << value << endl);
00215 rs->set_version(value);
00216 }
00217
00218 fgets(line, 255, data_source);
00219 slen = strlen(line);
00220 slen = min(slen, 256);
00221 line[slen - 1] = '\0';
00222 if (line[slen - 2] == '\r')
00223 line[slen - 2] = '\0';
00224 }
00225 }
00226
00227
00228
00236 Connect::Connect(const string &n, string uname, string password)
00237 throw(Error, InternalErr)
00238 : d_http(0), d_version("unknown"), d_protocol("2.0")
00239 {
00240 string name = prune_spaces(n);
00241
00242
00243
00244 if (name.find("http") == 0) {
00245 DBG(cerr << "Connect: The identifier is an http URL" << endl);
00246 d_http = new HTTPConnect(RCReader::instance());
00247
00248
00249 string::size_type dotpos = name.find('?');
00250 if (dotpos != name.npos) {
00251 _URL = name.substr(0, dotpos);
00252 string expr = name.substr(dotpos + 1);
00253
00254 dotpos = expr.find('&');
00255 if (dotpos != expr.npos) {
00256 _proj = expr.substr(0, dotpos);
00257 _sel = expr.substr(dotpos);
00258 }
00259 else {
00260 _proj = expr;
00261 _sel = "";
00262 }
00263 }
00264 else {
00265 _URL = name;
00266 _proj = "";
00267 _sel = "";
00268 }
00269
00270 _local = false;
00271 }
00272 else {
00273 DBG(cerr << "Connect: The identifier is a local data source." << endl);
00274
00275 d_http = 0;
00276 _URL = "";
00277 _local = true;
00278 }
00279
00280 set_credentials(uname, password);
00281 }
00282
00283 Connect::~Connect()
00284 {
00285 DBG2(cerr << "Entering the Connect dtor" << endl);
00286
00287 if (d_http)
00288 delete d_http; d_http = 0;
00289
00290 DBG2(cerr << "Leaving the Connect dtor" << endl);
00291 }
00292
00300 string
00301 Connect::request_version()
00302 {
00303 string version_url = _URL + ".ver";
00304 if (_proj.length() + _sel.length())
00305 version_url = version_url + "?" + id2www_ce(_proj + _sel);
00306
00307 Response *rs = 0;
00308 try {
00309 rs = d_http->fetch_url(version_url);
00310 }
00311 catch (Error &e) {
00312 delete rs; rs = 0;
00313 throw e;
00314 }
00315
00316 d_version = rs->get_version();
00317 d_protocol = rs->get_protocol();
00318 delete rs; rs = 0;
00319
00320 return d_version;
00321 }
00322
00330 string
00331 Connect::request_protocol()
00332 {
00333 string version_url = _URL + ".ver";
00334 if (_proj.length() + _sel.length())
00335 version_url = version_url + "?" + id2www_ce(_proj + _sel);
00336
00337 Response *rs = 0;
00338 try {
00339 rs = d_http->fetch_url(version_url);
00340 }
00341 catch (Error &e) {
00342 delete rs; rs = 0;
00343 throw e;
00344 }
00345
00346 d_version = rs->get_version();
00347 d_protocol = rs->get_protocol();
00348 delete rs; rs = 0;
00349
00350 return d_protocol;
00351 }
00352
00360 void
00361 Connect::request_das(DAS &das)
00362 {
00363 string das_url = _URL + ".das";
00364 if (_proj.length() + _sel.length())
00365 das_url = das_url + "?" + id2www_ce(_proj + _sel);
00366
00367 Response *rs = 0;
00368 try {
00369 rs = d_http->fetch_url(das_url);
00370 }
00371 catch (Error &e) {
00372 delete rs; rs = 0;
00373 throw e;
00374 }
00375
00376 d_version = rs->get_version();
00377 d_protocol = rs->get_protocol();
00378
00379 switch (rs->get_type()) {
00380 case dods_error: {
00381 Error e;
00382 if (!e.parse(rs->get_stream())) {
00383 throw InternalErr(__FILE__, __LINE__,
00384 "Could not parse error returned from server.");
00385 break;
00386 }
00387 throw e;
00388 break;
00389 }
00390
00391 case web_error:
00392
00393
00394 break;
00395
00396 case dods_das:
00397 default:
00398
00399 try {
00400 das.parse(rs->get_stream());
00401 }
00402 catch (Error &e) {
00403 delete rs; rs = 0;
00404 throw e;
00405 }
00406
00407 break;
00408
00409 #if 0
00410
00411 default:
00412 throw Error("The site did not return a valid response (it lacked the\nexpected content description header value of 'dods_das').\nThis may indicate that the server at the site is not correctly\nconfigured, or that the URL has changed.");
00413 #endif
00414 }
00415
00416 delete rs; rs = 0;
00417 }
00418
00429 void
00430 Connect::request_das_url(DAS &das)
00431 {
00432 string use_url = _URL + "?" + _proj + _sel ;
00433 Response *rs = 0;
00434 try {
00435 rs = d_http->fetch_url(use_url);
00436 }
00437 catch (Error &e) {
00438 delete rs; rs = 0;
00439 throw e;
00440 }
00441
00442 d_version = rs->get_version();
00443 d_protocol = rs->get_protocol();
00444
00445 switch (rs->get_type()) {
00446 case dods_error: {
00447 Error e;
00448 if (!e.parse(rs->get_stream())) {
00449 throw InternalErr(__FILE__, __LINE__,
00450 "Could not parse error returned from server.");
00451 break;
00452 }
00453 throw e;
00454 break;
00455 }
00456
00457 case web_error:
00458
00459
00460 break;
00461
00462 case dods_das:
00463 default:
00464
00465 try {
00466 das.parse(rs->get_stream());
00467 }
00468 catch (Error &e) {
00469 delete rs; rs = 0;
00470 throw e;
00471 }
00472
00473 break;
00474 }
00475
00476 delete rs; rs = 0;
00477 }
00478
00492 void
00493 Connect::request_dds(DDS &dds, string expr)
00494 {
00495 string proj, sel;
00496 string::size_type dotpos = expr.find('&');
00497 if (dotpos != expr.npos) {
00498 proj = expr.substr(0, dotpos);
00499 sel = expr.substr(dotpos);
00500 }
00501 else {
00502 proj = expr;
00503 sel = "";
00504 }
00505
00506 string dds_url = _URL + ".dds" + "?"
00507 + id2www_ce(_proj + proj + _sel + sel);
00508
00509 Response *rs = 0;
00510 try {
00511 rs = d_http->fetch_url(dds_url);
00512 }
00513 catch (Error &e) {
00514 delete rs; rs = 0;
00515 throw e;
00516 }
00517
00518 d_version = rs->get_version();
00519 d_protocol = rs->get_protocol();
00520
00521 switch (rs->get_type()) {
00522 case dods_error: {
00523 Error e;
00524 if (!e.parse(rs->get_stream())) {
00525 throw InternalErr(__FILE__, __LINE__,
00526 "Could not parse error returned from server.");
00527 break;
00528 }
00529 throw e;
00530 break;
00531 }
00532
00533 case web_error:
00534
00535
00536 break;
00537
00538 case dods_dds:
00539 default:
00540
00541 try {
00542 dds.parse(rs->get_stream());
00543 }
00544 catch (Error &e) {
00545 delete rs; rs = 0;
00546 throw e;
00547 }
00548 break;
00549
00550 #if 0
00551
00552 default:
00553 throw Error("The site did not return a valid response (it lacked the\nexpected content description header value of 'dods_dds').\nThis may indicate that the server at the site is not correctly\nconfigured, or that the URL has changed.");
00554 #endif
00555 }
00556
00557 delete rs; rs = 0;
00558 }
00559
00576 void
00577 Connect::request_dds_url(DDS &dds)
00578 {
00579 string use_url = _URL + "?" + _proj + _sel ;
00580 Response *rs = 0;
00581 try {
00582 rs = d_http->fetch_url(use_url);
00583 }
00584 catch (Error &e) {
00585 delete rs; rs = 0;
00586 throw e;
00587 }
00588
00589 d_version = rs->get_version();
00590 d_protocol = rs->get_protocol();
00591
00592 switch (rs->get_type()) {
00593 case dods_error: {
00594 Error e;
00595 if (!e.parse(rs->get_stream())) {
00596 throw InternalErr(__FILE__, __LINE__,
00597 "Could not parse error returned from server.");
00598 break;
00599 }
00600 throw e;
00601 break;
00602 }
00603
00604 case web_error:
00605
00606
00607 break;
00608
00609 case dods_dds:
00610 default:
00611
00612 try {
00613 dds.parse(rs->get_stream());
00614 }
00615 catch (Error &e) {
00616 delete rs; rs = 0;
00617 throw e;
00618 }
00619 break;
00620 }
00621
00622 delete rs; rs = 0;
00623 }
00624
00636 void
00637 Connect::request_ddx(DDS &dds, string expr)
00638 {
00639 string proj, sel;
00640 string::size_type dotpos = expr.find('&');
00641 if (dotpos != expr.npos) {
00642 proj = expr.substr(0, dotpos);
00643 sel = expr.substr(dotpos);
00644 }
00645 else {
00646 proj = expr;
00647 sel = "";
00648 }
00649
00650 string ddx_url = _URL + ".ddx" + "?"
00651 + id2www_ce(_proj + proj + _sel + sel);
00652
00653 Response *rs = 0;
00654 try {
00655 rs = d_http->fetch_url(ddx_url);
00656 }
00657 catch (Error &e) {
00658 delete rs; rs = 0;
00659 throw e;
00660 }
00661
00662 d_version = rs->get_version();
00663 d_protocol = rs->get_protocol();
00664
00665 switch (rs->get_type()) {
00666 case dods_error: {
00667 Error e;
00668 if (!e.parse(rs->get_stream())) {
00669 throw InternalErr(__FILE__, __LINE__,
00670 "Could not parse error returned from server.");
00671 break;
00672 }
00673 throw e;
00674 break;
00675 }
00676
00677 case web_error:
00678
00679
00680 break;
00681
00682 case dap4_ddx:
00683 default:
00684
00685 try {
00686 string blob;
00687 DDXParser ddxp(dds.get_factory());
00688 ddxp.intern_stream(rs->get_stream(), &dds, &blob);
00689 #if 0
00690 dds.parse(rs->get_stream());
00691 #endif
00692 }
00693 catch (Error &e) {
00694 delete rs; rs = 0;
00695 throw e;
00696 }
00697 break;
00698
00699 #if 0
00700
00701 default:
00702 throw Error("The site did not return a valid response (it lacked the\nexpected content description header value of 'dods_ddx').\nThis may indicate that the server at the site is not correctly\nconfigured, or that the URL has changed.");
00703 #endif
00704 }
00705
00706 delete rs; rs = 0;
00707 }
00708
00711 void
00712 Connect::request_ddx_url(DDS &dds)
00713 {
00714 string use_url = _URL + "?" + _proj + _sel ;
00715
00716 Response *rs = 0;
00717 try {
00718 rs = d_http->fetch_url(use_url);
00719 }
00720 catch (Error &e) {
00721 delete rs; rs = 0;
00722 throw e;
00723 }
00724
00725 d_version = rs->get_version();
00726 d_protocol = rs->get_protocol();
00727
00728 switch (rs->get_type()) {
00729 case dods_error: {
00730 Error e;
00731 if (!e.parse(rs->get_stream())) {
00732 throw InternalErr(__FILE__, __LINE__,
00733 "Could not parse error returned from server.");
00734 break;
00735 }
00736 throw e;
00737 break;
00738 }
00739
00740 case web_error:
00741
00742
00743 break;
00744
00745 case dap4_ddx:
00746 default:
00747
00748 try {
00749 dds.parse(rs->get_stream());
00750 }
00751 catch (Error &e) {
00752 delete rs; rs = 0;
00753 throw e;
00754 }
00755 break;
00756
00757 #if 0
00758
00759 default:
00760 throw Error("The site did not return a valid response (it lacked the\nexpected content description header value of 'dods_ddx').\nThis may indicate that the server at the site is not correctly\nconfigured, or that the URL has changed.");
00761 #endif
00762 }
00763
00764 delete rs; rs = 0;
00765 }
00766
00782 void
00783 Connect::request_data(DataDDS &data, string expr)
00784 {
00785 string proj, sel;
00786 string::size_type dotpos = expr.find('&');
00787 if (dotpos != expr.npos) {
00788 proj = expr.substr(0, dotpos);
00789 sel = expr.substr(dotpos);
00790 }
00791 else {
00792 proj = expr;
00793 sel = "";
00794 }
00795
00796 string data_url = _URL + ".dods?"
00797 + id2www_ce(_proj + proj + _sel + sel);
00798
00799 Response *rs = 0;
00800
00801 try {
00802 rs = d_http->fetch_url(data_url);
00803 d_version = rs->get_version();
00804 d_protocol = rs->get_protocol();
00805
00806 process_data(data, rs);
00807 delete rs; rs = 0;
00808 }
00809 catch (Error &e) {
00810 delete rs; rs = 0;
00811 throw e;
00812 }
00813 }
00814
00832 void
00833 Connect::request_data_url(DataDDS &data)
00834 {
00835 string use_url = _URL + "?" + _proj + _sel ;
00836 Response *rs = 0;
00837
00838 try {
00839 rs = d_http->fetch_url(use_url);
00840 d_version = rs->get_version();
00841 d_protocol = rs->get_protocol();
00842
00843 process_data(data, rs);
00844 delete rs; rs = 0;
00845 }
00846 catch (Error &e) {
00847 delete rs; rs = 0;
00848 throw e;
00849 }
00850 }
00851
00852
00869 void
00870 Connect::read_data(DataDDS &data, Response *rs)
00871 {
00872 if (!rs)
00873 throw InternalErr(__FILE__, __LINE__, "Response object is null.");
00874
00875
00876 parse_mime(rs);
00877
00878 read_data_no_mime(data, rs);
00879 }
00880
00889 void
00890 Connect::read_data_no_mime(DataDDS &data, Response *rs)
00891 {
00892 d_version = rs->get_version();
00893 d_protocol = rs->get_protocol();
00894
00895 process_data(data, rs);
00896 }
00897
00898 bool
00899 Connect::is_local()
00900 {
00901 return _local;
00902 }
00903
00920 string
00921 Connect::URL(bool ce)
00922 {
00923 if (_local)
00924 throw InternalErr(__FILE__, __LINE__,
00925 "URL(): This call is only valid for a DAP2 data source.");
00926
00927 if (ce)
00928 return _URL + "?" + _proj + _sel;
00929 else
00930 return _URL;
00931 }
00932
00941 string
00942 Connect::CE()
00943 {
00944 if (_local)
00945 throw InternalErr(__FILE__, __LINE__,
00946 "CE(): This call is only valid for a DAP2 data source.");
00947
00948 return _proj + _sel;
00949 }
00950
00956 void
00957 Connect::set_credentials(string u, string p)
00958 {
00959 if (d_http)
00960 d_http->set_credentials(u, p);
00961 }
00962
00966 void
00967 Connect::set_accept_deflate(bool deflate)
00968 {
00969 if (d_http)
00970 d_http->set_accept_deflate(deflate);
00971 }
00972
00976 void
00977 Connect::set_cache_enabled(bool cache)
00978 {
00979 if (d_http)
00980 d_http->set_cache_enabled(cache);
00981 }
00982
00983 bool
00984 Connect::is_cache_enabled()
00985 {
00986 bool status;
00987 DBG(cerr << "Entering is_cache_enabled (" << hex << d_http << dec
00988 << ")... ");
00989 if (d_http)
00990 status = d_http->is_cache_enabled();
00991 else
00992 status = false;
00993 DBGN(cerr << "exiting" << endl);
00994 return status;
00995 }