Add HTTP proxy support.
* Move default context management to BUrlRequest since some code (including the testsuite) bypass the BUrlProtocolRoster. * Introduce proxy host and port in BUrlContext * Have BHttpRequest use the proxy when making requests
This commit is contained in:
parent
cee64ce507
commit
c98378e51a
@ -26,7 +26,7 @@ public:
|
||||
virtual status_t Stop();
|
||||
|
||||
protected:
|
||||
bool _ResolveHostName(uint16_t port);
|
||||
bool _ResolveHostName(BString host, uint16_t port);
|
||||
|
||||
void _ProtocolSetup();
|
||||
status_t _GetLine(BString& destString);
|
||||
|
@ -2,6 +2,8 @@
|
||||
* Copyright 2010-2014 Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _B_URL_CONTEXT_H_
|
||||
#define _B_URL_CONTEXT_H_
|
||||
|
||||
@ -27,16 +29,24 @@ public:
|
||||
const BNetworkCookieJar& cookieJar);
|
||||
void AddAuthentication(const BUrl& url,
|
||||
const BHttpAuthentication& authentication);
|
||||
|
||||
void SetProxy(BString host, uint16 port);
|
||||
|
||||
// Context accessors
|
||||
BNetworkCookieJar& GetCookieJar();
|
||||
BHttpAuthentication& GetAuthentication(const BUrl& url);
|
||||
bool UseProxy();
|
||||
BString GetProxyHost();
|
||||
uint16 GetProxyPort();
|
||||
|
||||
private:
|
||||
BNetworkCookieJar fCookieJar;
|
||||
typedef BPrivate::SynchronizedHashMap<BPrivate::HashString,
|
||||
BHttpAuthentication*> BHttpAuthenticationMap;
|
||||
BHttpAuthenticationMap* fAuthenticationMap;
|
||||
|
||||
BString fProxyHost;
|
||||
uint16 fProxyPort;
|
||||
};
|
||||
|
||||
|
||||
#endif // _B_URL_CONTEXT_H_
|
||||
|
@ -235,7 +235,7 @@ BGopherRequest::_ProtocolLoop()
|
||||
if (fSocket == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
if (!_ResolveHostName(70)) {
|
||||
if (!_ResolveHostName(fUrl.Host(), fUrl.HasPort() ? fUrl.Port() : 70)) {
|
||||
_EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR,
|
||||
"Unable to resolve hostname (%s), aborting.",
|
||||
fUrl.Host().String());
|
||||
|
@ -319,7 +319,18 @@ BHttpRequest::_ProtocolLoop()
|
||||
fHeaders.Clear();
|
||||
_ResultHeaders().Clear();
|
||||
|
||||
if (!_ResolveHostName(fSSL ? 443 : 80)) {
|
||||
BString host = fUrl.Host();
|
||||
int port = fSSL ? 443 : 80;
|
||||
|
||||
if (fUrl.HasPort())
|
||||
port = fUrl.Port();
|
||||
|
||||
if (fContext->UseProxy()) {
|
||||
host = fContext->GetProxyHost();
|
||||
port = fContext->GetProxyPort();
|
||||
}
|
||||
|
||||
if (!_ResolveHostName(host, port)) {
|
||||
_EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR,
|
||||
"Unable to resolve hostname (%s), aborting.",
|
||||
fUrl.Host().String());
|
||||
@ -733,11 +744,20 @@ void
|
||||
BHttpRequest::_SendRequest()
|
||||
{
|
||||
BString request(fRequestMethod);
|
||||
request << ' ';
|
||||
|
||||
if (fContext->UseProxy()) {
|
||||
// When there is a proxy, the request must include the host and port so
|
||||
// the proxy knows where to send the request.
|
||||
request << Url().Protocol() << "://" << Url().Host();
|
||||
if (Url().HasPort())
|
||||
request << ':' << Url().Port();
|
||||
}
|
||||
|
||||
if (Url().HasPath())
|
||||
request << ' ' << Url().Path();
|
||||
request << Url().Path();
|
||||
else
|
||||
request << " /";
|
||||
request << '/';
|
||||
|
||||
if (Url().HasRequest())
|
||||
request << '?' << Url().Request();
|
||||
|
@ -36,17 +36,14 @@ BNetworkRequest::Stop()
|
||||
|
||||
|
||||
bool
|
||||
BNetworkRequest::_ResolveHostName(uint16_t port)
|
||||
BNetworkRequest::_ResolveHostName(BString host, uint16_t port)
|
||||
{
|
||||
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Resolving %s",
|
||||
fUrl.UrlString().String());
|
||||
|
||||
if (fUrl.HasPort())
|
||||
port = fUrl.Port();
|
||||
|
||||
// FIXME stop forcing AF_INET, when BNetworkAddress stops giving IPv6
|
||||
// addresses when there isn't an IPv6 link available.
|
||||
fRemoteAddr = BNetworkAddress(AF_INET, fUrl.Host(), port);
|
||||
fRemoteAddr = BNetworkAddress(AF_INET, host, port);
|
||||
|
||||
if (fRemoteAddr.InitCheck() != B_OK)
|
||||
return false;
|
||||
|
@ -18,7 +18,9 @@
|
||||
BUrlContext::BUrlContext()
|
||||
:
|
||||
fCookieJar(),
|
||||
fAuthenticationMap(NULL)
|
||||
fAuthenticationMap(NULL),
|
||||
fProxyHost(),
|
||||
fProxyPort(0)
|
||||
{
|
||||
fAuthenticationMap = new(std::nothrow) BHttpAuthenticationMap();
|
||||
|
||||
@ -31,8 +33,8 @@ BUrlContext::BUrlContext()
|
||||
|
||||
BUrlContext::~BUrlContext()
|
||||
{
|
||||
BHttpAuthenticationMap::Iterator iterator =
|
||||
fAuthenticationMap->GetIterator();
|
||||
BHttpAuthenticationMap::Iterator iterator
|
||||
= fAuthenticationMap->GetIterator();
|
||||
while (iterator.HasNext())
|
||||
delete *iterator.NextValue();
|
||||
|
||||
@ -74,6 +76,14 @@ BUrlContext::AddAuthentication(const BUrl& url,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BUrlContext::SetProxy(BString host, uint16 port)
|
||||
{
|
||||
fProxyHost = host;
|
||||
fProxyPort = port;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark Context accessors
|
||||
|
||||
|
||||
@ -102,3 +112,24 @@ BUrlContext::GetAuthentication(const BUrl& url)
|
||||
|
||||
return *authentication;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BUrlContext::UseProxy()
|
||||
{
|
||||
return !fProxyHost.IsEmpty();
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
BUrlContext::GetProxyHost()
|
||||
{
|
||||
return fProxyHost;
|
||||
}
|
||||
|
||||
|
||||
uint16
|
||||
BUrlContext::GetProxyPort()
|
||||
{
|
||||
return fProxyPort;
|
||||
}
|
||||
|
@ -19,22 +19,10 @@
|
||||
#include <UrlRequest.h>
|
||||
|
||||
|
||||
static BReference<BUrlContext> gDefaultContext = new(std::nothrow) BUrlContext();
|
||||
|
||||
|
||||
/* static */ BUrlRequest*
|
||||
BUrlProtocolRoster::MakeRequest(const BUrl& url,
|
||||
BUrlProtocolListener* listener, BUrlContext* context)
|
||||
{
|
||||
if (context == NULL)
|
||||
context = gDefaultContext;
|
||||
|
||||
if (context == NULL) {
|
||||
// Allocation of the gDefaultContext failed. Don't allow creating
|
||||
// requests without a context.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// TODO: instanciate the correct BUrlProtocol using add-on interface
|
||||
if (url.Protocol() == "http") {
|
||||
return new(std::nothrow) BHttpRequest(url, false, "HTTP", listener,
|
||||
|
@ -12,6 +12,9 @@
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
static BReference<BUrlContext> gDefaultContext = new(std::nothrow) BUrlContext();
|
||||
|
||||
|
||||
BUrlRequest::BUrlRequest(const BUrl& url, BUrlProtocolListener* listener,
|
||||
BUrlContext* context, const char* threadName, const char* protocolName)
|
||||
:
|
||||
@ -25,6 +28,8 @@ BUrlRequest::BUrlRequest(const BUrl& url, BUrlProtocolListener* listener,
|
||||
fThreadName(threadName),
|
||||
fProtocol(protocolName)
|
||||
{
|
||||
if (fContext == NULL)
|
||||
fContext = gDefaultContext;
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,7 +45,7 @@ HttpTest::GetTest()
|
||||
|
||||
CPPUNIT_ASSERT(t.Run());
|
||||
|
||||
while(t.IsRunning())
|
||||
while (t.IsRunning())
|
||||
snooze(1000);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, t.Status());
|
||||
@ -59,7 +59,44 @@ HttpTest::GetTest()
|
||||
// Fixed size as we know the response format.
|
||||
CPPUNIT_ASSERT(!c->GetCookieJar().GetIterator().HasNext());
|
||||
// This page should not set cookies
|
||||
|
||||
|
||||
c->ReleaseReference();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HttpTest::ProxyTest()
|
||||
{
|
||||
BUrl testUrl(fBaseUrl, "/user-agent");
|
||||
|
||||
BUrlContext* c = new BUrlContext();
|
||||
c->AcquireReference();
|
||||
c->SetProxy("120.203.214.182", 83);
|
||||
|
||||
BHttpRequest t(testUrl);
|
||||
t.SetContext(c);
|
||||
|
||||
BUrlProtocolListener l;
|
||||
t.SetListener(&l);
|
||||
|
||||
CPPUNIT_ASSERT(t.Run());
|
||||
|
||||
while (t.IsRunning())
|
||||
snooze(1000);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, t.Status());
|
||||
|
||||
const BHttpResult& r = dynamic_cast<const BHttpResult&>(t.Result());
|
||||
|
||||
printf("%s\n", r.StatusText().String());
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(200, r.StatusCode());
|
||||
CPPUNIT_ASSERT_EQUAL(BString("OK"), r.StatusText());
|
||||
CPPUNIT_ASSERT_EQUAL(42, r.Length());
|
||||
// Fixed size as we know the response format.
|
||||
CPPUNIT_ASSERT(!c->GetCookieJar().GetIterator().HasNext());
|
||||
// This page should not set cookies
|
||||
|
||||
c->ReleaseReference();
|
||||
}
|
||||
|
||||
@ -93,7 +130,7 @@ HttpTest::PortTest()
|
||||
|
||||
CPPUNIT_ASSERT(t.Run());
|
||||
|
||||
while(t.IsRunning())
|
||||
while (t.IsRunning())
|
||||
snooze(1000);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, t.Status());
|
||||
@ -123,7 +160,7 @@ HttpTest::UploadTest()
|
||||
|
||||
CPPUNIT_ASSERT(t.Run());
|
||||
|
||||
while(t.IsRunning())
|
||||
while (t.IsRunning())
|
||||
snooze(1000);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, t.Status());
|
||||
@ -131,7 +168,7 @@ HttpTest::UploadTest()
|
||||
const BHttpResult& r = dynamic_cast<const BHttpResult&>(t.Result());
|
||||
CPPUNIT_ASSERT_EQUAL(200, r.StatusCode());
|
||||
CPPUNIT_ASSERT_EQUAL(BString("OK"), r.StatusText());
|
||||
CPPUNIT_ASSERT_EQUAL(474, r.Length());
|
||||
CPPUNIT_ASSERT_EQUAL(466, r.Length());
|
||||
// Fixed size as we know the response format.
|
||||
}
|
||||
|
||||
@ -165,7 +202,7 @@ HttpTest::_AuthTest(BUrl& testUrl)
|
||||
|
||||
CPPUNIT_ASSERT(t.Run());
|
||||
|
||||
while(t.IsRunning())
|
||||
while (t.IsRunning())
|
||||
snooze(1000);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(B_OK, t.Status());
|
||||
@ -216,6 +253,9 @@ HttpTest::AddTests(BTestSuite& parent)
|
||||
suite.addTest(new CppUnit::TestCaller<HttpTest>(
|
||||
"HttpTest::PortTest", &HttpTest::PortTest));
|
||||
|
||||
suite.addTest(new CppUnit::TestCaller<HttpTest>("HttpTest::ProxyTest",
|
||||
&HttpTest::ProxyTest));
|
||||
|
||||
parent.addTest("HttpTest", &suite);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ public:
|
||||
void UploadTest();
|
||||
void AuthBasicTest();
|
||||
void AuthDigestTest();
|
||||
void ProxyTest();
|
||||
|
||||
static void AddTests(BTestSuite& suite);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user