libbnetapi: Disallow instantiation of BUrlRequest subclasses directly

This API change forces all creation of BUrlRequest to be done via
BUrlProtocolRoster::MakeRequest(). This allows the structure of protocol
addons to be altered without breaking ABI for client applications.

Change-Id: I1785c9136c50d19eaa9e57cb9d259ed8d88a5b56
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3080
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Leorize
2020-10-12 06:36:00 +00:00
committed by Adrien Destugues
parent 26ca2e3226
commit e67a4284c0
8 changed files with 121 additions and 71 deletions
+7 -3
View File
@@ -11,17 +11,21 @@
#define _B_DATA_REQUEST_H_ #define _B_DATA_REQUEST_H_
#include <UrlProtocolRoster.h>
#include <UrlRequest.h> #include <UrlRequest.h>
class BDataRequest: public BUrlRequest { class BDataRequest: public BUrlRequest {
public: public:
const BUrlResult& Result() const;
private:
friend class BUrlProtocolRoster;
BDataRequest(const BUrl& url, BDataRequest(const BUrl& url,
BUrlProtocolListener* listener = NULL, BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL); BUrlContext* context = NULL);
const BUrlResult& Result() const;
private: status_t _ProtocolLoop();
status_t _ProtocolLoop();
private: private:
BUrlResult fResult; BUrlResult fResult;
}; };
+8 -4
View File
@@ -10,19 +10,23 @@
#include <UrlRequest.h> #include <UrlRequest.h>
#include <UrlProtocolRoster.h>
class BFileRequest : public BUrlRequest { class BFileRequest : public BUrlRequest {
public: public:
BFileRequest(const BUrl& url,
BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL);
virtual ~BFileRequest(); virtual ~BFileRequest();
const BUrlResult& Result() const; const BUrlResult& Result() const;
void SetDisableListener(bool disable); void SetDisableListener(bool disable);
private: private:
friend class BUrlProtocolRoster;
BFileRequest(const BUrl& url,
BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL);
status_t _ProtocolLoop(); status_t _ProtocolLoop();
private: private:
BUrlResult fResult; BUrlResult fResult;
+7 -3
View File
@@ -9,13 +9,11 @@
#include <deque> #include <deque>
#include <NetworkRequest.h> #include <NetworkRequest.h>
#include <UrlProtocolRoster.h>
class BGopherRequest : public BNetworkRequest { class BGopherRequest : public BNetworkRequest {
public: public:
BGopherRequest(const BUrl& url,
BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL);
virtual ~BGopherRequest(); virtual ~BGopherRequest();
status_t Stop(); status_t Stop();
@@ -23,6 +21,12 @@ public:
void SetDisableListener(bool disable); void SetDisableListener(bool disable);
private: private:
friend class BUrlProtocolRoster;
BGopherRequest(const BUrl& url,
BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL);
status_t _ProtocolLoop(); status_t _ProtocolLoop();
void _SendRequest(); void _SendRequest();
+10 -6
View File
@@ -14,6 +14,7 @@
#include <HttpResult.h> #include <HttpResult.h>
#include <NetworkAddress.h> #include <NetworkAddress.h>
#include <NetworkRequest.h> #include <NetworkRequest.h>
#include <UrlProtocolRoster.h>
namespace BPrivate { namespace BPrivate {
@@ -24,12 +25,6 @@ namespace BPrivate {
class BHttpRequest : public BNetworkRequest { class BHttpRequest : public BNetworkRequest {
public: public:
BHttpRequest(const BUrl& url,
bool ssl = false,
const char* protocolName = "HTTP",
BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL);
BHttpRequest(const BHttpRequest& other);
virtual ~BHttpRequest(); virtual ~BHttpRequest();
void SetMethod(const char* const method); void SetMethod(const char* const method);
@@ -64,6 +59,15 @@ public:
static int16 StatusCodeClass(int16 code); static int16 StatusCodeClass(int16 code);
private: private:
friend class BUrlProtocolRoster;
BHttpRequest(const BUrl& url,
bool ssl = false,
const char* protocolName = "HTTP",
BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL);
BHttpRequest(const BHttpRequest& other);
void _ResetOptions(); void _ResetOptions();
status_t _ProtocolLoop(); status_t _ProtocolLoop();
status_t _MakeRequest(); status_t _MakeRequest();
@@ -344,14 +344,19 @@ AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath,
thread_id thread; thread_id thread;
{ BUrlRequest* request = BUrlProtocolRoster::MakeRequest(url, &listener);
fRequest = dynamic_cast<BHttpRequest *>( if (request == NULL)
BUrlProtocolRoster::MakeRequest(url, &listener)); return B_NO_MEMORY;
fRequest->SetHeaders(headers);
fRequest->SetMaxRedirections(0); fRequest = dynamic_cast<BHttpRequest *>(request);
fRequest->SetTimeout(TIMEOUT_MICROSECONDS); if (fRequest == NULL) {
thread = fRequest->Run(); delete request;
return B_ERROR;
} }
fRequest->SetHeaders(headers);
fRequest->SetMaxRedirections(0);
fRequest->SetTimeout(TIMEOUT_MICROSECONDS);
thread = fRequest->Run();
wait_for_thread(thread, NULL); wait_for_thread(thread, NULL);
+33 -13
View File
@@ -6,6 +6,7 @@
#include "WebAppInterface.h" #include "WebAppInterface.h"
#include <AutoDeleter.h>
#include <Application.h> #include <Application.h>
#include <HttpHeaders.h> #include <HttpHeaders.h>
#include <HttpRequest.h> #include <HttpRequest.h>
@@ -96,6 +97,21 @@ private:
}; };
static BHttpRequest*
make_http_request(const BUrl& url, BUrlProtocolListener* listener = NULL,
BUrlContext* context = NULL)
{
BUrlRequest* request = BUrlProtocolRoster::MakeRequest(url, listener,
context);
BHttpRequest* httpRequest = dynamic_cast<BHttpRequest*>(request);
if (httpRequest == NULL) {
delete request;
return NULL;
}
return httpRequest;
}
int int
WebAppInterface::fRequestIndex = 0; WebAppInterface::fRequestIndex = 0;
@@ -825,7 +841,6 @@ WebAppInterface::_SendJsonRequest(const char* domain,
} }
BUrl url = ServerSettings::CreateFullUrl(BString("/__api/v1/") << domain); BUrl url = ServerSettings::CreateFullUrl(BString("/__api/v1/") << domain);
bool isSecure = url.Protocol() == "https";
HDDEBUG("jrpc; will make request to [%s]", url.UrlString().String()); HDDEBUG("jrpc; will make request to [%s]", url.UrlString().String());
// If the request payload is logged then it must be copied to local memory // If the request payload is logged then it must be copied to local memory
@@ -846,9 +861,12 @@ WebAppInterface::_SendJsonRequest(const char* domain,
headers.AddHeader("Content-Type", "application/json"); headers.AddHeader("Content-Type", "application/json");
ServerSettings::AugmentHeaders(headers); ServerSettings::AugmentHeaders(headers);
BHttpRequest request(url, isSecure, "HTTP", &listener, &context); BHttpRequest* request = make_http_request(url, &listener, &context);
request.SetMethod(B_HTTP_POST); ObjectDeleter<BHttpRequest> _(request);
request.SetHeaders(headers); if (request == NULL)
return B_ERROR;
request->SetMethod(B_HTTP_POST);
request->SetHeaders(headers);
// Authentication via Basic Authentication // Authentication via Basic Authentication
// The other way would be to obtain a token and then use the Token Bearer // The other way would be to obtain a token and then use the Token Bearer
@@ -860,16 +878,16 @@ WebAppInterface::_SendJsonRequest(const char* domain,
context.AddAuthentication(url, authentication); context.AddAuthentication(url, authentication);
} }
request.AdoptInputData(requestData, requestDataSize); request->AdoptInputData(requestData, requestDataSize);
BMallocIO replyData; BMallocIO replyData;
listener.SetDownloadIO(&replyData); listener.SetDownloadIO(&replyData);
thread_id thread = request.Run(); thread_id thread = request->Run();
wait_for_thread(thread, NULL); wait_for_thread(thread, NULL);
const BHttpResult& result = dynamic_cast<const BHttpResult&>( const BHttpResult& result = dynamic_cast<const BHttpResult&>(
request.Result()); request->Result());
int32 statusCode = result.StatusCode(); int32 statusCode = result.StatusCode();
@@ -930,7 +948,6 @@ WebAppInterface::_SendRawGetRequest(const BString urlPathComponents,
BDataIO* stream) BDataIO* stream)
{ {
BUrl url = ServerSettings::CreateFullUrl(urlPathComponents); BUrl url = ServerSettings::CreateFullUrl(urlPathComponents);
bool isSecure = url.Protocol() == "https";
ProtocolListener listener; ProtocolListener listener;
listener.SetDownloadIO(stream); listener.SetDownloadIO(stream);
@@ -938,15 +955,18 @@ WebAppInterface::_SendRawGetRequest(const BString urlPathComponents,
BHttpHeaders headers; BHttpHeaders headers;
ServerSettings::AugmentHeaders(headers); ServerSettings::AugmentHeaders(headers);
BHttpRequest request(url, isSecure, "HTTP", &listener); BHttpRequest *request = make_http_request(url, &listener);
request.SetMethod(B_HTTP_GET); ObjectDeleter<BHttpRequest> _(request);
request.SetHeaders(headers); if (request == NULL)
return B_ERROR;
request->SetMethod(B_HTTP_GET);
request->SetHeaders(headers);
thread_id thread = request.Run(); thread_id thread = request->Run();
wait_for_thread(thread, NULL); wait_for_thread(thread, NULL);
const BHttpResult& result = dynamic_cast<const BHttpResult&>( const BHttpResult& result = dynamic_cast<const BHttpResult&>(
request.Result()); request->Result());
int32 statusCode = result.StatusCode(); int32 statusCode = result.StatusCode();
+8 -4
View File
@@ -6,7 +6,9 @@
#include "DataTest.h" #include "DataTest.h"
#include <AutoDeleter.h>
#include <DataRequest.h> #include <DataRequest.h>
#include <UrlProtocolRoster.h>
#include <cppunit/TestCaller.h> #include <cppunit/TestCaller.h>
@@ -155,12 +157,14 @@ DataTest::_RunTest(BString url, const char* expected, size_t expectedLength)
NextSubTest(); NextSubTest();
BUrl testUrl(url); BUrl testUrl(url);
BDataRequest t(testUrl); ObjectDeleter<BUrlRequest> requestDeleter(
BUrlProtocolRoster::MakeRequest(testUrl, this));
BDataRequest* request = dynamic_cast<BDataRequest*>(requestDeleter.Get());
CPPUNIT_ASSERT(request != NULL);
fReceivedData.clear(); fReceivedData.clear();
t.SetListener(this); request->Run();
t.Run();
while(t.IsRunning()) while(request->IsRunning())
snooze(1000); snooze(1000);
CPPUNIT_ASSERT_EQUAL(expectedLength, fReceivedData.size()); CPPUNIT_ASSERT_EQUAL(expectedLength, fReceivedData.size());
+36 -31
View File
@@ -20,6 +20,7 @@
#include <HttpRequest.h> #include <HttpRequest.h>
#include <NetworkKit.h> #include <NetworkKit.h>
#include <UrlProtocolListener.h> #include <UrlProtocolListener.h>
#include <UrlProtocolRoster.h>
#include <tools/cppunit/ThreadedTestCaller.h> #include <tools/cppunit/ThreadedTestCaller.h>
@@ -125,22 +126,23 @@ void SendAuthenticatedRequest(
{ {
TestListener listener(expectedResponseBody, expectedResponseHeaders); TestListener listener(expectedResponseBody, expectedResponseHeaders);
BHttpRequest request(testUrl, testUrl.Protocol() == "https"); ObjectDeleter<BUrlRequest> requestDeleter(
request.SetContext(&context); BUrlProtocolRoster::MakeRequest(testUrl, &listener, &context));
request.SetListener(&listener); BHttpRequest* request = dynamic_cast<BHttpRequest*>(requestDeleter.Get());
CPPUNIT_ASSERT(request != NULL);
request.SetUserName("walter"); request->SetUserName("walter");
request.SetPassword("secret"); request->SetPassword("secret");
CPPUNIT_ASSERT(request.Run()); CPPUNIT_ASSERT(request->Run());
while (request.IsRunning()) while (request->IsRunning())
snooze(1000); snooze(1000);
CPPUNIT_ASSERT_EQUAL(B_OK, request.Status()); CPPUNIT_ASSERT_EQUAL(B_OK, request->Status());
const BHttpResult &result = const BHttpResult &result =
dynamic_cast<const BHttpResult &>(request.Result()); dynamic_cast<const BHttpResult &>(request->Result());
CPPUNIT_ASSERT_EQUAL(200, result.StatusCode()); CPPUNIT_ASSERT_EQUAL(200, result.StatusCode());
CPPUNIT_ASSERT_EQUAL(BString("OK"), result.StatusText()); CPPUNIT_ASSERT_EQUAL(BString("OK"), result.StatusText());
@@ -220,18 +222,19 @@ HttpTest::GetTest()
TestListener listener(expectedResponseBody, expectedResponseHeaders); TestListener listener(expectedResponseBody, expectedResponseHeaders);
BHttpRequest request(testUrl, testUrl.Protocol() == "https"); ObjectDeleter<BUrlRequest> requestDeleter(
request.SetContext(context); BUrlProtocolRoster::MakeRequest(testUrl, &listener, context));
request.SetListener(&listener); BHttpRequest* request = dynamic_cast<BHttpRequest*>(requestDeleter.Get());
CPPUNIT_ASSERT(request != NULL);
CPPUNIT_ASSERT(request.Run()); CPPUNIT_ASSERT(request->Run());
while (request.IsRunning()) while (request->IsRunning())
snooze(1000); snooze(1000);
CPPUNIT_ASSERT_EQUAL(B_OK, request.Status()); CPPUNIT_ASSERT_EQUAL(B_OK, request->Status());
const BHttpResult& result const BHttpResult& result
= dynamic_cast<const BHttpResult&>(request.Result()); = dynamic_cast<const BHttpResult&>(request->Result());
CPPUNIT_ASSERT_EQUAL(200, result.StatusCode()); CPPUNIT_ASSERT_EQUAL(200, result.StatusCode());
CPPUNIT_ASSERT_EQUAL(BString("OK"), result.StatusText()); CPPUNIT_ASSERT_EQUAL(BString("OK"), result.StatusText());
@@ -282,19 +285,20 @@ HttpTest::ProxyTest()
TestListener listener(expectedResponseBody, expectedResponseHeaders); TestListener listener(expectedResponseBody, expectedResponseHeaders);
BHttpRequest request(testUrl); ObjectDeleter<BUrlRequest> requestDeleter(
request.SetContext(context); BUrlProtocolRoster::MakeRequest(testUrl, &listener, context));
request.SetListener(&listener); BHttpRequest* request = dynamic_cast<BHttpRequest*>(requestDeleter.Get());
CPPUNIT_ASSERT(request != NULL);
CPPUNIT_ASSERT(request.Run()); CPPUNIT_ASSERT(request->Run());
while (request.IsRunning()) while (request->IsRunning())
snooze(1000); snooze(1000);
CPPUNIT_ASSERT_EQUAL(B_OK, request.Status()); CPPUNIT_ASSERT_EQUAL(B_OK, request->Status());
const BHttpResult& response const BHttpResult& response
= dynamic_cast<const BHttpResult&>(request.Result()); = dynamic_cast<const BHttpResult&>(request->Result());
CPPUNIT_ASSERT_EQUAL(200, response.StatusCode()); CPPUNIT_ASSERT_EQUAL(200, response.StatusCode());
CPPUNIT_ASSERT_EQUAL(BString("OK"), response.StatusText()); CPPUNIT_ASSERT_EQUAL(BString("OK"), response.StatusText());
CPPUNIT_ASSERT_EQUAL(169, response.Length()); CPPUNIT_ASSERT_EQUAL(169, response.Length());
@@ -373,9 +377,10 @@ HttpTest::UploadTest()
BUrlContext context; BUrlContext context;
BHttpRequest request(testUrl, testUrl.Protocol() == "https"); ObjectDeleter<BUrlRequest> requestDeleter(
request.SetContext(&context); BUrlProtocolRoster::MakeRequest(testUrl, &listener, &context));
request.SetListener(&listener); BHttpRequest* request = dynamic_cast<BHttpRequest*>(requestDeleter.Get());
CPPUNIT_ASSERT(request != NULL);
BHttpForm form; BHttpForm form;
form.AddString("hello", "world"); form.AddString("hello", "world");
@@ -383,17 +388,17 @@ HttpTest::UploadTest()
B_OK, B_OK,
form.AddFile("_uploadfile", BPath(testFilePath.c_str()))); form.AddFile("_uploadfile", BPath(testFilePath.c_str())));
request.SetPostFields(form); request->SetPostFields(form);
CPPUNIT_ASSERT(request.Run()); CPPUNIT_ASSERT(request->Run());
while (request.IsRunning()) while (request->IsRunning())
snooze(1000); snooze(1000);
CPPUNIT_ASSERT_EQUAL(B_OK, request.Status()); CPPUNIT_ASSERT_EQUAL(B_OK, request->Status());
const BHttpResult &result = const BHttpResult &result =
dynamic_cast<const BHttpResult &>(request.Result()); dynamic_cast<const BHttpResult &>(request->Result());
CPPUNIT_ASSERT_EQUAL(200, result.StatusCode()); CPPUNIT_ASSERT_EQUAL(200, result.StatusCode());
CPPUNIT_ASSERT_EQUAL(BString("OK"), result.StatusText()); CPPUNIT_ASSERT_EQUAL(BString("OK"), result.StatusText());
CPPUNIT_ASSERT_EQUAL(913, result.Length()); CPPUNIT_ASSERT_EQUAL(913, result.Length());