8 #include <boost/algorithm/string/case_conv.hpp>
10 #include <simgear/simgear_config.h>
12 #include "HTTPClient.hxx"
13 #include "HTTPRequest.hxx"
15 #include "test_HTTP.hxx"
17 #include <simgear/misc/strutils.hxx>
18 #include <simgear/timing/timestamp.hxx>
19 #include <simgear/debug/logstream.hxx>
21 #if defined(ENABLE_CURL)
22 #include <curl/multi.h>
29 using std::stringstream;
31 using namespace simgear;
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.";
43 const unsigned int body2Size = 8 * 1024;
44 char body2[body2Size];
46 #define COMPARE(a, b) \
48 cerr << "failed:" << #a << " != " << #b << endl; \
49 cerr << "\tgot:'" << a << "'" << endl; \
55 cerr << "failed:" << #a << endl; \
59 class TestRequest : public HTTP::Request
66 TestRequest(const std::string& url, const std::string method = "GET") :
67 HTTP::Request(url, method),
74 std::map<string, string> headers;
87 virtual void gotBodyData(const char* s, int n)
89 //std::cout << "got body data:'" << string(s, n) << "'" <<std::endl;
90 bodyData += string(s, n);
93 virtual void responseHeader(const string& header, const string& value)
95 Request::responseHeader(header, value);
96 headers[header] = value;
100 class HTTPTestChannel : public TestServerChannel
104 virtual void processRequestHeaders()
106 if (path == "/test1") {
107 string contentStr(BODY1);
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
113 push(d.str().c_str());
114 } else if (path == "/testLorem") {
115 string contentStr(BODY3);
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
121 push(d.str().c_str());
122 } else if (path == "/test_zero_length_content") {
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
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"));
134 string contentStr(BODY1);
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
140 push(d.str().c_str());
141 } else if (path == "/test2") {
143 } else if (path == "/testchunked") {
145 d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
146 d << "Transfer-Encoding:chunked\r\n";
148 d << "8\r\n"; // first chunk
150 d << "6\r\n"; // second chunk
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
157 push(d.str().c_str());
158 } else if (path == "http://www.google.com/test2") {
160 if (requestHeaders["Host"] != "www.google.com") {
161 sendErrorResponse(400, true, "bad destination");
164 if (requestHeaders["Proxy-Authorization"] != string()) {
165 sendErrorResponse(401, false, "bad auth, not empty"); // shouldn't supply auth
169 } else if (path == "http://www.google.com/test3") {
171 if (requestHeaders["Host"] != "www.google.com") {
172 sendErrorResponse(400, true, "bad destination");
175 string credentials = requestHeaders["Proxy-Authorization"];
176 if (credentials.substr(0, 5) != "Basic") {
177 // request basic auth
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());
186 std::vector<unsigned char> userAndPass;
187 strutils::decodeBase64(credentials.substr(6), userAndPass);
188 std::string decodedUserPass((char*) userAndPass.data(), userAndPass.size());
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;
196 sendErrorResponse(401, false, "bad auth, not as set"); // forbidden
200 } else if (strutils::starts_with(path, "/test_1_0")) {
201 string contentStr(BODY1);
202 if (strutils::ends_with(path, "/B")) {
206 d << "HTTP/1.0 " << 200 << " " << reasonForCode(200) << "\r\n";
207 d << "\r\n"; // final CRLF to terminate the headers
209 push(d.str().c_str());
211 } else if (path == "/test_close") {
212 string contentStr(BODY1);
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
218 push(d.str().c_str());
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
226 } else if (path == "/test_args") {
227 if ((args["foo"] != "abc") || (args["bar"] != "1234") || (args["username"] != "johndoe")) {
228 sendErrorResponse(400, true, "bad arguments");
232 string contentStr(BODY1);
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
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");
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");
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
262 waitingOnNextRequestToContinue = true;
264 string contentStr(BODY3, 100); // only send first 100 chars
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
270 push(d.str().c_str());
271 } else if (path == "/test_get_during_send_2") {
274 if (waitingOnNextRequestToContinue) {
275 waitingOnNextRequestToContinue = false;
276 // push the rest of the first request
277 d << string(BODY3).substr(100);
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
287 push(d.str().c_str());
290 TestServerChannel::processRequestHeaders();
294 void processRequestBody()
296 if (path == "/test_post") {
297 if ((args["foo"] != "abc") || (args["bar"] != "1234") || (args["username"] != "johndoe")) {
298 sendErrorResponse(400, true, "bad arguments");
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;
309 COMPARE(buffer, BODY3);
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;
317 std::string entityStr = "http://localhost:2000/something.txt";
319 COMPARE(buffer, BODY3);
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
327 push(d.str().c_str());
329 TestServerChannel::processRequestBody();
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);
343 bool waitingOnNextRequestToContinue;
346 TestServer<HTTPTestChannel> testServer;
348 void waitForComplete(HTTP::Client* cl, TestRequest* tr)
350 SGTimeStamp start(SGTimeStamp::now());
351 while (start.elapsedMSec() < 10000) {
358 SGTimeStamp::sleepForMSec(15);
361 cerr << "timed out" << endl;
364 void waitForFailed(HTTP::Client* cl, TestRequest* tr)
366 SGTimeStamp start(SGTimeStamp::now());
367 while (start.elapsedMSec() < 10000) {
374 SGTimeStamp::sleepForMSec(15);
377 cerr << "timed out waiting for failure" << endl;
380 int main(int argc, char* argv[])
382 sglog().setLogLevels( SG_ALL, SG_INFO );
385 // force all requests to use the same connection for this test
386 cl.setMaxConnections(1);
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");
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");
405 TestRequest* tr = new TestRequest("http://localhost:2000/test1");
406 HTTP::Request_ptr own(tr);
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));
418 TestRequest* tr = new TestRequest("http://localhost:2000/testLorem");
419 HTTP::Request_ptr own(tr);
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));
431 TestRequest* tr = new TestRequest("http://localhost:2000/test_args?foo=abc&bar=1234&username=johndoe");
432 HTTP::Request_ptr own(tr);
434 waitForComplete(&cl, tr);
435 COMPARE(tr->responseCode(), 200);
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";
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));
453 // larger get request
454 for (unsigned int i=0; i<body2Size; ++i) {
455 body2[i] = (i << 4) | (i >> 2);
459 TestRequest* tr = new TestRequest("http://localhost:2000/test2");
460 HTTP::Request_ptr own(tr);
462 waitForComplete(&cl, tr);
463 COMPARE(tr->responseCode(), 200);
464 COMPARE(tr->responseBytesReceived(), body2Size);
465 COMPARE(tr->bodyData, string(body2, body2Size));
468 cerr << "testing chunked transfer encoding" << endl;
470 TestRequest* tr = new TestRequest("http://localhost:2000/testchunked");
471 HTTP::Request_ptr own(tr);
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"));
485 TestRequest* tr = new TestRequest("http://localhost:2000/not-found");
486 HTTP::Request_ptr own(tr);
488 waitForComplete(&cl, tr);
489 COMPARE(tr->responseCode(), 404);
490 COMPARE(tr->responseReason(), string("not found"));
491 COMPARE(tr->responseLength(), 0);
494 cout << "done 404 test" << endl;
497 TestRequest* tr = new TestRequest("http://localhost:2000/test_args?foo=abc&bar=1234&username=johndoe");
498 HTTP::Request_ptr own(tr);
500 waitForComplete(&cl, tr);
501 COMPARE(tr->responseCode(), 200);
504 cout << "done1" << endl;
507 TestRequest* tr = new TestRequest("http://localhost:2000/test_1_0");
508 HTTP::Request_ptr own(tr);
510 waitForComplete(&cl, tr);
511 COMPARE(tr->responseCode(), 200);
512 COMPARE(tr->responseLength(), strlen(BODY1));
513 COMPARE(tr->bodyData, string(BODY1));
516 cout << "done2" << endl;
517 // test HTTP/1.1 Connection::close
519 TestRequest* tr = new TestRequest("http://localhost:2000/test_close");
520 HTTP::Request_ptr own(tr);
522 waitForComplete(&cl, tr);
523 COMPARE(tr->responseCode(), 200);
524 COMPARE(tr->responseLength(), strlen(BODY1));
525 COMPARE(tr->bodyData, string(BODY1));
527 cout << "done3" << endl;
528 // test connectToHost failure
531 TestRequest* tr = new TestRequest("http://not.found/something");
532 HTTP::Request_ptr own(tr);
534 waitForFailed(&cl, tr);
538 #if defined(ENABLE_CURL)
539 const int HOST_NOT_FOUND_CODE = CURLE_COULDNT_RESOLVE_HOST;
541 const int HOST_NOT_FOUND_CODE = ENOENT;
543 COMPARE(tr->responseCode(), HOST_NOT_FOUND_CODE);
546 cout << "testing abrupt close" << endl;
547 // test server-side abrupt close
549 TestRequest* tr = new TestRequest("http://localhost:2000/test_abrupt_close");
550 HTTP::Request_ptr own(tr);
552 waitForFailed(&cl, tr);
554 #if defined(ENABLE_CURL)
555 const int SERVER_NO_DATA_CODE = CURLE_GOT_NOTHING;
557 const int SERVER_NO_DATA_CODE = 500;
559 COMPARE(tr->responseCode(), SERVER_NO_DATA_CODE);
562 cout << "testing proxy close" << endl;
565 cl.setProxy("localhost", 2000);
566 TestRequest* tr = new TestRequest("http://www.google.com/test2");
567 HTTP::Request_ptr own(tr);
569 waitForComplete(&cl, tr);
570 COMPARE(tr->responseCode(), 200);
571 COMPARE(tr->responseLength(), body2Size);
572 COMPARE(tr->bodyData, string(body2, body2Size));
575 #if defined(ENABLE_CURL)
577 cl.setProxy("localhost", 2000, "johndoe:swordfish");
578 TestRequest* tr = new TestRequest("http://www.google.com/test3");
579 HTTP::Request_ptr own(tr);
581 waitForComplete(&cl, tr);
582 COMPARE(tr->responseCode(), 200);
583 COMPARE(tr->responseBytesReceived(), body2Size);
584 COMPARE(tr->bodyData, string(body2, body2Size));
589 cout << "testing HTTP 1.1 pipelining" << endl;
592 testServer.resetConnectCount();
593 cl.clearAllConnections();
596 TestRequest* tr = new TestRequest("http://localhost:2000/test1");
597 HTTP::Request_ptr own(tr);
601 TestRequest* tr2 = new TestRequest("http://localhost:2000/testLorem");
602 HTTP::Request_ptr own2(tr2);
605 TestRequest* tr3 = new TestRequest("http://localhost:2000/test1");
606 HTTP::Request_ptr own3(tr3);
609 waitForComplete(&cl, tr3);
610 VERIFY(tr->complete);
611 VERIFY(tr2->complete);
612 COMPARE(tr->bodyData, string(BODY1));
614 COMPARE(tr2->responseLength(), strlen(BODY3));
615 COMPARE(tr2->responseBytesReceived(), strlen(BODY3));
616 COMPARE(tr2->bodyData, string(BODY3));
618 COMPARE(tr3->bodyData, string(BODY1));
620 COMPARE(testServer.connectCount(), 1);
623 // multiple requests with an HTTP 1.0 server
625 cout << "http 1.0 multiple requests" << endl;
628 TestRequest* tr = new TestRequest("http://localhost:2000/test_1_0/A");
629 HTTP::Request_ptr own(tr);
632 TestRequest* tr2 = new TestRequest("http://localhost:2000/test_1_0/B");
633 HTTP::Request_ptr own2(tr2);
636 TestRequest* tr3 = new TestRequest("http://localhost:2000/test_1_0/C");
637 HTTP::Request_ptr own3(tr3);
640 waitForComplete(&cl, tr3);
641 VERIFY(tr->complete);
642 VERIFY(tr2->complete);
644 COMPARE(tr->responseLength(), strlen(BODY1));
645 COMPARE(tr->responseBytesReceived(), strlen(BODY1));
646 COMPARE(tr->bodyData, string(BODY1));
648 COMPARE(tr2->responseLength(), strlen(BODY3));
649 COMPARE(tr2->responseBytesReceived(), strlen(BODY3));
650 COMPARE(tr2->bodyData, string(BODY3));
651 COMPARE(tr3->bodyData, string(BODY1));
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");
660 HTTP::Request_ptr own(tr);
662 waitForComplete(&cl, tr);
663 COMPARE(tr->responseCode(), 204);
668 cout << "testing PUT" << endl;
669 TestRequest* tr = new TestRequest("http://localhost:2000/test_put", "PUT");
670 tr->setBodyData(BODY3, "x-application/foobar");
672 HTTP::Request_ptr own(tr);
674 waitForComplete(&cl, tr);
675 COMPARE(tr->responseCode(), 204);
679 cout << "testing PUT create" << endl;
680 TestRequest* tr = new TestRequest("http://localhost:2000/test_create", "PUT");
681 tr->setBodyData(BODY3, "x-application/foobar");
683 HTTP::Request_ptr own(tr);
685 waitForComplete(&cl, tr);
686 COMPARE(tr->responseCode(), 201);
689 // test_zero_length_content
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);
695 waitForComplete(&cl, tr);
696 COMPARE(tr->responseCode(), 200);
697 COMPARE(tr->bodyData, string());
698 COMPARE(tr->responseBytesReceived(), 0);
703 cout << "cancel request" << endl;
704 testServer.resetConnectCount();
705 cl.clearAllConnections();
708 TestRequest* tr = new TestRequest("http://localhost:2000/test1");
709 HTTP::Request_ptr own(tr);
712 TestRequest* tr2 = new TestRequest("http://localhost:2000/testLorem");
713 HTTP::Request_ptr own2(tr2);
716 TestRequest* tr3 = new TestRequest("http://localhost:2000/test1");
717 HTTP::Request_ptr own3(tr3);
720 cl.cancelRequest(tr, "my reason 1");
722 cl.cancelRequest(tr2, "my reason 2");
724 waitForComplete(&cl, tr3);
726 COMPARE(tr->responseCode(), -1);
727 COMPARE(tr2->responseReason(), "my reason 2");
729 COMPARE(tr3->responseLength(), strlen(BODY1));
730 COMPARE(tr3->responseBytesReceived(), strlen(BODY1));
731 COMPARE(tr3->bodyData, string(BODY1));
736 cout << "cancel middle request" << endl;
737 testServer.resetConnectCount();
738 cl.clearAllConnections();
741 TestRequest* tr = new TestRequest("http://localhost:2000/test1");
742 HTTP::Request_ptr own(tr);
745 TestRequest* tr2 = new TestRequest("http://localhost:2000/testLorem");
746 HTTP::Request_ptr own2(tr2);
749 TestRequest* tr3 = new TestRequest("http://localhost:2000/test1");
750 HTTP::Request_ptr own3(tr3);
753 cl.cancelRequest(tr2, "middle request");
755 waitForComplete(&cl, tr3);
757 COMPARE(tr->responseCode(), 200);
758 COMPARE(tr->responseLength(), strlen(BODY1));
759 COMPARE(tr->responseBytesReceived(), strlen(BODY1));
760 COMPARE(tr->bodyData, string(BODY1));
762 COMPARE(tr2->responseCode(), -1);
764 COMPARE(tr3->responseLength(), strlen(BODY1));
765 COMPARE(tr3->responseBytesReceived(), strlen(BODY1));
766 COMPARE(tr3->bodyData, string(BODY1));
770 cout << "get-during-response-send" << endl;
771 cl.clearAllConnections();
772 //test_get_during_send
774 TestRequest* tr = new TestRequest("http://localhost:2000/test_get_during_send");
775 HTTP::Request_ptr own(tr);
779 for (int i=0; i<10; ++i) {
780 SGTimeStamp::sleepForMSec(1);
786 TestRequest* tr2 = new TestRequest("http://localhost:2000/test_get_during_send_2");
787 HTTP::Request_ptr own2(tr2);
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));
799 cout << "all tests passed ok" << endl;