diff options
author | arindam@chromium.org <arindam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-23 02:59:02 +0000 |
---|---|---|
committer | arindam@chromium.org <arindam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-23 02:59:02 +0000 |
commit | 3cd172426ed848f689a3c1363ed7832179ef7919 (patch) | |
tree | 56932a311fc046c8d3551b6449066dd1bc3375e8 /net/http | |
parent | d9117760905f5b6b5979cba386a2b8c41fe7699c (diff) | |
download | chromium_src-3cd172426ed848f689a3c1363ed7832179ef7919.zip chromium_src-3cd172426ed848f689a3c1363ed7832179ef7919.tar.gz chromium_src-3cd172426ed848f689a3c1363ed7832179ef7919.tar.bz2 |
Adding socks4 support for chromium. tested for windows and linux.
includes socks4, socks4a
TEST=change proxy settings to use proxy and set only the socks proxy fields (others must remain blank). Use CCProxy for windows or 'ssh -D' for linux / cygwin if trying it via localhost.
Browser should successfully open both http and https URLs.
tests are also at HttpNetworkTransactionTest.SOCKS*
BUG=none
Review URL: http://codereview.chromium.org/113811
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19005 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http')
-rw-r--r-- | net/http/http_network_transaction.cc | 67 | ||||
-rw-r--r-- | net/http/http_network_transaction.h | 5 | ||||
-rw-r--r-- | net/http/http_network_transaction_unittest.cc | 109 |
3 files changed, 172 insertions, 9 deletions
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 06bba2b..a6b5fe3 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -26,6 +26,7 @@ #include "net/http/http_response_headers.h" #include "net/http/http_util.h" #include "net/socket/client_socket_factory.h" +#include "net/socket/socks_client_socket.h" #include "net/socket/ssl_client_socket.h" using base::Time; @@ -141,6 +142,7 @@ HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session, using_ssl_(false), using_proxy_(false), using_tunnel_(false), + using_socks_proxy_(false), establishing_tunnel_(false), reading_body_from_socket_(false), request_headers_(new RequestHeaders()), @@ -448,6 +450,15 @@ int HttpNetworkTransaction::DoLoop(int result) { rv = DoInitConnectionComplete(rv); TRACE_EVENT_END("http.init_conn", request_, request_->url.spec()); break; + case STATE_SOCKS_CONNECT: + DCHECK_EQ(OK, rv); + TRACE_EVENT_BEGIN("http.socks_connect", request_, request_->url.spec()); + rv = DoSOCKSConnect(); + break; + case STATE_SOCKS_CONNECT_COMPLETE: + rv = DoSOCKSConnectComplete(rv); + TRACE_EVENT_END("http.socks_connect", request_, request_->url.spec()); + break; case STATE_SSL_CONNECT: DCHECK_EQ(OK, rv); TRACE_EVENT_BEGIN("http.ssl_connect", request_, request_->url.spec()); @@ -531,11 +542,10 @@ int HttpNetworkTransaction::DoResolveProxy() { int HttpNetworkTransaction::DoResolveProxyComplete(int result) { next_state_ = STATE_INIT_CONNECTION; - // Since we only support HTTP proxies or DIRECT connections, remove - // any other type of proxy from the list (i.e. SOCKS). - // Supporting SOCKS is issue http://crbug.com/469. + // Remove unsupported proxies (like SOCKS5) from the list. proxy_info_.RemoveProxiesWithoutScheme( - ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP); + ProxyServer::SCHEME_DIRECT | ProxyServer::SCHEME_HTTP | + ProxyServer::SCHEME_SOCKS4); pac_request_ = NULL; @@ -552,15 +562,17 @@ int HttpNetworkTransaction::DoInitConnection() { next_state_ = STATE_INIT_CONNECTION_COMPLETE; using_ssl_ = request_->url.SchemeIs("https"); - using_proxy_ = !proxy_info_.is_direct() && !using_ssl_; - using_tunnel_ = !proxy_info_.is_direct() && using_ssl_; + using_socks_proxy_ = !proxy_info_.is_direct() && + proxy_info_.proxy_server().is_socks(); + using_proxy_ = !proxy_info_.is_direct() && !using_ssl_ && !using_socks_proxy_; + using_tunnel_ = !proxy_info_.is_direct() && using_ssl_ && !using_socks_proxy_; // Build the string used to uniquely identify connections of this type. // Determine the host and port to connect to. std::string connection_group; std::string host; int port; - if (using_proxy_ || using_tunnel_) { + if (using_proxy_ || using_tunnel_ || using_socks_proxy_) { ProxyServer proxy_server = proxy_info_.proxy_server(); connection_group = "proxy/" + proxy_server.ToURI() + "/"; host = proxy_server.HostNoBrackets(); @@ -569,7 +581,7 @@ int HttpNetworkTransaction::DoInitConnection() { host = request_->url.HostNoBrackets(); port = request_->url.EffectiveIntPort(); } - if (!using_proxy_) + if (!using_proxy_ && !using_socks_proxy_) connection_group.append(request_->url.GetOrigin().spec()); DCHECK(!connection_group.empty()); @@ -608,7 +620,9 @@ int HttpNetworkTransaction::DoInitConnectionComplete(int result) { // Now we have a TCP connected socket. Perform other connection setup as // needed. LogTCPConnectedMetrics(); - if (using_ssl_ && !using_tunnel_) { + if (using_socks_proxy_) + next_state_ = STATE_SOCKS_CONNECT; + else if (using_ssl_ && !using_tunnel_) { next_state_ = STATE_SSL_CONNECT; } else { next_state_ = STATE_WRITE_HEADERS; @@ -620,6 +634,41 @@ int HttpNetworkTransaction::DoInitConnectionComplete(int result) { return OK; } +int HttpNetworkTransaction::DoSOCKSConnect() { + DCHECK(using_socks_proxy_); + DCHECK(!using_proxy_); + DCHECK(!using_tunnel_); + + next_state_ = STATE_SOCKS_CONNECT_COMPLETE; + + // Add a SOCKS connection on top of our existing transport socket. + ClientSocket* s = connection_.release_socket(); + HostResolver::RequestInfo req_info(request_->url.HostNoBrackets(), + request_->url.EffectiveIntPort()); + req_info.set_referrer(request_->referrer); + + s = new SOCKSClientSocket(s, req_info, session_->host_resolver()); + connection_.set_socket(s); + return connection_.socket()->Connect(&io_callback_); +} + +int HttpNetworkTransaction::DoSOCKSConnectComplete(int result) { + DCHECK(using_socks_proxy_); + DCHECK(!using_proxy_); + DCHECK(!using_tunnel_); + + if (result == OK) { + if (using_ssl_) { + next_state_ = STATE_SSL_CONNECT; + } else { + next_state_ = STATE_WRITE_HEADERS; + } + } else { + result = ReconsiderProxyAfterError(result); + } + return result; +} + int HttpNetworkTransaction::DoSSLConnect() { next_state_ = STATE_SSL_CONNECT_COMPLETE; diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index 45bef58..bdb8e1b 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -99,6 +99,8 @@ class HttpNetworkTransaction : public HttpTransaction { STATE_RESOLVE_PROXY_COMPLETE, STATE_INIT_CONNECTION, STATE_INIT_CONNECTION_COMPLETE, + STATE_SOCKS_CONNECT, + STATE_SOCKS_CONNECT_COMPLETE, STATE_SSL_CONNECT, STATE_SSL_CONNECT_COMPLETE, STATE_WRITE_HEADERS, @@ -128,6 +130,8 @@ class HttpNetworkTransaction : public HttpTransaction { int DoResolveProxyComplete(int result); int DoInitConnection(); int DoInitConnectionComplete(int result); + int DoSOCKSConnect(); + int DoSOCKSConnectComplete(int result); int DoSSLConnect(); int DoSSLConnectComplete(int result); int DoWriteHeaders(); @@ -305,6 +309,7 @@ class HttpNetworkTransaction : public HttpTransaction { bool using_ssl_; // True if handling a HTTPS request bool using_proxy_; // True if using a proxy for HTTP (not HTTPS) bool using_tunnel_; // True if using a tunnel for HTTPS + bool using_socks_proxy_; // True if using a SOCKS proxy // True while establishing a tunnel. This allows the HTTP CONNECT // request/response to reuse the STATE_WRITE_HEADERS, diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc index df889cd..57ea425 100644 --- a/net/http/http_network_transaction_unittest.cc +++ b/net/http/http_network_transaction_unittest.cc @@ -3006,6 +3006,115 @@ TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) { EXPECT_EQ(OK, rv); } +TEST_F(HttpNetworkTransactionTest, SOCKS4_HTTP_GET) { + SessionDependencies session_deps; + session_deps.proxy_service.reset(CreateFixedProxyService( + "socks4://myproxy:1080")); + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction( + CreateSession(&session_deps), + &session_deps.socket_factory)); + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("http://www.google.com/"); + request.load_flags = 0; + + char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 }; + char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; + + MockWrite data_writes[] = { + MockWrite(true, write_buffer, 9), + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n") + }; + + MockRead data_reads[] = { + MockWrite(true, read_buffer, 8), + MockRead("HTTP/1.0 200 OK\r\n"), + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), + MockRead("Payload"), + MockRead(false, OK) + }; + + StaticMockSocket data(data_reads, data_writes); + session_deps.socket_factory.AddMockSocket(&data); + + TestCompletionCallback callback; + + int rv = trans->Start(&request, &callback); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback.WaitForResult(); + EXPECT_EQ(OK, rv); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + EXPECT_FALSE(response == NULL); + + std::string response_text; + rv = ReadTransaction(trans.get(), &response_text); + EXPECT_EQ(OK, rv); + EXPECT_EQ("Payload", response_text); +} + +TEST_F(HttpNetworkTransactionTest, SOCKS4_SSL_GET) { + SessionDependencies session_deps; + session_deps.proxy_service.reset(CreateFixedProxyService( + "socks4://myproxy:1080")); + + scoped_ptr<HttpTransaction> trans( + new HttpNetworkTransaction( + CreateSession(&session_deps), + &session_deps.socket_factory)); + + HttpRequestInfo request; + request.method = "GET"; + request.url = GURL("https://www.google.com/"); + request.load_flags = 0; + + unsigned char write_buffer[] = { 0x04, 0x01, 0x01, 0xBB, 127, 0, 0, 1, 0 }; + unsigned char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; + + MockWrite data_writes[] = { + MockWrite(true, reinterpret_cast<char*>(write_buffer), 9), + MockWrite("GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + "Connection: keep-alive\r\n\r\n") + }; + + MockRead data_reads[] = { + MockWrite(true, reinterpret_cast<char*>(read_buffer), 8), + MockRead("HTTP/1.0 200 OK\r\n"), + MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), + MockRead("Payload"), + MockRead(false, OK) + }; + + StaticMockSocket data(data_reads, data_writes); + session_deps.socket_factory.AddMockSocket(&data); + + MockSSLSocket ssl(true, OK); + session_deps.socket_factory.AddMockSSLSocket(&ssl); + + TestCompletionCallback callback; + + int rv = trans->Start(&request, &callback); + EXPECT_EQ(ERR_IO_PENDING, rv); + + rv = callback.WaitForResult(); + EXPECT_EQ(OK, rv); + + const HttpResponseInfo* response = trans->GetResponseInfo(); + EXPECT_FALSE(response == NULL); + + std::string response_text; + rv = ReadTransaction(trans.get(), &response_text); + EXPECT_EQ(OK, rv); + EXPECT_EQ("Payload", response_text); +} + TEST_F(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) { scoped_refptr<RuleBasedHostMapper> host_mapper(new RuleBasedHostMapper()); ScopedHostMapper scoped_host_mapper(host_mapper.get()); |