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 16612 2007-06-04 22:08:57Z jimg $"
00043 };
00044
00045 #include <stdio.h>
00046 #ifndef WIN32
00047 #include <unistd.h>
00048 #endif
00049
00050 #include <fstream>
00051
00052 #include "debug.h"
00053 #include "DataDDS.h"
00054 #include "Connect.h"
00055 #include "escaping.h"
00056 #include "RCReader.h"
00057 #include "DDXParser.h"
00058
00059 using std::cerr;
00060 using std::endl;
00061 using std::ifstream;
00062 using std::ofstream;
00063
00064 extern ObjectType get_type(const string &value);
00065
00068 void
00069 Connect::process_data(DataDDS &data, Response *rs)
00070 {
00071 DBG(cerr << "Entering Connect::process_data" << endl);
00072
00073
00074
00075
00076
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 dods_data:
00097 default: {
00098
00099 data.parse(rs->get_stream());
00100 XDR *xdr_stream = new_xdrstdio(rs->get_stream(), XDR_DECODE);
00101
00102
00103 try {
00104 for (DDS::Vars_iter i = data.var_begin(); i != data.var_end();
00105 i++) {
00106 (*i)->deserialize(xdr_stream, &data);
00107 }
00108 }
00109 catch (Error &e) {
00110 delete_xdrstdio(xdr_stream);
00111 throw e;
00112 }
00113
00114 delete_xdrstdio(xdr_stream);
00115 return;
00116 }
00117
00118 #if 0
00119
00120
00121
00122
00123 default:
00124 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.");
00125 #endif
00126 }
00127 }
00128
00129
00130 ObjectType
00131 get_type(const string &value)
00132 {
00133 if (value == "dods_das")
00134 return dods_das;
00135 else if (value == "dods_dds")
00136 return dods_dds;
00137 else if (value == "dods_data")
00138 return dods_data;
00139 else if (value == "dods_error")
00140 return dods_error;
00141 else if (value == "web_error")
00142 return web_error;
00143 else
00144 return unknown_type;
00145 }
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00168 void
00169 Connect::parse_mime(Response *rs)
00170 {
00171 rs->set_version("dods/0.0");
00172 rs->set_protocol("2.0");
00173
00174
00175
00176 FILE *data_source = rs->get_stream();
00177
00178 char line[256];
00179 fgets(line, 255, data_source);
00180
00181 int slen = strlen(line);
00182 line[slen - 1] = '\0';
00183 if (line[slen - 2] == '\r')
00184 line[slen - 2] = '\0';
00185
00186 while (line[0] != '\0') {
00187 char h[256], v[256];
00188 sscanf(line, "%s %s\n", h, v);
00189 string header = h;
00190 string value = v;
00191 downcase(header);
00192 downcase(value);
00193
00194 if (header == "content-description:") {
00195 DBG(cout << header << ": " << value << endl);
00196 rs->set_type(get_type(value));
00197 }
00198 else if (header == "xdods-server:"
00199 && rs->get_version() == "dods/0.0") {
00200 DBG(cout << header << ": " << value << endl);
00201 rs->set_version(value);
00202 }
00203 else if (header == "xopendap-server:") {
00204 DBG(cout << header << ": " << value << endl);
00205 rs->set_version(value);
00206 }
00207 else if (header == "xdap:") {
00208 DBG(cout << header << ": " << value << endl);
00209 rs->set_protocol(value);
00210 }
00211 else if (rs->get_version() == "dods/0.0" && header == "server:") {
00212 DBG(cout << header << ": " << value << endl);
00213 rs->set_version(value);
00214 }
00215
00216 fgets(line, 255, data_source);
00217 slen = strlen(line);
00218 line[slen - 1] = '\0';
00219 if (line[slen - 2] == '\r')
00220 line[slen - 2] = '\0';
00221 }
00222 }
00223
00224
00225
00233 Connect::Connect(const string &n, string uname, string password)
00234 throw(Error, InternalErr)
00235 : d_http(0), d_version("unknown"), d_protocol("2.0")
00236 {
00237 string name = prune_spaces(n);
00238
00239
00240
00241 if (name.find("http") == 0) {
00242 DBG(cerr << "Connect: The identifier is an http URL" << endl);
00243 d_http = new HTTPConnect(RCReader::instance());
00244
00245
00246 string::size_type dotpos = name.find('?');
00247 if (dotpos != name.npos) {
00248 _URL = name.substr(0, dotpos);
00249 string expr = name.substr(dotpos + 1);
00250
00251 dotpos = expr.find('&');
00252 if (dotpos != expr.npos) {
00253 _proj = expr.substr(0, dotpos);
00254 _sel = expr.substr(dotpos);
00255 }
00256 else {
00257 _proj = expr;
00258 _sel = "";
00259 }
00260 }
00261 else {
00262 _URL = name;
00263 _proj = "";
00264 _sel = "";
00265 }
00266
00267 _local = false;
00268 }
00269 else {
00270 DBG(cerr << "Connect: The identifier is a local data source." << endl);
00271
00272 d_http = 0;
00273 _URL = "";
00274 _local = true;
00275 }
00276
00277 set_credentials(uname, password);
00278 }
00279
00280 Connect::~Connect()
00281 {
00282 DBG2(cerr << "Entering the Connect dtor" << endl);
00283
00284 if (d_http)
00285 delete d_http; d_http = 0;
00286
00287 DBG2(cerr << "Leaving the Connect dtor" << endl);
00288 }
00289
00297 string
00298 Connect::request_version()
00299 {
00300 string version_url = _URL + ".ver";
00301 if (_proj.length() + _sel.length())
00302 version_url = version_url + "?" + id2www_ce(_proj + _sel);
00303
00304 Response *rs = 0;
00305 try {
00306 rs = d_http->fetch_url(version_url);
00307 }
00308 catch (Error &e) {
00309 delete rs; rs = 0;
00310 throw e;
00311 }
00312
00313 d_version = rs->get_version();
00314 d_protocol = rs->get_protocol();
00315 delete rs; rs = 0;
00316
00317 return d_version;
00318 }
00319
00327 string
00328 Connect::request_protocol()
00329 {
00330 string version_url = _URL + ".ver";
00331 if (_proj.length() + _sel.length())
00332 version_url = version_url + "?" + id2www_ce(_proj + _sel);
00333
00334 Response *rs = 0;
00335 try {
00336 rs = d_http->fetch_url(version_url);
00337 }
00338 catch (Error &e) {
00339 delete rs; rs = 0;
00340 throw e;
00341 }
00342
00343 d_version = rs->get_version();
00344 d_protocol = rs->get_protocol();
00345 delete rs; rs = 0;
00346
00347 return d_protocol;
00348 }
00349
00357 void
00358 Connect::request_das(DAS &das)
00359 {
00360 string das_url = _URL + ".das";
00361 if (_proj.length() + _sel.length())
00362 das_url = das_url + "?" + id2www_ce(_proj + _sel);
00363
00364 Response *rs = 0;
00365 try {
00366 rs = d_http->fetch_url(das_url);
00367 }
00368 catch (Error &e) {
00369 delete rs; rs = 0;
00370 throw e;
00371 }
00372
00373 d_version = rs->get_version();
00374 d_protocol = rs->get_protocol();
00375
00376 switch (rs->get_type()) {
00377 case dods_error: {
00378 Error e;
00379 if (!e.parse(rs->get_stream())) {
00380 throw InternalErr(__FILE__, __LINE__,
00381 "Could not parse error returned from server.");
00382 break;
00383 }
00384 throw e;
00385 break;
00386 }
00387
00388 case web_error:
00389
00390
00391 break;
00392
00393 case dods_das:
00394 default:
00395
00396 try {
00397 das.parse(rs->get_stream());
00398 }
00399 catch (Error &e) {
00400 delete rs; rs = 0;
00401 throw e;
00402 }
00403
00404 break;
00405
00406 #if 0
00407
00408 default:
00409 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.");
00410 #endif
00411 }
00412
00413 delete rs; rs = 0;
00414 }
00415
00426 void
00427 Connect::request_das_url(DAS &das)
00428 {
00429 string use_url = _URL + "?" + _proj + _sel ;
00430 Response *rs = 0;
00431 try {
00432 rs = d_http->fetch_url(use_url);
00433 }
00434 catch (Error &e) {
00435 delete rs; rs = 0;
00436 throw e;
00437 }
00438
00439 d_version = rs->get_version();
00440 d_protocol = rs->get_protocol();
00441
00442 switch (rs->get_type()) {
00443 case dods_error: {
00444 Error e;
00445 if (!e.parse(rs->get_stream())) {
00446 throw InternalErr(__FILE__, __LINE__,
00447 "Could not parse error returned from server.");
00448 break;
00449 }
00450 throw e;
00451 break;
00452 }
00453
00454 case web_error:
00455
00456
00457 break;
00458
00459 case dods_das:
00460 default:
00461
00462 try {
00463 das.parse(rs->get_stream());
00464 }
00465 catch (Error &e) {
00466 delete rs; rs = 0;
00467 throw e;
00468 }
00469
00470 break;
00471 }
00472
00473 delete rs; rs = 0;
00474 }
00475
00489 void
00490 Connect::request_dds(DDS &dds, string expr)
00491 {
00492 string proj, sel;
00493 string::size_type dotpos = expr.find('&');
00494 if (dotpos != expr.npos) {
00495 proj = expr.substr(0, dotpos);
00496 sel = expr.substr(dotpos);
00497 }
00498 else {
00499 proj = expr;
00500 sel = "";
00501 }
00502
00503 string dds_url = _URL + ".dds" + "?"
00504 + id2www_ce(_proj + proj + _sel + sel);
00505
00506 Response *rs = 0;
00507 try {
00508 rs = d_http->fetch_url(dds_url);
00509 }
00510 catch (Error &e) {
00511 delete rs; rs = 0;
00512 throw e;
00513 }
00514
00515 d_version = rs->get_version();
00516 d_protocol = rs->get_protocol();
00517
00518 switch (rs->get_type()) {
00519 case dods_error: {
00520 Error e;
00521 if (!e.parse(rs->get_stream())) {
00522 throw InternalErr(__FILE__, __LINE__,
00523 "Could not parse error returned from server.");
00524 break;
00525 }
00526 throw e;
00527 break;
00528 }
00529
00530 case web_error:
00531
00532
00533 break;
00534
00535 case dods_dds:
00536 default:
00537
00538 try {
00539 dds.parse(rs->get_stream());
00540 }
00541 catch (Error &e) {
00542 delete rs; rs = 0;
00543 throw e;
00544 }
00545 break;
00546
00547 #if 0
00548
00549 default:
00550 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.");
00551 #endif
00552 }
00553
00554 delete rs; rs = 0;
00555 }
00556
00573 void
00574 Connect::request_dds_url(DDS &dds)
00575 {
00576 string use_url = _URL + "?" + _proj + _sel ;
00577 Response *rs = 0;
00578 try {
00579 rs = d_http->fetch_url(use_url);
00580 }
00581 catch (Error &e) {
00582 delete rs; rs = 0;
00583 throw e;
00584 }
00585
00586 d_version = rs->get_version();
00587 d_protocol = rs->get_protocol();
00588
00589 switch (rs->get_type()) {
00590 case dods_error: {
00591 Error e;
00592 if (!e.parse(rs->get_stream())) {
00593 throw InternalErr(__FILE__, __LINE__,
00594 "Could not parse error returned from server.");
00595 break;
00596 }
00597 throw e;
00598 break;
00599 }
00600
00601 case web_error:
00602
00603
00604 break;
00605
00606 case dods_dds:
00607 default:
00608
00609 try {
00610 dds.parse(rs->get_stream());
00611 }
00612 catch (Error &e) {
00613 delete rs; rs = 0;
00614 throw e;
00615 }
00616 break;
00617 }
00618
00619 delete rs; rs = 0;
00620 }
00621
00633 void
00634 Connect::request_ddx(DDS &dds, string expr)
00635 {
00636 string proj, sel;
00637 string::size_type dotpos = expr.find('&');
00638 if (dotpos != expr.npos) {
00639 proj = expr.substr(0, dotpos);
00640 sel = expr.substr(dotpos);
00641 }
00642 else {
00643 proj = expr;
00644 sel = "";
00645 }
00646
00647 string ddx_url = _URL + ".ddx" + "?"
00648 + id2www_ce(_proj + proj + _sel + sel);
00649
00650 Response *rs = 0;
00651 try {
00652 rs = d_http->fetch_url(ddx_url);
00653 }
00654 catch (Error &e) {
00655 delete rs; rs = 0;
00656 throw e;
00657 }
00658
00659 d_version = rs->get_version();
00660 d_protocol = rs->get_protocol();
00661
00662 switch (rs->get_type()) {
00663 case dods_error: {
00664 Error e;
00665 if (!e.parse(rs->get_stream())) {
00666 throw InternalErr(__FILE__, __LINE__,
00667 "Could not parse error returned from server.");
00668 break;
00669 }
00670 throw e;
00671 break;
00672 }
00673
00674 case web_error:
00675
00676
00677 break;
00678
00679 case dap4_ddx:
00680 default:
00681
00682 try {
00683 string blob;
00684 DDXParser ddxp(dds.get_factory());
00685 ddxp.intern_stream(rs->get_stream(), &dds, &blob);
00686 #if 0
00687 dds.parse(rs->get_stream());
00688 #endif
00689 }
00690 catch (Error &e) {
00691 delete rs; rs = 0;
00692 throw e;
00693 }
00694 break;
00695
00696 #if 0
00697
00698 default:
00699 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.");
00700 #endif
00701 }
00702
00703 delete rs; rs = 0;
00704 }
00705
00708 void
00709 Connect::request_ddx_url(DDS &dds)
00710 {
00711 string use_url = _URL + "?" + _proj + _sel ;
00712
00713 Response *rs = 0;
00714 try {
00715 rs = d_http->fetch_url(use_url);
00716 }
00717 catch (Error &e) {
00718 delete rs; rs = 0;
00719 throw e;
00720 }
00721
00722 d_version = rs->get_version();
00723 d_protocol = rs->get_protocol();
00724
00725 switch (rs->get_type()) {
00726 case dods_error: {
00727 Error e;
00728 if (!e.parse(rs->get_stream())) {
00729 throw InternalErr(__FILE__, __LINE__,
00730 "Could not parse error returned from server.");
00731 break;
00732 }
00733 throw e;
00734 break;
00735 }
00736
00737 case web_error:
00738
00739
00740 break;
00741
00742 case dap4_ddx:
00743 default:
00744
00745 try {
00746 dds.parse(rs->get_stream());
00747 }
00748 catch (Error &e) {
00749 delete rs; rs = 0;
00750 throw e;
00751 }
00752 break;
00753
00754 #if 0
00755
00756 default:
00757 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.");
00758 #endif
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 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 d_version = rs->get_version();
00838 d_protocol = rs->get_protocol();
00839
00840 process_data(data, rs);
00841 delete rs; rs = 0;
00842 }
00843 catch (Error &e) {
00844 delete rs; rs = 0;
00845 throw e;
00846 }
00847 }
00848
00849
00866 void
00867 Connect::read_data(DataDDS &data, Response *rs)
00868 {
00869 if (!rs)
00870 throw InternalErr(__FILE__, __LINE__, "Response object is null.");
00871
00872
00873 parse_mime(rs);
00874
00875 read_data_no_mime(data, rs);
00876 }
00877
00886 void
00887 Connect::read_data_no_mime(DataDDS &data, Response *rs)
00888 {
00889 d_version = rs->get_version();
00890 d_protocol = rs->get_protocol();
00891
00892 process_data(data, rs);
00893 }
00894
00895 bool
00896 Connect::is_local()
00897 {
00898 return _local;
00899 }
00900
00917 string
00918 Connect::URL(bool ce)
00919 {
00920 if (_local)
00921 throw InternalErr(__FILE__, __LINE__,
00922 "URL(): This call is only valid for a DAP2 data source.");
00923
00924 if (ce)
00925 return _URL + "?" + _proj + _sel;
00926 else
00927 return _URL;
00928 }
00929
00938 string
00939 Connect::CE()
00940 {
00941 if (_local)
00942 throw InternalErr(__FILE__, __LINE__,
00943 "CE(): This call is only valid for a DAP2 data source.");
00944
00945 return _proj + _sel;
00946 }
00947
00953 void
00954 Connect::set_credentials(string u, string p)
00955 {
00956 if (d_http)
00957 d_http->set_credentials(u, p);
00958 }
00959
00963 void
00964 Connect::set_accept_deflate(bool deflate)
00965 {
00966 if (d_http)
00967 d_http->set_accept_deflate(deflate);
00968 }
00969
00973 void
00974 Connect::set_cache_enabled(bool cache)
00975 {
00976 if (d_http)
00977 d_http->set_cache_enabled(cache);
00978 }
00979
00980 bool
00981 Connect::is_cache_enabled()
00982 {
00983 bool status;
00984 DBG(cerr << "Entering is_cache_enabled (" << hex << d_http << dec
00985 << ")... ");
00986 if (d_http)
00987 status = d_http->is_cache_enabled();
00988 else
00989 status = false;
00990 DBGN(cerr << "exiting" << endl);
00991 return status;
00992 }