xref: /haiku/src/tests/kits/net/service/HttpTest.cpp (revision 899e0ef82b5624ace2ccfa5f5a58c8ebee54aaef)
1 /*
2  * Copyright 2010, Christophe Huriaux
3  * Copyright 2014-2020, Haiku, inc.
4  * Distributed under the terms of the MIT licence
5  */
6 
7 
8 #include "HttpTest.h"
9 
10 #include <algorithm>
11 #include <cstdio>
12 #include <cstdlib>
13 #include <cstring>
14 #include <fstream>
15 #include <map>
16 #include <posix/libgen.h>
17 #include <string>
18 
19 #include <AutoDeleter.h>
20 #include <HttpRequest.h>
21 #include <NetworkKit.h>
22 #include <UrlProtocolListener.h>
23 #include <UrlProtocolRoster.h>
24 
25 #include <tools/cppunit/ThreadedTestCaller.h>
26 
27 #include "TestServer.h"
28 
29 
30 using namespace BPrivate::Network;
31 
32 
33 namespace {
34 
35 typedef std::map<std::string, std::string> HttpHeaderMap;
36 
37 
38 class TestListener : public BUrlProtocolListener, public BDataIO {
39 public:
40 	TestListener(const std::string& expectedResponseBody,
41 				 const HttpHeaderMap& expectedResponseHeaders)
42 		:
43 		fExpectedResponseBody(expectedResponseBody),
44 		fExpectedResponseHeaders(expectedResponseHeaders)
45 	{
46 	}
47 
48 	virtual ssize_t Write(
49 		const void *data,
50 		size_t size)
51 	{
52 		std::copy_n(
53 			(const char*)data,
54 			size,
55 			std::back_inserter(fActualResponseBody));
56 		return size;
57 	}
58 
59 	virtual void HeadersReceived(
60 		BUrlRequest* caller)
61 	{
62 		const BHttpResult& http_result
63 			= dynamic_cast<const BHttpResult&>(caller->Result());
64 		const BHttpHeaders& headers = http_result.Headers();
65 
66 		for (int32 i = 0; i < headers.CountHeaders(); ++i) {
67 			const BHttpHeader& header = headers.HeaderAt(i);
68 			fActualResponseHeaders[std::string(header.Name())]
69 				= std::string(header.Value());
70 		}
71 	}
72 
73 
74 	virtual bool CertificateVerificationFailed(
75 		BUrlRequest* caller,
76 		BCertificate& certificate,
77 		const char* message)
78 	{
79 		// TODO: Add tests that exercize this behavior.
80 		//
81 		// At the moment there doesn't seem to be any public API for providing
82 		// an alternate certificate authority, or for constructing a
83 		// BCertificate to be sent to BUrlContext::AddCertificateException().
84 		// Once we have such a public API then it will be useful to create
85 		// test scenarios that exercize the validation performed by the
86 		// undrelying TLS implementaiton to verify that it is configured
87 		// to do so.
88 		//
89 		// For now we just disable TLS certificate validation entirely because
90 		// we are generating a self-signed TLS certificate for these tests.
91 		return true;
92 	}
93 
94 
95 	void Verify()
96 	{
97 		CPPUNIT_ASSERT_EQUAL(fExpectedResponseBody, fActualResponseBody);
98 
99 		for (HttpHeaderMap::iterator iter = fActualResponseHeaders.begin();
100 			 iter != fActualResponseHeaders.end();
101 			 ++iter)
102 		{
103 			CPPUNIT_ASSERT_EQUAL_MESSAGE(
104 				"(header " + iter->first + ")",
105 				fExpectedResponseHeaders[iter->first],
106 				iter->second);
107 		}
108 		CPPUNIT_ASSERT_EQUAL(
109 			fExpectedResponseHeaders.size(),
110 			fActualResponseHeaders.size());
111 	}
112 
113 private:
114 	std::string fExpectedResponseBody;
115 	std::string fActualResponseBody;
116 
117 	HttpHeaderMap fExpectedResponseHeaders;
118 	HttpHeaderMap fActualResponseHeaders;
119 };
120 
121 
122 void SendAuthenticatedRequest(
123 	BUrlContext &context,
124 	BUrl &testUrl,
125 	const std::string& expectedResponseBody,
126 	const HttpHeaderMap &expectedResponseHeaders)
127 {
128 	TestListener listener(expectedResponseBody, expectedResponseHeaders);
129 
130 	ObjectDeleter<BUrlRequest> requestDeleter(
131 		BUrlProtocolRoster::MakeRequest(testUrl, &listener, &listener,
132 			&context));
133 	BHttpRequest* request = dynamic_cast<BHttpRequest*>(requestDeleter.Get());
134 	CPPUNIT_ASSERT(request != NULL);
135 
136 	request->SetUserName("walter");
137 	request->SetPassword("secret");
138 
139 	CPPUNIT_ASSERT(request->Run());
140 
141 	while (request->IsRunning())
142 		snooze(1000);
143 
144 	CPPUNIT_ASSERT_EQUAL(B_OK, request->Status());
145 
146 	const BHttpResult &result =
147 		dynamic_cast<const BHttpResult &>(request->Result());
148 	CPPUNIT_ASSERT_EQUAL(200, result.StatusCode());
149 	CPPUNIT_ASSERT_EQUAL(BString("OK"), result.StatusText());
150 
151 	listener.Verify();
152 }
153 
154 
155 // Return the path of a file path relative to this source file.
156 std::string TestFilePath(const std::string& relativePath)
157 {
158 	char *testFileSource = strdup(__FILE__);
159 	MemoryDeleter _(testFileSource);
160 
161 	std::string testSrcDir(::dirname(testFileSource));
162 
163 	return testSrcDir + "/" + relativePath;
164 }
165 
166 
167 template <typename T>
168 void AddCommonTests(BThreadedTestCaller<T>& testCaller)
169 {
170 	testCaller.addThread("GetTest", &T::GetTest);
171 	testCaller.addThread("HeadTest", &T::HeadTest);
172 	testCaller.addThread("NoContentTest", &T::NoContentTest);
173 	testCaller.addThread("UploadTest", &T::UploadTest);
174 	testCaller.addThread("BasicAuthTest", &T::AuthBasicTest);
175 	testCaller.addThread("DigestAuthTest", &T::AuthDigestTest);
176 	testCaller.addThread("AutoRedirectTest", &T::AutoRedirectTest);
177 }
178 
179 }
180 
181 
182 HttpTest::HttpTest(TestServerMode mode)
183 	:
184 	fTestServer(mode)
185 {
186 }
187 
188 
189 HttpTest::~HttpTest()
190 {
191 }
192 
193 
194 void
195 HttpTest::setUp()
196 {
197 	CPPUNIT_ASSERT_EQUAL_MESSAGE(
198 		"Starting up test server",
199 		B_OK,
200 		fTestServer.Start());
201 }
202 
203 
204 void
205 HttpTest::GetTest()
206 {
207 	_GetTest("/");
208 }
209 
210 
211 void
212 HttpTest::HeadTest()
213 {
214 	BUrl testUrl(fTestServer.BaseUrl(), "/");
215 	BUrlContext* context = new BUrlContext();
216 	context->AcquireReference();
217 
218 	std::string expectedResponseBody("");
219 	HttpHeaderMap expectedResponseHeaders;
220 	expectedResponseHeaders["Content-Encoding"] = "gzip";
221 	expectedResponseHeaders["Content-Length"] = "144";
222 	expectedResponseHeaders["Content-Type"] = "text/plain";
223 	expectedResponseHeaders["Date"] = "Sun, 09 Feb 2020 19:32:42 GMT";
224 	expectedResponseHeaders["Server"] = "Test HTTP Server for Haiku";
225 
226 	TestListener listener(expectedResponseBody, expectedResponseHeaders);
227 
228 	ObjectDeleter<BUrlRequest> requestDeleter(
229 		BUrlProtocolRoster::MakeRequest(testUrl, &listener, &listener,
230 			context));
231 	BHttpRequest* request = dynamic_cast<BHttpRequest*>(requestDeleter.Get());
232 	CPPUNIT_ASSERT(request != NULL);
233 
234 	request->SetAutoReferrer(false);
235 	request->SetMethod("HEAD");
236 
237 	CPPUNIT_ASSERT(request->Run());
238 	while (request->IsRunning())
239 		snooze(1000);
240 
241 	CPPUNIT_ASSERT_EQUAL(B_OK, request->Status());
242 
243 	const BHttpResult& result
244 		= dynamic_cast<const BHttpResult&>(request->Result());
245 	CPPUNIT_ASSERT_EQUAL(200, result.StatusCode());
246 	CPPUNIT_ASSERT_EQUAL(BString("OK"), result.StatusText());
247 
248 	CPPUNIT_ASSERT_EQUAL(144, result.Length());
249 
250 	listener.Verify();
251 
252 	CPPUNIT_ASSERT(!context->GetCookieJar().GetIterator().HasNext());
253 		// This page should not set cookies
254 
255 	context->ReleaseReference();
256 }
257 
258 
259 void
260 HttpTest::NoContentTest()
261 {
262 	BUrl testUrl(fTestServer.BaseUrl(), "/204");
263 	BUrlContext* context = new BUrlContext();
264 	context->AcquireReference();
265 
266 	std::string expectedResponseBody("");
267 	HttpHeaderMap expectedResponseHeaders;
268 	expectedResponseHeaders["Date"] = "Sun, 09 Feb 2020 19:32:42 GMT";
269 	expectedResponseHeaders["Server"] = "Test HTTP Server for Haiku";
270 
271 	TestListener listener(expectedResponseBody, expectedResponseHeaders);
272 
273 	ObjectDeleter<BUrlRequest> requestDeleter(
274 		BUrlProtocolRoster::MakeRequest(testUrl, &listener, &listener,
275 			context));
276 	BHttpRequest* request = dynamic_cast<BHttpRequest*>(requestDeleter.Get());
277 	CPPUNIT_ASSERT(request != NULL);
278 
279 	request->SetAutoReferrer(false);
280 
281 	CPPUNIT_ASSERT(request->Run());
282 	while (request->IsRunning())
283 		snooze(1000);
284 
285 	CPPUNIT_ASSERT_EQUAL(B_OK, request->Status());
286 
287 	const BHttpResult& result
288 		= dynamic_cast<const BHttpResult&>(request->Result());
289 	CPPUNIT_ASSERT_EQUAL(204, result.StatusCode());
290 	CPPUNIT_ASSERT_EQUAL(BString("No Content"), result.StatusText());
291 
292 	listener.Verify();
293 
294 	CPPUNIT_ASSERT(!context->GetCookieJar().GetIterator().HasNext());
295 		// This page should not set cookies
296 
297 	context->ReleaseReference();
298 }
299 
300 
301 void
302 HttpTest::ProxyTest()
303 {
304 	BUrl testUrl(fTestServer.BaseUrl(), "/");
305 
306 	TestProxyServer proxy;
307 	CPPUNIT_ASSERT_EQUAL_MESSAGE(
308 		"Test proxy server startup",
309 		B_OK,
310 		proxy.Start());
311 
312 	BUrlContext* context = new BUrlContext();
313 	context->AcquireReference();
314 	context->SetProxy("127.0.0.1", proxy.Port());
315 
316 	std::string expectedResponseBody(
317 		"Path: /\r\n"
318 		"\r\n"
319 		"Headers:\r\n"
320 		"--------\r\n"
321 		"Host: 127.0.0.1:PORT\r\n"
322 		"Content-Length: 0\r\n"
323 		"Accept: */*\r\n"
324 		"Accept-Encoding: gzip\r\n"
325 		"Connection: close\r\n"
326 		"User-Agent: Services Kit (Haiku)\r\n"
327 		"X-Forwarded-For: 127.0.0.1:PORT\r\n");
328 	HttpHeaderMap expectedResponseHeaders;
329 	expectedResponseHeaders["Content-Encoding"] = "gzip";
330 	expectedResponseHeaders["Content-Length"] = "169";
331 	expectedResponseHeaders["Content-Type"] = "text/plain";
332 	expectedResponseHeaders["Date"] = "Sun, 09 Feb 2020 19:32:42 GMT";
333 	expectedResponseHeaders["Server"] = "Test HTTP Server for Haiku";
334 
335 	TestListener listener(expectedResponseBody, expectedResponseHeaders);
336 
337 	ObjectDeleter<BUrlRequest> requestDeleter(
338 		BUrlProtocolRoster::MakeRequest(testUrl, &listener, &listener,
339 			context));
340 	BHttpRequest* request = dynamic_cast<BHttpRequest*>(requestDeleter.Get());
341 	CPPUNIT_ASSERT(request != NULL);
342 
343 	CPPUNIT_ASSERT(request->Run());
344 
345 	while (request->IsRunning())
346 		snooze(1000);
347 
348 	CPPUNIT_ASSERT_EQUAL(B_OK, request->Status());
349 
350 	const BHttpResult& response
351 		= dynamic_cast<const BHttpResult&>(request->Result());
352 	CPPUNIT_ASSERT_EQUAL(200, response.StatusCode());
353 	CPPUNIT_ASSERT_EQUAL(BString("OK"), response.StatusText());
354 	CPPUNIT_ASSERT_EQUAL(169, response.Length());
355 		// Fixed size as we know the response format.
356 	CPPUNIT_ASSERT(!context->GetCookieJar().GetIterator().HasNext());
357 		// This page should not set cookies
358 
359 	listener.Verify();
360 
361 	context->ReleaseReference();
362 }
363 
364 
365 void
366 HttpTest::UploadTest()
367 {
368 	std::string testFilePath = TestFilePath("testfile.txt");
369 
370 	// The test server will echo the POST body back to us in the HTTP response,
371 	// so here we load it into memory so that we can compare to make sure that
372 	// the server received it.
373 	std::string fileContents;
374 	{
375 		std::ifstream inputStream(
376 			testFilePath.c_str(),
377 			std::ios::in | std::ios::binary);
378 		CPPUNIT_ASSERT(inputStream);
379 
380 		inputStream.seekg(0, std::ios::end);
381 		fileContents.resize(inputStream.tellg());
382 
383 		inputStream.seekg(0, std::ios::beg);
384 		inputStream.read(&fileContents[0], fileContents.size());
385 		inputStream.close();
386 
387 		CPPUNIT_ASSERT(!fileContents.empty());
388 	}
389 
390 	std::string expectedResponseBody(
391 		"Path: /post\r\n"
392 		"\r\n"
393 		"Headers:\r\n"
394 		"--------\r\n"
395 		"Host: 127.0.0.1:PORT\r\n"
396 		"Accept: */*\r\n"
397 		"Accept-Encoding: gzip\r\n"
398 		"Connection: close\r\n"
399 		"User-Agent: Services Kit (Haiku)\r\n"
400 		"Content-Type: multipart/form-data; boundary=<<BOUNDARY-ID>>\r\n"
401 		"Content-Length: 1404\r\n"
402 		"\r\n"
403 		"Request body:\r\n"
404 		"-------------\r\n"
405 		"--<<BOUNDARY-ID>>\r\n"
406 		"Content-Disposition: form-data; name=\"_uploadfile\";"
407 		" filename=\"testfile.txt\"\r\n"
408 		"Content-Type: application/octet-stream\r\n"
409 		"\r\n"
410 		+ fileContents
411 		+ "\r\n"
412 		"--<<BOUNDARY-ID>>\r\n"
413 		"Content-Disposition: form-data; name=\"hello\"\r\n"
414 		"\r\n"
415 		"world\r\n"
416 		"--<<BOUNDARY-ID>>--\r\n"
417 		"\r\n");
418 	HttpHeaderMap expectedResponseHeaders;
419 	expectedResponseHeaders["Content-Encoding"] = "gzip";
420 	expectedResponseHeaders["Content-Length"] = "913";
421 	expectedResponseHeaders["Content-Type"] = "text/plain";
422 	expectedResponseHeaders["Date"] = "Sun, 09 Feb 2020 19:32:42 GMT";
423 	expectedResponseHeaders["Server"] = "Test HTTP Server for Haiku";
424 	TestListener listener(expectedResponseBody, expectedResponseHeaders);
425 
426 	BUrl testUrl(fTestServer.BaseUrl(), "/post");
427 
428 	BUrlContext context;
429 
430 	ObjectDeleter<BUrlRequest> requestDeleter(
431 		BUrlProtocolRoster::MakeRequest(testUrl, &listener, &listener,
432 			&context));
433 	BHttpRequest* request = dynamic_cast<BHttpRequest*>(requestDeleter.Get());
434 	CPPUNIT_ASSERT(request != NULL);
435 
436 	BHttpForm form;
437 	form.AddString("hello", "world");
438 	CPPUNIT_ASSERT_EQUAL(
439 		B_OK,
440 		form.AddFile("_uploadfile", BPath(testFilePath.c_str())));
441 
442 	request->SetPostFields(form);
443 
444 	CPPUNIT_ASSERT(request->Run());
445 
446 	while (request->IsRunning())
447 		snooze(1000);
448 
449 	CPPUNIT_ASSERT_EQUAL(B_OK, request->Status());
450 
451 	const BHttpResult &result =
452 		dynamic_cast<const BHttpResult &>(request->Result());
453 	CPPUNIT_ASSERT_EQUAL(200, result.StatusCode());
454 	CPPUNIT_ASSERT_EQUAL(BString("OK"), result.StatusText());
455 	CPPUNIT_ASSERT_EQUAL(913, result.Length());
456 
457 	listener.Verify();
458 }
459 
460 
461 void
462 HttpTest::AuthBasicTest()
463 {
464 	BUrlContext context;
465 
466 	BUrl testUrl(fTestServer.BaseUrl(), "/auth/basic/walter/secret");
467 
468 	std::string expectedResponseBody(
469 		"Path: /auth/basic/walter/secret\r\n"
470 		"\r\n"
471 		"Headers:\r\n"
472 		"--------\r\n"
473 		"Host: 127.0.0.1:PORT\r\n"
474 		"Accept: */*\r\n"
475 		"Accept-Encoding: gzip\r\n"
476 		"Connection: close\r\n"
477 		"User-Agent: Services Kit (Haiku)\r\n"
478 		"Referer: SCHEME://127.0.0.1:PORT/auth/basic/walter/secret\r\n"
479 		"Authorization: Basic d2FsdGVyOnNlY3JldA==\r\n");
480 
481 	HttpHeaderMap expectedResponseHeaders;
482 	expectedResponseHeaders["Content-Encoding"] = "gzip";
483 	expectedResponseHeaders["Content-Length"] = "212";
484 	expectedResponseHeaders["Content-Type"] = "text/plain";
485 	expectedResponseHeaders["Date"] = "Sun, 09 Feb 2020 19:32:42 GMT";
486 	expectedResponseHeaders["Server"] = "Test HTTP Server for Haiku";
487 	expectedResponseHeaders["Www-Authenticate"] = "Basic realm=\"Fake Realm\"";
488 
489 	SendAuthenticatedRequest(context, testUrl, expectedResponseBody,
490 		expectedResponseHeaders);
491 
492 	CPPUNIT_ASSERT(!context.GetCookieJar().GetIterator().HasNext());
493 		// This page should not set cookies
494 }
495 
496 
497 void
498 HttpTest::AuthDigestTest()
499 {
500 	BUrlContext context;
501 
502 	BUrl testUrl(fTestServer.BaseUrl(), "/auth/digest/walter/secret");
503 
504 	std::string expectedResponseBody(
505 		"Path: /auth/digest/walter/secret\r\n"
506 		"\r\n"
507 		"Headers:\r\n"
508 		"--------\r\n"
509 		"Host: 127.0.0.1:PORT\r\n"
510 		"Accept: */*\r\n"
511 		"Accept-Encoding: gzip\r\n"
512 		"Connection: close\r\n"
513 		"User-Agent: Services Kit (Haiku)\r\n"
514 		"Referer: SCHEME://127.0.0.1:PORT/auth/digest/walter/secret\r\n"
515 		"Authorization: Digest username=\"walter\","
516 		" realm=\"user@shredder\","
517 		" nonce=\"f3a95f20879dd891a5544bf96a3e5518\","
518 		" algorithm=MD5,"
519 		" opaque=\"f0bb55f1221a51b6d38117c331611799\","
520 		" uri=\"/auth/digest/walter/secret\","
521 		" qop=auth,"
522 		" cnonce=\"60a3d95d286a732374f0f35fb6d21e79\","
523 		" nc=00000001,"
524 		" response=\"f4264de468aa1a91d81ac40fa73445f3\"\r\n"
525 		"Cookie: stale_after=never; fake=fake_value\r\n");
526 
527 	HttpHeaderMap expectedResponseHeaders;
528 	expectedResponseHeaders["Content-Encoding"] = "gzip";
529 	expectedResponseHeaders["Content-Length"] = "403";
530 	expectedResponseHeaders["Content-Type"] = "text/plain";
531 	expectedResponseHeaders["Date"] = "Sun, 09 Feb 2020 19:32:42 GMT";
532 	expectedResponseHeaders["Server"] = "Test HTTP Server for Haiku";
533 	expectedResponseHeaders["Set-Cookie"] = "fake=fake_value; Path=/";
534 	expectedResponseHeaders["Www-Authenticate"]
535 		= "Digest realm=\"user@shredder\", "
536 		"nonce=\"f3a95f20879dd891a5544bf96a3e5518\", "
537 		"qop=\"auth\", "
538 		"opaque=f0bb55f1221a51b6d38117c331611799, "
539 		"algorithm=MD5, "
540 		"stale=FALSE";
541 
542 	SendAuthenticatedRequest(context, testUrl, expectedResponseBody,
543 		expectedResponseHeaders);
544 
545 	std::map<BString, BString> cookies;
546 	BNetworkCookieJar::Iterator iter
547 		= context.GetCookieJar().GetIterator();
548 	while (iter.HasNext()) {
549 		const BNetworkCookie* cookie = iter.Next();
550 		cookies[cookie->Name()] = cookie->Value();
551 	}
552 	CPPUNIT_ASSERT_EQUAL(2, cookies.size());
553 	CPPUNIT_ASSERT_EQUAL(BString("fake_value"), cookies["fake"]);
554 	CPPUNIT_ASSERT_EQUAL(BString("never"), cookies["stale_after"]);
555 }
556 
557 
558 void
559 HttpTest::AutoRedirectTest()
560 {
561 	_GetTest("/302");
562 }
563 
564 
565 /* static */ void
566 HttpTest::AddTests(BTestSuite& parent)
567 {
568 	{
569 		CppUnit::TestSuite& suite = *new CppUnit::TestSuite("HttpTest");
570 
571 		HttpTest* httpTest = new HttpTest();
572 		BThreadedTestCaller<HttpTest>* httpTestCaller
573 			= new BThreadedTestCaller<HttpTest>("HttpTest::", httpTest);
574 
575 		// HTTP + HTTPs
576 		AddCommonTests<HttpTest>(*httpTestCaller);
577 
578 		httpTestCaller->addThread("ProxyTest", &HttpTest::ProxyTest);
579 
580 		suite.addTest(httpTestCaller);
581 		parent.addTest("HttpTest", &suite);
582 	}
583 
584 	{
585 		CppUnit::TestSuite& suite = *new CppUnit::TestSuite("HttpsTest");
586 
587 		HttpsTest* httpsTest = new HttpsTest();
588 		BThreadedTestCaller<HttpsTest>* httpsTestCaller
589 			= new BThreadedTestCaller<HttpsTest>("HttpsTest::", httpsTest);
590 
591 		// HTTP + HTTPs
592 		AddCommonTests<HttpsTest>(*httpsTestCaller);
593 
594 		suite.addTest(httpsTestCaller);
595 		parent.addTest("HttpsTest", &suite);
596 	}
597 }
598 
599 
600 void
601 HttpTest::_GetTest(const BString& path)
602 {
603 	BUrl testUrl(fTestServer.BaseUrl(), path);
604 	BUrlContext* context = new BUrlContext();
605 	context->AcquireReference();
606 
607 	std::string expectedResponseBody(
608 		"Path: /\r\n"
609 		"\r\n"
610 		"Headers:\r\n"
611 		"--------\r\n"
612 		"Host: 127.0.0.1:PORT\r\n"
613 		"Accept: */*\r\n"
614 		"Accept-Encoding: gzip\r\n"
615 		"Connection: close\r\n"
616 		"User-Agent: Services Kit (Haiku)\r\n");
617 	HttpHeaderMap expectedResponseHeaders;
618 	expectedResponseHeaders["Content-Encoding"] = "gzip";
619 	expectedResponseHeaders["Content-Length"] = "144";
620 	expectedResponseHeaders["Content-Type"] = "text/plain";
621 	expectedResponseHeaders["Date"] = "Sun, 09 Feb 2020 19:32:42 GMT";
622 	expectedResponseHeaders["Server"] = "Test HTTP Server for Haiku";
623 
624 	TestListener listener(expectedResponseBody, expectedResponseHeaders);
625 
626 	ObjectDeleter<BUrlRequest> requestDeleter(
627 		BUrlProtocolRoster::MakeRequest(testUrl, &listener, &listener,
628 			context));
629 	BHttpRequest* request = dynamic_cast<BHttpRequest*>(requestDeleter.Get());
630 	CPPUNIT_ASSERT(request != NULL);
631 
632 	request->SetAutoReferrer(false);
633 
634 	CPPUNIT_ASSERT(request->Run());
635 	while (request->IsRunning())
636 		snooze(1000);
637 
638 	CPPUNIT_ASSERT_EQUAL(B_OK, request->Status());
639 
640 	const BHttpResult& result
641 		= dynamic_cast<const BHttpResult&>(request->Result());
642 	CPPUNIT_ASSERT_EQUAL(200, result.StatusCode());
643 	CPPUNIT_ASSERT_EQUAL(BString("OK"), result.StatusText());
644 
645 	CPPUNIT_ASSERT_EQUAL(144, result.Length());
646 
647 	listener.Verify();
648 
649 	CPPUNIT_ASSERT(!context->GetCookieJar().GetIterator().HasNext());
650 		// This page should not set cookies
651 
652 	context->ReleaseReference();
653 }
654 
655 
656 // # pragma mark - HTTPS
657 
658 
659 HttpsTest::HttpsTest()
660 	:
661 	HttpTest(TEST_SERVER_MODE_HTTPS)
662 {
663 }
664