Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(700)

Unified Diff: net/http/http_network_transaction_unittest.cc

Issue 862133002: Update from https://crrev.com/312398 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/http/http_network_transaction_unittest.cc
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 136791ec5bea3af66d2574b228272ccf6e8becb0..a85e6ea9e9d44841946df4ff17345c44c3e3abe1 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -14,6 +14,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/json/json_writer.h"
+#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
@@ -27,6 +28,7 @@
#include "net/base/elements_upload_data_stream.h"
#include "net/base/load_timing_info.h"
#include "net/base/load_timing_info_test_util.h"
+#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_log_unittest.h"
#include "net/base/request_priority.h"
@@ -41,12 +43,15 @@
#include "net/http/http_auth_handler_digest.h"
#include "net/http/http_auth_handler_mock.h"
#include "net/http/http_auth_handler_ntlm.h"
+#include "net/http/http_basic_state.h"
#include "net/http/http_basic_stream.h"
#include "net/http/http_network_session.h"
#include "net/http/http_network_session_peer.h"
+#include "net/http/http_request_headers.h"
#include "net/http/http_server_properties_impl.h"
#include "net/http/http_stream.h"
#include "net/http/http_stream_factory.h"
+#include "net/http/http_stream_parser.h"
#include "net/http/http_transaction_test_util.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/proxy/proxy_info.h"
@@ -210,6 +215,14 @@ void TestLoadTimingNotReusedWithPac(const net::LoadTimingInfo& load_timing_info,
EXPECT_TRUE(load_timing_info.receive_headers_end.is_null());
}
+void AddWebSocketHeaders(net::HttpRequestHeaders* headers) {
+ headers->SetHeader("Connection", "Upgrade");
+ headers->SetHeader("Upgrade", "websocket");
+ headers->SetHeader("Origin", "http://www.google.com");
+ headers->SetHeader("Sec-WebSocket-Version", "13");
+ headers->SetHeader("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ==");
+}
+
} // namespace
namespace net {
@@ -564,19 +577,18 @@ CaptureGroupNameSocketPool<ParentPool>::CaptureGroupNameSocketPool(
template <>
CaptureGroupNameHttpProxySocketPool::CaptureGroupNameSocketPool(
- HostResolver* host_resolver,
+ HostResolver* /* host_resolver */,
CertVerifier* /* cert_verifier */)
- : HttpProxyClientSocketPool(0, 0, NULL, host_resolver, NULL, NULL, NULL) {
+ : HttpProxyClientSocketPool(0, 0, NULL, NULL, NULL, NULL) {
}
template <>
CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool(
- HostResolver* host_resolver,
+ HostResolver* /* host_resolver */,
CertVerifier* cert_verifier)
: SSLClientSocketPool(0,
0,
NULL,
- host_resolver,
cert_verifier,
NULL,
NULL,
@@ -1842,8 +1854,8 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) {
"HTTP/1.1 301 Moved Permanently",
};
- COMPILE_ASSERT(kNumUnreadBodies == arraysize(kStatusLines),
- forgot_to_update_kStatusLines);
+ static_assert(kNumUnreadBodies == arraysize(kStatusLines),
+ "forgot to update kStatusLines");
for (int i = 0; i < kNumUnreadBodies; ++i)
EXPECT_EQ(kStatusLines[i], response_lines[i]);
@@ -12471,6 +12483,118 @@ class FakeStreamFactory : public HttpStreamFactory {
DISALLOW_COPY_AND_ASSIGN(FakeStreamFactory);
};
+// TODO(ricea): Maybe unify this with the one in
+// url_request_http_job_unittest.cc ?
+class FakeWebSocketBasicHandshakeStream : public WebSocketHandshakeStreamBase {
+ public:
+ FakeWebSocketBasicHandshakeStream(scoped_ptr<ClientSocketHandle> connection,
+ bool using_proxy)
+ : state_(connection.release(), using_proxy) {}
+
+ // Fake implementation of HttpStreamBase methods.
+ // This ends up being quite "real" because this object has to really send data
+ // on the mock socket. It might be easier to use the real implementation, but
+ // the fact that the WebSocket code is not compiled on iOS makes that
+ // difficult.
+ int InitializeStream(const HttpRequestInfo* request_info,
+ RequestPriority priority,
+ const BoundNetLog& net_log,
+ const CompletionCallback& callback) override {
+ state_.Initialize(request_info, priority, net_log, callback);
+ return OK;
+ }
+
+ int SendRequest(const HttpRequestHeaders& request_headers,
+ HttpResponseInfo* response,
+ const CompletionCallback& callback) override {
+ return parser()->SendRequest(state_.GenerateRequestLine(), request_headers,
+ response, callback);
+ }
+
+ int ReadResponseHeaders(const CompletionCallback& callback) override {
+ return parser()->ReadResponseHeaders(callback);
+ }
+
+ int ReadResponseBody(IOBuffer* buf,
+ int buf_len,
+ const CompletionCallback& callback) override {
+ NOTREACHED();
+ return ERR_IO_PENDING;
+ }
+
+ void Close(bool not_reusable) override {
+ if (parser())
+ parser()->Close(true);
+ }
+
+ bool IsResponseBodyComplete() const override {
+ NOTREACHED();
+ return false;
+ }
+
+ bool CanFindEndOfResponse() const override {
+ return parser()->CanFindEndOfResponse();
+ }
+
+ bool IsConnectionReused() const override {
+ NOTREACHED();
+ return false;
+ }
+ void SetConnectionReused() override { NOTREACHED(); }
+
+ bool IsConnectionReusable() const override {
+ NOTREACHED();
+ return false;
+ }
+
+ int64 GetTotalReceivedBytes() const override {
+ NOTREACHED();
+ return 0;
+ }
+
+ bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override {
+ NOTREACHED();
+ return false;
+ }
+
+ void GetSSLInfo(SSLInfo* ssl_info) override { NOTREACHED(); }
+
+ void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override {
+ NOTREACHED();
+ }
+
+ bool IsSpdyHttpStream() const override {
+ NOTREACHED();
+ return false;
+ }
+
+ void Drain(HttpNetworkSession* session) override { NOTREACHED(); }
+
+ void SetPriority(RequestPriority priority) override { NOTREACHED(); }
+
+ UploadProgress GetUploadProgress() const override {
+ NOTREACHED();
+ return UploadProgress();
+ }
+
+ HttpStream* RenewStreamForAuth() override {
+ NOTREACHED();
+ return nullptr;
+ }
+
+ // Fake implementation of WebSocketHandshakeStreamBase method(s)
+ scoped_ptr<WebSocketStream> Upgrade() override {
+ NOTREACHED();
+ return scoped_ptr<WebSocketStream>();
+ }
+
+ private:
+ HttpStreamParser* parser() const { return state_.parser(); }
+ HttpBasicState state_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeWebSocketBasicHandshakeStream);
+};
+
// TODO(yhirano): Split this class out into a net/websockets file, if it is
// worth doing.
class FakeWebSocketStreamCreateHelper :
@@ -12479,8 +12603,8 @@ class FakeWebSocketStreamCreateHelper :
WebSocketHandshakeStreamBase* CreateBasicStream(
scoped_ptr<ClientSocketHandle> connection,
bool using_proxy) override {
- NOTREACHED();
- return NULL;
+ return new FakeWebSocketBasicHandshakeStream(connection.Pass(),
+ using_proxy);
}
WebSocketHandshakeStreamBase* CreateSpdyStream(
@@ -13254,4 +13378,188 @@ TEST_P(HttpNetworkTransactionTest, PostIgnoresPartial400HeadersAfterReset) {
EXPECT_TRUE(response == NULL);
}
+// Verify that proxy headers are not sent to the destination server when
+// establishing a tunnel for a secure WebSocket connection.
+TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWssTunnel) {
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("wss://www.google.com/");
+ AddWebSocketHeaders(&request.extra_headers);
+
+ // Configure against proxy server "myproxy:70".
+ session_deps_.proxy_service.reset(
+ ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+ // Since a proxy is configured, try to establish a tunnel.
+ MockWrite data_writes[] = {
+ MockWrite(
+ "CONNECT www.google.com:443 HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n"),
+
+ // After calling trans->RestartWithAuth(), this is the request we should
+ // be issuing -- the final header line contains the credentials.
+ MockWrite(
+ "CONNECT www.google.com:443 HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n"
+ "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
+
+ MockWrite(
+ "GET / HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Connection: Upgrade\r\n"
+ "Upgrade: websocket\r\n"
+ "Origin: http://www.google.com\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n"),
+ };
+
+ // The proxy responds to the connect with a 407, using a persistent
+ // connection.
+ MockRead data_reads[] = {
+ // No credentials.
+ MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
+ MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
+ MockRead("Proxy-Connection: close\r\n\r\n"),
+
+ MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
+
+ MockRead("HTTP/1.1 101 Switching Protocols\r\n"),
+ MockRead("Upgrade: websocket\r\n"),
+ MockRead("Connection: Upgrade\r\n"),
+ MockRead("Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"),
+ };
+
+ StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes,
+ arraysize(data_writes));
+ session_deps_.socket_factory->AddSocketDataProvider(&data);
+ SSLSocketDataProvider ssl(ASYNC, OK);
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+
+ scoped_ptr<HttpTransaction> trans(
+ new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ FakeWebSocketStreamCreateHelper websocket_stream_create_helper;
+ trans->SetWebSocketHandshakeStreamCreateHelper(
+ &websocket_stream_create_helper);
+
+ {
+ TestCompletionCallback callback;
+
+ int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+ }
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response);
+ ASSERT_TRUE(response->headers.get());
+ EXPECT_EQ(407, response->headers->response_code());
+
+ {
+ TestCompletionCallback callback;
+
+ int rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar),
+ callback.callback());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+ }
+
+ response = trans->GetResponseInfo();
+ ASSERT_TRUE(response);
+ ASSERT_TRUE(response->headers.get());
+
+ EXPECT_EQ(101, response->headers->response_code());
+
+ trans.reset();
+ session->CloseAllConnections();
+}
+
+// Verify that proxy headers are not sent to the destination server when
+// establishing a tunnel for an insecure WebSocket connection.
+// This requires the authentication info to be injected into the auth cache
+// due to crbug.com/395064
+// TODO(ricea): Change to use a 407 response once issue 395064 is fixed.
+TEST_P(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWsTunnel) {
+ HttpRequestInfo request;
+ request.method = "GET";
+ request.url = GURL("ws://www.google.com/");
+ AddWebSocketHeaders(&request.extra_headers);
+
+ // Configure against proxy server "myproxy:70".
+ session_deps_.proxy_service.reset(
+ ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
+
+ scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+ MockWrite data_writes[] = {
+ // Try to establish a tunnel for the WebSocket connection, with
+ // credentials. Because WebSockets have a separate set of socket pools,
+ // they cannot and will not use the same TCP/IP connection as the
+ // preflight HTTP request.
+ MockWrite(
+ "CONNECT www.google.com:80 HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Proxy-Connection: keep-alive\r\n"
+ "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
+
+ MockWrite(
+ "GET / HTTP/1.1\r\n"
+ "Host: www.google.com\r\n"
+ "Connection: Upgrade\r\n"
+ "Upgrade: websocket\r\n"
+ "Origin: http://www.google.com\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n"),
+ };
+
+ MockRead data_reads[] = {
+ // HTTP CONNECT with credentials.
+ MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
+
+ // WebSocket connection established inside tunnel.
+ MockRead("HTTP/1.1 101 Switching Protocols\r\n"),
+ MockRead("Upgrade: websocket\r\n"),
+ MockRead("Connection: Upgrade\r\n"),
+ MockRead("Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"),
+ };
+
+ StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes,
+ arraysize(data_writes));
+ session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+ session->http_auth_cache()->Add(
+ GURL("http://myproxy:70/"), "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC,
+ "Basic realm=MyRealm1", AuthCredentials(kFoo, kBar), "/");
+
+ scoped_ptr<HttpTransaction> trans(
+ new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+ FakeWebSocketStreamCreateHelper websocket_stream_create_helper;
+ trans->SetWebSocketHandshakeStreamCreateHelper(
+ &websocket_stream_create_helper);
+
+ TestCompletionCallback callback;
+
+ int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+ EXPECT_EQ(ERR_IO_PENDING, rv);
+
+ rv = callback.WaitForResult();
+ EXPECT_EQ(OK, rv);
+
+ const HttpResponseInfo* response = trans->GetResponseInfo();
+ ASSERT_TRUE(response);
+ ASSERT_TRUE(response->headers.get());
+
+ EXPECT_EQ(101, response->headers->response_code());
+
+ trans.reset();
+ session->CloseAllConnections();
+}
+
} // namespace net

Powered by Google App Engine
This is Rietveld 408576698