summaryrefslogtreecommitdiffstats
path: root/net/http
diff options
context:
space:
mode:
authorarindam@chromium.org <arindam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-23 02:59:02 +0000
committerarindam@chromium.org <arindam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-23 02:59:02 +0000
commit3cd172426ed848f689a3c1363ed7832179ef7919 (patch)
tree56932a311fc046c8d3551b6449066dd1bc3375e8 /net/http
parentd9117760905f5b6b5979cba386a2b8c41fe7699c (diff)
downloadchromium_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.cc67
-rw-r--r--net/http/http_network_transaction.h5
-rw-r--r--net/http/http_network_transaction_unittest.cc109
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());