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();
|
virtual status_t Stop();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool _ResolveHostName(uint16_t port);
|
bool _ResolveHostName(BString host, uint16_t port);
|
||||||
|
|
||||||
void _ProtocolSetup();
|
void _ProtocolSetup();
|
||||||
status_t _GetLine(BString& destString);
|
status_t _GetLine(BString& destString);
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
* Copyright 2010-2014 Haiku Inc. All rights reserved.
|
* Copyright 2010-2014 Haiku Inc. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef _B_URL_CONTEXT_H_
|
#ifndef _B_URL_CONTEXT_H_
|
||||||
#define _B_URL_CONTEXT_H_
|
#define _B_URL_CONTEXT_H_
|
||||||
|
|
||||||
@ -27,16 +29,24 @@ public:
|
|||||||
const BNetworkCookieJar& cookieJar);
|
const BNetworkCookieJar& cookieJar);
|
||||||
void AddAuthentication(const BUrl& url,
|
void AddAuthentication(const BUrl& url,
|
||||||
const BHttpAuthentication& authentication);
|
const BHttpAuthentication& authentication);
|
||||||
|
void SetProxy(BString host, uint16 port);
|
||||||
|
|
||||||
// Context accessors
|
// Context accessors
|
||||||
BNetworkCookieJar& GetCookieJar();
|
BNetworkCookieJar& GetCookieJar();
|
||||||
BHttpAuthentication& GetAuthentication(const BUrl& url);
|
BHttpAuthentication& GetAuthentication(const BUrl& url);
|
||||||
|
bool UseProxy();
|
||||||
|
BString GetProxyHost();
|
||||||
|
uint16 GetProxyPort();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BNetworkCookieJar fCookieJar;
|
BNetworkCookieJar fCookieJar;
|
||||||
typedef BPrivate::SynchronizedHashMap<BPrivate::HashString,
|
typedef BPrivate::SynchronizedHashMap<BPrivate::HashString,
|
||||||
BHttpAuthentication*> BHttpAuthenticationMap;
|
BHttpAuthentication*> BHttpAuthenticationMap;
|
||||||
BHttpAuthenticationMap* fAuthenticationMap;
|
BHttpAuthenticationMap* fAuthenticationMap;
|
||||||
|
|
||||||
|
BString fProxyHost;
|
||||||
|
uint16 fProxyPort;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // _B_URL_CONTEXT_H_
|
#endif // _B_URL_CONTEXT_H_
|
||||||
|
@ -235,7 +235,7 @@ BGopherRequest::_ProtocolLoop()
|
|||||||
if (fSocket == NULL)
|
if (fSocket == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
if (!_ResolveHostName(70)) {
|
if (!_ResolveHostName(fUrl.Host(), fUrl.HasPort() ? fUrl.Port() : 70)) {
|
||||||
_EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR,
|
_EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR,
|
||||||
"Unable to resolve hostname (%s), aborting.",
|
"Unable to resolve hostname (%s), aborting.",
|
||||||
fUrl.Host().String());
|
fUrl.Host().String());
|
||||||
|
@ -319,7 +319,18 @@ BHttpRequest::_ProtocolLoop()
|
|||||||
fHeaders.Clear();
|
fHeaders.Clear();
|
||||||
_ResultHeaders().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,
|
_EmitDebug(B_URL_PROTOCOL_DEBUG_ERROR,
|
||||||
"Unable to resolve hostname (%s), aborting.",
|
"Unable to resolve hostname (%s), aborting.",
|
||||||
fUrl.Host().String());
|
fUrl.Host().String());
|
||||||
@ -733,11 +744,20 @@ void
|
|||||||
BHttpRequest::_SendRequest()
|
BHttpRequest::_SendRequest()
|
||||||
{
|
{
|
||||||
BString request(fRequestMethod);
|
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())
|
if (Url().HasPath())
|
||||||
request << ' ' << Url().Path();
|
request << Url().Path();
|
||||||
else
|
else
|
||||||
request << " /";
|
request << '/';
|
||||||
|
|
||||||
if (Url().HasRequest())
|
if (Url().HasRequest())
|
||||||
request << '?' << Url().Request();
|
request << '?' << Url().Request();
|
||||||
|
@ -36,17 +36,14 @@ BNetworkRequest::Stop()
|
|||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BNetworkRequest::_ResolveHostName(uint16_t port)
|
BNetworkRequest::_ResolveHostName(BString host, uint16_t port)
|
||||||
{
|
{
|
||||||
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Resolving %s",
|
_EmitDebug(B_URL_PROTOCOL_DEBUG_TEXT, "Resolving %s",
|
||||||
fUrl.UrlString().String());
|
fUrl.UrlString().String());
|
||||||
|
|
||||||
if (fUrl.HasPort())
|
|
||||||
port = fUrl.Port();
|
|
||||||
|
|
||||||
// FIXME stop forcing AF_INET, when BNetworkAddress stops giving IPv6
|
// FIXME stop forcing AF_INET, when BNetworkAddress stops giving IPv6
|
||||||
// addresses when there isn't an IPv6 link available.
|
// 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)
|
if (fRemoteAddr.InitCheck() != B_OK)
|
||||||
return false;
|
return false;
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
BUrlContext::BUrlContext()
|
BUrlContext::BUrlContext()
|
||||||
:
|
:
|
||||||
fCookieJar(),
|
fCookieJar(),
|
||||||
fAuthenticationMap(NULL)
|
fAuthenticationMap(NULL),
|
||||||
|
fProxyHost(),
|
||||||
|
fProxyPort(0)
|
||||||
{
|
{
|
||||||
fAuthenticationMap = new(std::nothrow) BHttpAuthenticationMap();
|
fAuthenticationMap = new(std::nothrow) BHttpAuthenticationMap();
|
||||||
|
|
||||||
@ -31,8 +33,8 @@ BUrlContext::BUrlContext()
|
|||||||
|
|
||||||
BUrlContext::~BUrlContext()
|
BUrlContext::~BUrlContext()
|
||||||
{
|
{
|
||||||
BHttpAuthenticationMap::Iterator iterator =
|
BHttpAuthenticationMap::Iterator iterator
|
||||||
fAuthenticationMap->GetIterator();
|
= fAuthenticationMap->GetIterator();
|
||||||
while (iterator.HasNext())
|
while (iterator.HasNext())
|
||||||
delete *iterator.NextValue();
|
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
|
// #pragma mark Context accessors
|
||||||
|
|
||||||
|
|
||||||
@ -102,3 +112,24 @@ BUrlContext::GetAuthentication(const BUrl& url)
|
|||||||
|
|
||||||
return *authentication;
|
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>
|
#include <UrlRequest.h>
|
||||||
|
|
||||||
|
|
||||||
static BReference<BUrlContext> gDefaultContext = new(std::nothrow) BUrlContext();
|
|
||||||
|
|
||||||
|
|
||||||
/* static */ BUrlRequest*
|
/* static */ BUrlRequest*
|
||||||
BUrlProtocolRoster::MakeRequest(const BUrl& url,
|
BUrlProtocolRoster::MakeRequest(const BUrl& url,
|
||||||
BUrlProtocolListener* listener, BUrlContext* context)
|
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
|
// TODO: instanciate the correct BUrlProtocol using add-on interface
|
||||||
if (url.Protocol() == "http") {
|
if (url.Protocol() == "http") {
|
||||||
return new(std::nothrow) BHttpRequest(url, false, "HTTP", listener,
|
return new(std::nothrow) BHttpRequest(url, false, "HTTP", listener,
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
static BReference<BUrlContext> gDefaultContext = new(std::nothrow) BUrlContext();
|
||||||
|
|
||||||
|
|
||||||
BUrlRequest::BUrlRequest(const BUrl& url, BUrlProtocolListener* listener,
|
BUrlRequest::BUrlRequest(const BUrl& url, BUrlProtocolListener* listener,
|
||||||
BUrlContext* context, const char* threadName, const char* protocolName)
|
BUrlContext* context, const char* threadName, const char* protocolName)
|
||||||
:
|
:
|
||||||
@ -25,6 +28,8 @@ BUrlRequest::BUrlRequest(const BUrl& url, BUrlProtocolListener* listener,
|
|||||||
fThreadName(threadName),
|
fThreadName(threadName),
|
||||||
fProtocol(protocolName)
|
fProtocol(protocolName)
|
||||||
{
|
{
|
||||||
|
if (fContext == NULL)
|
||||||
|
fContext = gDefaultContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -64,6 +64,43 @@ HttpTest::GetTest()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class PortTestListener: public BUrlProtocolListener
|
class PortTestListener: public BUrlProtocolListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -131,7 +168,7 @@ HttpTest::UploadTest()
|
|||||||
const BHttpResult& r = dynamic_cast<const BHttpResult&>(t.Result());
|
const BHttpResult& r = dynamic_cast<const BHttpResult&>(t.Result());
|
||||||
CPPUNIT_ASSERT_EQUAL(200, r.StatusCode());
|
CPPUNIT_ASSERT_EQUAL(200, r.StatusCode());
|
||||||
CPPUNIT_ASSERT_EQUAL(BString("OK"), r.StatusText());
|
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.
|
// Fixed size as we know the response format.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,6 +253,9 @@ HttpTest::AddTests(BTestSuite& parent)
|
|||||||
suite.addTest(new CppUnit::TestCaller<HttpTest>(
|
suite.addTest(new CppUnit::TestCaller<HttpTest>(
|
||||||
"HttpTest::PortTest", &HttpTest::PortTest));
|
"HttpTest::PortTest", &HttpTest::PortTest));
|
||||||
|
|
||||||
|
suite.addTest(new CppUnit::TestCaller<HttpTest>("HttpTest::ProxyTest",
|
||||||
|
&HttpTest::ProxyTest));
|
||||||
|
|
||||||
parent.addTest("HttpTest", &suite);
|
parent.addTest("HttpTest", &suite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ public:
|
|||||||
void UploadTest();
|
void UploadTest();
|
||||||
void AuthBasicTest();
|
void AuthBasicTest();
|
||||||
void AuthDigestTest();
|
void AuthDigestTest();
|
||||||
|
void ProxyTest();
|
||||||
|
|
||||||
static void AddTests(BTestSuite& suite);
|
static void AddTests(BTestSuite& suite);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user