1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
4 // Access Protocol.
5 
6 // Copyright (c) 2002,2003,2013 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@opendap.org>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 //
23 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24 
25 #include <cppunit/TextTestRunner.h>
26 #include <cppunit/extensions/TestFactoryRegistry.h>
27 #include <cppunit/extensions/HelperMacros.h>
28 
29 #include <cstring>
30 #include <iterator>
31 #include <string>
32 #include <algorithm>
33 #include <functional>
34 
35 #include "GNURegex.h"
36 #include "HTTPConnect.h"
37 #include "RCReader.h"
38 
39 #include "debug.h"
40 
41 #include "test_config.h"
42 #include "GetOpt.h"
43 
44 using namespace CppUnit;
45 using namespace std;
46 
47 // FIXME By default this should be false, but we're tracking down a
48 //  potential bug in this code or test. jhrg 1/28/21
49 static bool debug = false;
50 
51 #undef DBG
52 #define DBG(x) do { if (debug) (x); } while(false);
53 
54 #define prolog std::string("HTTPConnectTest::").append(__func__).append("() - ")
55 
56 namespace libdap {
57 
58 class HTTPConnectTest: public TestFixture {
59 private:
60     HTTPConnect * http;
61     string localhost_url, localhost_pw_url, localhost_digest_pw_url;
62     string etag;
63     string lm;
64     string netcdf_das_url;
65 
66     // char env_data[128];
67 
68 protected:
re_match(Regex & r,const char * s)69     bool re_match(Regex & r, const char *s)
70     {
71         return r.match(s, strlen(s)) == (int) strlen(s);
72     }
73 
74     struct REMatch: public unary_function<const string &, bool> {
75         Regex &d_re;
REMatchlibdap::HTTPConnectTest::REMatch76         REMatch(Regex &re) :
77             d_re(re)
78         {
79         }
~REMatchlibdap::HTTPConnectTest::REMatch80         ~REMatch()
81         {
82         }
operator ()libdap::HTTPConnectTest::REMatch83         bool operator()(const string &str)
84         {
85             const char *s = str.c_str();
86             return d_re.match(s, strlen(s)) == (int) strlen(s);
87         }
88     };
89 
90     // This is defined in HTTPConnect.cc but has to be defined here as well.
91     // Don't know why... jhrg
92     class HeaderMatch: public unary_function<const string &, bool> {
93         const string &d_header;
94     public:
HeaderMatch(const string & header)95         HeaderMatch(const string &header) :
96             d_header(header)
97         {
98         }
operator ()(const string & arg)99         bool operator()(const string &arg)
100         {
101             return arg.find(d_header) == 0;
102         }
103     };
104 
105 public:
HTTPConnectTest()106     HTTPConnectTest()
107     {
108     }
~HTTPConnectTest()109     ~HTTPConnectTest()
110     {
111     }
112 
setUp()113     void setUp()
114     {
115         DBG(cerr << prolog << "Setting the DODS_CONF env var" << endl);
116         setenv("DODS_CONF", "cache-testsuite/dodsrc", 1);
117         http = new HTTPConnect(RCReader::instance());
118 
119         localhost_url = "http://test.opendap.org/test-304.html";
120 
121         // Two request header values that will generate a 304 response to the
122         // above URL. The values below much match the etag and last-modified
123         // time returned by the server. Run this test with DODS_DEBUG defined
124         // to see the values it's returning.
125         //
126         // etag = "\"a10df-157-139c2680\"";
127         // etag = "\"2a008e-157-3fbcd139c2680\"";
128         // etag = "\"181893-157-3fbcd139c2680\""; // On 10/13/14 we moved to a new httpd and the etag value changed.
129         etag ="\"157-3df1e87884680\""; // New httpd service, new etag, ndp - 01/11/21
130         lm = "Wed, 13 Jul 2005 19:32:26 GMT";
131 
132         localhost_pw_url = "http://jimg:dods_test@test.opendap.org/basic/page.txt";
133         localhost_digest_pw_url = "http://jimg:dods_digest@test.opendap.org/digest/page.txt";
134         netcdf_das_url = "http://test.opendap.org/dap/data/nc/fnoc1.nc.das";
135     }
136 
tearDown()137     void tearDown()
138     {
139         // normal code doesn't do this - it happens at exit() but not doing
140         // this here make valgrind think there are leaks.
141         http->d_http_cache->delete_instance();
142         delete http;
143         http = 0;
144         unsetenv("DODS_CONF");
145     }
146 
147     CPPUNIT_TEST_SUITE (HTTPConnectTest);
148 
149     CPPUNIT_TEST (read_url_test);
150 
151     CPPUNIT_TEST (fetch_url_test_1);
152     CPPUNIT_TEST (fetch_url_test_2);
153     CPPUNIT_TEST (fetch_url_test_3);
154     CPPUNIT_TEST (fetch_url_test_4);
155 
156     CPPUNIT_TEST (fetch_url_test_1_cpp);
157     CPPUNIT_TEST (fetch_url_test_2_cpp);
158     CPPUNIT_TEST (fetch_url_test_3_cpp);
159     CPPUNIT_TEST (fetch_url_test_4_cpp);
160 
161     CPPUNIT_TEST (get_response_headers_test);
162     CPPUNIT_TEST (server_version_test);
163     CPPUNIT_TEST (type_test);
164 
165     CPPUNIT_TEST (cache_test);
166     CPPUNIT_TEST (cache_test_cpp);
167 
168     CPPUNIT_TEST (set_accept_deflate_test);
169     CPPUNIT_TEST (set_xdap_protocol_test);
170     CPPUNIT_TEST (read_url_password_test);
171     CPPUNIT_TEST (read_url_password_test2);
172 
173     // CPPUNIT_TEST(read_url_password_proxy_test);
174 
175     CPPUNIT_TEST_SUITE_END();
176 
read_url_test()177     void read_url_test()
178     {
179         vector<string> *resp_h = new vector<string>;
180 
181         try {
182             DBG(cerr << prolog << "BEGIN" << endl);
183             DBG(cerr << prolog << "Testing with URL: " << localhost_url << endl);
184 
185             FILE *dump = fopen("/dev/null", "w");
186             long status = http->read_url(localhost_url, dump, resp_h);
187             CPPUNIT_ASSERT(status == 200);
188 
189             vector<string> request_h;
190 
191             // First test using a time with if-modified-since
192             request_h.push_back(string("If-Modified-Since: ") + lm);
193             status = http->read_url(localhost_url, dump, resp_h, &request_h);
194             DBG(cerr << prolog << "If modified since test. Returned http status: " << status << endl);
195             DBG(copy(resp_h->begin(), resp_h->end(), ostream_iterator<string>(cerr, "\n")));
196             DBG(cerr << endl);
197             CPPUNIT_ASSERT(status == 304);
198 
199             // Now test an etag
200             resp_h->clear();
201             request_h.clear();
202             request_h.push_back(string("If-None-Match: ") + etag);
203             status = http->read_url(localhost_url, dump, resp_h, &request_h);
204             DBG(cerr << prolog << "If none match test. Returned http status: " << status << endl);
205             DBG(copy(resp_h->begin(), resp_h->end(), ostream_iterator<string>(cerr, "\n")));
206             DBG(cerr << endl);
207             CPPUNIT_ASSERT(status == 304);
208 
209             // now test a combined etag and time4
210             resp_h->clear();
211             request_h.clear();
212             request_h.push_back(string("If-None-Match: ") + etag);
213             request_h.push_back(string("If-Modified-Since: ") + lm);
214             status = http->read_url(localhost_url, dump, resp_h, &request_h);
215             DBG(cerr << prolog << "Combined test. Returned http status: " << status << endl);
216             DBG(copy(resp_h->begin(), resp_h->end(), ostream_iterator<string>(cerr, "\n")));
217             CPPUNIT_ASSERT(status == 304);
218 
219             delete resp_h;
220             resp_h = 0;
221 
222         }
223         catch (Error & e) {
224             delete resp_h;
225             resp_h = 0;
226             CPPUNIT_FAIL(prolog + "Error: " + e.get_error_message());
227         }
228     }
229 
fetch_url_test_1()230     void fetch_url_test_1()
231     {
232         DBG(cerr << "Entering fetch_url_test 1" << endl);
233         HTTPResponse *stuff = 0;
234         char c;
235         try {
236             stuff = http->fetch_url(localhost_url);
237             CPPUNIT_ASSERT(
238                 fread(&c, 1, 1, stuff->get_stream()) == 1 && !ferror(stuff->get_stream())
239                     && !feof(stuff->get_stream()));
240             delete stuff;
241             stuff = 0;
242 
243         }
244         catch (InternalErr & e) {
245             delete stuff;
246             stuff = 0;
247             CPPUNIT_FAIL("Caught an InternalErr from fetch_url: " + e.get_error_message());
248         }
249         catch (Error & e) {
250             delete stuff;
251             stuff = 0;
252             CPPUNIT_FAIL("Caught an Error from fetch_url: " + e.get_error_message());
253         }
254         // Catch the exception from a failed ASSERT and clean up. Deleting a
255         // Response object also unlocks the HTTPCache in some cases. If delete
256         // is not called, then a failed test can leave the cache with locked
257         // entries
258         catch (...) {
259             cerr << "Caught unknown exception" << endl;
260             delete stuff;
261             stuff = 0;
262             throw;
263         }
264     }
265 
fetch_url_test_1_cpp()266     void fetch_url_test_1_cpp()
267     {
268         DBG(cerr << "Entering fetch_url_test 1" << endl);
269         HTTPResponse *stuff = 0;
270         http->set_use_cpp_streams(true);
271         char c;
272         try {
273             stuff = http->fetch_url(localhost_url);
274             stuff->get_cpp_stream()->read(&c, 1);
275             CPPUNIT_ASSERT(*(stuff->get_cpp_stream()));
276             CPPUNIT_ASSERT(!stuff->get_cpp_stream()->bad());
277             CPPUNIT_ASSERT(!stuff->get_cpp_stream()->eof());
278 
279             delete stuff;
280         }
281         catch (InternalErr &e) {
282             delete stuff;
283             CPPUNIT_FAIL("Caught an InternalErr from fetch_url: " + e.get_error_message());
284         }
285         catch (Error &e) {
286             delete stuff;
287             CPPUNIT_FAIL("Caught an Error from fetch_url: " + e.get_error_message());
288         }
289         catch (std::exception &e) {
290             delete stuff;
291             CPPUNIT_FAIL(string("Caught an std::exception from fetch_url: ") + e.what());
292         }
293         // Catch the exception from a failed ASSERT and clean up. Deleting a
294         // Response object also unlocks the HTTPCache in some cases. If delete
295         // is not called, then a failed test can leave the cache with locked
296         // entries
297         catch (...) {
298             cerr << "Caught unknown exception" << endl;
299             delete stuff;
300             throw;
301         }
302     }
303 
fetch_url_test_2()304     void fetch_url_test_2()
305     {
306         DBG(cerr << "Entering fetch_url_test 2" << endl);
307         HTTPResponse *stuff = 0;
308         char c;
309         try {
310             stuff = http->fetch_url(netcdf_das_url);
311             DBG2(char ln[1024]; while (!feof(stuff->get_stream())) {
312                     fgets(ln, 1024, stuff->get_stream()); cerr << ln;}
313                 rewind(stuff->get_stream()));
314 
315             CPPUNIT_ASSERT(
316                 fread(&c, 1, 1, stuff->get_stream()) == 1 && !ferror(stuff->get_stream())
317                     && !feof(stuff->get_stream()));
318             delete stuff;
319             stuff = 0;
320         }
321         catch (InternalErr & e) {
322             delete stuff;
323             stuff = 0;
324             CPPUNIT_FAIL("Caught an InternalErr from fetch_url: " + e.get_error_message());
325         }
326         catch (Error & e) {
327             delete stuff;
328             stuff = 0;
329             CPPUNIT_FAIL("Caught an Error from fetch_url: " + e.get_error_message());
330         }
331         // Catch the exception from a failed ASSERT and clean up. Deleting a
332         // Response object also unlocks the HTTPCache in some cases. If delete
333         // is not called, then a failed test can leave the cache with locked
334         // entries
335         catch (...) {
336             delete stuff;
337             stuff = 0;
338             throw;
339         }
340     }
341 
fetch_url_test_2_cpp()342     void fetch_url_test_2_cpp()
343     {
344         DBG(cerr << "Entering fetch_url_test 2" << endl);
345         http->set_use_cpp_streams(true);
346 
347         HTTPResponse *stuff = 0;
348         char c;
349 
350         try {
351             stuff = http->fetch_url(netcdf_das_url);
352 
353             stuff->get_cpp_stream()->read(&c, 1);
354             CPPUNIT_ASSERT(
355                 *(stuff->get_cpp_stream()) && !stuff->get_cpp_stream()->bad() && !stuff->get_cpp_stream()->eof());
356 
357             delete stuff;
358             stuff = 0;
359         }
360         catch (InternalErr & e) {
361             delete stuff;
362             stuff = 0;
363             CPPUNIT_FAIL("Caught an InternalErr from fetch_url: " + e.get_error_message());
364         }
365         catch (Error & e) {
366             delete stuff;
367             stuff = 0;
368             CPPUNIT_FAIL("Caught an Error from fetch_url: " + e.get_error_message());
369         }
370         // Catch the exception from a failed ASSERT and clean up. Deleting a
371         // Response object also unlocks the HTTPCache in some cases. If delete
372         // is not called, then a failed test can leave the cache with locked
373         // entries
374         catch (...) {
375             delete stuff;
376             stuff = 0;
377             throw;
378         }
379     }
380 
fetch_url_test_3()381     void fetch_url_test_3()
382     {
383         DBG(cerr << "Entering fetch_url_test 3" << endl);
384         HTTPResponse *stuff = 0;
385         char c;
386         try {
387             stuff = http->fetch_url("file:///etc/passwd");
388             CPPUNIT_ASSERT(
389                 fread(&c, 1, 1, stuff->get_stream()) == 1 && !ferror(stuff->get_stream())
390                     && !feof(stuff->get_stream()));
391             delete stuff;
392             stuff = 0;
393         }
394         catch (InternalErr & e) {
395             delete stuff;
396             stuff = 0;
397             CPPUNIT_FAIL("Caught an InternalErr from fetch_url" + e.get_error_message());
398         }
399         catch (Error & e) {
400             delete stuff;
401             stuff = 0;
402             CPPUNIT_FAIL("Caught an Error from fetch_url: " + e.get_error_message());
403         }
404         // Catch the exception from a failed ASSERT and clean up. Deleting a
405         // Response object also unlocks the HTTPCache in some cases. If delete
406         // is not called, then a failed test can leave the cache with locked
407         // entries
408         catch (...) {
409             delete stuff;
410             stuff = 0;
411             throw;
412         }
413     }
414 
fetch_url_test_3_cpp()415     void fetch_url_test_3_cpp()
416     {
417         DBG(cerr << "Entering fetch_url_test 3" << endl);
418         http->set_use_cpp_streams(true);
419 
420         HTTPResponse *stuff = 0;
421         char c;
422         try {
423             stuff = http->fetch_url("file:///etc/passwd");
424 
425             stuff->get_cpp_stream()->read(&c, 1);
426             CPPUNIT_ASSERT(
427                 *(stuff->get_cpp_stream()) && !stuff->get_cpp_stream()->bad() && !stuff->get_cpp_stream()->eof());
428 
429             delete stuff;
430             stuff = 0;
431         }
432         catch (InternalErr & e) {
433             delete stuff;
434             stuff = 0;
435             CPPUNIT_FAIL("Caught an InternalErr from fetch_url" + e.get_error_message());
436         }
437         catch (Error & e) {
438             delete stuff;
439             stuff = 0;
440             CPPUNIT_FAIL("Caught an Error from fetch_url: " + e.get_error_message());
441         }
442         // Catch the exception from a failed ASSERT and clean up. Deleting a
443         // Response object also unlocks the HTTPCache in some cases. If delete
444         // is not called, then a failed test can leave the cache with locked
445         // entries
446         catch (...) {
447             delete stuff;
448             stuff = 0;
449             throw;
450         }
451     }
452 
fetch_url_test_4()453     void fetch_url_test_4()
454     {
455         DBG(cerr << "Entering fetch_url_test 4" << endl);
456         HTTPResponse *stuff = 0;
457         char c;
458         try {
459             string url = (string) "file://" + TEST_SRC_DIR + "/test_config.h";
460             stuff = http->fetch_url(url);
461             CPPUNIT_ASSERT(
462                 fread(&c, 1, 1, stuff->get_stream()) == 1 && !ferror(stuff->get_stream())
463                     && !feof(stuff->get_stream()));
464             delete stuff;
465             stuff = 0;
466         }
467         catch (InternalErr & e) {
468             delete stuff;
469             stuff = 0;
470             CPPUNIT_FAIL("Caught an InternalErr from fetch_url" + e.get_error_message());
471         }
472         catch (Error & e) {
473             delete stuff;
474             stuff = 0;
475             CPPUNIT_FAIL("Caught an Error from fetch_url: " + e.get_error_message());
476         }
477         // Catch the exception from a failed ASSERT and clean up. Deleting a
478         // Response object also unlocks the HTTPCache in some cases. If delete
479         // is not called, then a failed test can leave the cache with locked
480         // entries
481         catch (...) {
482             delete stuff;
483             stuff = 0;
484             throw;
485         }
486     }
487 
fetch_url_test_4_cpp()488     void fetch_url_test_4_cpp()
489     {
490         DBG(cerr << "Entering fetch_url_test_4_cpp" << endl);
491         http->set_use_cpp_streams(true);
492 
493         HTTPResponse *stuff = 0;
494         char c;
495         try {
496             string url = (string) "file://" + TEST_SRC_DIR + "/test_config.h";
497             stuff = http->fetch_url(url);
498 
499             stuff->get_cpp_stream()->read(&c, 1);
500             CPPUNIT_ASSERT(
501                 *(stuff->get_cpp_stream()) && !stuff->get_cpp_stream()->bad() && !stuff->get_cpp_stream()->eof());
502 
503             delete stuff;
504             stuff = 0;
505         }
506         catch (InternalErr & e) {
507             delete stuff;
508             stuff = 0;
509             CPPUNIT_FAIL("Caught an InternalErr from fetch_url" + e.get_error_message());
510         }
511         catch (Error & e) {
512             delete stuff;
513             stuff = 0;
514             CPPUNIT_FAIL("Caught an Error from fetch_url: " + e.get_error_message());
515         }
516         // Catch the exception from a failed ASSERT and clean up. Deleting a
517         // Response object also unlocks the HTTPCache in some cases. If delete
518         // is not called, then a failed test can leave the cache with locked
519         // entries
520         catch (...) {
521             delete stuff;
522             stuff = 0;
523             throw;
524         }
525     }
526 
get_response_headers_test()527     void get_response_headers_test()
528     {
529         HTTPResponse *r = 0;
530 
531         try {
532             r = http->fetch_url(netcdf_das_url);
533             vector<string> *h = r->get_headers();
534 
535             DBG(copy(h->begin(), h->end(), ostream_iterator<string>(cerr, "\n")));
536 
537             // Should get five or six headers back.
538             Regex header("X.*-Server: .*/.*");
539 
540             CPPUNIT_ASSERT(find_if(h->begin(), h->end(), REMatch(header)) != h->end());
541 
542             Regex protocol_header("X.*DAP: .*");	// Matches both XDAP and X-DAP
543             CPPUNIT_ASSERT(find_if(h->begin(), h->end(), REMatch(protocol_header)) != h->end());
544 
545             delete r;
546             r = 0;
547         }
548         catch (InternalErr & e) {
549             delete r;
550             r = 0;
551             CPPUNIT_FAIL("Caught an InternalErr exception from get_response_headers: " + e.get_error_message());
552         }
553         catch (...) {
554             delete r;
555             r = 0;
556             throw;
557         }
558     }
559 
server_version_test()560     void server_version_test()
561     {
562         Response *r = 0;
563         Regex protocol("^[0-9]+\\.[0-9]+$");
564         try {
565             r = http->fetch_url(netcdf_das_url);
566 
567             DBG(cerr << "r->get_version().c_str(): " << r->get_protocol().c_str() << endl);
568 
569             CPPUNIT_ASSERT(re_match(protocol, r->get_protocol().c_str()));
570             delete r;
571             r = 0;
572         }
573         catch (InternalErr & e) {
574             delete r;
575             r = 0;
576             CPPUNIT_FAIL("Caught an InternalErr exception from server_version: " + e.get_error_message());
577         }
578         catch (...) {
579             delete r;
580             r = 0;
581             throw;
582         }
583 
584     }
585 
type_test()586     void type_test()
587     {
588         Response *r = 0;
589         try {
590             r = http->fetch_url(netcdf_das_url);
591             DBG(cerr << "r->get_type(): " << r->get_type() << endl);
592             CPPUNIT_ASSERT(r->get_type() == dods_das);
593             delete r;
594             r = 0;
595         }
596         catch (InternalErr & e) {
597             delete r;
598             r = 0;
599             CPPUNIT_FAIL("Caught an InternalErr exception from type(): " + e.get_error_message());
600         }
601 
602     }
603 
set_credentials_test()604     void set_credentials_test()
605     {
606         http->set_credentials("jimg", "was_quit");
607         Response *stuff = http->fetch_url("http://localhost/secret");
608 
609         try {
610             char c;
611             CPPUNIT_ASSERT(
612                 fread(&c, 1, 1, stuff->get_stream()) == 1 && !ferror(stuff->get_stream())
613                     && !feof(stuff->get_stream()));
614             delete stuff;
615             stuff = 0;
616         }
617         catch (InternalErr & e) {
618             delete stuff;
619             stuff = 0;
620             CPPUNIT_FAIL("Caught an InternalErrexception from output: " + e.get_error_message());
621         }
622     }
623 
cache_test()624     void cache_test()
625     {
626         DBG(cerr << endl << "Entering Caching tests." << endl);
627         try {
628             // The cache-testsuite/dodsrc file turns this off; all the other
629             // params are set up. It used to be that HTTPConnect had an option to
630             // turn caching on, but that no longer is present. This hack enables
631             // caching for this test. 06/18/04 jhrg
632             http->d_http_cache = HTTPCache::instance(http->d_rcr->get_dods_cache_root(), true);
633             DBG(cerr << "Instantiate the cache" << endl);
634 
635             CPPUNIT_ASSERT(http->d_http_cache != 0);
636             http->d_http_cache->set_cache_enabled(true);
637             DBG(cerr << "Enable the cache" << endl);
638 
639             fetch_url_test_4();
640             DBG(cerr << "fetch_url_test" << endl);
641             get_response_headers_test();
642             DBG(cerr << "get_response_headers_test" << endl);
643             server_version_test();
644             DBG(cerr << "server_version_test" << endl);
645             type_test();
646             DBG(cerr << "type_test" << endl);
647         }
648         catch (Error &e) {
649             CPPUNIT_FAIL((string) "Error: " + e.get_error_message());
650         }
651     }
652 
cache_test_cpp()653     void cache_test_cpp()
654     {
655         DBG(cerr << endl << "Entering Caching tests." << endl);
656         try {
657             // The cache-testsuite/dodsrc file turns this off; all the other
658             // params are set up. It used to be that HTTPConnect had an option to
659             // turn caching on, but that no longer is present. This hack enables
660             // caching for this test. 06/18/04 jhrg
661             http->d_http_cache = HTTPCache::instance(http->d_rcr->get_dods_cache_root(), true);
662             DBG(cerr << "Instantiate the cache" << endl);
663 
664             CPPUNIT_ASSERT(http->d_http_cache != 0);
665             http->d_http_cache->set_cache_enabled(true);
666             DBG(cerr << "Enable the cache" << endl);
667 
668             fetch_url_test_4_cpp();
669             DBG(cerr << "fetch_url_test_4_cpp" << endl);
670 
671             get_response_headers_test();
672             DBG(cerr << "get_response_headers_test" << endl);
673 
674             server_version_test();
675             DBG(cerr << "server_version_test" << endl);
676 
677             type_test();
678             DBG(cerr << "type_test" << endl);
679         }
680         catch (Error &e) {
681             CPPUNIT_FAIL((string) "Error: " + e.get_error_message());
682         }
683     }
684 
set_accept_deflate_test()685     void set_accept_deflate_test()
686     {
687         http->set_accept_deflate(false);
688         CPPUNIT_ASSERT(
689             count(http->d_request_headers.begin(), http->d_request_headers.end(),
690                 "Accept-Encoding: deflate, gzip, compress") == 0);
691 
692         http->set_accept_deflate(true);
693         CPPUNIT_ASSERT(
694             count(http->d_request_headers.begin(), http->d_request_headers.end(),
695                 "Accept-Encoding: deflate, gzip, compress") == 1);
696 
697         http->set_accept_deflate(true);
698         CPPUNIT_ASSERT(
699             count(http->d_request_headers.begin(), http->d_request_headers.end(),
700                 "Accept-Encoding: deflate, gzip, compress") == 1);
701 
702         http->set_accept_deflate(false);
703         CPPUNIT_ASSERT(
704             count(http->d_request_headers.begin(), http->d_request_headers.end(),
705                 "Accept-Encoding: deflate, gzip, compress") == 0);
706     }
707 
set_xdap_protocol_test()708     void set_xdap_protocol_test()
709     {
710         // Initially there should be no header and the protocol should be 2.0
711         CPPUNIT_ASSERT(http->d_dap_client_protocol_major == 2 && http->d_dap_client_protocol_minor == 0);
712 
713         CPPUNIT_ASSERT(
714             count_if(http->d_request_headers.begin(), http->d_request_headers.end(), HeaderMatch("XDAP-Accept:")) == 0);
715 
716         http->set_xdap_protocol(8, 9);
717         CPPUNIT_ASSERT(http->d_dap_client_protocol_major == 8 && http->d_dap_client_protocol_minor == 9);
718         CPPUNIT_ASSERT(count(http->d_request_headers.begin(), http->d_request_headers.end(), "XDAP-Accept: 8.9") == 1);
719 
720         http->set_xdap_protocol(3, 2);
721         CPPUNIT_ASSERT(http->d_dap_client_protocol_major == 3 && http->d_dap_client_protocol_minor == 2);
722         CPPUNIT_ASSERT(count(http->d_request_headers.begin(), http->d_request_headers.end(), "XDAP-Accept: 3.2") == 1);
723     }
724 
read_url_password_test()725     void read_url_password_test()
726     {
727         FILE *dump = fopen("/dev/null", "w");
728         vector<string> *resp_h = new vector<string>;
729         long status = http->read_url(localhost_pw_url, dump, resp_h);
730 
731         DBG(cerr << endl << http->d_upstring << endl);
732         CPPUNIT_ASSERT(http->d_upstring == "jimg:dods_test");
733         DBG(cerr << "Status: " << status << endl);
734         CPPUNIT_ASSERT(status == 200);
735         delete resp_h;
736         resp_h = 0;
737     }
738 
read_url_password_test2()739     void read_url_password_test2()
740     {
741         FILE *dump = fopen("/dev/null", "w");
742         vector<string> *resp_h = new vector<string>;
743         long status = http->read_url(localhost_digest_pw_url, dump, resp_h);
744 
745         DBG(cerr << endl << http->d_upstring << endl);
746         CPPUNIT_ASSERT(http->d_upstring == "jimg:dods_digest");
747         DBG(cerr << "Status: " << status << endl);
748         CPPUNIT_ASSERT(status == 200);
749         delete resp_h;
750         resp_h = 0;
751     }
752 };
753 
754 CPPUNIT_TEST_SUITE_REGISTRATION (HTTPConnectTest);
755 
756 }
757 
main(int argc,char * argv[])758 int main(int argc, char*argv[])
759 {
760     GetOpt getopt(argc, argv, "dh");
761     int option_char;
762 
763     while ((option_char = getopt()) != -1)
764         switch (option_char) {
765         case 'd':
766             debug = 1;  // debug is a static global
767             break;
768         case 'h': {     // help - show test names
769             cerr << "Usage: HTTPConnectTest has the following tests:" << endl;
770             const std::vector<Test*> &tests = libdap::HTTPConnectTest::suite()->getTests();
771             unsigned int prefix_len = libdap::HTTPConnectTest::suite()->getName().append("::").length();
772             for (std::vector<Test*>::const_iterator i = tests.begin(), e = tests.end(); i != e; ++i) {
773                 cerr << (*i)->getName().replace(0, prefix_len, "") << endl;
774             }
775             break;
776         }
777         default:
778             break;
779         }
780 
781     CppUnit::TextTestRunner runner;
782     runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
783 
784     bool wasSuccessful = true;
785     string test = "";
786     int i = getopt.optind;
787     if (i == argc) {
788         // run them all
789         wasSuccessful = runner.run("");
790     }
791     else {
792         for (; i < argc; ++i) {
793             if (debug) cerr << "Running " << argv[i] << endl;
794             test = libdap::HTTPConnectTest::suite()->getName().append("::").append(argv[i]);
795             wasSuccessful = wasSuccessful && runner.run(test);
796         }
797     }
798 
799     return wasSuccessful ? 0 : 1;
800 }
801