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 18315 2008-03-03 20:14:44Z 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 "DDXParser.h"
00055 #include "XDRFileUnMarshaller.h"
00056
00057 using std::cerr;
00058 using std::endl;
00059 using std::ifstream;
00060 using std::ofstream;
00061 using std::min;
00062
00063 namespace libdap {
00064
00067 void
00068 Connect::process_data(DataDDS &data, Response *rs)
00069 {
00070 DBG(cerr << "Entering Connect::process_data" << endl);
00071
00072
00073
00074
00075
00076
00077 data.set_version(rs->get_version());
00078 data.set_protocol(rs->get_protocol());
00079
00080 DBG(cerr << "Entering process_data: d_stream = " << rs << endl);
00081 switch (rs->get_type()) {
00082 case dods_error: {
00083 Error e;
00084 if (!e.parse(rs->get_stream()))
00085 throw InternalErr(__FILE__, __LINE__,
00086 "Could not parse the Error object returned by the server!");
00087 throw e;
00088 }
00089
00090 case web_error:
00091
00092
00093 throw InternalErr(__FILE__, __LINE__, "An error was reported by the remote httpd; this should have been processed by HTTPConnect..");
00094
00095 case dods_data:
00096 default: {
00097
00098 data.parse(rs->get_stream());
00099 XDRFileUnMarshaller um( rs->get_stream() ) ;
00100
00101
00102 try {
00103 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end();
00104 i++) {
00105 (*i)->deserialize(um, &data);
00106 }
00107 }
00108 catch (Error &e) {
00109 throw e;
00110 }
00111
00112 return;
00113 }
00114
00115 #if 0
00116
00117
00118
00119
00120 default:
00121 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.");
00122 #endif
00123 }
00124 }
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00147 void
00148 Connect::parse_mime(Response *rs)
00149 {
00150 rs->set_version("dods/0.0");
00151 rs->set_protocol("2.0");
00152
00153
00154
00155 FILE *data_source = rs->get_stream();
00156
00157 char line[256];
00158 fgets(line, 255, data_source);
00159
00160 int slen = strlen(line);
00161 slen = min(slen, 256);
00162 line[slen - 1] = '\0';
00163 if (line[slen - 2] == '\r')
00164 line[slen - 2] = '\0';
00165
00166 while (line[0] != '\0') {
00167 char h[256], v[256];
00168 sscanf(line, "%s %s\n", h, v);
00169 string header = h;
00170 string value = v;
00171 downcase(header);
00172 downcase(value);
00173
00174 if (header == "content-description:") {
00175 DBG(cout << header << ": " << value << endl);
00176 rs->set_type(get_type(value));
00177 }
00178 else if (header == "xdods-server:"
00179 && rs->get_version() == "dods/0.0") {
00180 DBG(cout << header << ": " << value << endl);
00181 rs->set_version(value);
00182 }
00183 else if (header == "xopendap-server:") {
00184 DBG(cout << header << ": " << value << endl);
00185 rs->set_version(value);
00186 }
00187 else if (header == "xdap:") {
00188 DBG(cout << header << ": " << value << endl);
00189 rs->set_protocol(value);
00190 }
00191 else if (rs->get_version() == "dods/0.0" && header == "server:") {
00192 DBG(cout << header << ": " << value << endl);
00193 rs->set_version(value);
00194 }
00195
00196 fgets(line, 255, data_source);
00197 slen = strlen(line);
00198 slen = min(slen, 256);
00199 line[slen - 1] = '\0';
00200 if (line[slen - 2] == '\r')
00201 line[slen - 2] = '\0';
00202 }
00203 }
00204
00205
00206
00214 Connect::Connect(const string &n, string uname, string password)
00215 throw(Error, InternalErr)
00216 : d_http(0), d_version("unknown"), d_protocol("2.0")
00217 {
00218 string name = prune_spaces(n);
00219
00220
00221
00222 if (name.find("http") == 0) {
00223 DBG(cerr << "Connect: The identifier is an http URL" << endl);
00224 d_http = new HTTPConnect(RCReader::instance());
00225
00226
00227 string::size_type dotpos = name.find('?');
00228 if (dotpos != name.npos) {
00229 _URL = name.substr(0, dotpos);
00230 string expr = name.substr(dotpos + 1);
00231
00232 dotpos = expr.find('&');
00233 if (dotpos != expr.npos) {
00234 _proj = expr.substr(0, dotpos);
00235 _sel = expr.substr(dotpos);
00236 }
00237 else {
00238 _proj = expr;
00239 _sel = "";
00240 }
00241 }
00242 else {
00243 _URL = name;
00244 _proj = "";
00245 _sel = "";
00246 }
00247
00248 _local = false;
00249 }
00250 else {
00251 DBG(cerr << "Connect: The identifier is a local data source." << endl);
00252
00253 d_http = 0;
00254 _URL = "";
00255 _local = true;
00256 }
00257
00258 set_credentials(uname, password);
00259 }
00260
00261 Connect::~Connect()
00262 {
00263 DBG2(cerr << "Entering the Connect dtor" << endl);
00264
00265 if (d_http)
00266 delete d_http; d_http = 0;
00267
00268 DBG2(cerr << "Leaving the Connect dtor" << endl);
00269 }
00270
00278 string
00279 Connect::request_version()
00280 {
00281 string version_url = _URL + ".ver";
00282 if (_proj.length() + _sel.length())
00283 version_url = version_url + "?" + id2www_ce(_proj + _sel);
00284
00285 Response *rs = 0;
00286 try {
00287 rs = d_http->fetch_url(version_url);
00288 }
00289 catch (Error &e) {
00290 delete rs; rs = 0;
00291 throw e;
00292 }
00293
00294 d_version = rs->get_version();
00295 d_protocol = rs->get_protocol();
00296 delete rs; rs = 0;
00297
00298 return d_version;
00299 }
00300
00308 string
00309 Connect::request_protocol()
00310 {
00311 string version_url = _URL + ".ver";
00312 if (_proj.length() + _sel.length())
00313 version_url = version_url + "?" + id2www_ce(_proj + _sel);
00314
00315 Response *rs = 0;
00316 try {
00317 rs = d_http->fetch_url(version_url);
00318 }
00319 catch (Error &e) {
00320 delete rs; rs = 0;
00321 throw e;
00322 }
00323
00324 d_version = rs->get_version();
00325 d_protocol = rs->get_protocol();
00326 delete rs; rs = 0;
00327
00328 return d_protocol;
00329 }
00330
00338 void
00339 Connect::request_das(DAS &das)
00340 {
00341 string das_url = _URL + ".das";
00342 if (_proj.length() + _sel.length())
00343 das_url = das_url + "?" + id2www_ce(_proj + _sel);
00344
00345 Response *rs = 0;
00346 try {
00347 rs = d_http->fetch_url(das_url);
00348 }
00349 catch (Error &e) {
00350 delete rs; rs = 0;
00351 throw e;
00352 }
00353
00354 d_version = rs->get_version();
00355 d_protocol = rs->get_protocol();
00356
00357 switch (rs->get_type()) {
00358 case dods_error: {
00359 Error e;
00360 if (!e.parse(rs->get_stream())) {
00361 throw InternalErr(__FILE__, __LINE__,
00362 "Could not parse error returned from server.");
00363 break;
00364 }
00365 throw e;
00366 break;
00367 }
00368
00369 case web_error:
00370
00371
00372 break;
00373
00374 case dods_das:
00375 default:
00376
00377 try {
00378 das.parse(rs->get_stream());
00379 }
00380 catch (Error &e) {
00381 delete rs; rs = 0;
00382 throw e;
00383 }
00384
00385 break;
00386
00387 #if 0
00388
00389 default:
00390 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.");
00391 #endif
00392 }
00393
00394 delete rs; rs = 0;
00395 }
00396
00407 void
00408 Connect::request_das_url(DAS &das)
00409 {
00410 string use_url = _URL + "?" + _proj + _sel ;
00411 Response *rs = 0;
00412 try {
00413 rs = d_http->fetch_url(use_url);
00414 }
00415 catch (Error &e) {
00416 delete rs; rs = 0;
00417 throw e;
00418 }
00419
00420 d_version = rs->get_version();
00421 d_protocol = rs->get_protocol();
00422
00423 switch (rs->get_type()) {
00424 case dods_error: {
00425 Error e;
00426 if (!e.parse(rs->get_stream())) {
00427 throw InternalErr(__FILE__, __LINE__,
00428 "Could not parse error returned from server.");
00429 break;
00430 }
00431 throw e;
00432 break;
00433 }
00434
00435 case web_error:
00436
00437
00438 break;
00439
00440 case dods_das:
00441 default:
00442
00443 try {
00444 das.parse(rs->get_stream());
00445 }
00446 catch (Error &e) {
00447 delete rs; rs = 0;
00448 throw e;
00449 }
00450
00451 break;
00452 }
00453
00454 delete rs; rs = 0;
00455 }
00456
00470 void
00471 Connect::request_dds(DDS &dds, string expr)
00472 {
00473 string proj, sel;
00474 string::size_type dotpos = expr.find('&');
00475 if (dotpos != expr.npos) {
00476 proj = expr.substr(0, dotpos);
00477 sel = expr.substr(dotpos);
00478 }
00479 else {
00480 proj = expr;
00481 sel = "";
00482 }
00483
00484 string dds_url = _URL + ".dds" + "?"
00485 + id2www_ce(_proj + proj + _sel + sel);
00486
00487 Response *rs = 0;
00488 try {
00489 rs = d_http->fetch_url(dds_url);
00490 }
00491 catch (Error &e) {
00492 delete rs; rs = 0;
00493 throw e;
00494 }
00495
00496 d_version = rs->get_version();
00497 d_protocol = rs->get_protocol();
00498
00499 switch (rs->get_type()) {
00500 case dods_error: {
00501 Error e;
00502 if (!e.parse(rs->get_stream())) {
00503 throw InternalErr(__FILE__, __LINE__,
00504 "Could not parse error returned from server.");
00505 break;
00506 }
00507 throw e;
00508 break;
00509 }
00510
00511 case web_error:
00512
00513
00514 break;
00515
00516 case dods_dds:
00517 default:
00518
00519 try {
00520 dds.parse(rs->get_stream());
00521 }
00522 catch (Error &e) {
00523 delete rs; rs = 0;
00524 throw e;
00525 }
00526 break;
00527
00528 #if 0
00529
00530 default:
00531 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.");
00532 #endif
00533 }
00534
00535 delete rs; rs = 0;
00536 }
00537
00554 void
00555 Connect::request_dds_url(DDS &dds)
00556 {
00557 string use_url = _URL + "?" + _proj + _sel ;
00558 Response *rs = 0;
00559 try {
00560 rs = d_http->fetch_url(use_url);
00561 }
00562 catch (Error &e) {
00563 delete rs; rs = 0;
00564 throw e;
00565 }
00566
00567 d_version = rs->get_version();
00568 d_protocol = rs->get_protocol();
00569
00570 switch (rs->get_type()) {
00571 case dods_error: {
00572 Error e;
00573 if (!e.parse(rs->get_stream())) {
00574 throw InternalErr(__FILE__, __LINE__,
00575 "Could not parse error returned from server.");
00576 break;
00577 }
00578 throw e;
00579 break;
00580 }
00581
00582 case web_error:
00583
00584
00585 break;
00586
00587 case dods_dds:
00588 default:
00589
00590 try {
00591 dds.parse(rs->get_stream());
00592 }
00593 catch (Error &e) {
00594 delete rs; rs = 0;
00595 throw e;
00596 }
00597 break;
00598 }
00599
00600 delete rs; rs = 0;
00601 }
00602
00614 void
00615 Connect::request_ddx(DDS &dds, string expr)
00616 {
00617 string proj, sel;
00618 string::size_type dotpos = expr.find('&');
00619 if (dotpos != expr.npos) {
00620 proj = expr.substr(0, dotpos);
00621 sel = expr.substr(dotpos);
00622 }
00623 else {
00624 proj = expr;
00625 sel = "";
00626 }
00627
00628 string ddx_url = _URL + ".ddx" + "?"
00629 + id2www_ce(_proj + proj + _sel + sel);
00630
00631 Response *rs = 0;
00632 try {
00633 rs = d_http->fetch_url(ddx_url);
00634 }
00635 catch (Error &e) {
00636 delete rs; rs = 0;
00637 throw e;
00638 }
00639
00640 d_version = rs->get_version();
00641 d_protocol = rs->get_protocol();
00642
00643 switch (rs->get_type()) {
00644 case dods_error: {
00645 Error e;
00646 if (!e.parse(rs->get_stream())) {
00647 throw InternalErr(__FILE__, __LINE__,
00648 "Could not parse error returned from server.");
00649 break;
00650 }
00651 throw e;
00652 break;
00653 }
00654
00655 case web_error:
00656
00657
00658 break;
00659
00660 case dap4_ddx:
00661 default:
00662
00663 try {
00664 string blob;
00665 DDXParser ddxp(dds.get_factory());
00666 ddxp.intern_stream(rs->get_stream(), &dds, &blob);
00667 #if 0
00668 dds.parse(rs->get_stream());
00669 #endif
00670 }
00671 catch (Error &e) {
00672 delete rs; rs = 0;
00673 throw e;
00674 }
00675 break;
00676
00677 #if 0
00678
00679 default:
00680 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.");
00681 #endif
00682 }
00683
00684 delete rs; rs = 0;
00685 }
00686
00689 void
00690 Connect::request_ddx_url(DDS &dds)
00691 {
00692 string use_url = _URL + "?" + _proj + _sel ;
00693
00694 Response *rs = 0;
00695 try {
00696 rs = d_http->fetch_url(use_url);
00697 }
00698 catch (Error &e) {
00699 delete rs; rs = 0;
00700 throw e;
00701 }
00702
00703 d_version = rs->get_version();
00704 d_protocol = rs->get_protocol();
00705
00706 switch (rs->get_type()) {
00707 case dods_error: {
00708 Error e;
00709 if (!e.parse(rs->get_stream())) {
00710 throw InternalErr(__FILE__, __LINE__,
00711 "Could not parse error returned from server.");
00712 break;
00713 }
00714 throw e;
00715 break;
00716 }
00717
00718 case web_error:
00719
00720
00721 break;
00722
00723 case dap4_ddx:
00724 default:
00725
00726 try {
00727 dds.parse(rs->get_stream());
00728 }
00729 catch (Error &e) {
00730 delete rs; rs = 0;
00731 throw e;
00732 }
00733 break;
00734
00735 #if 0
00736
00737 default:
00738 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.");
00739 #endif
00740 }
00741
00742 delete rs; rs = 0;
00743 }
00744
00760 void
00761 Connect::request_data(DataDDS &data, string expr)
00762 {
00763 string proj, sel;
00764 string::size_type dotpos = expr.find('&');
00765 if (dotpos != expr.npos) {
00766 proj = expr.substr(0, dotpos);
00767 sel = expr.substr(dotpos);
00768 }
00769 else {
00770 proj = expr;
00771 sel = "";
00772 }
00773
00774 string data_url = _URL + ".dods?"
00775 + id2www_ce(_proj + proj + _sel + sel);
00776
00777 Response *rs = 0;
00778
00779 try {
00780 rs = d_http->fetch_url(data_url);
00781 d_version = rs->get_version();
00782 d_protocol = rs->get_protocol();
00783
00784 process_data(data, rs);
00785 delete rs; rs = 0;
00786 }
00787 catch (Error &e) {
00788 delete rs; rs = 0;
00789 throw e;
00790 }
00791 }
00792
00810 void
00811 Connect::request_data_url(DataDDS &data)
00812 {
00813 string use_url = _URL + "?" + _proj + _sel ;
00814 Response *rs = 0;
00815
00816 try {
00817 rs = d_http->fetch_url(use_url);
00818 d_version = rs->get_version();
00819 d_protocol = rs->get_protocol();
00820
00821 process_data(data, rs);
00822 delete rs; rs = 0;
00823 }
00824 catch (Error &e) {
00825 delete rs; rs = 0;
00826 throw e;
00827 }
00828 }
00829
00830
00847 void
00848 Connect::read_data(DataDDS &data, Response *rs)
00849 {
00850 if (!rs)
00851 throw InternalErr(__FILE__, __LINE__, "Response object is null.");
00852
00853
00854 parse_mime(rs);
00855
00856 read_data_no_mime(data, rs);
00857 }
00858
00867 void
00868 Connect::read_data_no_mime(DataDDS &data, Response *rs)
00869 {
00870 d_version = rs->get_version();
00871 d_protocol = rs->get_protocol();
00872
00873 process_data(data, rs);
00874 }
00875
00876 bool
00877 Connect::is_local()
00878 {
00879 return _local;
00880 }
00881
00898 string
00899 Connect::URL(bool ce)
00900 {
00901 if (_local)
00902 throw InternalErr(__FILE__, __LINE__,
00903 "URL(): This call is only valid for a DAP2 data source.");
00904
00905 if (ce)
00906 return _URL + "?" + _proj + _sel;
00907 else
00908 return _URL;
00909 }
00910
00919 string
00920 Connect::CE()
00921 {
00922 if (_local)
00923 throw InternalErr(__FILE__, __LINE__,
00924 "CE(): This call is only valid for a DAP2 data source.");
00925
00926 return _proj + _sel;
00927 }
00928
00934 void
00935 Connect::set_credentials(string u, string p)
00936 {
00937 if (d_http)
00938 d_http->set_credentials(u, p);
00939 }
00940
00944 void
00945 Connect::set_accept_deflate(bool deflate)
00946 {
00947 if (d_http)
00948 d_http->set_accept_deflate(deflate);
00949 }
00950
00954 void
00955 Connect::set_cache_enabled(bool cache)
00956 {
00957 if (d_http)
00958 d_http->set_cache_enabled(cache);
00959 }
00960
00961 bool
00962 Connect::is_cache_enabled()
00963 {
00964 bool status;
00965 DBG(cerr << "Entering is_cache_enabled (" << hex << d_http << dec
00966 << ")... ");
00967 if (d_http)
00968 status = d_http->is_cache_enabled();
00969 else
00970 status = false;
00971 DBGN(cerr << "exiting" << endl);
00972 return status;
00973 }
00974
00975 }