HttpRequest: Don't trigger listener on auto redirect

When the user enable auto-redirection, what they meant is that they do
not want to handle redirections, thus we should take total control of this
step and hide it from the user. In fact, a majority of in-tree users
write code to disable their listener when a redirection happen.

This should also allow us to simplify BUrlResult, which has been turned
into a BArchivable for the sole reason of "preserving" headers when
auto redirect is enabled when used with BUrlDispatchingListener, which
has been shown to have little (if any) practical usage.

Change-Id: I9b10b81de0a13edbaec25f6b48ed7a4335ea691a
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3081
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Leorize
2021-02-28 20:39:31 +00:00
committed by Niels Sascha Reedijk
parent 3d2fd2acaf
commit 8e3c76b3d2
4 changed files with 89 additions and 56 deletions
@@ -590,6 +590,7 @@ BHttpRequest::_MakeRequest()
// Receive loop
bool disableListener = false;
bool receiveEnd = false;
bool parseEnd = false;
bool readByChunks = false;
@@ -640,8 +641,16 @@ BHttpRequest::_MakeRequest()
if (fRequestStatus < kRequestStatusReceived) {
_ParseStatus();
#ifndef LIBNETAPI_DEPRECATED
// Deprecated behavior is to not disable the listener on redirect
if (fOptFollowLocation
&& IsRedirectionStatusCode(fResult.StatusCode()))
disableListener = true;
#endif
//! ProtocolHook:ResponseStarted
if (fRequestStatus >= kRequestStatusReceived && fListener != NULL)
if (fRequestStatus >= kRequestStatusReceived && fListener != NULL
&& !disableListener)
fListener->ResponseStarted(this);
}
@@ -662,7 +671,7 @@ BHttpRequest::_MakeRequest()
}
//! ProtocolHook:HeadersReceived
if (fListener != NULL)
if (fListener != NULL && !disableListener)
fListener->HeadersReceived(this, fResult);
@@ -768,7 +777,7 @@ BHttpRequest::_MakeRequest()
if (bytesRead >= 0) {
bytesReceived += bytesRead;
if (fListener != NULL) {
if (fListener != NULL && !disableListener) {
if (decompress) {
readError = decompressingStream->WriteExactly(
inputTempBuffer, bytesRead);
@@ -791,7 +800,7 @@ BHttpRequest::_MakeRequest()
if (bytesTotal >= 0 && bytesReceived >= bytesTotal)
receiveEnd = true;
if (decompress && receiveEnd) {
if (decompress && receiveEnd && !disableListener) {
readError = decompressingStream->Flush();
if (readError == B_BUFFER_OVERFLOW)
@@ -803,9 +812,11 @@ BHttpRequest::_MakeRequest()
ssize_t size = decompressorStorage.Size();
BStackOrHeapArray<char, 4096> buffer(size);
size = decompressorStorage.Read(buffer, size);
_NotifyDataReceived(buffer, bytesUnpacked, size,
bytesReceived, bytesTotal);
bytesUnpacked += size;
if (fListener != NULL) {
_NotifyDataReceived(buffer, bytesUnpacked, size,
bytesReceived, bytesTotal);
bytesUnpacked += size;
}
}
}
}
+64 -47
View File
@@ -172,6 +172,7 @@ void AddCommonTests(BThreadedTestCaller<T>& testCaller)
testCaller.addThread("UploadTest", &T::UploadTest);
testCaller.addThread("BasicAuthTest", &T::AuthBasicTest);
testCaller.addThread("DigestAuthTest", &T::AuthDigestTest);
testCaller.addThread("AutoRedirectTest", &T::AutoRedirectTest);
}
}
@@ -202,53 +203,7 @@ HttpTest::setUp()
void
HttpTest::GetTest()
{
BUrl testUrl(fTestServer.BaseUrl(), "/");
BUrlContext* context = new BUrlContext();
context->AcquireReference();
std::string expectedResponseBody(
"Path: /\r\n"
"\r\n"
"Headers:\r\n"
"--------\r\n"
"Host: 127.0.0.1:PORT\r\n"
"Accept: */*\r\n"
"Accept-Encoding: gzip\r\n"
"Connection: close\r\n"
"User-Agent: Services Kit (Haiku)\r\n");
HttpHeaderMap expectedResponseHeaders;
expectedResponseHeaders["Content-Encoding"] = "gzip";
expectedResponseHeaders["Content-Length"] = "144";
expectedResponseHeaders["Content-Type"] = "text/plain";
expectedResponseHeaders["Date"] = "Sun, 09 Feb 2020 19:32:42 GMT";
expectedResponseHeaders["Server"] = "Test HTTP Server for Haiku";
TestListener listener(expectedResponseBody, expectedResponseHeaders);
ObjectDeleter<BUrlRequest> requestDeleter(
BUrlProtocolRoster::MakeRequest(testUrl, &listener, context));
BHttpRequest* request = dynamic_cast<BHttpRequest*>(requestDeleter.Get());
CPPUNIT_ASSERT(request != NULL);
CPPUNIT_ASSERT(request->Run());
while (request->IsRunning())
snooze(1000);
CPPUNIT_ASSERT_EQUAL(B_OK, request->Status());
const BHttpResult& result
= dynamic_cast<const BHttpResult&>(request->Result());
CPPUNIT_ASSERT_EQUAL(200, result.StatusCode());
CPPUNIT_ASSERT_EQUAL(BString("OK"), result.StatusText());
CPPUNIT_ASSERT_EQUAL(144, result.Length());
listener.Verify();
CPPUNIT_ASSERT(!context->GetCookieJar().GetIterator().HasNext());
// This page should not set cookies
context->ReleaseReference();
_GetTest("/");
}
@@ -507,6 +462,13 @@ HttpTest::AuthDigestTest()
}
void
HttpTest::AutoRedirectTest()
{
_GetTest("/302");
}
/* static */ void
HttpTest::AddTests(BTestSuite& parent)
{
@@ -542,6 +504,61 @@ HttpTest::AddTests(BTestSuite& parent)
}
void
HttpTest::_GetTest(const BString& path)
{
BUrl testUrl(fTestServer.BaseUrl(), path);
BUrlContext* context = new BUrlContext();
context->AcquireReference();
std::string expectedResponseBody(
"Path: /\r\n"
"\r\n"
"Headers:\r\n"
"--------\r\n"
"Host: 127.0.0.1:PORT\r\n"
"Accept: */*\r\n"
"Accept-Encoding: gzip\r\n"
"Connection: close\r\n"
"User-Agent: Services Kit (Haiku)\r\n");
HttpHeaderMap expectedResponseHeaders;
expectedResponseHeaders["Content-Encoding"] = "gzip";
expectedResponseHeaders["Content-Length"] = "144";
expectedResponseHeaders["Content-Type"] = "text/plain";
expectedResponseHeaders["Date"] = "Sun, 09 Feb 2020 19:32:42 GMT";
expectedResponseHeaders["Server"] = "Test HTTP Server for Haiku";
TestListener listener(expectedResponseBody, expectedResponseHeaders);
ObjectDeleter<BUrlRequest> requestDeleter(
BUrlProtocolRoster::MakeRequest(testUrl, &listener, context));
BHttpRequest* request = dynamic_cast<BHttpRequest*>(requestDeleter.Get());
CPPUNIT_ASSERT(request != NULL);
request->SetAutoReferrer(false);
CPPUNIT_ASSERT(request->Run());
while (request->IsRunning())
snooze(1000);
CPPUNIT_ASSERT_EQUAL(B_OK, request->Status());
const BHttpResult& result
= dynamic_cast<const BHttpResult&>(request->Result());
CPPUNIT_ASSERT_EQUAL(200, result.StatusCode());
CPPUNIT_ASSERT_EQUAL(BString("OK"), result.StatusText());
CPPUNIT_ASSERT_EQUAL(144, result.Length());
listener.Verify();
CPPUNIT_ASSERT(!context->GetCookieJar().GetIterator().HasNext());
// This page should not set cookies
context->ReleaseReference();
}
// # pragma mark - HTTPS
+3
View File
@@ -29,9 +29,12 @@ public:
void AuthBasicTest();
void AuthDigestTest();
void ProxyTest();
void AutoRedirectTest();
static void AddTests(BTestSuite& suite);
private:
void _GetTest(const BString& path);
private:
TestServer fTestServer;
};
+4 -2
View File
@@ -64,8 +64,10 @@ class RequestHandler(http.server.BaseHTTPRequestHandler):
encoding, response_body = self._build_response_body()
self.send_response(
extract_desired_status_code_from_path(self.path, 200))
status_code = extract_desired_status_code_from_path(self.path, 200)
self.send_response(status_code)
if status_code >= 300 and status_code < 400:
self.send_header('Location', '/')
self.send_header('Content-Type', 'text/plain')
self.send_header('Content-Length', str(len(response_body)))
if encoding: