blob: dce87359562dc41062f6ae2719ef8b6c2ac74631 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "build/build_config.h"
#if defined(OS_WIN)
#include <windows.h>
#include <shlobj.h>
#endif
#include <algorithm>
#include <string>
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/format_macros.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "net/base/cert_test_util.h"
#include "net/base/ev_root_ca_metadata.h"
#include "net/base/load_flags.h"
#include "net/base/mock_host_resolver.h"
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_log_unittest.h"
#include "net/base/net_module.h"
#include "net/base/net_util.h"
#include "net/base/ssl_connection_status_flags.h"
#include "net/base/test_data_directory.h"
#include "net/base/test_root_certs.h"
#include "net/base/upload_bytes_element_reader.h"
#include "net/base/upload_data_stream.h"
#include "net/base/upload_file_element_reader.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store_test_helpers.h"
#include "net/disk_cache/disk_cache.h"
#include "net/ftp/ftp_network_layer.h"
#include "net/http/http_cache.h"
#include "net/http/http_network_layer.h"
#include "net/http/http_network_session.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/ocsp/nss_ocsp.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/ssl_client_socket.h"
#include "net/test/test_server.h"
#include "net/url_request/ftp_protocol_handler.h"
#include "net/url_request/static_http_user_agent_settings.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_file_dir_job.h"
#include "net/url_request/url_request_http_job.h"
#include "net/url_request/url_request_job_factory_impl.h"
#include "net/url_request/url_request_redirect_job.h"
#include "net/url_request/url_request_test_job.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#if defined(OS_WIN)
#include "base/win/scoped_com_initializer.h"
#include "base/win/windows_version.h"
#endif
using base::Time;
namespace net {
namespace {
const string16 kChrome(ASCIIToUTF16("chrome"));
const string16 kSecret(ASCIIToUTF16("secret"));
const string16 kUser(ASCIIToUTF16("user"));
base::StringPiece TestNetResourceProvider(int key) {
return "header";
}
// Do a case-insensitive search through |haystack| for |needle|.
bool ContainsString(const std::string& haystack, const char* needle) {
std::string::const_iterator it =
std::search(haystack.begin(),
haystack.end(),
needle,
needle + strlen(needle),
base::CaseInsensitiveCompare<char>());
return it != haystack.end();
}
void FillBuffer(char* buffer, size_t len) {
static bool called = false;
if (!called) {
called = true;
int seed = static_cast<int>(Time::Now().ToInternalValue());
srand(seed);
}
for (size_t i = 0; i < len; i++) {
buffer[i] = static_cast<char>(rand());
if (!buffer[i])
buffer[i] = 'g';
}
}
UploadDataStream* CreateSimpleUploadData(const char* data) {
scoped_ptr<UploadElementReader> reader(
new UploadBytesElementReader(data, strlen(data)));
return UploadDataStream::CreateWithReader(reader.Pass(), 0);
}
// Verify that the SSLInfo of a successful SSL connection has valid values.
void CheckSSLInfo(const SSLInfo& ssl_info) {
// Allow ChromeFrame fake SSLInfo to get through.
if (ssl_info.cert.get() &&
ssl_info.cert.get()->issuer().GetDisplayName() == "Chrome Internal") {
// -1 means unknown.
EXPECT_EQ(ssl_info.security_bits, -1);
return;
}
// -1 means unknown. 0 means no encryption.
EXPECT_GT(ssl_info.security_bits, 0);
// The cipher suite TLS_NULL_WITH_NULL_NULL (0) must not be negotiated.
int cipher_suite = SSLConnectionStatusToCipherSuite(
ssl_info.connection_status);
EXPECT_NE(0, cipher_suite);
}
bool FingerprintsEqual(const HashValueVector& a, const HashValueVector& b) {
size_t size = a.size();
if (size != b.size())
return false;
for (size_t i = 0; i < size; ++i) {
if (!a[i].Equals(b[i]))
return false;
}
return true;
}
// A network delegate that allows the user to choose a subset of request stages
// to block in. When blocking, the delegate can do one of the following:
// * synchronously return a pre-specified error code, or
// * asynchronously return that value via an automatically called callback,
// or
// * block and wait for the user to do a callback.
// Additionally, the user may also specify a redirect URL -- then each request
// with the current URL different from the redirect target will be redirected
// to that target, in the on-before-URL-request stage, independent of whether
// the delegate blocks in ON_BEFORE_URL_REQUEST or not.
class BlockingNetworkDelegate : public TestNetworkDelegate {
public:
// Stages in which the delegate can block.
enum Stage {
NOT_BLOCKED = 0,
ON_BEFORE_URL_REQUEST = 1 << 0,
ON_BEFORE_SEND_HEADERS = 1 << 1,
ON_HEADERS_RECEIVED = 1 << 2,
ON_AUTH_REQUIRED = 1 << 3
};
// Behavior during blocked stages. During other stages, just
// returns net::OK or NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION.
enum BlockMode {
SYNCHRONOUS, // No callback, returns specified return values.
AUTO_CALLBACK, // |this| posts a task to run the callback using the
// specified return codes.
USER_CALLBACK, // User takes care of doing a callback. |retval_| and
// |auth_retval_| are ignored. In every blocking stage the
// message loop is quit.
};
// Creates a delegate which does not block at all.
explicit BlockingNetworkDelegate(BlockMode block_mode);
// For users to trigger a callback returning |response|.
// Side-effects: resets |stage_blocked_for_callback_| and stored callbacks.
// Only call if |block_mode_| == USER_CALLBACK.
void DoCallback(int response);
void DoAuthCallback(NetworkDelegate::AuthRequiredResponse response);
// Setters.
void set_retval(int retval) {
ASSERT_NE(USER_CALLBACK, block_mode_);
ASSERT_NE(ERR_IO_PENDING, retval);
ASSERT_NE(OK, retval);
retval_ = retval;
}
// If |auth_retval| == AUTH_REQUIRED_RESPONSE_SET_AUTH, then
// |auth_credentials_| will be passed with the response.
void set_auth_retval(AuthRequiredResponse auth_retval) {
ASSERT_NE(USER_CALLBACK, block_mode_);
ASSERT_NE(AUTH_REQUIRED_RESPONSE_IO_PENDING, auth_retval);
auth_retval_ = auth_retval;
}
void set_auth_credentials(const AuthCredentials& auth_credentials) {
auth_credentials_ = auth_credentials;
}
void set_redirect_url(const GURL& url) {
redirect_url_ = url;
}
void set_block_on(int block_on) {
block_on_ = block_on;
}
// Allows the user to check in which state did we block.
Stage stage_blocked_for_callback() const {
EXPECT_EQ(USER_CALLBACK, block_mode_);
return stage_blocked_for_callback_;
}
private:
void RunCallback(int response, const CompletionCallback& callback);
void RunAuthCallback(AuthRequiredResponse response,
const AuthCallback& callback);
// TestNetworkDelegate implementation.
virtual int OnBeforeURLRequest(URLRequest* request,
const CompletionCallback& callback,
GURL* new_url) override;
virtual int OnBeforeSendHeaders(URLRequest* request,
const CompletionCallback& callback,
HttpRequestHeaders* headers) override;
virtual int OnHeadersReceived(
URLRequest* request,
const CompletionCallback& callback,
const HttpResponseHeaders* original_response_headers,
scoped_refptr<HttpResponseHeaders>* override_response_headers) override;
virtual NetworkDelegate::AuthRequiredResponse OnAuthRequired(
URLRequest* request,
const AuthChallengeInfo& auth_info,
const AuthCallback& callback,
AuthCredentials* credentials) override;
// Resets the callbacks and |stage_blocked_for_callback_|.
void Reset();
// Checks whether we should block in |stage|. If yes, returns an error code
// and optionally sets up callback based on |block_mode_|. If no, returns OK.
int MaybeBlockStage(Stage stage, const CompletionCallback& callback);
// Configuration parameters, can be adjusted by public methods:
const BlockMode block_mode_;
// Values returned on blocking stages when mode is SYNCHRONOUS or
// AUTO_CALLBACK. For USER_CALLBACK these are set automatically to IO_PENDING.
int retval_; // To be returned in non-auth stages.
AuthRequiredResponse auth_retval_;
GURL redirect_url_; // Used if non-empty.
int block_on_; // Bit mask: in which stages to block.
// |auth_credentials_| will be copied to |*target_auth_credential_| on
// callback.
AuthCredentials auth_credentials_;
AuthCredentials* target_auth_credentials_;
// Internal variables, not set by not the user:
// Last blocked stage waiting for user callback (unused if |block_mode_| !=
// USER_CALLBACK).
Stage stage_blocked_for_callback_;
// Callback objects stored during blocking stages.
CompletionCallback callback_;
AuthCallback auth_callback_;
base::WeakPtrFactory<BlockingNetworkDelegate> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(BlockingNetworkDelegate);
};
BlockingNetworkDelegate::BlockingNetworkDelegate(BlockMode block_mode)
: block_mode_(block_mode),
retval_(OK),
auth_retval_(AUTH_REQUIRED_RESPONSE_NO_ACTION),
block_on_(0),
target_auth_credentials_(NULL),
stage_blocked_for_callback_(NOT_BLOCKED),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
}
void BlockingNetworkDelegate::DoCallback(int response) {
ASSERT_EQ(USER_CALLBACK, block_mode_);
ASSERT_NE(NOT_BLOCKED, stage_blocked_for_callback_);
ASSERT_NE(ON_AUTH_REQUIRED, stage_blocked_for_callback_);
CompletionCallback callback = callback_;
Reset();
RunCallback(response, callback);
}
void BlockingNetworkDelegate::DoAuthCallback(
NetworkDelegate::AuthRequiredResponse response) {
ASSERT_EQ(USER_CALLBACK, block_mode_);
ASSERT_EQ(ON_AUTH_REQUIRED, stage_blocked_for_callback_);
AuthCallback auth_callback = auth_callback_;
Reset();
RunAuthCallback(response, auth_callback);
}
void BlockingNetworkDelegate::RunCallback(int response,
const CompletionCallback& callback) {
callback.Run(response);
}
void BlockingNetworkDelegate::RunAuthCallback(AuthRequiredResponse response,
const AuthCallback& callback) {
if (auth_retval_ == AUTH_REQUIRED_RESPONSE_SET_AUTH) {
ASSERT_TRUE(target_auth_credentials_ != NULL);
*target_auth_credentials_ = auth_credentials_;
}
callback.Run(response);
}
int BlockingNetworkDelegate::OnBeforeURLRequest(
URLRequest* request,
const CompletionCallback& callback,
GURL* new_url) {
if (redirect_url_ == request->url())
return OK; // We've already seen this request and redirected elsewhere.
TestNetworkDelegate::OnBeforeURLRequest(request, callback, new_url);
if (!redirect_url_.is_empty())
*new_url = redirect_url_;
return MaybeBlockStage(ON_BEFORE_URL_REQUEST, callback);
}
int BlockingNetworkDelegate::OnBeforeSendHeaders(
URLRequest* request,
const CompletionCallback& callback,
HttpRequestHeaders* headers) {
TestNetworkDelegate::OnBeforeSendHeaders(request, callback, headers);
return MaybeBlockStage(ON_BEFORE_SEND_HEADERS, callback);
}
int BlockingNetworkDelegate::OnHeadersReceived(
URLRequest* request,
const CompletionCallback& callback,
const HttpResponseHeaders* original_response_headers,
scoped_refptr<HttpResponseHeaders>* override_response_headers) {
TestNetworkDelegate::OnHeadersReceived(
request, callback, original_response_headers,
override_response_headers);
return MaybeBlockStage(ON_HEADERS_RECEIVED, callback);
}
NetworkDelegate::AuthRequiredResponse BlockingNetworkDelegate::OnAuthRequired(
URLRequest* request,
const AuthChallengeInfo& auth_info,
const AuthCallback& callback,
AuthCredentials* credentials) {
TestNetworkDelegate::OnAuthRequired(request, auth_info, callback,
credentials);
// Check that the user has provided callback for the previous blocked stage.
EXPECT_EQ(NOT_BLOCKED, stage_blocked_for_callback_);
if ((block_on_ & ON_AUTH_REQUIRED) == 0) {
return AUTH_REQUIRED_RESPONSE_NO_ACTION;
}
target_auth_credentials_ = credentials;
switch (block_mode_) {
case SYNCHRONOUS:
if (auth_retval_ == AUTH_REQUIRED_RESPONSE_SET_AUTH)
*target_auth_credentials_ = auth_credentials_;
return auth_retval_;
case AUTO_CALLBACK:
MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&BlockingNetworkDelegate::RunAuthCallback,
weak_factory_.GetWeakPtr(), auth_retval_, callback));
return AUTH_REQUIRED_RESPONSE_IO_PENDING;
case USER_CALLBACK:
auth_callback_ = callback;
stage_blocked_for_callback_ = ON_AUTH_REQUIRED;
MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
return AUTH_REQUIRED_RESPONSE_IO_PENDING;
}
NOTREACHED();
return AUTH_REQUIRED_RESPONSE_NO_ACTION; // Dummy value.
}
void BlockingNetworkDelegate::Reset() {
EXPECT_NE(NOT_BLOCKED, stage_blocked_for_callback_);
stage_blocked_for_callback_ = NOT_BLOCKED;
callback_.Reset();
auth_callback_.Reset();
}
int BlockingNetworkDelegate::MaybeBlockStage(
BlockingNetworkDelegate::Stage stage,
const CompletionCallback& callback) {
// Check that the user has provided callback for the previous blocked stage.
EXPECT_EQ(NOT_BLOCKED, stage_blocked_for_callback_);
if ((block_on_ & stage) == 0) {
return OK;
}
switch (block_mode_) {
case SYNCHRONOUS:
EXPECT_NE(OK, retval_);
return retval_;
case AUTO_CALLBACK:
MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&BlockingNetworkDelegate::RunCallback,
weak_factory_.GetWeakPtr(), retval_, callback));
return ERR_IO_PENDING;
case USER_CALLBACK:
callback_ = callback;
stage_blocked_for_callback_ = stage;
MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure());
return ERR_IO_PENDING;
}
NOTREACHED();
return 0;
}
class TestURLRequestContextWithProxy : public TestURLRequestContext {
public:
// Does not own |delegate|.
TestURLRequestContextWithProxy(const std::string& proxy,
NetworkDelegate* delegate)
: TestURLRequestContext(true) {
context_storage_.set_proxy_service(ProxyService::CreateFixed(proxy));
set_network_delegate(delegate);
Init();
}
virtual ~TestURLRequestContextWithProxy() {}
};
} // namespace
// Inherit PlatformTest since we require the autorelease pool on Mac OS X.
class URLRequestTest : public PlatformTest {
public:
URLRequestTest() : default_context_(true) {
default_context_.set_network_delegate(&default_network_delegate_);
default_context_.Init();
}
// Adds the TestJobInterceptor to the default context.
TestJobInterceptor* AddTestInterceptor() {
TestJobInterceptor* interceptor = new TestJobInterceptor();
default_context_.set_job_factory(&job_factory_);
job_factory_.AddInterceptor(interceptor);
return interceptor;
}
protected:
TestNetworkDelegate default_network_delegate_; // Must outlive URLRequest.
URLRequestJobFactoryImpl job_factory_;
TestURLRequestContext default_context_;
};
TEST_F(URLRequestTest, AboutBlankTest) {
TestDelegate d;
{
URLRequest r(GURL("about:blank"), &d, &default_context_);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_TRUE(!r.is_pending());
EXPECT_FALSE(d.received_data_before_response());
EXPECT_EQ(d.bytes_received(), 0);
EXPECT_EQ("", r.GetSocketAddress().host());
EXPECT_EQ(0, r.GetSocketAddress().port());
}
}
TEST_F(URLRequestTest, DataURLImageTest) {
TestDelegate d;
{
// Use our nice little Chrome logo.
URLRequest r(GURL(
"data:image/png;base64,"
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADVklEQVQ4jX2TfUwUBBjG3"
"w1y+HGcd9dxhXR8T4awOccJGgOSWclHImznLkTlSw0DDQXkrmgYgbUYnlQTqQxIEVxitD"
"5UMCATRA1CEEg+Qjw3bWDxIauJv/5oumqs39/P827vnucRmYN0gyF01GI5MpCVdW0gO7t"
"vNC+vqSEtbZefk5NuLv1jdJ46p/zw0HeH4+PHr3h7c1mjoV2t5rKzMx1+fg9bAgK6zHq9"
"cU5z+LpA3xOtx34+vTeT21onRuzssC3zxbbSwC13d/pFuC7CkIMDxQpF7r/MWq12UctI1"
"dWWm99ypqSYmRUBdKem8MkrO/kgaTt1O7YzlpzE5GIVd0WYUqt57yWf2McHTObYPbVD+Z"
"wbtlLTVMZ3BW+TnLyXLaWtmEq6WJVbT3HBh3Svj2HQQcm43XwmtoYM6vVKleh0uoWvnzW"
"3v3MpidruPTQPf0bia7sJOtBM0ufTWNvus/nkDFHF9ZS+uYVjRUasMeHUmyLYtcklTvzW"
"GFZnNOXczThvpKIzjcahSqIzkvDLayDq6D3eOjtBbNUEIZYyqsvj4V4wY92eNJ4IoyhTb"
"xXX1T5xsV9tm9r4TQwHLiZw/pdDZJea8TKmsmR/K0uLh/GwnCHghTja6lPhphezPfO5/5"
"MrVvMzNaI3+ERHfrFzPKQukrQGI4d/3EFD/3E2mVNYvi4at7CXWREaxZGD+3hg28zD3gV"
"Md6q5c8GdosynKmSeRuGzpjyl1/9UDGtPR5HeaKT8Wjo17WXk579BXVUhN64ehF9fhRtq"
"/uxxZKzNiZFGD0wRC3NFROZ5mwIPL/96K/rKMMLrIzF9uhHr+/sYH7DAbwlgC4J+R2Z7F"
"Ux1qLnV7MGF40smVSoJ/jvHRfYhQeUJd/SnYtGWhPHR0Sz+GE2F2yth0B36Vcz2KpnufB"
"JbsysjjW4kblBUiIjiURUWqJY65zxbnTy57GQyH58zgy0QBtTQv5gH15XMdKkYu+TGaJM"
"nlm2O34uI4b9tflqp1+QEFGzoW/ulmcofcpkZCYJhDfSpme7QcrHa+Xfji8paEQkTkSfm"
"moRWRNZr/F1KfVMjW+IKEnv2FwZfKdzt0BQR6lClcZR0EfEXEfv/G6W9iLiIyCoReV5En"
"hORIBHx+ufPj/gLB/zGI/G4Bk0AAAAASUVORK5CYII="),
&d,
&default_context_);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_TRUE(!r.is_pending());
EXPECT_FALSE(d.received_data_before_response());
EXPECT_EQ(d.bytes_received(), 911);
EXPECT_EQ("", r.GetSocketAddress().host());
EXPECT_EQ(0, r.GetSocketAddress().port());
}
}
TEST_F(URLRequestTest, FileTest) {
FilePath app_path;
PathService::Get(base::FILE_EXE, &app_path);
GURL app_url = FilePathToFileURL(app_path);
TestDelegate d;
{
URLRequest r(app_url, &d, &default_context_);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
int64 file_size = -1;
EXPECT_TRUE(file_util::GetFileSize(app_path, &file_size));
EXPECT_TRUE(!r.is_pending());
EXPECT_EQ(1, d.response_started_count());
EXPECT_FALSE(d.received_data_before_response());
EXPECT_EQ(d.bytes_received(), static_cast<int>(file_size));
EXPECT_EQ("", r.GetSocketAddress().host());
EXPECT_EQ(0, r.GetSocketAddress().port());
}
}
TEST_F(URLRequestTest, FileTestCancel) {
FilePath app_path;
PathService::Get(base::FILE_EXE, &app_path);
GURL app_url = FilePathToFileURL(app_path);
TestDelegate d;
{
URLRequest r(app_url, &d, &default_context_);
r.Start();
EXPECT_TRUE(r.is_pending());
r.Cancel();
}
// Async cancelation should be safe even when URLRequest has been already
// destroyed.
MessageLoop::current()->RunUntilIdle();
}
TEST_F(URLRequestTest, FileTestFullSpecifiedRange) {
const size_t buffer_size = 4000;
scoped_array<char> buffer(new char[buffer_size]);
FillBuffer(buffer.get(), buffer_size);
FilePath temp_path;
EXPECT_TRUE(file_util::CreateTemporaryFile(&temp_path));
GURL temp_url = FilePathToFileURL(temp_path);
EXPECT_TRUE(file_util::WriteFile(temp_path, buffer.get(), buffer_size));
int64 file_size;
EXPECT_TRUE(file_util::GetFileSize(temp_path, &file_size));
const size_t first_byte_position = 500;
const size_t last_byte_position = buffer_size - first_byte_position;
const size_t content_length = last_byte_position - first_byte_position + 1;
std::string partial_buffer_string(buffer.get() + first_byte_position,
buffer.get() + last_byte_position + 1);
TestDelegate d;
{
URLRequest r(temp_url, &d, &default_context_);
HttpRequestHeaders headers;
headers.SetHeader(HttpRequestHeaders::kRange,
base::StringPrintf(
"bytes=%" PRIuS "-%" PRIuS,
first_byte_position, last_byte_position));
r.SetExtraRequestHeaders(headers);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_TRUE(!r.is_pending());
EXPECT_EQ(1, d.response_started_count());
EXPECT_FALSE(d.received_data_before_response());
EXPECT_EQ(static_cast<int>(content_length), d.bytes_received());
// Don't use EXPECT_EQ, it will print out a lot of garbage if check failed.
EXPECT_TRUE(partial_buffer_string == d.data_received());
}
EXPECT_TRUE(file_util::Delete(temp_path, false));
}
TEST_F(URLRequestTest, FileTestHalfSpecifiedRange) {
const size_t buffer_size = 4000;
scoped_array<char> buffer(new char[buffer_size]);
FillBuffer(buffer.get(), buffer_size);
FilePath temp_path;
EXPECT_TRUE(file_util::CreateTemporaryFile(&temp_path));
GURL temp_url = FilePathToFileURL(temp_path);
EXPECT_TRUE(file_util::WriteFile(temp_path, buffer.get(), buffer_size));
int64 file_size;
EXPECT_TRUE(file_util::GetFileSize(temp_path, &file_size));
const size_t first_byte_position = 500;
const size_t last_byte_position = buffer_size - 1;
const size_t content_length = last_byte_position - first_byte_position + 1;
std::string partial_buffer_string(buffer.get() + first_byte_position,
buffer.get() + last_byte_position + 1);
TestDelegate d;
{
URLRequest r(temp_url, &d, &default_context_);
HttpRequestHeaders headers;
headers.SetHeader(HttpRequestHeaders::kRange,
base::StringPrintf("bytes=%" PRIuS "-",
first_byte_position));
r.SetExtraRequestHeaders(headers);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_TRUE(!r.is_pending());
EXPECT_EQ(1, d.response_started_count());
EXPECT_FALSE(d.received_data_before_response());
EXPECT_EQ(static_cast<int>(content_length), d.bytes_received());
// Don't use EXPECT_EQ, it will print out a lot of garbage if check failed.
EXPECT_TRUE(partial_buffer_string == d.data_received());
}
EXPECT_TRUE(file_util::Delete(temp_path, false));
}
TEST_F(URLRequestTest, FileTestMultipleRanges) {
const size_t buffer_size = 400000;
scoped_array<char> buffer(new char[buffer_size]);
FillBuffer(buffer.get(), buffer_size);
FilePath temp_path;
EXPECT_TRUE(file_util::CreateTemporaryFile(&temp_path));
GURL temp_url = FilePathToFileURL(temp_path);
EXPECT_TRUE(file_util::WriteFile(temp_path, buffer.get(), buffer_size));
int64 file_size;
EXPECT_TRUE(file_util::GetFileSize(temp_path, &file_size));
TestDelegate d;
{
URLRequest r(temp_url, &d, &default_context_);
HttpRequestHeaders headers;
headers.SetHeader(HttpRequestHeaders::kRange,
"bytes=0-0,10-200,200-300");
r.SetExtraRequestHeaders(headers);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_TRUE(d.request_failed());
}
EXPECT_TRUE(file_util::Delete(temp_path, false));
}
TEST_F(URLRequestTest, InvalidUrlTest) {
TestDelegate d;
{
URLRequest r(GURL("invalid url"), &d, &default_context_);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_TRUE(d.request_failed());
}
}
#if defined(OS_WIN)
TEST_F(URLRequestTest, ResolveShortcutTest) {
FilePath app_path;
PathService::Get(base::DIR_TEST_DATA, &app_path);
app_path = app_path.AppendASCII("net");
app_path = app_path.AppendASCII("data");
app_path = app_path.AppendASCII("url_request_unittest");
app_path = app_path.AppendASCII("with-headers.html");
std::wstring lnk_path = app_path.value() + L".lnk";
base::win::ScopedCOMInitializer com_initializer;
// Temporarily create a shortcut for test
IShellLink* shell = NULL;
ASSERT_TRUE(SUCCEEDED(CoCreateInstance(
CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
reinterpret_cast<LPVOID*>(&shell))));
IPersistFile* persist = NULL;
ASSERT_TRUE(SUCCEEDED(shell->QueryInterface(
IID_IPersistFile, reinterpret_cast<LPVOID*>(&persist))));
EXPECT_TRUE(SUCCEEDED(shell->SetPath(app_path.value().c_str())));
EXPECT_TRUE(SUCCEEDED(shell->SetDescription(L"ResolveShortcutTest")));
EXPECT_TRUE(SUCCEEDED(persist->Save(lnk_path.c_str(), TRUE)));
if (persist)
persist->Release();
if (shell)
shell->Release();
TestDelegate d;
{
URLRequest r(FilePathToFileURL(FilePath(lnk_path)), &d, &default_context_);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
WIN32_FILE_ATTRIBUTE_DATA data;
GetFileAttributesEx(app_path.value().c_str(),
GetFileExInfoStandard, &data);
HANDLE file = CreateFile(app_path.value().c_str(), GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
EXPECT_NE(INVALID_HANDLE_VALUE, file);
scoped_array<char> buffer(new char[data.nFileSizeLow]);
DWORD read_size;
BOOL result;
result = ReadFile(file, buffer.get(), data.nFileSizeLow,
&read_size, NULL);
std::string content(buffer.get(), read_size);
CloseHandle(file);
EXPECT_TRUE(!r.is_pending());
EXPECT_EQ(1, d.received_redirect_count());
EXPECT_EQ(content, d.data_received());
}
// Clean the shortcut
DeleteFile(lnk_path.c_str());
}
#endif // defined(OS_WIN)
TEST_F(URLRequestTest, FileDirCancelTest) {
// Put in mock resource provider.
NetModule::SetResourceProvider(TestNetResourceProvider);
TestDelegate d;
{
FilePath file_path;
PathService::Get(base::DIR_TEST_DATA, &file_path);
file_path = file_path.Append(FILE_PATH_LITERAL("net"));
file_path = file_path.Append(FILE_PATH_LITERAL("data"));
URLRequest req(FilePathToFileURL(file_path), &d, &default_context_);
req.Start();
EXPECT_TRUE(req.is_pending());
d.set_cancel_in_received_data_pending(true);
MessageLoop::current()->Run();
}
// Take out mock resource provider.
NetModule::SetResourceProvider(NULL);
}
TEST_F(URLRequestTest, FileDirRedirectNoCrash) {
// There is an implicit redirect when loading a file path that matches a
// directory and does not end with a slash. Ensure that following such
// redirects does not crash. See http://crbug.com/18686.
FilePath path;
PathService::Get(base::DIR_TEST_DATA, &path);
path = path.Append(FILE_PATH_LITERAL("net"));
path = path.Append(FILE_PATH_LITERAL("data"));
path = path.Append(FILE_PATH_LITERAL("url_request_unittest"));
TestDelegate d;
URLRequest req(FilePathToFileURL(path), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
ASSERT_EQ(1, d.received_redirect_count());
ASSERT_LT(0, d.bytes_received());
ASSERT_FALSE(d.request_failed());
ASSERT_TRUE(req.status().is_success());
}
#if defined(OS_WIN)
// Don't accept the url "file:///" on windows. See http://crbug.com/1474.
TEST_F(URLRequestTest, FileDirRedirectSingleSlash) {
TestDelegate d;
URLRequest req(GURL("file:///"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
ASSERT_EQ(1, d.received_redirect_count());
ASSERT_FALSE(req.status().is_success());
}
#endif
// Custom URLRequestJobs for use with interceptor tests
class RestartTestJob : public URLRequestTestJob {
public:
RestartTestJob(URLRequest* request, NetworkDelegate* network_delegate)
: URLRequestTestJob(request, network_delegate, true) {}
protected:
virtual void StartAsync() {
this->NotifyRestartRequired();
}
private:
~RestartTestJob() {}
};
class CancelTestJob : public URLRequestTestJob {
public:
explicit CancelTestJob(URLRequest* request, NetworkDelegate* network_delegate)
: URLRequestTestJob(request, network_delegate, true) {}
protected:
virtual void StartAsync() {
request_->Cancel();
}
private:
~CancelTestJob() {}
};
class CancelThenRestartTestJob : public URLRequestTestJob {
public:
explicit CancelThenRestartTestJob(URLRequest* request,
NetworkDelegate* network_delegate)
: URLRequestTestJob(request, network_delegate, true) {
}
protected:
virtual void StartAsync() {
request_->Cancel();
this->NotifyRestartRequired();
}
private:
~CancelThenRestartTestJob() {}
};
// An Interceptor for use with interceptor tests
class TestInterceptor : URLRequest::Interceptor {
public:
TestInterceptor()
: intercept_main_request_(false), restart_main_request_(false),
cancel_main_request_(false), cancel_then_restart_main_request_(false),
simulate_main_network_error_(false),
intercept_redirect_(false), cancel_redirect_request_(false),
intercept_final_response_(false), cancel_final_request_(false),
did_intercept_main_(false), did_restart_main_(false),
did_cancel_main_(false), did_cancel_then_restart_main_(false),
did_simulate_error_main_(false),
did_intercept_redirect_(false), did_cancel_redirect_(false),
did_intercept_final_(false), did_cancel_final_(false) {
URLRequest::Deprecated::RegisterRequestInterceptor(this);
}
~TestInterceptor() {
URLRequest::Deprecated::UnregisterRequestInterceptor(this);
}
virtual URLRequestJob* MaybeIntercept(URLRequest* request,
NetworkDelegate* network_delegate) {
if (restart_main_request_) {
restart_main_request_ = false;
did_restart_main_ = true;
return new RestartTestJob(request, network_delegate);
}
if (cancel_main_request_) {
cancel_main_request_ = false;
did_cancel_main_ = true;
return new CancelTestJob(request, network_delegate);
}
if (cancel_then_restart_main_request_) {
cancel_then_restart_main_request_ = false;
did_cancel_then_restart_main_ = true;
return new CancelThenRestartTestJob(request, network_delegate);
}
if (simulate_main_network_error_) {
simulate_main_network_error_ = false;
did_simulate_error_main_ = true;
// will error since the requeted url is not one of its canned urls
return new URLRequestTestJob(request, network_delegate, true);
}
if (!intercept_main_request_)
return NULL;
intercept_main_request_ = false;
did_intercept_main_ = true;
return new URLRequestTestJob(request,
network_delegate,
main_headers_,
main_data_,
true);
}
virtual URLRequestJob* MaybeInterceptRedirect(
URLRequest* request,
NetworkDelegate* network_delegate,
const GURL& location) {
if (cancel_redirect_request_) {
cancel_redirect_request_ = false;
did_cancel_redirect_ = true;
return new CancelTestJob(request, network_delegate);
}
if (!intercept_redirect_)
return NULL;
intercept_redirect_ = false;
did_intercept_redirect_ = true;
return new URLRequestTestJob(request,
network_delegate,
redirect_headers_,
redirect_data_,
true);
}
virtual URLRequestJob* MaybeInterceptResponse(
URLRequest* request, NetworkDelegate* network_delegate) {
if (cancel_final_request_) {
cancel_final_request_ = false;
did_cancel_final_ = true;
return new CancelTestJob(request, network_delegate);
}
if (!intercept_final_response_)
return NULL;
intercept_final_response_ = false;
did_intercept_final_ = true;
return new URLRequestTestJob(request,
network_delegate,
final_headers_,
final_data_,
true);
}
// Whether to intercept the main request, and if so the response to return.
bool intercept_main_request_;
std::string main_headers_;
std::string main_data_;
// Other actions we take at MaybeIntercept time
bool restart_main_request_;
bool cancel_main_request_;
bool cancel_then_restart_main_request_;
bool simulate_main_network_error_;
// Whether to intercept redirects, and if so the response to return.
bool intercept_redirect_;
std::string redirect_headers_;
std::string redirect_data_;
// Other actions we can take at MaybeInterceptRedirect time
bool cancel_redirect_request_;
// Whether to intercept final response, and if so the response to return.
bool intercept_final_response_;
std::string final_headers_;
std::string final_data_;
// Other actions we can take at MaybeInterceptResponse time
bool cancel_final_request_;
// If we did something or not
bool did_intercept_main_;
bool did_restart_main_;
bool did_cancel_main_;
bool did_cancel_then_restart_main_;
bool did_simulate_error_main_;
bool did_intercept_redirect_;
bool did_cancel_redirect_;
bool did_intercept_final_;
bool did_cancel_final_;
// Static getters for canned response header and data strings
static std::string ok_data() {
return URLRequestTestJob::test_data_1();
}
static std::string ok_headers() {
return URLRequestTestJob::test_headers();
}
static std::string redirect_data() {
return std::string();
}
static std::string redirect_headers() {
return URLRequestTestJob::test_redirect_headers();
}
static std::string error_data() {
return std::string("ohhh nooooo mr. bill!");
}
static std::string error_headers() {
return URLRequestTestJob::test_error_headers();
}
};
TEST_F(URLRequestTest, Intercept) {
TestInterceptor interceptor;
// intercept the main request and respond with a simple response
interceptor.intercept_main_request_ = true;
interceptor.main_headers_ = TestInterceptor::ok_headers();
interceptor.main_data_ = TestInterceptor::ok_data();
TestDelegate d;
URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
base::SupportsUserData::Data* user_data0 = new base::SupportsUserData::Data();
base::SupportsUserData::Data* user_data1 = new base::SupportsUserData::Data();
base::SupportsUserData::Data* user_data2 = new base::SupportsUserData::Data();
req.SetUserData(NULL, user_data0);
req.SetUserData(&user_data1, user_data1);
req.SetUserData(&user_data2, user_data2);
req.set_method("GET");
req.Start();
MessageLoop::current()->Run();
// Make sure we can retrieve our specific user data
EXPECT_EQ(user_data0, req.GetUserData(NULL));
EXPECT_EQ(user_data1, req.GetUserData(&user_data1));
EXPECT_EQ(user_data2, req.GetUserData(&user_data2));
// Check the interceptor got called as expected
EXPECT_TRUE(interceptor.did_intercept_main_);
// Check we got one good response
EXPECT_TRUE(req.status().is_success());
EXPECT_EQ(200, req.response_headers()->response_code());
EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(0, d.received_redirect_count());
}
TEST_F(URLRequestTest, InterceptRedirect) {
TestInterceptor interceptor;
// intercept the main request and respond with a redirect
interceptor.intercept_main_request_ = true;
interceptor.main_headers_ = TestInterceptor::redirect_headers();
interceptor.main_data_ = TestInterceptor::redirect_data();
// intercept that redirect and respond a final OK response
interceptor.intercept_redirect_ = true;
interceptor.redirect_headers_ = TestInterceptor::ok_headers();
interceptor.redirect_data_ = TestInterceptor::ok_data();
TestDelegate d;
URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
req.set_method("GET");
req.Start();
MessageLoop::current()->Run();
// Check the interceptor got called as expected
EXPECT_TRUE(interceptor.did_intercept_main_);
EXPECT_TRUE(interceptor.did_intercept_redirect_);
// Check we got one good response
EXPECT_TRUE(req.status().is_success());
if (req.status().is_success()) {
EXPECT_EQ(200, req.response_headers()->response_code());
}
EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(0, d.received_redirect_count());
}
TEST_F(URLRequestTest, InterceptServerError) {
TestInterceptor interceptor;
// intercept the main request to generate a server error response
interceptor.intercept_main_request_ = true;
interceptor.main_headers_ = TestInterceptor::error_headers();
interceptor.main_data_ = TestInterceptor::error_data();
// intercept that error and respond with an OK response
interceptor.intercept_final_response_ = true;
interceptor.final_headers_ = TestInterceptor::ok_headers();
interceptor.final_data_ = TestInterceptor::ok_data();
TestDelegate d;
URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
req.set_method("GET");
req.Start();
MessageLoop::current()->Run();
// Check the interceptor got called as expected
EXPECT_TRUE(interceptor.did_intercept_main_);
EXPECT_TRUE(interceptor.did_intercept_final_);
// Check we got one good response
EXPECT_TRUE(req.status().is_success());
EXPECT_EQ(200, req.response_headers()->response_code());
EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(0, d.received_redirect_count());
}
TEST_F(URLRequestTest, InterceptNetworkError) {
TestInterceptor interceptor;
// intercept the main request to simulate a network error
interceptor.simulate_main_network_error_ = true;
// intercept that error and respond with an OK response
interceptor.intercept_final_response_ = true;
interceptor.final_headers_ = TestInterceptor::ok_headers();
interceptor.final_data_ = TestInterceptor::ok_data();
TestDelegate d;
URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
req.set_method("GET");
req.Start();
MessageLoop::current()->Run();
// Check the interceptor got called as expected
EXPECT_TRUE(interceptor.did_simulate_error_main_);
EXPECT_TRUE(interceptor.did_intercept_final_);
// Check we received one good response
EXPECT_TRUE(req.status().is_success());
EXPECT_EQ(200, req.response_headers()->response_code());
EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(0, d.received_redirect_count());
}
TEST_F(URLRequestTest, InterceptRestartRequired) {
TestInterceptor interceptor;
// restart the main request
interceptor.restart_main_request_ = true;
// then intercept the new main request and respond with an OK response
interceptor.intercept_main_request_ = true;
interceptor.main_headers_ = TestInterceptor::ok_headers();
interceptor.main_data_ = TestInterceptor::ok_data();
TestDelegate d;
URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
req.set_method("GET");
req.Start();
MessageLoop::current()->Run();
// Check the interceptor got called as expected
EXPECT_TRUE(interceptor.did_restart_main_);
EXPECT_TRUE(interceptor.did_intercept_main_);
// Check we received one good response
EXPECT_TRUE(req.status().is_success());
if (req.status().is_success()) {
EXPECT_EQ(200, req.response_headers()->response_code());
}
EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(0, d.received_redirect_count());
}
TEST_F(URLRequestTest, InterceptRespectsCancelMain) {
TestInterceptor interceptor;
// intercept the main request and cancel from within the restarted job
interceptor.cancel_main_request_ = true;
// setup to intercept final response and override it with an OK response
interceptor.intercept_final_response_ = true;
interceptor.final_headers_ = TestInterceptor::ok_headers();
interceptor.final_data_ = TestInterceptor::ok_data();
TestDelegate d;
URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
req.set_method("GET");
req.Start();
MessageLoop::current()->Run();
// Check the interceptor got called as expected
EXPECT_TRUE(interceptor.did_cancel_main_);
EXPECT_FALSE(interceptor.did_intercept_final_);
// Check we see a canceled request
EXPECT_FALSE(req.status().is_success());
EXPECT_EQ(URLRequestStatus::CANCELED, req.status().status());
}
TEST_F(URLRequestTest, InterceptRespectsCancelRedirect) {
TestInterceptor interceptor;
// intercept the main request and respond with a redirect
interceptor.intercept_main_request_ = true;
interceptor.main_headers_ = TestInterceptor::redirect_headers();
interceptor.main_data_ = TestInterceptor::redirect_data();
// intercept the redirect and cancel from within that job
interceptor.cancel_redirect_request_ = true;
// setup to intercept final response and override it with an OK response
interceptor.intercept_final_response_ = true;
interceptor.final_headers_ = TestInterceptor::ok_headers();
interceptor.final_data_ = TestInterceptor::ok_data();
TestDelegate d;
URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
req.set_method("GET");
req.Start();
MessageLoop::current()->Run();
// Check the interceptor got called as expected
EXPECT_TRUE(interceptor.did_intercept_main_);
EXPECT_TRUE(interceptor.did_cancel_redirect_);
EXPECT_FALSE(interceptor.did_intercept_final_);
// Check we see a canceled request
EXPECT_FALSE(req.status().is_success());
EXPECT_EQ(URLRequestStatus::CANCELED, req.status().status());
}
TEST_F(URLRequestTest, InterceptRespectsCancelFinal) {
TestInterceptor interceptor;
// intercept the main request to simulate a network error
interceptor.simulate_main_network_error_ = true;
// setup to intercept final response and cancel from within that job
interceptor.cancel_final_request_ = true;
TestDelegate d;
URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
req.set_method("GET");
req.Start();
MessageLoop::current()->Run();
// Check the interceptor got called as expected
EXPECT_TRUE(interceptor.did_simulate_error_main_);
EXPECT_TRUE(interceptor.did_cancel_final_);
// Check we see a canceled request
EXPECT_FALSE(req.status().is_success());
EXPECT_EQ(URLRequestStatus::CANCELED, req.status().status());
}
TEST_F(URLRequestTest, InterceptRespectsCancelInRestart) {
TestInterceptor interceptor;
// intercept the main request and cancel then restart from within that job
interceptor.cancel_then_restart_main_request_ = true;
// setup to intercept final response and override it with an OK response
interceptor.intercept_final_response_ = true;
interceptor.final_headers_ = TestInterceptor::ok_headers();
interceptor.final_data_ = TestInterceptor::ok_data();
TestDelegate d;
URLRequest req(GURL("http://test_intercept/foo"), &d, &default_context_);
req.set_method("GET");
req.Start();
MessageLoop::current()->Run();
// Check the interceptor got called as expected
EXPECT_TRUE(interceptor.did_cancel_then_restart_main_);
EXPECT_FALSE(interceptor.did_intercept_final_);
// Check we see a canceled request
EXPECT_FALSE(req.status().is_success());
EXPECT_EQ(URLRequestStatus::CANCELED, req.status().status());
}
// Check that two different URL requests have different identifiers.
TEST_F(URLRequestTest, Identifiers) {
TestDelegate d;
TestURLRequestContext context;
TestURLRequest req(GURL("http://example.com"), &d, &context);
TestURLRequest other_req(GURL("http://example.com"), &d, &context);
ASSERT_NE(req.identifier(), other_req.identifier());
}
// Check that a failure to connect to the proxy is reported to the network
// delegate.
TEST_F(URLRequestTest, NetworkDelegateProxyError) {
MockHostResolver host_resolver;
host_resolver.rules()->AddSimulatedFailure("*");
TestNetworkDelegate network_delegate; // Must outlive URLRequests.
TestURLRequestContextWithProxy context("myproxy:70", &network_delegate);
TestDelegate d;
URLRequest req(GURL("http://example.com"), &d, &context);
req.set_method("GET");
req.Start();
MessageLoop::current()->Run();
// Check we see a failed request.
EXPECT_FALSE(req.status().is_success());
EXPECT_EQ(URLRequestStatus::FAILED, req.status().status());
EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, req.status().error());
EXPECT_EQ(1, network_delegate.error_count());
EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, network_delegate.last_error());
EXPECT_EQ(1, network_delegate.completed_requests());
}
// Make sure that net::NetworkDelegate::NotifyCompleted is called if
// content is empty.
TEST_F(URLRequestTest, RequestCompletionForEmptyResponse) {
TestDelegate d;
URLRequest req(GURL("data:,"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ("", d.data_received());
EXPECT_EQ(1, default_network_delegate_.completed_requests());
}
// TODO(droger): Support TestServer on iOS (see http://crbug.com/148666).
#if !defined(OS_IOS)
// A subclass of TestServer that uses a statically-configured hostname. This is
// to work around mysterious failures in chrome_frame_net_tests. See:
// http://crbug.com/114369
class LocalHttpTestServer : public TestServer {
public:
explicit LocalHttpTestServer(const FilePath& document_root)
: TestServer(TestServer::TYPE_HTTP,
ScopedCustomUrlRequestTestHttpHost::value(),
document_root) {}
LocalHttpTestServer()
: TestServer(TestServer::TYPE_HTTP,
ScopedCustomUrlRequestTestHttpHost::value(),
FilePath()) {}
};
TEST_F(URLRequestTest, FLAKY_DelayedCookieCallback) {
LocalHttpTestServer test_server;
ASSERT_TRUE(test_server.Start());
TestURLRequestContext context;
scoped_refptr<DelayedCookieMonster> delayed_cm =
new DelayedCookieMonster();
scoped_refptr<CookieStore> cookie_store = delayed_cm;
context.set_cookie_store(delayed_cm);
// Set up a cookie.
{
TestNetworkDelegate network_delegate;
context.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(
test_server.GetURL("set-cookie?CookieToNotSend=1"), &d, &context);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
EXPECT_EQ(1, network_delegate.set_cookie_count());
}
// Verify that the cookie is set.
{
TestNetworkDelegate network_delegate;
context.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(test_server.GetURL("echoheader?Cookie"), &d, &context);
req.Start();
MessageLoop::current()->Run();
EXPECT_TRUE(d.data_received().find("CookieToNotSend=1")
!= std::string::npos);
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
}
TEST_F(URLRequestTest, DoNotSendCookies) {
LocalHttpTestServer test_server;
ASSERT_TRUE(test_server.Start());
// Set up a cookie.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(test_server.GetURL("set-cookie?CookieToNotSend=1"),
&d,
&default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
// Verify that the cookie is set.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(
test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_TRUE(d.data_received().find("CookieToNotSend=1")
!= std::string::npos);
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
// Verify that the cookie isn't sent when LOAD_DO_NOT_SEND_COOKIES is set.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(
test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
req.set_load_flags(LOAD_DO_NOT_SEND_COOKIES);
req.Start();
MessageLoop::current()->Run();
EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1")
== std::string::npos);
// LOAD_DO_NOT_SEND_COOKIES does not trigger OnGetCookies.
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
}
TEST_F(URLRequestTest, DoNotSaveCookies) {
LocalHttpTestServer test_server;
ASSERT_TRUE(test_server.Start());
// Set up a cookie.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(test_server.GetURL("set-cookie?CookieToNotUpdate=2"),
&d,
&default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
EXPECT_EQ(1, network_delegate.set_cookie_count());
}
// Try to set-up another cookie and update the previous cookie.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(
test_server.GetURL("set-cookie?CookieToNotSave=1&CookieToNotUpdate=1"),
&d,
&default_context_);
req.set_load_flags(LOAD_DO_NOT_SAVE_COOKIES);
req.Start();
MessageLoop::current()->Run();
// LOAD_DO_NOT_SAVE_COOKIES does not trigger OnSetCookie.
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
EXPECT_EQ(0, network_delegate.set_cookie_count());
}
// Verify the cookies weren't saved or updated.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(
test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_TRUE(d.data_received().find("CookieToNotSave=1")
== std::string::npos);
EXPECT_TRUE(d.data_received().find("CookieToNotUpdate=2")
!= std::string::npos);
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
EXPECT_EQ(0, network_delegate.set_cookie_count());
}
}
TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy) {
LocalHttpTestServer test_server;
ASSERT_TRUE(test_server.Start());
// Set up a cookie.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(test_server.GetURL("set-cookie?CookieToNotSend=1"),
&d,
&default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
// Verify that the cookie is set.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(
test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_TRUE(d.data_received().find("CookieToNotSend=1")
!= std::string::npos);
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
// Verify that the cookie isn't sent.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
network_delegate.set_cookie_options(TestNetworkDelegate::NO_GET_COOKIES);
URLRequest req(
test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1")
== std::string::npos);
EXPECT_EQ(1, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
}
TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy) {
LocalHttpTestServer test_server;
ASSERT_TRUE(test_server.Start());
// Set up a cookie.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(test_server.GetURL("set-cookie?CookieToNotUpdate=2"),
&d,
&default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
// Try to set-up another cookie and update the previous cookie.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
network_delegate.set_cookie_options(TestNetworkDelegate::NO_SET_COOKIE);
URLRequest req(
test_server.GetURL("set-cookie?CookieToNotSave=1&CookieToNotUpdate=1"),
&d,
&default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(2, network_delegate.blocked_set_cookie_count());
}
// Verify the cookies weren't saved or updated.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(
test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_TRUE(d.data_received().find("CookieToNotSave=1")
== std::string::npos);
EXPECT_TRUE(d.data_received().find("CookieToNotUpdate=2")
!= std::string::npos);
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
}
TEST_F(URLRequestTest, DoNotSaveEmptyCookies) {
LocalHttpTestServer test_server;
ASSERT_TRUE(test_server.Start());
// Set up an empty cookie.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(test_server.GetURL("set-cookie"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
EXPECT_EQ(0, network_delegate.set_cookie_count());
}
}
TEST_F(URLRequestTest, DoNotSendCookies_ViaPolicy_Async) {
LocalHttpTestServer test_server;
ASSERT_TRUE(test_server.Start());
// Set up a cookie.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(test_server.GetURL("set-cookie?CookieToNotSend=1"),
&d,
&default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
// Verify that the cookie is set.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(
test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_TRUE(d.data_received().find("CookieToNotSend=1")
!= std::string::npos);
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
// Verify that the cookie isn't sent.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
network_delegate.set_cookie_options(TestNetworkDelegate::NO_GET_COOKIES);
URLRequest req(
test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_TRUE(d.data_received().find("Cookie: CookieToNotSend=1")
== std::string::npos);
EXPECT_EQ(1, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
}
TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy_Async) {
LocalHttpTestServer test_server;
ASSERT_TRUE(test_server.Start());
// Set up a cookie.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(test_server.GetURL("set-cookie?CookieToNotUpdate=2"),
&d,
&default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
// Try to set-up another cookie and update the previous cookie.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
network_delegate.set_cookie_options(TestNetworkDelegate::NO_SET_COOKIE);
URLRequest req(
test_server.GetURL("set-cookie?CookieToNotSave=1&CookieToNotUpdate=1"),
&d,
&default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(2, network_delegate.blocked_set_cookie_count());
}
// Verify the cookies weren't saved or updated.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(
test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_TRUE(d.data_received().find("CookieToNotSave=1")
== std::string::npos);
EXPECT_TRUE(d.data_received().find("CookieToNotUpdate=2")
!= std::string::npos);
EXPECT_EQ(0, network_delegate.blocked_get_cookies_count());
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
}
}
// FixedDateNetworkDelegate swaps out the server's HTTP Date response header
// value for the |fixed_date| argument given to the constructor.
class FixedDateNetworkDelegate : public TestNetworkDelegate {
public:
explicit FixedDateNetworkDelegate(const std::string& fixed_date)
: fixed_date_(fixed_date) {}
virtual ~FixedDateNetworkDelegate() {}
// net::NetworkDelegate implementation
virtual int OnHeadersReceived(
net::URLRequest* request,
const net::CompletionCallback& callback,
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers)
override;
private:
std::string fixed_date_;
DISALLOW_COPY_AND_ASSIGN(FixedDateNetworkDelegate);
};
int FixedDateNetworkDelegate::OnHeadersReceived(
net::URLRequest* request,
const net::CompletionCallback& callback,
const net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
net::HttpResponseHeaders* new_response_headers =
new net::HttpResponseHeaders(original_response_headers->raw_headers());
new_response_headers->RemoveHeader("Date");
new_response_headers->AddHeader("Date: " + fixed_date_);
*override_response_headers = new_response_headers;
return TestNetworkDelegate::OnHeadersReceived(request,
callback,
original_response_headers,
override_response_headers);
}
// Test that cookie expiration times are adjusted for server/client clock
// skew and that we handle incorrect timezone specifier "UTC" in HTTP Date
// headers by defaulting to GMT. (crbug.com/135131)
TEST_F(URLRequestTest, AcceptClockSkewCookieWithWrongDateTimezone) {
LocalHttpTestServer test_server;
ASSERT_TRUE(test_server.Start());
// Set up an expired cookie.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(test_server.GetURL(
"set-cookie?StillGood=1;expires=Mon,18-Apr-1977,22:50:13,GMT"),
&d,
&default_context_);
req.Start();
MessageLoop::current()->Run();
}
// Verify that the cookie is not set.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(
test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_TRUE(d.data_received().find("StillGood=1") == std::string::npos);
}
// Set up a cookie with clock skew and "UTC" HTTP Date timezone specifier.
{
FixedDateNetworkDelegate network_delegate("18-Apr-1977 22:49:13 UTC");
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(test_server.GetURL(
"set-cookie?StillGood=1;expires=Mon,18-Apr-1977,22:50:13,GMT"),
&d,
&default_context_);
req.Start();
MessageLoop::current()->Run();
}
// Verify that the cookie is set.
{
TestNetworkDelegate network_delegate;
default_context_.set_network_delegate(&network_delegate);
TestDelegate d;
URLRequest req(
test_server.GetURL("echoheader?Cookie"), &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_TRUE(d.data_received().find("StillGood=1") != std::string::npos);
}
}
// Check that it is impossible to change the referrer in the extra headers of
// an URLRequest.
TEST_F(URLRequestTest, DoNotOverrideReferrer) {
LocalHttpTestServer test_server;
ASSERT_TRUE(test_server.Start());
// If extra headers contain referer and the request contains a referer,
// only the latter shall be respected.
{
TestDelegate d;
URLRequest req(
test_server.GetURL("echoheader?Referer"), &d, &default_context_);
req.set_referrer("http://foo.com/");
HttpRequestHeaders headers;
headers.SetHeader(HttpRequestHeaders::kReferer, "http://bar.com/");
req.SetExtraRequestHeaders(headers);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ("http://foo.com/", d.data_received());
}
// If extra headers contain a referer but the request does not, no referer
// shall be sent in the header.
{
TestDelegate d;
URLRequest req(
test_server.GetURL("echoheader?Referer"), &d, &default_context_);
HttpRequestHeaders headers;
headers.SetHeader(HttpRequestHeaders::kReferer, "http://bar.com/");
req.SetExtraRequestHeaders(headers);
req.set_load_flags(LOAD_VALIDATE_CACHE);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ("None", d.data_received());
}
}
class URLRequestTestHTTP : public URLRequestTest {
public:
URLRequestTestHTTP()
: test_server_(FilePath(FILE_PATH_LITERAL(
"net/data/url_request_unittest"))) {
}
protected:
// Requests |redirect_url|, which must return a HTTP 3xx redirect.
// |request_method| is the method to use for the initial request.
// |redirect_method| is the method that is expected to be used for the second
// request, after redirection.
// If |include_data| is true, data is uploaded with the request. The
// response body is expected to match it exactly, if and only if
// |request_method| == |redirect_method|.
void HTTPRedirectMethodTest(const GURL& redirect_url,
const std::string& request_method,
const std::string& redirect_method,
bool include_data) {
static const char kData[] = "hello world";
TestDelegate d;
URLRequest req(redirect_url, &d, &default_context_);
req.set_method(request_method);
if (include_data) {
req.set_upload(make_scoped_ptr(CreateSimpleUploadData(kData)));
HttpRequestHeaders headers;
headers.SetHeader(HttpRequestHeaders::kContentLength,
base::UintToString(arraysize(kData) - 1));
req.SetExtraRequestHeaders(headers);
}
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(redirect_method, req.method());
EXPECT_EQ(URLRequestStatus::SUCCESS, req.status().status());
EXPECT_EQ(OK, req.status().error());
if (include_data) {
if (request_method == redirect_method) {
EXPECT_EQ(kData, d.data_received());
} else {
EXPECT_NE(kData, d.data_received());
}
}
if (HasFailure())
LOG(WARNING) << "Request method was: " << request_method;
}
void HTTPUploadDataOperationTest(const std::string& method) {
const int kMsgSize = 20000; // multiple of 10
const int kIterations = 50;
char* uploadBytes = new char[kMsgSize+1];
char* ptr = uploadBytes;
char marker = 'a';
for (int idx = 0; idx < kMsgSize/10; idx++) {
memcpy(ptr, "----------", 10);
ptr += 10;
if (idx % 100 == 0) {
ptr--;
*ptr++ = marker;
if (++marker > 'z')
marker = 'a';
}
}
uploadBytes[kMsgSize] = '\0';
for (int i = 0; i < kIterations; ++i) {
TestDelegate d;
URLRequest r(test_server_.GetURL("echo"), &d, &default_context_);
r.set_method(method.c_str());
r.set_upload(make_scoped_ptr(CreateSimpleUploadData(uploadBytes)));
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
ASSERT_EQ(1, d.response_started_count())
<< "request failed: " << r.status().status()
<< ", os error: " << r.status().error();
EXPECT_FALSE(d.received_data_before_response());
EXPECT_EQ(uploadBytes, d.data_received());
}
delete[] uploadBytes;
}
void AddChunksToUpload(URLRequest* r) {
r->AppendChunkToUpload("a", 1, false);
r->AppendChunkToUpload("bcd", 3, false);
r->AppendChunkToUpload("this is a longer chunk than before.", 35, false);
r->AppendChunkToUpload("\r\n\r\n", 4, false);
r->AppendChunkToUpload("0", 1, false);
r->AppendChunkToUpload("2323", 4, true);
}
void VerifyReceivedDataMatchesChunks(URLRequest* r, TestDelegate* d) {
// This should match the chunks sent by AddChunksToUpload().
const std::string expected_data =
"abcdthis is a longer chunk than before.\r\n\r\n02323";
ASSERT_EQ(1, d->response_started_count())
<< "request failed: " << r->status().status()
<< ", os error: " << r->status().error();
EXPECT_FALSE(d->received_data_before_response());
EXPECT_EQ(expected_data.size(), static_cast<size_t>(d->bytes_received()));
EXPECT_EQ(expected_data, d->data_received());
}
bool DoManyCookiesRequest(int num_cookies) {
TestDelegate d;
URLRequest r(test_server_.GetURL("set-many-cookies?" +
base::IntToString(num_cookies)),
&d,
&default_context_);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
bool is_success = r.status().is_success();
if (!is_success) {
// Requests handled by ChromeFrame send a less precise error message,
// ERR_CONNECTION_ABORTED.
EXPECT_TRUE(r.status().error() == ERR_RESPONSE_HEADERS_TOO_BIG ||
r.status().error() == ERR_CONNECTION_ABORTED);
// The test server appears to be unable to handle subsequent requests
// after this error is triggered. Force it to restart.
EXPECT_TRUE(test_server_.Stop());
EXPECT_TRUE(test_server_.Start());
}
return is_success;
}
LocalHttpTestServer test_server_;
};
// In this unit test, we're using the HTTPTestServer as a proxy server and
// issuing a CONNECT request with the magic host name "www.redirect.com".
// The HTTPTestServer will return a 302 response, which we should not
// follow.
// flaky: crbug.com/96594
TEST_F(URLRequestTestHTTP, FLAKY_ProxyTunnelRedirectTest) {
ASSERT_TRUE(test_server_.Start());
TestNetworkDelegate network_delegate; // Must outlive URLRequest.
TestURLRequestContextWithProxy context(
test_server_.host_port_pair().ToString(),
&network_delegate);
TestDelegate d;
{
URLRequest r(GURL("https://www.redirect.com/"), &d, &context);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, r.status().error());
EXPECT_EQ(1, d.response_started_count());
// We should not have followed the redirect.
EXPECT_EQ(0, d.received_redirect_count());
}
}
// This is the same as the previous test, but checks that the network delegate
// registers the error.
// This test was disabled because it made chrome_frame_net_tests hang
// (see bug 102991).
TEST_F(URLRequestTestHTTP, DISABLED_NetworkDelegateTunnelConnectionFailed) {
ASSERT_TRUE(test_server_.Start());
TestNetworkDelegate network_delegate; // Must outlive URLRequest.
TestURLRequestContextWithProxy context(
test_server_.host_port_pair().ToString(),
&network_delegate);
TestDelegate d;
{
URLRequest r(GURL("https://www.redirect.com/"), &d, &context);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, r.status().error());
EXPECT_EQ(1, d.response_started_count());
// We should not have followed the redirect.
EXPECT_EQ(0, d.received_redirect_count());
EXPECT_EQ(1, network_delegate.error_count());
EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, network_delegate.last_error());
}
}
// Tests that we can block and asynchronously return OK in various stages.
TEST_F(URLRequestTestHTTP, NetworkDelegateBlockAsynchronously) {
static const BlockingNetworkDelegate::Stage blocking_stages[] = {
BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST,
BlockingNetworkDelegate::ON_BEFORE_SEND_HEADERS,
BlockingNetworkDelegate::ON_HEADERS_RECEIVED
};
static const size_t blocking_stages_length = arraysize(blocking_stages);
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::USER_CALLBACK);
network_delegate.set_block_on(
BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST |
BlockingNetworkDelegate::ON_BEFORE_SEND_HEADERS |
BlockingNetworkDelegate::ON_HEADERS_RECEIVED);
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
{
URLRequest r(test_server_.GetURL("empty.html"), &d, &context);
r.Start();
for (size_t i = 0; i < blocking_stages_length; ++i) {
MessageLoop::current()->Run();
EXPECT_EQ(blocking_stages[i],
network_delegate.stage_blocked_for_callback());
network_delegate.DoCallback(OK);
}
MessageLoop::current()->Run();
EXPECT_EQ(200, r.GetResponseCode());
EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that the network delegate can block and cancel a request.
TEST_F(URLRequestTestHTTP, NetworkDelegateCancelRequest) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::AUTO_CALLBACK);
network_delegate.set_block_on(BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST);
network_delegate.set_retval(ERR_EMPTY_RESPONSE);
TestURLRequestContextWithProxy context(
test_server_.host_port_pair().ToString(),
&network_delegate);
{
URLRequest r(test_server_.GetURL(""), &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
EXPECT_EQ(ERR_EMPTY_RESPONSE, r.status().error());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Helper function for NetworkDelegateCancelRequestAsynchronously and
// NetworkDelegateCancelRequestSynchronously. Sets up a blocking network
// delegate operating in |block_mode| and a request for |url|. It blocks the
// request in |stage| and cancels it with ERR_BLOCKED_BY_CLIENT.
void NetworkDelegateCancelRequest(BlockingNetworkDelegate::BlockMode block_mode,
BlockingNetworkDelegate::Stage stage,
const GURL& url) {
TestDelegate d;
BlockingNetworkDelegate network_delegate(block_mode);
network_delegate.set_retval(ERR_BLOCKED_BY_CLIENT);
network_delegate.set_block_on(stage);
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
{
URLRequest r(url, &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
EXPECT_EQ(ERR_BLOCKED_BY_CLIENT, r.status().error());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// The following 3 tests check that the network delegate can cancel a request
// synchronously in various stages of the request.
TEST_F(URLRequestTestHTTP, NetworkDelegateCancelRequestSynchronously1) {
ASSERT_TRUE(test_server_.Start());
NetworkDelegateCancelRequest(BlockingNetworkDelegate::SYNCHRONOUS,
BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST,
test_server_.GetURL(""));
}
TEST_F(URLRequestTestHTTP, NetworkDelegateCancelRequestSynchronously2) {
ASSERT_TRUE(test_server_.Start());
NetworkDelegateCancelRequest(BlockingNetworkDelegate::SYNCHRONOUS,
BlockingNetworkDelegate::ON_BEFORE_SEND_HEADERS,
test_server_.GetURL(""));
}
TEST_F(URLRequestTestHTTP, NetworkDelegateCancelRequestSynchronously3) {
ASSERT_TRUE(test_server_.Start());
NetworkDelegateCancelRequest(BlockingNetworkDelegate::SYNCHRONOUS,
BlockingNetworkDelegate::ON_HEADERS_RECEIVED,
test_server_.GetURL(""));
}
// The following 3 tests check that the network delegate can cancel a request
// asynchronously in various stages of the request.
TEST_F(URLRequestTestHTTP, NetworkDelegateCancelRequestAsynchronously1) {
ASSERT_TRUE(test_server_.Start());
NetworkDelegateCancelRequest(BlockingNetworkDelegate::AUTO_CALLBACK,
BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST,
test_server_.GetURL(""));
}
TEST_F(URLRequestTestHTTP, NetworkDelegateCancelRequestAsynchronously2) {
ASSERT_TRUE(test_server_.Start());
NetworkDelegateCancelRequest(BlockingNetworkDelegate::AUTO_CALLBACK,
BlockingNetworkDelegate::ON_BEFORE_SEND_HEADERS,
test_server_.GetURL(""));
}
TEST_F(URLRequestTestHTTP, NetworkDelegateCancelRequestAsynchronously3) {
ASSERT_TRUE(test_server_.Start());
NetworkDelegateCancelRequest(BlockingNetworkDelegate::AUTO_CALLBACK,
BlockingNetworkDelegate::ON_HEADERS_RECEIVED,
test_server_.GetURL(""));
}
// Tests that the network delegate can block and redirect a request to a new
// URL.
TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequest) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::AUTO_CALLBACK);
network_delegate.set_block_on(BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST);
GURL redirect_url(test_server_.GetURL("simple.html"));
network_delegate.set_redirect_url(redirect_url);
TestURLRequestContextWithProxy context(
test_server_.host_port_pair().ToString(),
&network_delegate);
{
GURL original_url(test_server_.GetURL("empty.html"));
URLRequest r(original_url, &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
EXPECT_EQ(0, r.status().error());
EXPECT_EQ(redirect_url, r.url());
EXPECT_EQ(original_url, r.original_url());
EXPECT_EQ(2U, r.url_chain().size());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that the network delegate can block and redirect a request to a new
// URL by setting a redirect_url and returning in OnBeforeURLRequest directly.
TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequestSynchronously) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::SYNCHRONOUS);
GURL redirect_url(test_server_.GetURL("simple.html"));
network_delegate.set_redirect_url(redirect_url);
TestURLRequestContextWithProxy context(
test_server_.host_port_pair().ToString(),
&network_delegate);
{
GURL original_url(test_server_.GetURL("empty.html"));
URLRequest r(original_url, &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
EXPECT_EQ(0, r.status().error());
EXPECT_EQ(redirect_url, r.url());
EXPECT_EQ(original_url, r.original_url());
EXPECT_EQ(2U, r.url_chain().size());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that redirects caused by the network delegate preserve POST data.
TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequestPost) {
ASSERT_TRUE(test_server_.Start());
const char kData[] = "hello world";
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::AUTO_CALLBACK);
network_delegate.set_block_on(BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST);
GURL redirect_url(test_server_.GetURL("echo"));
network_delegate.set_redirect_url(redirect_url);
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
{
GURL original_url(test_server_.GetURL("empty.html"));
URLRequest r(original_url, &d, &context);
r.set_method("POST");
r.set_upload(make_scoped_ptr(CreateSimpleUploadData(kData)));
HttpRequestHeaders headers;
headers.SetHeader(HttpRequestHeaders::kContentLength,
base::UintToString(arraysize(kData) - 1));
r.SetExtraRequestHeaders(headers);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
EXPECT_EQ(0, r.status().error());
EXPECT_EQ(redirect_url, r.url());
EXPECT_EQ(original_url, r.original_url());
EXPECT_EQ(2U, r.url_chain().size());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
EXPECT_EQ("POST", r.method());
EXPECT_EQ(kData, d.data_received());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that the network delegate can synchronously complete OnAuthRequired
// by taking no action. This indicates that the NetworkDelegate does not want to
// handle the challenge, and is passing the buck along to the
// URLRequest::Delegate.
TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncNoAction) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::SYNCHRONOUS);
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
d.set_credentials(AuthCredentials(kUser, kSecret));
{
GURL url(test_server_.GetURL("auth-basic"));
URLRequest r(url, &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
EXPECT_EQ(0, r.status().error());
EXPECT_EQ(200, r.GetResponseCode());
EXPECT_TRUE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that the network delegate can synchronously complete OnAuthRequired
// by setting credentials.
TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncSetAuth) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::SYNCHRONOUS);
network_delegate.set_block_on(BlockingNetworkDelegate::ON_AUTH_REQUIRED);
network_delegate.set_auth_retval(
NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH);
network_delegate.set_auth_credentials(AuthCredentials(kUser, kSecret));
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
{
GURL url(test_server_.GetURL("auth-basic"));
URLRequest r(url, &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
EXPECT_EQ(0, r.status().error());
EXPECT_EQ(200, r.GetResponseCode());
EXPECT_FALSE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that the network delegate can synchronously complete OnAuthRequired
// by cancelling authentication.
TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncCancel) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::SYNCHRONOUS);
network_delegate.set_block_on(BlockingNetworkDelegate::ON_AUTH_REQUIRED);
network_delegate.set_auth_retval(
NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH);
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
{
GURL url(test_server_.GetURL("auth-basic"));
URLRequest r(url, &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
EXPECT_EQ(OK, r.status().error());
EXPECT_EQ(401, r.GetResponseCode());
EXPECT_FALSE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that the network delegate can asynchronously complete OnAuthRequired
// by taking no action. This indicates that the NetworkDelegate does not want
// to handle the challenge, and is passing the buck along to the
// URLRequest::Delegate.
TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredAsyncNoAction) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::AUTO_CALLBACK);
network_delegate.set_block_on(BlockingNetworkDelegate::ON_AUTH_REQUIRED);
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
d.set_credentials(AuthCredentials(kUser, kSecret));
{
GURL url(test_server_.GetURL("auth-basic"));
URLRequest r(url, &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
EXPECT_EQ(0, r.status().error());
EXPECT_EQ(200, r.GetResponseCode());
EXPECT_TRUE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that the network delegate can asynchronously complete OnAuthRequired
// by setting credentials.
TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredAsyncSetAuth) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::AUTO_CALLBACK);
network_delegate.set_block_on(BlockingNetworkDelegate::ON_AUTH_REQUIRED);
network_delegate.set_auth_retval(
NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH);
AuthCredentials auth_credentials(kUser, kSecret);
network_delegate.set_auth_credentials(auth_credentials);
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
{
GURL url(test_server_.GetURL("auth-basic"));
URLRequest r(url, &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
EXPECT_EQ(0, r.status().error());
EXPECT_EQ(200, r.GetResponseCode());
EXPECT_FALSE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that the network delegate can asynchronously complete OnAuthRequired
// by cancelling authentication.
TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredAsyncCancel) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::AUTO_CALLBACK);
network_delegate.set_block_on(BlockingNetworkDelegate::ON_AUTH_REQUIRED);
network_delegate.set_auth_retval(
NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH);
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
{
GURL url(test_server_.GetURL("auth-basic"));
URLRequest r(url, &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
EXPECT_EQ(OK, r.status().error());
EXPECT_EQ(401, r.GetResponseCode());
EXPECT_FALSE(d.auth_required_called());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that we can handle when a network request was canceled while we were
// waiting for the network delegate.
// Part 1: Request is cancelled while waiting for OnBeforeURLRequest callback.
TEST_F(URLRequestTestHTTP, NetworkDelegateCancelWhileWaiting1) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::USER_CALLBACK);
network_delegate.set_block_on(BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST);
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
{
URLRequest r(test_server_.GetURL(""), &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(BlockingNetworkDelegate::ON_BEFORE_URL_REQUEST,
network_delegate.stage_blocked_for_callback());
EXPECT_EQ(0, network_delegate.completed_requests());
// Cancel before callback.
r.Cancel();
// Ensure that network delegate is notified.
EXPECT_EQ(1, network_delegate.completed_requests());
EXPECT_EQ(URLRequestStatus::CANCELED, r.status().status());
EXPECT_EQ(ERR_ABORTED, r.status().error());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that we can handle when a network request was canceled while we were
// waiting for the network delegate.
// Part 2: Request is cancelled while waiting for OnBeforeSendHeaders callback.
TEST_F(URLRequestTestHTTP, NetworkDelegateCancelWhileWaiting2) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::USER_CALLBACK);
network_delegate.set_block_on(
BlockingNetworkDelegate::ON_BEFORE_SEND_HEADERS);
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
{
URLRequest r(test_server_.GetURL(""), &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(BlockingNetworkDelegate::ON_BEFORE_SEND_HEADERS,
network_delegate.stage_blocked_for_callback());
EXPECT_EQ(0, network_delegate.completed_requests());
// Cancel before callback.
r.Cancel();
// Ensure that network delegate is notified.
EXPECT_EQ(1, network_delegate.completed_requests());
EXPECT_EQ(URLRequestStatus::CANCELED, r.status().status());
EXPECT_EQ(ERR_ABORTED, r.status().error());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that we can handle when a network request was canceled while we were
// waiting for the network delegate.
// Part 3: Request is cancelled while waiting for OnHeadersReceived callback.
TEST_F(URLRequestTestHTTP, NetworkDelegateCancelWhileWaiting3) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::USER_CALLBACK);
network_delegate.set_block_on(BlockingNetworkDelegate::ON_HEADERS_RECEIVED);
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
{
URLRequest r(test_server_.GetURL(""), &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(BlockingNetworkDelegate::ON_HEADERS_RECEIVED,
network_delegate.stage_blocked_for_callback());
EXPECT_EQ(0, network_delegate.completed_requests());
// Cancel before callback.
r.Cancel();
// Ensure that network delegate is notified.
EXPECT_EQ(1, network_delegate.completed_requests());
EXPECT_EQ(URLRequestStatus::CANCELED, r.status().status());
EXPECT_EQ(ERR_ABORTED, r.status().error());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// Tests that we can handle when a network request was canceled while we were
// waiting for the network delegate.
// Part 4: Request is cancelled while waiting for OnAuthRequired callback.
TEST_F(URLRequestTestHTTP, NetworkDelegateCancelWhileWaiting4) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
BlockingNetworkDelegate network_delegate(
BlockingNetworkDelegate::USER_CALLBACK);
network_delegate.set_block_on(BlockingNetworkDelegate::ON_AUTH_REQUIRED);
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
{
URLRequest r(test_server_.GetURL("auth-basic"), &d, &context);
r.Start();
MessageLoop::current()->Run();
EXPECT_EQ(BlockingNetworkDelegate::ON_AUTH_REQUIRED,
network_delegate.stage_blocked_for_callback());
EXPECT_EQ(0, network_delegate.completed_requests());
// Cancel before callback.
r.Cancel();
// Ensure that network delegate is notified.
EXPECT_EQ(1, network_delegate.completed_requests());
EXPECT_EQ(URLRequestStatus::CANCELED, r.status().status());
EXPECT_EQ(ERR_ABORTED, r.status().error());
EXPECT_EQ(1, network_delegate.created_requests());
EXPECT_EQ(0, network_delegate.destroyed_requests());
}
EXPECT_EQ(1, network_delegate.destroyed_requests());
}
// In this unit test, we're using the HTTPTestServer as a proxy server and
// issuing a CONNECT request with the magic host name "www.server-auth.com".
// The HTTPTestServer will return a 401 response, which we should balk at.
TEST_F(URLRequestTestHTTP, UnexpectedServerAuthTest) {
ASSERT_TRUE(test_server_.Start());
TestNetworkDelegate network_delegate; // Must outlive URLRequest.
TestURLRequestContextWithProxy context(
test_server_.host_port_pair().ToString(),
&network_delegate);
TestDelegate d;
{
URLRequest r(GURL("https://www.server-auth.com/"), &d, &context);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, r.status().error());
}
}
TEST_F(URLRequestTestHTTP, GetTest_NoCache) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
{
URLRequest r(test_server_.GetURL(""), &d, &default_context_);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_EQ(1, d.response_started_count());
EXPECT_FALSE(d.received_data_before_response());
EXPECT_NE(0, d.bytes_received());
EXPECT_EQ(test_server_.host_port_pair().host(),
r.GetSocketAddress().host());
EXPECT_EQ(test_server_.host_port_pair().port(),
r.GetSocketAddress().port());
// TODO(eroman): Add back the NetLog tests...
}
}
// This test has the server send a large number of cookies to the client.
// To ensure that no number of cookies causes a crash, a galloping binary
// search is used to estimate that maximum number of cookies that are accepted
// by the browser. Beyond the maximum number, the request will fail with
// ERR_RESPONSE_HEADERS_TOO_BIG.
TEST_F(URLRequestTestHTTP, GetTest_ManyCookies) {
ASSERT_TRUE(test_server_.Start());
int lower_bound = 0;
int upper_bound = 1;
// Double the number of cookies until the response header limits are
// exceeded.
while (DoManyCookiesRequest(upper_bound)) {
lower_bound = upper_bound;
upper_bound *= 2;
ASSERT_LT(upper_bound, 1000000);
}
int tolerance = upper_bound * 0.005;
if (tolerance < 2)
tolerance = 2;
// Perform a binary search to find the highest possible number of cookies,
// within the desired tolerance.
while (upper_bound - lower_bound >= tolerance) {
int num_cookies = (lower_bound + upper_bound) / 2;
if (DoManyCookiesRequest(num_cookies))
lower_bound = num_cookies;
else
upper_bound = num_cookies;
}
// Success: the test did not crash.
}
TEST_F(URLRequestTestHTTP, GetTest) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
{
URLRequest r(test_server_.GetURL(""), &d, &default_context_);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_EQ(1, d.response_started_count());
EXPECT_FALSE(d.received_data_before_response());
EXPECT_NE(0, d.bytes_received());
EXPECT_EQ(test_server_.host_port_pair().host(),
r.GetSocketAddress().host());
EXPECT_EQ(test_server_.host_port_pair().port(),
r.GetSocketAddress().port());
}
}
TEST_F(URLRequestTestHTTP, GetZippedTest) {
ASSERT_TRUE(test_server_.Start());
// Parameter that specifies the Content-Length field in the response:
// C - Compressed length.
// U - Uncompressed length.
// L - Large length (larger than both C & U).
// M - Medium length (between C & U).
// S - Small length (smaller than both C & U).
const char test_parameters[] = "CULMS";
const int num_tests = arraysize(test_parameters)- 1; // Skip NULL.
// C & U should be OK.
// L & M are larger than the data sent, and show an error.
// S has too little data, but we seem to accept it.
const bool test_expect_success[num_tests] =
{ true, true, false, false, true };
for (int i = 0; i < num_tests ; i++) {
TestDelegate d;
{
std::string test_file =
base::StringPrintf("compressedfiles/BullRunSpeech.txt?%c",
test_parameters[i]);
TestNetworkDelegate network_delegate; // Must outlive URLRequest.
TestURLRequestContext context(true);
context.set_network_delegate(&network_delegate);
context.Init();
URLRequest r(test_server_.GetURL(test_file), &d, &context);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_EQ(1, d.response_started_count());
EXPECT_FALSE(d.received_data_before_response());
VLOG(1) << " Received " << d.bytes_received() << " bytes"
<< " status = " << r.status().status()
<< " error = " << r.status().error();
if (test_expect_success[i]) {
EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status())
<< " Parameter = \"" << test_file << "\"";
} else {
EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
EXPECT_EQ(ERR_CONTENT_LENGTH_MISMATCH, r.status().error())
<< " Parameter = \"" << test_file << "\"";
}
}
}
}
// This test was disabled because it made chrome_frame_net_tests hang
// (see bug 102991).
TEST_F(URLRequestTestHTTP, DISABLED_HTTPSToHTTPRedirectNoRefererTest) {
ASSERT_TRUE(test_server_.Start());
TestServer https_test_server(TestServer::TYPE_HTTPS,
TestServer::kLocalhost,
FilePath(FILE_PATH_LITERAL("net/data/ssl")));
ASSERT_TRUE(https_test_server.Start());
// An https server is sent a request with an https referer,
// and responds with a redirect to an http url. The http
// server should not be sent the referer.
GURL http_destination = test_server_.GetURL("");
TestDelegate d;
URLRequest req(https_test_server.GetURL(
"server-redirect?" + http_destination.spec()), &d, &default_context_);
req.set_referrer("https://www.referrer.com/");
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(1, d.received_redirect_count());
EXPECT_EQ(http_destination, req.url());
EXPECT_EQ(std::string(), req.referrer());
}
TEST_F(URLRequestTestHTTP, MultipleRedirectTest) {
ASSERT_TRUE(test_server_.Start());
GURL destination_url = test_server_.GetURL("");
GURL middle_redirect_url = test_server_.GetURL(
"server-redirect?" + destination_url.spec());
GURL original_url = test_server_.GetURL(
"server-redirect?" + middle_redirect_url.spec());
TestDelegate d;
URLRequest req(original_url, &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(2, d.received_redirect_count());
EXPECT_EQ(destination_url, req.url());
EXPECT_EQ(original_url, req.original_url());
ASSERT_EQ(3U, req.url_chain().size());
EXPECT_EQ(original_url, req.url_chain()[0]);
EXPECT_EQ(middle_redirect_url, req.url_chain()[1]);
EXPECT_EQ(destination_url, req.url_chain()[2]);
}
namespace {
const char kExtraHeader[] = "Allow-Snafu";
const char kExtraValue[] = "fubar";
class RedirectWithAdditionalHeadersDelegate : public TestDelegate {
void OnReceivedRedirect(net::URLRequest* request,
const GURL& new_url,
bool* defer_redirect) {
TestDelegate::OnReceivedRedirect(request, new_url, defer_redirect);
request->SetExtraRequestHeaderByName(kExtraHeader, kExtraValue, false);
}
};
} // namespace
TEST_F(URLRequestTestHTTP, RedirectWithAdditionalHeadersTest) {
ASSERT_TRUE(test_server_.Start());
GURL destination_url = test_server_.GetURL(
"echoheader?" + std::string(kExtraHeader));
GURL original_url = test_server_.GetURL(
"server-redirect?" + destination_url.spec());
RedirectWithAdditionalHeadersDelegate d;
URLRequest req(original_url, &d, &default_context_);
req.Start();
MessageLoop::current()->Run();
std::string value;
const HttpRequestHeaders& headers = req.extra_request_headers();
EXPECT_TRUE(headers.GetHeader(kExtraHeader, &value));
EXPECT_EQ(kExtraValue, value);
EXPECT_FALSE(req.is_pending());
EXPECT_FALSE(req.is_redirecting());
EXPECT_EQ(kExtraValue, d.data_received());
}
namespace {
const char kExtraHeaderToRemove[] = "To-Be-Removed";
class RedirectWithHeaderRemovalDelegate : public TestDelegate {
void OnReceivedRedirect(net::URLRequest* request,
const GURL& new_url,
bool* defer_redirect) {
TestDelegate::OnReceivedRedirect(request, new_url, defer_redirect);
request->RemoveRequestHeaderByName(kExtraHeaderToRemove);
}
};
} // namespace
TEST_F(URLRequestTestHTTP, RedirectWithHeaderRemovalTest) {
ASSERT_TRUE(test_server_.Start());
GURL destination_url = test_server_.GetURL(
"echoheader?" + std::string(kExtraHeaderToRemove));
GURL original_url = test_server_.GetURL(
"server-redirect?" + destination_url.spec());
RedirectWithHeaderRemovalDelegate d;
URLRequest req(original_url, &d, &default_context_);
req.SetExtraRequestHeaderByName(kExtraHeaderToRemove, "dummy", false);
req.Start();
MessageLoop::current()->Run();
std::string value;
const HttpRequestHeaders& headers = req.extra_request_headers();
EXPECT_FALSE(headers.GetHeader(kExtraHeaderToRemove, &value));
EXPECT_FALSE(req.is_pending());
EXPECT_FALSE(req.is_redirecting());
EXPECT_EQ("None", d.data_received());
}
TEST_F(URLRequestTestHTTP, CancelTest) {
TestDelegate d;
{
URLRequest r(GURL("http://www.google.com/"), &d, &default_context_);
r.Start();
EXPECT_TRUE(r.is_pending());
r.Cancel();
MessageLoop::current()->Run();
// We expect to receive OnResponseStarted even though the request has been
// cancelled.
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(0, d.bytes_received());
EXPECT_FALSE(d.received_data_before_response());
}
}
TEST_F(URLRequestTestHTTP, CancelTest2) {
ASSERT_TRUE(test_server_.Start());
TestDelegate d;
{
URLRequest r(test_server_.GetURL(""), &d, &default_context_);
d.set_cancel_in_response_started(true);
r.Start();
EXPECT_TRUE(r.is_pending());
MessageLoop::current()->Run();
EXPECT_EQ(1, d.response_started_count());
EXPECT_EQ(0, d.bytes_received());
EXPECT_FALSE(d.received_data_before_response());
EXPECT_EQ(URLRequestStatus::CANCELED, r.status().status());
}
}