hrev47865 adds 1 changeset to branch 'master' old head: cee64ce5074d04f8517bc086dccb3759d1454d91 new head: c98378e51ae02d8ad6e833c7eb8223a10cbd46f5 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=c98378e+%5Ecee64ce ---------------------------------------------------------------------------- c98378e: 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 [ Adrien Destugues <pulkomandy@xxxxxxxxx> ] ---------------------------------------------------------------------------- Revision: hrev47865 Commit: c98378e51ae02d8ad6e833c7eb8223a10cbd46f5 URL: http://cgit.haiku-os.org/haiku/commit/?id=c98378e Author: Adrien Destugues <pulkomandy@xxxxxxxxx> Date: Mon Sep 15 12:24:37 2014 UTC ---------------------------------------------------------------------------- 10 files changed, 124 insertions(+), 32 deletions(-) headers/os/net/NetworkRequest.h | 2 +- headers/os/net/UrlContext.h | 12 ++++- src/kits/network/libnetapi/GopherRequest.cpp | 2 +- src/kits/network/libnetapi/HttpRequest.cpp | 26 ++++++++-- src/kits/network/libnetapi/NetworkRequest.cpp | 7 +-- src/kits/network/libnetapi/UrlContext.cpp | 37 ++++++++++++-- src/kits/network/libnetapi/UrlProtocolRoster.cpp | 12 ----- src/kits/network/libnetapi/UrlRequest.cpp | 5 ++ src/tests/kits/net/service/HttpTest.cpp | 52 +++++++++++++++++--- src/tests/kits/net/service/HttpTest.h | 1 + ---------------------------------------------------------------------------- diff --git a/headers/os/net/NetworkRequest.h b/headers/os/net/NetworkRequest.h index 7158dab..1d139c7 100644 --- a/headers/os/net/NetworkRequest.h +++ b/headers/os/net/NetworkRequest.h @@ -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); diff --git a/headers/os/net/UrlContext.h b/headers/os/net/UrlContext.h index eed0813..d561ef5 100644 --- a/headers/os/net/UrlContext.h +++ b/headers/os/net/UrlContext.h @@ -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_ diff --git a/src/kits/network/libnetapi/GopherRequest.cpp b/src/kits/network/libnetapi/GopherRequest.cpp index f78cda7..ac3a127 100644 --- a/src/kits/network/libnetapi/GopherRequest.cpp +++ b/src/kits/network/libnetapi/GopherRequest.cpp @@ -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()); diff --git a/src/kits/network/libnetapi/HttpRequest.cpp b/src/kits/network/libnetapi/HttpRequest.cpp index 8e065c0..a017a21 100644 --- a/src/kits/network/libnetapi/HttpRequest.cpp +++ b/src/kits/network/libnetapi/HttpRequest.cpp @@ -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(); diff --git a/src/kits/network/libnetapi/NetworkRequest.cpp b/src/kits/network/libnetapi/NetworkRequest.cpp index 43e64b0..779bd9c 100644 --- a/src/kits/network/libnetapi/NetworkRequest.cpp +++ b/src/kits/network/libnetapi/NetworkRequest.cpp @@ -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; diff --git a/src/kits/network/libnetapi/UrlContext.cpp b/src/kits/network/libnetapi/UrlContext.cpp index 3818adf..6a9f6e1 100644 --- a/src/kits/network/libnetapi/UrlContext.cpp +++ b/src/kits/network/libnetapi/UrlContext.cpp @@ -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; +} diff --git a/src/kits/network/libnetapi/UrlProtocolRoster.cpp b/src/kits/network/libnetapi/UrlProtocolRoster.cpp index 54e27e2..1284bee 100644 --- a/src/kits/network/libnetapi/UrlProtocolRoster.cpp +++ b/src/kits/network/libnetapi/UrlProtocolRoster.cpp @@ -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, diff --git a/src/kits/network/libnetapi/UrlRequest.cpp b/src/kits/network/libnetapi/UrlRequest.cpp index 35bb8a5..c1e2042 100644 --- a/src/kits/network/libnetapi/UrlRequest.cpp +++ b/src/kits/network/libnetapi/UrlRequest.cpp @@ -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; } diff --git a/src/tests/kits/net/service/HttpTest.cpp b/src/tests/kits/net/service/HttpTest.cpp index d2b0a2c..dd3240f 100644 --- a/src/tests/kits/net/service/HttpTest.cpp +++ b/src/tests/kits/net/service/HttpTest.cpp @@ -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); } diff --git a/src/tests/kits/net/service/HttpTest.h b/src/tests/kits/net/service/HttpTest.h index c8abf55..7401920 100644 --- a/src/tests/kits/net/service/HttpTest.h +++ b/src/tests/kits/net/service/HttpTest.h @@ -24,6 +24,7 @@ public: void UploadTest(); void AuthBasicTest(); void AuthDigestTest(); + void ProxyTest(); static void AddTests(BTestSuite& suite);