]> git.mxchange.org Git - simgear.git/blob - simgear/io/text_DNS.cxx
Initial commit for a DNS service resolver
[simgear.git] / simgear / io / text_DNS.cxx
1 #include <cstdlib>
2
3 #include <iostream>
4 #include <map>
5 #include <sstream>
6 #include <errno.h>
7
8 #include <boost/algorithm/string/case_conv.hpp>
9
10 #include <simgear/simgear_config.h>
11
12 #include "HTTPClient.hxx"
13 #include "HTTPRequest.hxx"
14
15 #include "test_HTTP.hxx"
16
17 #include <simgear/misc/strutils.hxx>
18 #include <simgear/timing/timestamp.hxx>
19 #include <simgear/debug/logstream.hxx>
20
21 #if defined(ENABLE_CURL)
22 #include <curl/multi.h>
23 #endif
24
25 using std::cout;
26 using std::cerr;
27 using std::endl;
28 using std::string;
29 using std::stringstream;
30
31 using namespace simgear;
32
33 const char* BODY1 = "The quick brown fox jumps over a lazy dog.";
34 const char* BODY3 = "Cras ut neque nulla. Duis ut velit neque, sit amet "
35 "pharetra risus. In est ligula, lacinia vitae congue in, sollicitudin at "
36 "libero. Mauris pharetra pretium elit, nec placerat dui semper et. Maecenas "
37 "magna magna, placerat sed luctus ac, commodo et ligula. Mauris at purus et "
38 "nisl molestie auctor placerat at quam. Donec sapien magna, venenatis sed "
39 "iaculis id, fringilla vel arcu. Duis sed neque nisi. Cras a arcu sit amet "
40 "risus ultrices varius. Integer sagittis euismod dui id varius. Cras vel "
41 "justo gravida metus.";
42
43 const unsigned int body2Size = 8 * 1024;
44 char body2[body2Size];
45
46 #define COMPARE(a, b) \
47     if ((a) != (b))  { \
48         cerr << "failed:" << #a << " != " << #b << endl; \
49         cerr << "\tgot:'" << a << "'" << endl; \
50         exit(1); \
51     }
52
53 #define VERIFY(a) \
54     if (!(a))  { \
55         cerr << "failed:" << #a << endl; \
56         exit(1); \
57     }
58
59 class TestRequest : public HTTP::Request
60 {
61 public:
62     bool complete;
63     bool failed;
64     string bodyData;
65
66     TestRequest(const std::string& url, const std::string method = "GET") :
67         HTTP::Request(url, method),
68         complete(false),
69         failed(false)
70     {
71
72     }
73
74     std::map<string, string> headers;
75 protected:
76
77     virtual void onDone()
78     {
79         complete = true;
80     }
81
82     virtual void onFail()
83     {
84         failed = true;
85     }
86
87     virtual void gotBodyData(const char* s, int n)
88     {
89         //std::cout << "got body data:'" << string(s, n) << "'" <<std::endl;
90         bodyData += string(s, n);
91     }
92
93     virtual void responseHeader(const string& header, const string& value)
94     {
95         Request::responseHeader(header, value);
96         headers[header] =  value;
97     }
98 };
99
100 class HTTPTestChannel : public TestServerChannel
101 {
102 public:
103
104     virtual void processRequestHeaders()
105     {
106         if (path == "/test1") {
107             string contentStr(BODY1);
108             stringstream d;
109             d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
110             d << "Content-Length:" << contentStr.size() << "\r\n";
111             d << "\r\n"; // final CRLF to terminate the headers
112             d << contentStr;
113             push(d.str().c_str());
114         } else if (path == "/testLorem") {
115             string contentStr(BODY3);
116             stringstream d;
117             d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
118             d << "Content-Length:" << contentStr.size() << "\r\n";
119             d << "\r\n"; // final CRLF to terminate the headers
120             d << contentStr;
121             push(d.str().c_str());
122         } else if (path == "/test_zero_length_content") {
123             string contentStr;
124             stringstream d;
125             d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
126             d << "Content-Length:" << contentStr.size() << "\r\n";
127             d << "\r\n"; // final CRLF to terminate the headers
128             d << contentStr;
129             push(d.str().c_str());
130         } else if (path == "/test_headers") {
131             COMPARE(requestHeaders["X-Foo"], string("Bar"));
132             COMPARE(requestHeaders["X-AnotherHeader"], string("A longer value"));
133
134             string contentStr(BODY1);
135             stringstream d;
136             d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
137             d << "Content-Length:" << contentStr.size() << "\r\n";
138             d << "\r\n"; // final CRLF to terminate the headers
139             d << contentStr;
140             push(d.str().c_str());
141         } else if (path == "/test2") {
142             sendBody2();
143         } else if (path == "/testchunked") {
144             stringstream d;
145             d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
146             d << "Transfer-Encoding:chunked\r\n";
147             d << "\r\n";
148             d << "8\r\n"; // first chunk
149             d << "ABCDEFGH\r\n";
150             d << "6\r\n"; // second chunk
151             d << "ABCDEF\r\n";
152             d << "10\r\n"; // third chunk
153             d << "ABCDSTUVABCDSTUV\r\n";
154             d << "0\r\n"; // start of trailer
155             d << "X-Foobar: wibble\r\n"; // trailer data
156             d << "\r\n";
157             push(d.str().c_str());
158         } else if (path == "http://www.google.com/test2") {
159             // proxy test
160             if (requestHeaders["Host"] != "www.google.com") {
161                 sendErrorResponse(400, true, "bad destination");
162             }
163
164             if (requestHeaders["Proxy-Authorization"] != string()) {
165                 sendErrorResponse(401, false, "bad auth, not empty"); // shouldn't supply auth
166             }
167
168             sendBody2();
169         } else if (path == "http://www.google.com/test3") {
170             // proxy test
171             if (requestHeaders["Host"] != "www.google.com") {
172                 sendErrorResponse(400, true, "bad destination");
173             }
174
175             string credentials = requestHeaders["Proxy-Authorization"];
176             if (credentials.substr(0, 5) != "Basic") {
177               // request basic auth
178               stringstream d;
179               d << "HTTP/1.1 " << 407 << " " << reasonForCode(407) << "\r\n";
180               d << "WWW-Authenticate: Basic real=\"simgear\"\r\n";
181               d << "\r\n"; // final CRLF to terminate the headers
182               push(d.str().c_str());
183               return;
184             }
185
186             std::vector<unsigned char> userAndPass;
187             strutils::decodeBase64(credentials.substr(6), userAndPass);
188             std::string decodedUserPass((char*) userAndPass.data(), userAndPass.size());
189
190             if (decodedUserPass != "johndoe:swordfish") {
191                 std::map<string, string>::const_iterator it;
192                 for (it = requestHeaders.begin(); it != requestHeaders.end(); ++it) {
193                   cerr << "header:" << it->first << " = " << it->second << endl;
194                 }
195
196                 sendErrorResponse(401, false, "bad auth, not as set"); // forbidden
197             }
198
199             sendBody2();
200         } else if (strutils::starts_with(path, "/test_1_0")) {
201             string contentStr(BODY1);
202             if (strutils::ends_with(path, "/B")) {
203                 contentStr = BODY3;
204             }
205             stringstream d;
206             d << "HTTP/1.0 " << 200 << " " << reasonForCode(200) << "\r\n";
207             d << "\r\n"; // final CRLF to terminate the headers
208             d << contentStr;
209             push(d.str().c_str());
210             closeAfterSending();
211         } else if (path == "/test_close") {
212             string contentStr(BODY1);
213             stringstream d;
214             d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
215             d << "Connection: close\r\n";
216             d << "\r\n"; // final CRLF to terminate the headers
217             d << contentStr;
218             push(d.str().c_str());
219             closeAfterSending();
220         } else if (path == "/test_abrupt_close") {
221             // simulate server doing socket close before sending any
222             // response - this used to cause a TerraSync failure since we
223             // would get stuck restarting the request
224             closeAfterSending();
225
226         } else if (path == "/test_args") {
227             if ((args["foo"] != "abc") || (args["bar"] != "1234") || (args["username"] != "johndoe")) {
228                 sendErrorResponse(400, true, "bad arguments");
229                 return;
230             }
231
232             string contentStr(BODY1);
233             stringstream d;
234             d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
235             d << "Content-Length:" << contentStr.size() << "\r\n";
236             d << "\r\n"; // final CRLF to terminate the headers
237             d << contentStr;
238             push(d.str().c_str());
239         } else if (path == "/test_post") {
240             if (requestHeaders["Content-Type"] != "application/x-www-form-urlencoded") {
241                 cerr << "bad content type: '" << requestHeaders["Content-Type"] << "'" << endl;
242                  sendErrorResponse(400, true, "bad content type");
243                  return;
244             }
245
246             requestContentLength = strutils::to_int(requestHeaders["Content-Length"]);
247             setByteCount(requestContentLength);
248             state = STATE_REQUEST_BODY;
249         } else if ((path == "/test_put") || (path == "/test_create")) {
250               if (requestHeaders["Content-Type"] != "x-application/foobar") {
251                   cerr << "bad content type: '" << requestHeaders["Content-Type"] << "'" << endl;
252                    sendErrorResponse(400, true, "bad content type");
253                    return;
254               }
255
256               requestContentLength = strutils::to_int(requestHeaders["Content-Length"]);
257               setByteCount(requestContentLength);
258               state = STATE_REQUEST_BODY;
259         } else if (path == "/test_get_during_send") {
260             // indicate we will send some number of bytes, but only send
261             // some of them now.
262             waitingOnNextRequestToContinue = true;
263
264             string contentStr(BODY3, 100); // only send first 100 chars
265             stringstream d;
266             d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
267             d << "Content-Length:" << strlen(BODY3) << "\r\n";
268             d << "\r\n"; // final CRLF to terminate the headers
269             d << contentStr;
270             push(d.str().c_str());
271         } else if (path == "/test_get_during_send_2") {
272             stringstream d;
273
274             if (waitingOnNextRequestToContinue) {
275                 waitingOnNextRequestToContinue = false;
276                 // push the rest of the first request
277                 d << string(BODY3).substr(100);
278             }
279
280
281             // push the response to this request
282             string contentStr(BODY1);
283             d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
284             d << "Content-Length:" << contentStr.size() << "\r\n";
285             d << "\r\n"; // final CRLF to terminate the headers
286             d << contentStr;
287             push(d.str().c_str());
288
289         } else {
290           TestServerChannel::processRequestHeaders();
291         }
292     }
293
294     void processRequestBody()
295     {
296       if (path == "/test_post") {
297             if ((args["foo"] != "abc") || (args["bar"] != "1234") || (args["username"] != "johndoe")) {
298                 sendErrorResponse(400, true, "bad arguments");
299                 return;
300             }
301
302             stringstream d;
303             d << "HTTP/1.1 " << 204 << " " << reasonForCode(204) << "\r\n";
304             d << "\r\n"; // final CRLF to terminate the headers
305             push(d.str().c_str());
306         } else if (path == "/test_put") {
307           std::cerr << "sending PUT response" << std::endl;
308
309           COMPARE(buffer, BODY3);
310           stringstream d;
311           d << "HTTP/1.1 " << 204 << " " << reasonForCode(204) << "\r\n";
312           d << "\r\n"; // final CRLF to terminate the headers
313           push(d.str().c_str());
314         } else if (path == "/test_create") {
315           std::cerr << "sending create response" << std::endl;
316
317           std::string entityStr = "http://localhost:2000/something.txt";
318
319           COMPARE(buffer, BODY3);
320           stringstream d;
321           d << "HTTP/1.1 " << 201 << " " << reasonForCode(201) << "\r\n";
322           d << "Location:" << entityStr << "\r\n";
323           d << "Content-Length:" << entityStr.size() << "\r\n";
324           d << "\r\n"; // final CRLF to terminate the headers
325           d << entityStr;
326
327           push(d.str().c_str());
328         } else {
329           TestServerChannel::processRequestBody();
330         }
331     }
332
333     void sendBody2()
334     {
335         stringstream d;
336         d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
337         d << "Content-Length:" << body2Size << "\r\n";
338         d << "\r\n"; // final CRLF to terminate the headers
339         push(d.str().c_str());
340         bufferSend(body2, body2Size);
341     }
342
343     bool waitingOnNextRequestToContinue;
344 };
345
346 TestServer<HTTPTestChannel> testServer;
347
348 void waitForComplete(HTTP::Client* cl, TestRequest* tr)
349 {
350     SGTimeStamp start(SGTimeStamp::now());
351     while (start.elapsedMSec() <  10000) {
352         cl->update();
353         testServer.poll();
354
355         if (tr->complete) {
356             return;
357         }
358         SGTimeStamp::sleepForMSec(15);
359     }
360
361     cerr << "timed out" << endl;
362 }
363
364 void waitForFailed(HTTP::Client* cl, TestRequest* tr)
365 {
366     SGTimeStamp start(SGTimeStamp::now());
367     while (start.elapsedMSec() <  10000) {
368         cl->update();
369         testServer.poll();
370
371         if (tr->failed) {
372             return;
373         }
374         SGTimeStamp::sleepForMSec(15);
375     }
376
377     cerr << "timed out waiting for failure" << endl;
378 }
379
380 int main(int argc, char* argv[])
381 {
382     sglog().setLogLevels( SG_ALL, SG_INFO );
383
384     HTTP::Client cl;
385     // force all requests to use the same connection for this test
386     cl.setMaxConnections(1);
387
388 // test URL parsing
389     TestRequest* tr1 = new TestRequest("http://localhost.woo.zar:2000/test1?foo=bar");
390     COMPARE(tr1->scheme(), "http");
391     COMPARE(tr1->hostAndPort(), "localhost.woo.zar:2000");
392     COMPARE(tr1->host(), "localhost.woo.zar");
393     COMPARE(tr1->port(), 2000);
394     COMPARE(tr1->path(), "/test1");
395
396     TestRequest* tr2 = new TestRequest("http://192.168.1.1/test1/dir/thing/file.png");
397     COMPARE(tr2->scheme(), "http");
398     COMPARE(tr2->hostAndPort(), "192.168.1.1");
399     COMPARE(tr2->host(), "192.168.1.1");
400     COMPARE(tr2->port(), 80);
401     COMPARE(tr2->path(), "/test1/dir/thing/file.png");
402
403 // basic get request
404     {
405         TestRequest* tr = new TestRequest("http://localhost:2000/test1");
406         HTTP::Request_ptr own(tr);
407         cl.makeRequest(tr);
408
409         waitForComplete(&cl, tr);
410         COMPARE(tr->responseCode(), 200);
411         COMPARE(tr->responseReason(), string("OK"));
412         COMPARE(tr->responseLength(), strlen(BODY1));
413         COMPARE(tr->responseBytesReceived(), strlen(BODY1));
414         COMPARE(tr->bodyData, string(BODY1));
415     }
416
417     {
418       TestRequest* tr = new TestRequest("http://localhost:2000/testLorem");
419       HTTP::Request_ptr own(tr);
420       cl.makeRequest(tr);
421
422       waitForComplete(&cl, tr);
423       COMPARE(tr->responseCode(), 200);
424       COMPARE(tr->responseReason(), string("OK"));
425       COMPARE(tr->responseLength(), strlen(BODY3));
426       COMPARE(tr->responseBytesReceived(), strlen(BODY3));
427       COMPARE(tr->bodyData, string(BODY3));
428     }
429
430     {
431         TestRequest* tr = new TestRequest("http://localhost:2000/test_args?foo=abc&bar=1234&username=johndoe");
432         HTTP::Request_ptr own(tr);
433         cl.makeRequest(tr);
434         waitForComplete(&cl, tr);
435         COMPARE(tr->responseCode(), 200);
436     }
437
438     {
439         TestRequest* tr = new TestRequest("http://localhost:2000/test_headers");
440         HTTP::Request_ptr own(tr);
441         tr->requestHeader("X-Foo") = "Bar";
442         tr->requestHeader("X-AnotherHeader") = "A longer value";
443         cl.makeRequest(tr);
444
445         waitForComplete(&cl, tr);
446         COMPARE(tr->responseCode(), 200);
447         COMPARE(tr->responseReason(), string("OK"));
448         COMPARE(tr->responseLength(), strlen(BODY1));
449         COMPARE(tr->responseBytesReceived(), strlen(BODY1));
450         COMPARE(tr->bodyData, string(BODY1));
451     }
452
453 // larger get request
454     for (unsigned int i=0; i<body2Size; ++i) {
455         body2[i] = (i << 4) | (i >> 2);
456     }
457
458     {
459         TestRequest* tr = new TestRequest("http://localhost:2000/test2");
460         HTTP::Request_ptr own(tr);
461         cl.makeRequest(tr);
462         waitForComplete(&cl, tr);
463         COMPARE(tr->responseCode(), 200);
464         COMPARE(tr->responseBytesReceived(), body2Size);
465         COMPARE(tr->bodyData, string(body2, body2Size));
466     }
467
468     cerr << "testing chunked transfer encoding" << endl;
469     {
470         TestRequest* tr = new TestRequest("http://localhost:2000/testchunked");
471         HTTP::Request_ptr own(tr);
472         cl.makeRequest(tr);
473
474         waitForComplete(&cl, tr);
475         COMPARE(tr->responseCode(), 200);
476         COMPARE(tr->responseReason(), string("OK"));
477         COMPARE(tr->responseBytesReceived(), 30);
478         COMPARE(tr->bodyData, "ABCDEFGHABCDEFABCDSTUVABCDSTUV");
479     // check trailers made it too
480         COMPARE(tr->headers["x-foobar"], string("wibble"));
481     }
482
483 // test 404
484     {
485         TestRequest* tr = new TestRequest("http://localhost:2000/not-found");
486         HTTP::Request_ptr own(tr);
487         cl.makeRequest(tr);
488         waitForComplete(&cl, tr);
489         COMPARE(tr->responseCode(), 404);
490         COMPARE(tr->responseReason(), string("not found"));
491         COMPARE(tr->responseLength(), 0);
492     }
493
494     cout << "done 404 test" << endl;
495
496     {
497         TestRequest* tr = new TestRequest("http://localhost:2000/test_args?foo=abc&bar=1234&username=johndoe");
498         HTTP::Request_ptr own(tr);
499         cl.makeRequest(tr);
500         waitForComplete(&cl, tr);
501         COMPARE(tr->responseCode(), 200);
502     }
503
504     cout << "done1" << endl;
505 // test HTTP/1.0
506     {
507         TestRequest* tr = new TestRequest("http://localhost:2000/test_1_0");
508         HTTP::Request_ptr own(tr);
509         cl.makeRequest(tr);
510         waitForComplete(&cl, tr);
511         COMPARE(tr->responseCode(), 200);
512         COMPARE(tr->responseLength(), strlen(BODY1));
513         COMPARE(tr->bodyData, string(BODY1));
514     }
515
516     cout << "done2" << endl;
517 // test HTTP/1.1 Connection::close
518     {
519         TestRequest* tr = new TestRequest("http://localhost:2000/test_close");
520         HTTP::Request_ptr own(tr);
521         cl.makeRequest(tr);
522         waitForComplete(&cl, tr);
523         COMPARE(tr->responseCode(), 200);
524         COMPARE(tr->responseLength(), strlen(BODY1));
525         COMPARE(tr->bodyData, string(BODY1));
526     }
527     cout << "done3" << endl;
528 // test connectToHost failure
529
530     {
531         TestRequest* tr = new TestRequest("http://not.found/something");
532         HTTP::Request_ptr own(tr);
533         cl.makeRequest(tr);
534         waitForFailed(&cl, tr);
535
536
537
538 #if defined(ENABLE_CURL)
539       const int HOST_NOT_FOUND_CODE = CURLE_COULDNT_RESOLVE_HOST;
540 #else
541       const int HOST_NOT_FOUND_CODE = ENOENT;
542 #endif
543         COMPARE(tr->responseCode(), HOST_NOT_FOUND_CODE);
544     }
545
546   cout << "testing abrupt close" << endl;
547     // test server-side abrupt close
548     {
549         TestRequest* tr = new TestRequest("http://localhost:2000/test_abrupt_close");
550         HTTP::Request_ptr own(tr);
551         cl.makeRequest(tr);
552         waitForFailed(&cl, tr);
553
554   #if defined(ENABLE_CURL)
555         const int SERVER_NO_DATA_CODE = CURLE_GOT_NOTHING;
556   #else
557         const int SERVER_NO_DATA_CODE = 500;
558   #endif
559         COMPARE(tr->responseCode(), SERVER_NO_DATA_CODE);
560     }
561
562 cout << "testing proxy close" << endl;
563 // test proxy
564     {
565         cl.setProxy("localhost", 2000);
566         TestRequest* tr = new TestRequest("http://www.google.com/test2");
567         HTTP::Request_ptr own(tr);
568         cl.makeRequest(tr);
569         waitForComplete(&cl, tr);
570         COMPARE(tr->responseCode(), 200);
571         COMPARE(tr->responseLength(), body2Size);
572         COMPARE(tr->bodyData, string(body2, body2Size));
573     }
574
575 #if defined(ENABLE_CURL)
576     {
577         cl.setProxy("localhost", 2000, "johndoe:swordfish");
578         TestRequest* tr = new TestRequest("http://www.google.com/test3");
579         HTTP::Request_ptr own(tr);
580         cl.makeRequest(tr);
581         waitForComplete(&cl, tr);
582         COMPARE(tr->responseCode(), 200);
583         COMPARE(tr->responseBytesReceived(), body2Size);
584         COMPARE(tr->bodyData, string(body2, body2Size));
585     }
586 #endif
587
588 // pipelining
589     cout << "testing HTTP 1.1 pipelining" << endl;
590
591     {
592         testServer.resetConnectCount();
593         cl.clearAllConnections();
594         
595         cl.setProxy("", 80);
596         TestRequest* tr = new TestRequest("http://localhost:2000/test1");
597         HTTP::Request_ptr own(tr);
598         cl.makeRequest(tr);
599
600
601         TestRequest* tr2 = new TestRequest("http://localhost:2000/testLorem");
602         HTTP::Request_ptr own2(tr2);
603         cl.makeRequest(tr2);
604
605         TestRequest* tr3 = new TestRequest("http://localhost:2000/test1");
606         HTTP::Request_ptr own3(tr3);
607         cl.makeRequest(tr3);
608
609         waitForComplete(&cl, tr3);
610         VERIFY(tr->complete);
611         VERIFY(tr2->complete);
612         COMPARE(tr->bodyData, string(BODY1));
613
614         COMPARE(tr2->responseLength(), strlen(BODY3));
615         COMPARE(tr2->responseBytesReceived(), strlen(BODY3));
616         COMPARE(tr2->bodyData, string(BODY3));
617
618         COMPARE(tr3->bodyData, string(BODY1));
619
620         COMPARE(testServer.connectCount(), 1);
621     }
622
623 // multiple requests with an HTTP 1.0 server
624     {
625         cout << "http 1.0 multiple requests" << endl;
626
627         cl.setProxy("", 80);
628         TestRequest* tr = new TestRequest("http://localhost:2000/test_1_0/A");
629         HTTP::Request_ptr own(tr);
630         cl.makeRequest(tr);
631
632         TestRequest* tr2 = new TestRequest("http://localhost:2000/test_1_0/B");
633         HTTP::Request_ptr own2(tr2);
634         cl.makeRequest(tr2);
635
636         TestRequest* tr3 = new TestRequest("http://localhost:2000/test_1_0/C");
637         HTTP::Request_ptr own3(tr3);
638         cl.makeRequest(tr3);
639
640         waitForComplete(&cl, tr3);
641         VERIFY(tr->complete);
642         VERIFY(tr2->complete);
643
644         COMPARE(tr->responseLength(), strlen(BODY1));
645         COMPARE(tr->responseBytesReceived(), strlen(BODY1));
646         COMPARE(tr->bodyData, string(BODY1));
647
648         COMPARE(tr2->responseLength(), strlen(BODY3));
649         COMPARE(tr2->responseBytesReceived(), strlen(BODY3));
650         COMPARE(tr2->bodyData, string(BODY3));
651         COMPARE(tr3->bodyData, string(BODY1));
652     }
653
654 // POST
655     {
656         cout << "testing POST" << endl;
657         TestRequest* tr = new TestRequest("http://localhost:2000/test_post?foo=abc&bar=1234&username=johndoe", "POST");
658         tr->setBodyData("", "application/x-www-form-urlencoded");
659
660         HTTP::Request_ptr own(tr);
661         cl.makeRequest(tr);
662         waitForComplete(&cl, tr);
663         COMPARE(tr->responseCode(), 204);
664     }
665
666     // PUT
667         {
668             cout << "testing PUT" << endl;
669             TestRequest* tr = new TestRequest("http://localhost:2000/test_put", "PUT");
670             tr->setBodyData(BODY3, "x-application/foobar");
671
672             HTTP::Request_ptr own(tr);
673             cl.makeRequest(tr);
674             waitForComplete(&cl, tr);
675             COMPARE(tr->responseCode(), 204);
676         }
677
678         {
679             cout << "testing PUT create" << endl;
680             TestRequest* tr = new TestRequest("http://localhost:2000/test_create", "PUT");
681             tr->setBodyData(BODY3, "x-application/foobar");
682
683             HTTP::Request_ptr own(tr);
684             cl.makeRequest(tr);
685             waitForComplete(&cl, tr);
686             COMPARE(tr->responseCode(), 201);
687         }
688
689     // test_zero_length_content
690     {
691         cout << "zero-length-content-response" << endl;
692         TestRequest* tr = new TestRequest("http://localhost:2000/test_zero_length_content");
693         HTTP::Request_ptr own(tr);
694         cl.makeRequest(tr);
695         waitForComplete(&cl, tr);
696         COMPARE(tr->responseCode(), 200);
697         COMPARE(tr->bodyData, string());
698         COMPARE(tr->responseBytesReceived(), 0);
699     }
700
701     // test cancel
702     {
703         cout <<  "cancel  request" << endl;
704         testServer.resetConnectCount();
705         cl.clearAllConnections();
706
707         cl.setProxy("", 80);
708         TestRequest* tr = new TestRequest("http://localhost:2000/test1");
709         HTTP::Request_ptr own(tr);
710         cl.makeRequest(tr);
711
712         TestRequest* tr2 = new TestRequest("http://localhost:2000/testLorem");
713         HTTP::Request_ptr own2(tr2);
714         cl.makeRequest(tr2);
715
716         TestRequest* tr3 = new TestRequest("http://localhost:2000/test1");
717         HTTP::Request_ptr own3(tr3);
718         cl.makeRequest(tr3);
719
720         cl.cancelRequest(tr, "my reason 1");
721
722         cl.cancelRequest(tr2, "my reason 2");
723
724         waitForComplete(&cl, tr3);
725
726         COMPARE(tr->responseCode(), -1);
727         COMPARE(tr2->responseReason(), "my reason 2");
728
729         COMPARE(tr3->responseLength(), strlen(BODY1));
730         COMPARE(tr3->responseBytesReceived(), strlen(BODY1));
731         COMPARE(tr3->bodyData, string(BODY1));
732     }
733
734     // test cancel
735     {
736         cout <<  "cancel middle request" << endl;
737         testServer.resetConnectCount();
738         cl.clearAllConnections();
739
740         cl.setProxy("", 80);
741         TestRequest* tr = new TestRequest("http://localhost:2000/test1");
742         HTTP::Request_ptr own(tr);
743         cl.makeRequest(tr);
744
745         TestRequest* tr2 = new TestRequest("http://localhost:2000/testLorem");
746         HTTP::Request_ptr own2(tr2);
747         cl.makeRequest(tr2);
748
749         TestRequest* tr3 = new TestRequest("http://localhost:2000/test1");
750         HTTP::Request_ptr own3(tr3);
751         cl.makeRequest(tr3);
752
753         cl.cancelRequest(tr2, "middle request");
754
755         waitForComplete(&cl, tr3);
756
757         COMPARE(tr->responseCode(), 200);
758         COMPARE(tr->responseLength(), strlen(BODY1));
759         COMPARE(tr->responseBytesReceived(), strlen(BODY1));
760         COMPARE(tr->bodyData, string(BODY1));
761
762         COMPARE(tr2->responseCode(), -1);
763
764         COMPARE(tr3->responseLength(), strlen(BODY1));
765         COMPARE(tr3->responseBytesReceived(), strlen(BODY1));
766         COMPARE(tr3->bodyData, string(BODY1));
767     }
768
769     {
770         cout << "get-during-response-send" << endl;
771         cl.clearAllConnections();
772         //test_get_during_send
773
774         TestRequest* tr = new TestRequest("http://localhost:2000/test_get_during_send");
775         HTTP::Request_ptr own(tr);
776         cl.makeRequest(tr);
777
778         // kick things along
779         for (int i=0; i<10; ++i) {
780             SGTimeStamp::sleepForMSec(1);
781             cl.update();
782             testServer.poll();
783
784         }
785
786         TestRequest* tr2 = new TestRequest("http://localhost:2000/test_get_during_send_2");
787         HTTP::Request_ptr own2(tr2);
788         cl.makeRequest(tr2);
789
790         waitForComplete(&cl, tr2);
791         COMPARE(tr->responseCode(), 200);
792         COMPARE(tr->bodyData, string(BODY3));
793         COMPARE(tr->responseBytesReceived(), strlen(BODY3));
794         COMPARE(tr2->responseCode(), 200);
795         COMPARE(tr2->bodyData, string(BODY1));
796         COMPARE(tr2->responseBytesReceived(), strlen(BODY1));
797     }
798
799     cout << "all tests passed ok" << endl;
800     return EXIT_SUCCESS;
801 }