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 19917 2008-11-25 23:47:56Z 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_description_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
00312 string
00313 Connect::request_protocol()
00314 {
00315 string version_url = _URL + ".ver";
00316 if (_proj.length() + _sel.length())
00317 version_url = version_url + "?" + id2www_ce(_proj + _sel);
00318
00319 Response *rs = 0;
00320 try {
00321 rs = d_http->fetch_url(version_url);
00322 }
00323 catch (Error &e) {
00324 delete rs; rs = 0;
00325 throw e;
00326 }
00327
00328 d_version = rs->get_version();
00329 d_protocol = rs->get_protocol();
00330 delete rs; rs = 0;
00331
00332 return d_protocol;
00333 }
00334
00342 void
00343 Connect::request_das(DAS &das)
00344 {
00345 string das_url = _URL + ".das";
00346 if (_proj.length() + _sel.length())
00347 das_url = das_url + "?" + id2www_ce(_proj + _sel);
00348
00349 Response *rs = 0;
00350 try {
00351 rs = d_http->fetch_url(das_url);
00352 }
00353 catch (Error &e) {
00354 delete rs; rs = 0;
00355 throw e;
00356 }
00357
00358 d_version = rs->get_version();
00359 d_protocol = rs->get_protocol();
00360
00361 switch (rs->get_type()) {
00362 case dods_error: {
00363 Error e;
00364 if (!e.parse(rs->get_stream())) {
00365 throw InternalErr(__FILE__, __LINE__,
00366 "Could not parse error returned from server.");
00367 break;
00368 }
00369 throw e;
00370 break;
00371 }
00372
00373 case web_error:
00374
00375
00376 break;
00377
00378 case dods_das:
00379 default:
00380
00381 try {
00382 das.parse(rs->get_stream());
00383 }
00384 catch (Error &e) {
00385 delete rs; rs = 0;
00386 throw e;
00387 }
00388
00389 break;
00390
00391 #if 0
00392
00393 default:
00394 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.");
00395 #endif
00396 }
00397
00398 delete rs; rs = 0;
00399 }
00400
00411 void
00412 Connect::request_das_url(DAS &das)
00413 {
00414 string use_url = _URL + "?" + _proj + _sel ;
00415 Response *rs = 0;
00416 try {
00417 rs = d_http->fetch_url(use_url);
00418 }
00419 catch (Error &e) {
00420 delete rs; rs = 0;
00421 throw e;
00422 }
00423
00424 d_version = rs->get_version();
00425 d_protocol = rs->get_protocol();
00426
00427 switch (rs->get_type()) {
00428 case dods_error: {
00429 Error e;
00430 if (!e.parse(rs->get_stream())) {
00431 throw InternalErr(__FILE__, __LINE__,
00432 "Could not parse error returned from server.");
00433 break;
00434 }
00435 throw e;
00436 break;
00437 }
00438
00439 case web_error:
00440
00441
00442 break;
00443
00444 case dods_das:
00445 default:
00446
00447 try {
00448 das.parse(rs->get_stream());
00449 }
00450 catch (Error &e) {
00451 delete rs; rs = 0;
00452 throw e;
00453 }
00454
00455 break;
00456 }
00457
00458 delete rs; rs = 0;
00459 }
00460
00474 void
00475 Connect::request_dds(DDS &dds, string expr)
00476 {
00477 string proj, sel;
00478 string::size_type dotpos = expr.find('&');
00479 if (dotpos != expr.npos) {
00480 proj = expr.substr(0, dotpos);
00481 sel = expr.substr(dotpos);
00482 }
00483 else {
00484 proj = expr;
00485 sel = "";
00486 }
00487
00488 string dds_url = _URL + ".dds" + "?"
00489 + id2www_ce(_proj + proj + _sel + sel);
00490
00491 Response *rs = 0;
00492 try {
00493 rs = d_http->fetch_url(dds_url);
00494 }
00495 catch (Error &e) {
00496 delete rs; rs = 0;
00497 throw e;
00498 }
00499
00500 d_version = rs->get_version();
00501 d_protocol = rs->get_protocol();
00502
00503 switch (rs->get_type()) {
00504 case dods_error: {
00505 Error e;
00506 if (!e.parse(rs->get_stream())) {
00507 throw InternalErr(__FILE__, __LINE__,
00508 "Could not parse error returned from server.");
00509 break;
00510 }
00511 throw e;
00512 break;
00513 }
00514
00515 case web_error:
00516
00517
00518 break;
00519
00520 case dods_dds:
00521 default:
00522
00523 try {
00524 dds.parse(rs->get_stream());
00525 }
00526 catch (Error &e) {
00527 delete rs; rs = 0;
00528 throw e;
00529 }
00530 break;
00531
00532 #if 0
00533
00534 default:
00535 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.");
00536 #endif
00537 }
00538
00539 delete rs; rs = 0;
00540 }
00541
00558 void
00559 Connect::request_dds_url(DDS &dds)
00560 {
00561 string use_url = _URL + "?" + _proj + _sel ;
00562 Response *rs = 0;
00563 try {
00564 rs = d_http->fetch_url(use_url);
00565 }
00566 catch (Error &e) {
00567 delete rs; rs = 0;
00568 throw e;
00569 }
00570
00571 d_version = rs->get_version();
00572 d_protocol = rs->get_protocol();
00573
00574 switch (rs->get_type()) {
00575 case dods_error: {
00576 Error e;
00577 if (!e.parse(rs->get_stream())) {
00578 throw InternalErr(__FILE__, __LINE__,
00579 "Could not parse error returned from server.");
00580 break;
00581 }
00582 throw e;
00583 break;
00584 }
00585
00586 case web_error:
00587
00588
00589 break;
00590
00591 case dods_dds:
00592 default:
00593
00594 try {
00595 dds.parse(rs->get_stream());
00596 }
00597 catch (Error &e) {
00598 delete rs; rs = 0;
00599 throw e;
00600 }
00601 break;
00602 }
00603
00604 delete rs; rs = 0;
00605 }
00606
00618 void
00619 Connect::request_ddx(DDS &dds, string expr)
00620 {
00621 string proj, sel;
00622 string::size_type dotpos = expr.find('&');
00623 if (dotpos != expr.npos) {
00624 proj = expr.substr(0, dotpos);
00625 sel = expr.substr(dotpos);
00626 }
00627 else {
00628 proj = expr;
00629 sel = "";
00630 }
00631
00632 string ddx_url = _URL + ".ddx" + "?"
00633 + id2www_ce(_proj + proj + _sel + sel);
00634
00635 Response *rs = 0;
00636 try {
00637 rs = d_http->fetch_url(ddx_url);
00638 }
00639 catch (Error &e) {
00640 delete rs; rs = 0;
00641 throw e;
00642 }
00643
00644 d_version = rs->get_version();
00645 d_protocol = rs->get_protocol();
00646
00647 switch (rs->get_type()) {
00648 case dods_error: {
00649 Error e;
00650 if (!e.parse(rs->get_stream())) {
00651 throw InternalErr(__FILE__, __LINE__,
00652 "Could not parse error returned from server.");
00653 break;
00654 }
00655 throw e;
00656 break;
00657 }
00658
00659 case web_error:
00660
00661
00662 break;
00663
00664 case dap4_ddx:
00665 default:
00666
00667 try {
00668 #if 0
00669 string blob;
00670 #endif
00671 DDXParser ddxp(dds.get_factory());
00672 ddxp.intern_stream(rs->get_stream(), &dds);
00673 #if 0
00674 dds.parse(rs->get_stream());
00675 #endif
00676 }
00677 catch (Error &e) {
00678 delete rs; rs = 0;
00679 throw e;
00680 }
00681 break;
00682
00683 #if 0
00684
00685 default:
00686 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.");
00687 #endif
00688 }
00689
00690 delete rs; rs = 0;
00691 }
00692
00695 void
00696 Connect::request_ddx_url(DDS &dds)
00697 {
00698 string use_url = _URL + "?" + _proj + _sel ;
00699
00700 Response *rs = 0;
00701 try {
00702 rs = d_http->fetch_url(use_url);
00703 }
00704 catch (Error &e) {
00705 delete rs; rs = 0;
00706 throw e;
00707 }
00708
00709 d_version = rs->get_version();
00710 d_protocol = rs->get_protocol();
00711
00712 switch (rs->get_type()) {
00713 case dods_error: {
00714 Error e;
00715 if (!e.parse(rs->get_stream())) {
00716 throw InternalErr(__FILE__, __LINE__,
00717 "Could not parse error returned from server.");
00718 break;
00719 }
00720 throw e;
00721 break;
00722 }
00723
00724 case web_error:
00725
00726
00727 break;
00728
00729 case dap4_ddx:
00730 default:
00731
00732 try {
00733 dds.parse(rs->get_stream());
00734 }
00735 catch (Error &e) {
00736 delete rs; rs = 0;
00737 throw e;
00738 }
00739 break;
00740
00741 #if 0
00742
00743 default:
00744 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.");
00745 #endif
00746 }
00747
00748 delete rs; rs = 0;
00749 }
00750
00766 void
00767 Connect::request_data(DataDDS &data, string expr)
00768 {
00769 string proj, sel;
00770 string::size_type dotpos = expr.find('&');
00771 if (dotpos != expr.npos) {
00772 proj = expr.substr(0, dotpos);
00773 sel = expr.substr(dotpos);
00774 }
00775 else {
00776 proj = expr;
00777 sel = "";
00778 }
00779
00780 string data_url = _URL + ".dods?"
00781 + id2www_ce(_proj + proj + _sel + sel);
00782
00783 Response *rs = 0;
00784
00785 try {
00786 rs = d_http->fetch_url(data_url);
00787 d_version = rs->get_version();
00788 d_protocol = rs->get_protocol();
00789
00790 process_data(data, rs);
00791 delete rs; rs = 0;
00792 }
00793 catch (Error &e) {
00794 delete rs; rs = 0;
00795 throw e;
00796 }
00797 }
00798
00816 void
00817 Connect::request_data_url(DataDDS &data)
00818 {
00819 string use_url = _URL + "?" + _proj + _sel ;
00820 Response *rs = 0;
00821
00822 try {
00823 rs = d_http->fetch_url(use_url);
00824 d_version = rs->get_version();
00825 d_protocol = rs->get_protocol();
00826
00827 process_data(data, rs);
00828 delete rs; rs = 0;
00829 }
00830 catch (Error &e) {
00831 delete rs; rs = 0;
00832 throw e;
00833 }
00834 }
00835
00836
00853 void
00854 Connect::read_data(DataDDS &data, Response *rs)
00855 {
00856 if (!rs)
00857 throw InternalErr(__FILE__, __LINE__, "Response object is null.");
00858
00859
00860 parse_mime(rs);
00861
00862 read_data_no_mime(data, rs);
00863 }
00864
00873 void
00874 Connect::read_data_no_mime(DataDDS &data, Response *rs)
00875 {
00876 d_version = rs->get_version();
00877 d_protocol = rs->get_protocol();
00878
00879 process_data(data, rs);
00880 }
00881
00882 bool
00883 Connect::is_local()
00884 {
00885 return _local;
00886 }
00887
00904 string
00905 Connect::URL(bool ce)
00906 {
00907 if (_local)
00908 throw InternalErr(__FILE__, __LINE__,
00909 "URL(): This call is only valid for a DAP data source.");
00910
00911 if (ce)
00912 return _URL + "?" + _proj + _sel;
00913 else
00914 return _URL;
00915 }
00916
00925 string
00926 Connect::CE()
00927 {
00928 if (_local)
00929 throw InternalErr(__FILE__, __LINE__,
00930 "CE(): This call is only valid for a DAP data source.");
00931
00932 return _proj + _sel;
00933 }
00934
00940 void
00941 Connect::set_credentials(string u, string p)
00942 {
00943 if (d_http)
00944 d_http->set_credentials(u, p);
00945 }
00946
00950 void
00951 Connect::set_accept_deflate(bool deflate)
00952 {
00953 if (d_http)
00954 d_http->set_accept_deflate(deflate);
00955 }
00956
00962 void
00963 Connect::set_xdap_protocol(int major, int minor)
00964 {
00965 if (d_http)
00966 d_http->set_xdap_protocol(major, minor);
00967 }
00968
00972 void
00973 Connect::set_cache_enabled(bool cache)
00974 {
00975 if (d_http)
00976 d_http->set_cache_enabled(cache);
00977 }
00978
00979 bool
00980 Connect::is_cache_enabled()
00981 {
00982 bool status;
00983 DBG(cerr << "Entering is_cache_enabled (" << hex << d_http << dec
00984 << ")... ");
00985 if (d_http)
00986 status = d_http->is_cache_enabled();
00987 else
00988 status = false;
00989 DBGN(cerr << "exiting" << endl);
00990 return status;
00991 }
00992
00993 }