| // 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 <algorithm> |
| #include <utility> |
| |
| // This must be before Windows headers |
| #include "build/build_config.h" |
| |
| #if defined(OS_WIN) |
| #include <objbase.h> |
| #include <shlobj.h> |
| #include <windows.h> |
| #include <wrl/client.h> |
| #endif |
| |
| #include <algorithm> |
| #include <limits> |
| #include <memory> |
| |
| #include "base/base64url.h" |
| #include "base/bind.h" |
| #include "base/compiler_specific.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/format_macros.h" |
| #include "base/json/json_reader.h" |
| #include "base/location.h" |
| #include "base/macros.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/path_service.h" |
| #include "base/power_monitor/power_monitor.h" |
| #include "base/power_monitor/power_monitor_source.h" |
| #include "base/run_loop.h" |
| #include "base/single_thread_task_runner.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_piece.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/values.h" |
| #if defined(STARBOARD) |
| #include "base/buildflag.h" |
| #else |
| #include "build/buildflag.h" |
| #endif |
| #include "net/base/chunked_upload_data_stream.h" |
| #include "net/base/directory_listing.h" |
| #include "net/base/elements_upload_data_stream.h" |
| #include "net/base/load_flags.h" |
| #include "net/base/load_timing_info.h" |
| #include "net/base/load_timing_info_test_util.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/net_module.h" |
| #include "net/base/proxy_server.h" |
| #include "net/base/request_priority.h" |
| #include "net/base/test_completion_callback.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/base/url_util.h" |
| #include "net/cert/crl_set.h" |
| #include "net/cert/ct_policy_enforcer.h" |
| #include "net/cert/ct_policy_status.h" |
| #include "net/cert/do_nothing_ct_verifier.h" |
| #include "net/cert/ev_root_ca_metadata.h" |
| #include "net/cert/mock_cert_verifier.h" |
| #include "net/cert/multi_log_ct_verifier.h" |
| #include "net/cert/signed_certificate_timestamp_and_status.h" |
| #include "net/cert/test_root_certs.h" |
| #include "net/cookies/cookie_monster.h" |
| #include "net/cookies/cookie_store_test_helpers.h" |
| #include "net/disk_cache/disk_cache.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/http/http_byte_range.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/http/http_server_properties_impl.h" |
| #include "net/http/http_util.h" |
| #include "net/log/net_log_event_type.h" |
| #include "net/log/net_log_source.h" |
| #include "net/log/test_net_log.h" |
| #include "net/log/test_net_log_entry.h" |
| #include "net/log/test_net_log_util.h" |
| #include "net/net_buildflags.h" |
| #include "net/proxy_resolution/proxy_resolution_service.h" |
| #include "net/quic/mock_crypto_client_stream_factory.h" |
| #include "net/quic/quic_server_info.h" |
| #include "net/socket/socket_test_util.h" |
| #include "net/socket/ssl_client_socket.h" |
| #include "net/ssl/channel_id_service.h" |
| #include "net/ssl/client_cert_identity_test_util.h" |
| #include "net/ssl/default_channel_id_store.h" |
| #include "net/ssl/ssl_connection_status_flags.h" |
| #include "net/ssl/ssl_private_key.h" |
| #include "net/ssl/ssl_server_config.h" |
| #include "net/test/cert_test_util.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/test/embedded_test_server/http_request.h" |
| #include "net/test/embedded_test_server/http_response.h" |
| #include "net/test/gtest_util.h" |
| #include "net/test/spawned_test_server/spawned_test_server.h" |
| #include "net/test/test_data_directory.h" |
| #include "net/test/test_with_scoped_task_environment.h" |
| #include "net/test/url_request/url_request_failed_job.h" |
| #include "net/test/url_request/url_request_mock_http_job.h" |
| #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
| #include "net/url_request/data_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_filter.h" |
| #include "net/url_request/url_request_http_job.h" |
| #include "net/url_request/url_request_http_job_histogram.h" |
| #include "net/url_request/url_request_intercepting_job_factory.h" |
| #include "net/url_request/url_request_interceptor.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/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/platform_test.h" |
| |
| #if defined(OS_FUCHSIA) |
| #define USE_BUILTIN_CERT_VERIFIER |
| #endif |
| |
| #if !BUILDFLAG(DISABLE_FILE_SUPPORT) |
| #include "net/base/filename_util.h" |
| #include "net/url_request/file_protocol_handler.h" |
| #include "net/url_request/url_request_file_dir_job.h" |
| #endif |
| |
| #if !BUILDFLAG(DISABLE_FTP_SUPPORT) && !defined(OS_ANDROID) |
| #include "net/ftp/ftp_network_layer.h" |
| #include "net/url_request/ftp_protocol_handler.h" |
| #endif |
| |
| #if defined(OS_WIN) |
| #include "base/win/scoped_com_initializer.h" |
| #endif |
| |
| #if BUILDFLAG(ENABLE_REPORTING) |
| #include "net/network_error_logging/network_error_logging_service.h" |
| #include "net/reporting/reporting_policy.h" |
| #include "net/reporting/reporting_service.h" |
| #endif // BUILDFLAG(ENABLE_REPORTING) |
| |
| #if defined(OS_ANDROID) || defined(USE_BUILTIN_CERT_VERIFIER) |
| #include "net/cert/cert_net_fetcher.h" |
| #include "net/cert_net/cert_net_fetcher_impl.h" |
| #endif |
| |
| #if defined(USE_NSS_CERTS) |
| #include "net/cert_net/nss_ocsp.h" |
| #endif |
| |
| using net::test::IsError; |
| using net::test::IsOk; |
| |
| using base::ASCIIToUTF16; |
| using base::Time; |
| using std::string; |
| |
| namespace net { |
| |
| namespace { |
| |
| namespace test_default { |
| #include "net/http/transport_security_state_static_unittest_default.h" |
| #include "starboard/common/string.h" |
| #include "starboard/memory.h" |
| #include "starboard/types.h" |
| } |
| |
| const base::string16 kChrome(ASCIIToUTF16("chrome")); |
| const base::string16 kSecret(ASCIIToUTF16("secret")); |
| const base::string16 kUser(ASCIIToUTF16("user")); |
| |
| const base::FilePath::CharType kTestFilePath[] = |
| FILE_PATH_LITERAL("net/data/url_request_unittest"); |
| |
| #if !BUILDFLAG(DISABLE_FTP_SUPPORT) && !defined(OS_ANDROID) && \ |
| !defined(OS_FUCHSIA) |
| // Test file used in most FTP tests. |
| const char kFtpTestFile[] = "BullRunSpeech.txt"; |
| #endif |
| |
| // Tests load timing information in the case a fresh connection was used, with |
| // no proxy. |
| void TestLoadTimingNotReused(const LoadTimingInfo& load_timing_info, |
| int connect_timing_flags) { |
| EXPECT_FALSE(load_timing_info.socket_reused); |
| EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id); |
| |
| EXPECT_FALSE(load_timing_info.request_start_time.is_null()); |
| EXPECT_FALSE(load_timing_info.request_start.is_null()); |
| |
| EXPECT_LE(load_timing_info.request_start, |
| load_timing_info.connect_timing.connect_start); |
| ExpectConnectTimingHasTimes(load_timing_info.connect_timing, |
| connect_timing_flags); |
| EXPECT_LE(load_timing_info.connect_timing.connect_end, |
| load_timing_info.send_start); |
| EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); |
| EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_end); |
| |
| EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null()); |
| EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null()); |
| } |
| |
| // Same as above, but with proxy times. |
| void TestLoadTimingNotReusedWithProxy( |
| const LoadTimingInfo& load_timing_info, |
| int connect_timing_flags) { |
| EXPECT_FALSE(load_timing_info.socket_reused); |
| EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id); |
| |
| EXPECT_FALSE(load_timing_info.request_start_time.is_null()); |
| EXPECT_FALSE(load_timing_info.request_start.is_null()); |
| |
| EXPECT_LE(load_timing_info.request_start, |
| load_timing_info.proxy_resolve_start); |
| EXPECT_LE(load_timing_info.proxy_resolve_start, |
| load_timing_info.proxy_resolve_end); |
| EXPECT_LE(load_timing_info.proxy_resolve_end, |
| load_timing_info.connect_timing.connect_start); |
| ExpectConnectTimingHasTimes(load_timing_info.connect_timing, |
| connect_timing_flags); |
| EXPECT_LE(load_timing_info.connect_timing.connect_end, |
| load_timing_info.send_start); |
| EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); |
| EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_end); |
| } |
| |
| // Same as above, but with a reused socket and proxy times. |
| void TestLoadTimingReusedWithProxy( |
| const LoadTimingInfo& load_timing_info) { |
| EXPECT_TRUE(load_timing_info.socket_reused); |
| EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id); |
| |
| EXPECT_FALSE(load_timing_info.request_start_time.is_null()); |
| EXPECT_FALSE(load_timing_info.request_start.is_null()); |
| |
| ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); |
| |
| EXPECT_LE(load_timing_info.request_start, |
| load_timing_info.proxy_resolve_start); |
| EXPECT_LE(load_timing_info.proxy_resolve_start, |
| load_timing_info.proxy_resolve_end); |
| EXPECT_LE(load_timing_info.proxy_resolve_end, |
| load_timing_info.send_start); |
| EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); |
| EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_end); |
| } |
| |
| #if !BUILDFLAG(DISABLE_FILE_SUPPORT) |
| // Tests load timing information in the case of a cache hit, when no cache |
| // validation request was sent over the wire. |
| base::StringPiece TestNetResourceProvider(int key) { |
| return "header"; |
| } |
| |
| 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'; |
| } |
| } |
| #endif |
| |
| void TestLoadTimingCacheHitNoNetwork( |
| const LoadTimingInfo& load_timing_info) { |
| EXPECT_FALSE(load_timing_info.socket_reused); |
| EXPECT_EQ(NetLogSource::kInvalidId, load_timing_info.socket_log_id); |
| |
| EXPECT_FALSE(load_timing_info.request_start_time.is_null()); |
| EXPECT_FALSE(load_timing_info.request_start.is_null()); |
| |
| ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); |
| EXPECT_LE(load_timing_info.request_start, load_timing_info.send_start); |
| EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end); |
| EXPECT_LE(load_timing_info.send_end, load_timing_info.receive_headers_end); |
| |
| EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null()); |
| EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null()); |
| } |
| |
| #if !BUILDFLAG(DISABLE_FTP_SUPPORT) && !defined(OS_ANDROID) && \ |
| !defined(OS_FUCHSIA) |
| // Tests load timing in the case that there is no HTTP response. This can be |
| // used to test in the case of errors or non-HTTP requests. |
| void TestLoadTimingNoHttpResponse( |
| const LoadTimingInfo& load_timing_info) { |
| EXPECT_FALSE(load_timing_info.socket_reused); |
| EXPECT_EQ(NetLogSource::kInvalidId, load_timing_info.socket_log_id); |
| |
| // Only the request times should be non-null. |
| EXPECT_FALSE(load_timing_info.request_start_time.is_null()); |
| EXPECT_FALSE(load_timing_info.request_start.is_null()); |
| |
| ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing); |
| |
| EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null()); |
| EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null()); |
| EXPECT_TRUE(load_timing_info.send_start.is_null()); |
| EXPECT_TRUE(load_timing_info.send_end.is_null()); |
| EXPECT_TRUE(load_timing_info.receive_headers_end.is_null()); |
| } |
| #endif |
| |
| // Test power monitor source that can simulate entering suspend mode. Can't use |
| // the one in base/ because it insists on bringing its own MessageLoop. |
| class TestPowerMonitorSource : public base::PowerMonitorSource { |
| public: |
| TestPowerMonitorSource() = default; |
| ~TestPowerMonitorSource() override = default; |
| |
| void Shutdown() override {} |
| |
| void Suspend() { ProcessPowerEvent(SUSPEND_EVENT); } |
| |
| void Resume() { ProcessPowerEvent(RESUME_EVENT); } |
| |
| bool IsOnBatteryPowerImpl() override { return false; } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(TestPowerMonitorSource); |
| }; |
| |
| // Job that allows monitoring of its priority. |
| class PriorityMonitoringURLRequestJob : public URLRequestTestJob { |
| public: |
| // The latest priority of the job is always written to |request_priority_|. |
| PriorityMonitoringURLRequestJob(URLRequest* request, |
| NetworkDelegate* network_delegate, |
| RequestPriority* request_priority) |
| : URLRequestTestJob(request, network_delegate), |
| request_priority_(request_priority) { |
| *request_priority_ = DEFAULT_PRIORITY; |
| } |
| |
| void SetPriority(RequestPriority priority) override { |
| *request_priority_ = priority; |
| URLRequestTestJob::SetPriority(priority); |
| } |
| |
| private: |
| RequestPriority* const request_priority_; |
| }; |
| |
| // 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::CaseInsensitiveCompareASCII<char>()); |
| return it != haystack.end(); |
| } |
| |
| std::unique_ptr<UploadDataStream> CreateSimpleUploadData(const char* data) { |
| std::unique_ptr<UploadElementReader> reader( |
| new UploadBytesElementReader(data, strlen(data))); |
| return ElementsUploadDataStream::CreateWithReader(std::move(reader), 0); |
| } |
| |
| // Verify that the SSLInfo of a successful SSL connection has valid values. |
| void CheckSSLInfo(const SSLInfo& ssl_info) { |
| // -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. |
| uint16_t cipher_suite = |
| SSLConnectionStatusToCipherSuite(ssl_info.connection_status); |
| EXPECT_NE(0U, cipher_suite); |
| } |
| |
| void CheckFullRequestHeaders(const HttpRequestHeaders& headers, |
| const GURL& host_url) { |
| std::string sent_value; |
| |
| EXPECT_TRUE(headers.GetHeader("Host", &sent_value)); |
| EXPECT_EQ(GetHostAndOptionalPort(host_url), sent_value); |
| |
| EXPECT_TRUE(headers.GetHeader("Connection", &sent_value)); |
| EXPECT_EQ("keep-alive", sent_value); |
| } |
| |
| // 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 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); |
| |
| // Runs the message loop until the delegate blocks. |
| void RunUntilBlocked(); |
| |
| // 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 OnBlocked(); |
| |
| void RunCallback(int response, CompletionOnceCallback callback); |
| void RunAuthCallback(AuthRequiredResponse response, AuthCallback callback); |
| |
| // TestNetworkDelegate implementation. |
| int OnBeforeURLRequest(URLRequest* request, |
| CompletionOnceCallback callback, |
| GURL* new_url) override; |
| |
| int OnBeforeStartTransaction(URLRequest* request, |
| CompletionOnceCallback callback, |
| HttpRequestHeaders* headers) override; |
| |
| int OnHeadersReceived( |
| URLRequest* request, |
| CompletionOnceCallback callback, |
| const HttpResponseHeaders* original_response_headers, |
| scoped_refptr<HttpResponseHeaders>* override_response_headers, |
| GURL* allowed_unsafe_redirect_url) override; |
| |
| NetworkDelegate::AuthRequiredResponse OnAuthRequired( |
| URLRequest* request, |
| const AuthChallengeInfo& auth_info, |
| 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, CompletionOnceCallback 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 during OnBeforeURLRequest. |
| 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. |
| CompletionOnceCallback callback_; |
| AuthCallback auth_callback_; |
| |
| // Closure to run to exit RunUntilBlocked(). |
| base::OnceClosure on_blocked_; |
| |
| 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), |
| weak_factory_(this) { |
| } |
| |
| void BlockingNetworkDelegate::RunUntilBlocked() { |
| base::RunLoop run_loop; |
| on_blocked_ = run_loop.QuitClosure(); |
| run_loop.Run(); |
| } |
| |
| 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_); |
| CompletionOnceCallback callback = std::move(callback_); |
| Reset(); |
| |
| // |callback| may trigger completion of a request, so post it as a task, so |
| // it will run under a subsequent TestDelegate::RunUntilComplete() loop. |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::BindOnce(&BlockingNetworkDelegate::RunCallback, |
| weak_factory_.GetWeakPtr(), response, |
| std::move(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 = std::move(auth_callback_); |
| Reset(); |
| RunAuthCallback(response, std::move(auth_callback)); |
| } |
| |
| void BlockingNetworkDelegate::OnBlocked() { |
| // If this fails due to |on_blocked_| being null then OnBlocked() was run by |
| // a RunLoop other than RunUntilBlocked(), indicating a bug in the calling |
| // test. |
| std::move(on_blocked_).Run(); |
| } |
| |
| void BlockingNetworkDelegate::RunCallback(int response, |
| CompletionOnceCallback callback) { |
| std::move(callback).Run(response); |
| } |
| |
| void BlockingNetworkDelegate::RunAuthCallback(AuthRequiredResponse response, |
| AuthCallback callback) { |
| if (auth_retval_ == AUTH_REQUIRED_RESPONSE_SET_AUTH) { |
| ASSERT_TRUE(target_auth_credentials_ != NULL); |
| *target_auth_credentials_ = auth_credentials_; |
| } |
| std::move(callback).Run(response); |
| } |
| |
| int BlockingNetworkDelegate::OnBeforeURLRequest(URLRequest* request, |
| CompletionOnceCallback callback, |
| GURL* new_url) { |
| if (redirect_url_ == request->url()) |
| return OK; // We've already seen this request and redirected elsewhere. |
| |
| // TestNetworkDelegate always completes synchronously. |
| CHECK_NE(ERR_IO_PENDING, TestNetworkDelegate::OnBeforeURLRequest( |
| request, base::NullCallback(), new_url)); |
| |
| if (!redirect_url_.is_empty()) |
| *new_url = redirect_url_; |
| |
| return MaybeBlockStage(ON_BEFORE_URL_REQUEST, std::move(callback)); |
| } |
| |
| int BlockingNetworkDelegate::OnBeforeStartTransaction( |
| URLRequest* request, |
| CompletionOnceCallback callback, |
| HttpRequestHeaders* headers) { |
| // TestNetworkDelegate always completes synchronously. |
| CHECK_NE(ERR_IO_PENDING, TestNetworkDelegate::OnBeforeStartTransaction( |
| request, base::NullCallback(), headers)); |
| |
| return MaybeBlockStage(ON_BEFORE_SEND_HEADERS, std::move(callback)); |
| } |
| |
| int BlockingNetworkDelegate::OnHeadersReceived( |
| URLRequest* request, |
| CompletionOnceCallback callback, |
| const HttpResponseHeaders* original_response_headers, |
| scoped_refptr<HttpResponseHeaders>* override_response_headers, |
| GURL* allowed_unsafe_redirect_url) { |
| // TestNetworkDelegate always completes synchronously. |
| CHECK_NE(ERR_IO_PENDING, |
| TestNetworkDelegate::OnHeadersReceived( |
| request, base::NullCallback(), original_response_headers, |
| override_response_headers, allowed_unsafe_redirect_url)); |
| |
| return MaybeBlockStage(ON_HEADERS_RECEIVED, std::move(callback)); |
| } |
| |
| NetworkDelegate::AuthRequiredResponse BlockingNetworkDelegate::OnAuthRequired( |
| URLRequest* request, |
| const AuthChallengeInfo& auth_info, |
| AuthCallback callback, |
| AuthCredentials* credentials) { |
| // TestNetworkDelegate always completes synchronously. |
| CHECK_NE(AUTH_REQUIRED_RESPONSE_IO_PENDING, |
| TestNetworkDelegate::OnAuthRequired( |
| request, auth_info, base::NullCallback(), 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: |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::BindOnce(&BlockingNetworkDelegate::RunAuthCallback, |
| weak_factory_.GetWeakPtr(), auth_retval_, |
| std::move(callback))); |
| return AUTH_REQUIRED_RESPONSE_IO_PENDING; |
| |
| case USER_CALLBACK: |
| auth_callback_ = std::move(callback); |
| stage_blocked_for_callback_ = ON_AUTH_REQUIRED; |
| // We may reach here via a callback prior to RunUntilBlocked(), so post |
| // a task to fetch and run the |on_blocked_| closure. |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::BindOnce(&BlockingNetworkDelegate::OnBlocked, |
| weak_factory_.GetWeakPtr())); |
| 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, |
| CompletionOnceCallback 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: |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::BindOnce(&BlockingNetworkDelegate::RunCallback, |
| weak_factory_.GetWeakPtr(), retval_, |
| std::move(callback))); |
| return ERR_IO_PENDING; |
| |
| case USER_CALLBACK: |
| callback_ = std::move(callback); |
| stage_blocked_for_callback_ = stage; |
| // We may reach here via a callback prior to RunUntilBlocked(), so post |
| // a task to fetch and run the |on_blocked_| closure. |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::BindOnce(&BlockingNetworkDelegate::OnBlocked, |
| weak_factory_.GetWeakPtr())); |
| 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_resolution_service( |
| ProxyResolutionService::CreateFixed(proxy, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| set_network_delegate(delegate); |
| Init(); |
| } |
| ~TestURLRequestContextWithProxy() override = default; |
| }; |
| |
| // A mock ReportSenderInterface that just remembers the latest report |
| // URI and report to be sent. |
| class MockCertificateReportSender |
| : public TransportSecurityState::ReportSenderInterface { |
| public: |
| MockCertificateReportSender() = default; |
| ~MockCertificateReportSender() override = default; |
| |
| void Send(const GURL& report_uri, |
| base::StringPiece content_type, |
| base::StringPiece report, |
| const base::Callback<void()>& success_callback, |
| const base::Callback<void(const GURL&, int, int)>& error_callback) |
| override { |
| latest_report_uri_ = report_uri; |
| report.CopyToString(&latest_report_); |
| content_type.CopyToString(&latest_content_type_); |
| } |
| const GURL& latest_report_uri() { return latest_report_uri_; } |
| const std::string& latest_report() { return latest_report_; } |
| const std::string& latest_content_type() { return latest_content_type_; } |
| |
| private: |
| GURL latest_report_uri_; |
| std::string latest_report_; |
| std::string latest_content_type_; |
| }; |
| |
| class TestExperimentalFeaturesNetworkDelegate : public TestNetworkDelegate { |
| public: |
| bool OnAreExperimentalCookieFeaturesEnabled() const override { return true; } |
| }; |
| |
| // OCSPErrorTestDelegate caches the SSLInfo passed to OnSSLCertificateError. |
| // This is needed because after the certificate failure, the URLRequest will |
| // retry the connection, and return a partial SSLInfo with a cached cert status. |
| // The partial SSLInfo does not have the OCSP information filled out. |
| class OCSPErrorTestDelegate : public TestDelegate { |
| public: |
| void OnSSLCertificateError(URLRequest* request, |
| const SSLInfo& ssl_info, |
| bool fatal) override { |
| ssl_info_ = ssl_info; |
| on_ssl_certificate_error_called_ = true; |
| TestDelegate::OnSSLCertificateError(request, ssl_info, fatal); |
| } |
| |
| bool on_ssl_certificate_error_called() { |
| return on_ssl_certificate_error_called_; |
| } |
| |
| SSLInfo ssl_info() { return ssl_info_; } |
| |
| private: |
| bool on_ssl_certificate_error_called_ = false; |
| SSLInfo ssl_info_; |
| }; |
| |
| } // namespace |
| |
| // Inherit PlatformTest since we require the autorelease pool on Mac OS X. |
| class URLRequestTest : public PlatformTest, public WithScopedTaskEnvironment { |
| public: |
| URLRequestTest() |
| : default_context_(std::make_unique<TestURLRequestContext>(true)) { |
| default_context_->set_network_delegate(&default_network_delegate_); |
| default_context_->set_net_log(&net_log_); |
| job_factory_impl_ = new URLRequestJobFactoryImpl(); |
| job_factory_.reset(job_factory_impl_); |
| } |
| |
| ~URLRequestTest() override { |
| // URLRequestJobs may post clean-up tasks on destruction. |
| base::RunLoop().RunUntilIdle(); |
| |
| SetTransportSecurityStateSourceForTesting(nullptr); |
| } |
| |
| void SetUp() override { |
| SetUpFactory(); |
| default_context_->set_job_factory(job_factory_.get()); |
| default_context_->Init(); |
| PlatformTest::SetUp(); |
| } |
| |
| void TearDown() override { default_context_.reset(); } |
| |
| virtual void SetUpFactory() { |
| job_factory_impl_->SetProtocolHandler( |
| "data", std::make_unique<DataProtocolHandler>()); |
| #if !BUILDFLAG(DISABLE_FILE_SUPPORT) |
| job_factory_impl_->SetProtocolHandler( |
| "file", std::make_unique<FileProtocolHandler>( |
| base::ThreadTaskRunnerHandle::Get())); |
| #endif |
| } |
| |
| TestNetworkDelegate* default_network_delegate() { |
| return &default_network_delegate_; |
| } |
| |
| TestURLRequestContext& default_context() const { return *default_context_; } |
| |
| // Adds the TestJobInterceptor to the default context. |
| TestJobInterceptor* AddTestInterceptor() { |
| TestJobInterceptor* protocol_handler_ = new TestJobInterceptor(); |
| job_factory_impl_->SetProtocolHandler("http", nullptr); |
| job_factory_impl_->SetProtocolHandler("http", |
| base::WrapUnique(protocol_handler_)); |
| return protocol_handler_; |
| } |
| |
| // Creates a temp test file and writes |data| to the file. The file will be |
| // deleted after the test completes. |
| void CreateTestFile(const char* data, |
| size_t data_size, |
| base::FilePath* test_file) { |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| // Get an absolute path since |temp_dir| can contain a symbolic link. As of |
| // now, Mac and Android bots return a path with a symbolic link. |
| base::FilePath absolute_temp_dir = |
| base::MakeAbsoluteFilePath(temp_dir_.GetPath()); |
| |
| ASSERT_TRUE(base::CreateTemporaryFileInDir(absolute_temp_dir, test_file)); |
| ASSERT_EQ(static_cast<int>(data_size), |
| base::WriteFile(*test_file, data, data_size)); |
| } |
| |
| protected: |
| TestNetLog net_log_; |
| TestNetworkDelegate default_network_delegate_; // Must outlive URLRequest. |
| URLRequestJobFactoryImpl* job_factory_impl_; |
| std::unique_ptr<URLRequestJobFactory> job_factory_; |
| std::unique_ptr<TestURLRequestContext> default_context_; |
| base::ScopedTempDir temp_dir_; |
| }; |
| |
| // This NetworkDelegate is picky about what files are accessible. Only |
| // whitelisted files are allowed. |
| class CookieBlockingNetworkDelegate : public TestNetworkDelegate { |
| public: |
| CookieBlockingNetworkDelegate() = default; |
| ; |
| |
| // Adds |directory| to the access white list. |
| void AddToWhitelist(const base::FilePath& directory) { |
| whitelist_.insert(directory); |
| } |
| |
| private: |
| // Returns true if |path| matches the white list. |
| bool OnCanAccessFileInternal(const base::FilePath& path) const { |
| for (const auto& directory : whitelist_) { |
| if (directory == path || directory.IsParent(path)) |
| return true; |
| } |
| return false; |
| } |
| |
| // Returns true only if both |original_path| and |absolute_path| match the |
| // white list. |
| bool OnCanAccessFile(const URLRequest& request, |
| const base::FilePath& original_path, |
| const base::FilePath& absolute_path) const override { |
| return (OnCanAccessFileInternal(original_path) && |
| OnCanAccessFileInternal(absolute_path)); |
| } |
| |
| std::set<base::FilePath> whitelist_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CookieBlockingNetworkDelegate); |
| }; |
| |
| TEST_F(URLRequestTest, AboutBlankTest) { |
| TestDelegate d; |
| { |
| std::unique_ptr<URLRequest> r( |
| default_context().CreateRequest(GURL("about:blank"), DEFAULT_PRIORITY, |
| &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| r->Start(); |
| EXPECT_TRUE(r->is_pending()); |
| |
| d.RunUntilComplete(); |
| |
| 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()); |
| |
| HttpRequestHeaders headers; |
| EXPECT_FALSE(r->GetFullRequestHeaders(&headers)); |
| } |
| } |
| |
| TEST_F(URLRequestTest, DataURLImageTest) { |
| TestDelegate d; |
| { |
| // Use our nice little Chrome logo. |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| GURL("data:image/png;base64," |
| "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADVklEQVQ4jX2TfUwUB" |
| "BjG3w1y+HGcd9dxhXR8T4awOccJGgOSWclHImznLkTlSw0DDQXkrmgYgbUYnlQTqQ" |
| "xIEVxitD5UMCATRA1CEEg+Qjw3bWDxIauJv/5oumqs39/P827vnucRmYN0gyF01GI" |
| "5MpCVdW0gO7tvNC+vqSEtbZefk5NuLv1jdJ46p/zw0HeH4+PHr3h7c1mjoV2t5rKz" |
| "Mx1+fg9bAgK6zHq9cU5z+LpA3xOtx34+vTeT21onRuzssC3zxbbSwC13d/pFuC7Ck" |
| "IMDxQpF7r/MWq12UctI1dWWm99ypqSYmRUBdKem8MkrO/kgaTt1O7YzlpzE5GIVd0" |
| "WYUqt57yWf2McHTObYPbVD+ZwbtlLTVMZ3BW+TnLyXLaWtmEq6WJVbT3HBh3Svj2H" |
| "QQcm43XwmtoYM6vVKleh0uoWvnzW3v3MpidruPTQPf0bia7sJOtBM0ufTWNvus/nk" |
| "DFHF9ZS+uYVjRUasMeHUmyLYtcklTvzWGFZnNOXczThvpKIzjcahSqIzkvDLayDq6" |
| "D3eOjtBbNUEIZYyqsvj4V4wY92eNJ4IoyhTbxXX1T5xsV9tm9r4TQwHLiZw/pdDZJ" |
| "ea8TKmsmR/K0uLh/GwnCHghTja6lPhphezPfO5/5MrVvMzNaI3+ERHfrFzPKQukrQ" |
| "GI4d/3EFD/3E2mVNYvi4at7CXWREaxZGD+3hg28zD3gVMd6q5c8GdosynKmSeRuGz" |
| "pjyl1/9UDGtPR5HeaKT8Wjo17WXk579BXVUhN64ehF9fhRtq/uxxZKzNiZFGD0wRC" |
| "3NFROZ5mwIPL/96K/rKMMLrIzF9uhHr+/sYH7DAbwlgC4J+R2Z7FUx1qLnV7MGF40" |
| "smVSoJ/jvHRfYhQeUJd/SnYtGWhPHR0Sz+GE2F2yth0B36Vcz2KpnufBJbsysjjW4" |
| "kblBUiIjiURUWqJY65zxbnTy57GQyH58zgy0QBtTQv5gH15XMdKkYu+TGaJMnlm2O" |
| "34uI4b9tflqp1+QEFGzoW/ulmcofcpkZCYJhDfSpme7QcrHa+Xfji8paEQkTkSfmm" |
| "oRWRNZr/F1KfVMjW+IKEnv2FwZfKdzt0BQR6lClcZR0EfEXEfv/G6W9iLiIyCoReV" |
| "5EnhORIBHx+ufPj/gLB/zGI/G4Bk0AAAAASUVORK5CYII="), |
| DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| r->Start(); |
| EXPECT_TRUE(r->is_pending()); |
| |
| d.RunUntilComplete(); |
| |
| 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()); |
| |
| HttpRequestHeaders headers; |
| EXPECT_FALSE(r->GetFullRequestHeaders(&headers)); |
| } |
| } |
| |
| #if !BUILDFLAG(DISABLE_FILE_SUPPORT) |
| TEST_F(URLRequestTest, FileTest) { |
| const char kTestFileContent[] = "Hello"; |
| base::FilePath test_file; |
| ASSERT_NO_FATAL_FAILURE( |
| CreateTestFile(kTestFileContent, sizeof(kTestFileContent), &test_file)); |
| |
| GURL test_url = FilePathToFileURL(test_file); |
| |
| TestDelegate d; |
| { |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| test_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| r->Start(); |
| EXPECT_TRUE(r->is_pending()); |
| |
| d.RunUntilComplete(); |
| |
| 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>(sizeof(kTestFileContent))); |
| EXPECT_EQ("", r->GetSocketAddress().host()); |
| EXPECT_EQ(0, r->GetSocketAddress().port()); |
| |
| HttpRequestHeaders headers; |
| EXPECT_FALSE(r->GetFullRequestHeaders(&headers)); |
| } |
| } |
| |
| TEST_F(URLRequestTest, FileTestCancel) { |
| const char kTestFileContent[] = "Hello"; |
| base::FilePath test_file; |
| ASSERT_NO_FATAL_FAILURE( |
| CreateTestFile(kTestFileContent, sizeof(kTestFileContent), &test_file)); |
| |
| GURL test_url = FilePathToFileURL(test_file); |
| |
| TestDelegate d; |
| { |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| test_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| r->Start(); |
| EXPECT_TRUE(r->is_pending()); |
| r->Cancel(); |
| } |
| // Async cancellation should be safe even when URLRequest has been already |
| // destroyed. |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST_F(URLRequestTest, FileTestFullSpecifiedRange) { |
| const size_t buffer_size = 4000; |
| std::unique_ptr<char[]> buffer(new char[buffer_size]); |
| FillBuffer(buffer.get(), buffer_size); |
| |
| base::FilePath test_file; |
| ASSERT_NO_FATAL_FAILURE( |
| CreateTestFile(buffer.get(), buffer_size, &test_file)); |
| GURL temp_url = FilePathToFileURL(test_file); |
| |
| 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; |
| { |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| temp_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| HttpRequestHeaders headers; |
| headers.SetHeader( |
| HttpRequestHeaders::kRange, |
| HttpByteRange::Bounded( |
| first_byte_position, last_byte_position).GetHeaderValue()); |
| r->SetExtraRequestHeaders(headers); |
| r->Start(); |
| EXPECT_TRUE(r->is_pending()); |
| |
| d.RunUntilComplete(); |
| |
| 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()); |
| } |
| } |
| |
| TEST_F(URLRequestTest, FileTestHalfSpecifiedRange) { |
| const size_t buffer_size = 4000; |
| std::unique_ptr<char[]> buffer(new char[buffer_size]); |
| FillBuffer(buffer.get(), buffer_size); |
| |
| base::FilePath test_file; |
| ASSERT_NO_FATAL_FAILURE( |
| CreateTestFile(buffer.get(), buffer_size, &test_file)); |
| GURL temp_url = FilePathToFileURL(test_file); |
| |
| 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; |
| { |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| temp_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| HttpRequestHeaders headers; |
| headers.SetHeader(HttpRequestHeaders::kRange, |
| HttpByteRange::RightUnbounded( |
| first_byte_position).GetHeaderValue()); |
| r->SetExtraRequestHeaders(headers); |
| r->Start(); |
| EXPECT_TRUE(r->is_pending()); |
| |
| base::RunLoop().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()); |
| } |
| } |
| |
| TEST_F(URLRequestTest, FileTestMultipleRanges) { |
| const size_t buffer_size = 400000; |
| std::unique_ptr<char[]> buffer(new char[buffer_size]); |
| FillBuffer(buffer.get(), buffer_size); |
| |
| base::FilePath test_file; |
| ASSERT_NO_FATAL_FAILURE( |
| CreateTestFile(buffer.get(), buffer_size, &test_file)); |
| GURL temp_url = FilePathToFileURL(test_file); |
| |
| TestDelegate d; |
| { |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| temp_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| HttpRequestHeaders headers; |
| headers.SetHeader(HttpRequestHeaders::kRange, "bytes=0-0,10-200,200-300"); |
| r->SetExtraRequestHeaders(headers); |
| r->Start(); |
| EXPECT_TRUE(r->is_pending()); |
| |
| d.RunUntilComplete(); |
| |
| EXPECT_TRUE(d.request_failed()); |
| } |
| } |
| |
| TEST_F(URLRequestTest, AllowFileURLs) { |
| std::string test_data("monkey"); |
| base::FilePath test_file; |
| ASSERT_NO_FATAL_FAILURE( |
| CreateTestFile(test_data.data(), test_data.size(), &test_file)); |
| |
| // The directory part of the path returned from CreateTemporaryFileInDir() |
| // can be slightly different from |absolute_temp_dir| on Windows. |
| // Example: C:\\Users\\CHROME~2 -> C:\\Users\\chrome-bot |
| // Hence the test should use the directory name of |test_file|, rather than |
| // |absolute_temp_dir|, for whitelisting. |
| base::FilePath real_temp_dir = test_file.DirName(); |
| GURL test_file_url = FilePathToFileURL(test_file); |
| { |
| TestDelegate d; |
| CookieBlockingNetworkDelegate network_delegate; |
| network_delegate.AddToWhitelist(real_temp_dir); |
| default_context().set_network_delegate(&network_delegate); |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| test_file_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| r->Start(); |
| d.RunUntilComplete(); |
| // This should be allowed as the file path is whitelisted. |
| EXPECT_FALSE(d.request_failed()); |
| EXPECT_EQ(test_data, d.data_received()); |
| } |
| |
| { |
| TestDelegate d; |
| CookieBlockingNetworkDelegate network_delegate; |
| default_context().set_network_delegate(&network_delegate); |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| test_file_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| r->Start(); |
| d.RunUntilComplete(); |
| // This should be rejected as the file path is not whitelisted. |
| EXPECT_TRUE(d.request_failed()); |
| EXPECT_EQ("", d.data_received()); |
| EXPECT_EQ(ERR_ACCESS_DENIED, d.request_status()); |
| } |
| } |
| |
| #if defined(OS_POSIX) // Because of symbolic links. |
| |
| TEST_F(URLRequestTest, SymlinksToFiles) { |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| // Get an absolute path since temp_dir can contain a symbolic link. |
| base::FilePath absolute_temp_dir = |
| base::MakeAbsoluteFilePath(temp_dir_.GetPath()); |
| |
| // Create a good directory (will be whitelisted) and a good file. |
| base::FilePath good_dir = absolute_temp_dir.AppendASCII("good"); |
| ASSERT_TRUE(base::CreateDirectory(good_dir)); |
| base::FilePath good_file; |
| ASSERT_TRUE(base::CreateTemporaryFileInDir(good_dir, &good_file)); |
| std::string good_data("good"); |
| base::WriteFile(good_file, good_data.data(), good_data.size()); |
| // See the comment in AllowFileURLs() for why this is done. |
| base::FilePath real_good_dir = good_file.DirName(); |
| |
| // Create a bad directory (will not be whitelisted) and a bad file. |
| base::FilePath bad_dir = absolute_temp_dir.AppendASCII("bad"); |
| ASSERT_TRUE(base::CreateDirectory(bad_dir)); |
| base::FilePath bad_file; |
| ASSERT_TRUE(base::CreateTemporaryFileInDir(bad_dir, &bad_file)); |
| std::string bad_data("bad"); |
| base::WriteFile(bad_file, bad_data.data(), bad_data.size()); |
| |
| // This symlink will point to the good file. Access to the symlink will be |
| // allowed as both the symlink and the destination file are in the same |
| // good directory. |
| base::FilePath good_symlink = good_dir.AppendASCII("good_symlink"); |
| ASSERT_TRUE(base::CreateSymbolicLink(good_file, good_symlink)); |
| GURL good_file_url = FilePathToFileURL(good_symlink); |
| // This symlink will point to the bad file. Even though the symlink is in |
| // the good directory, access to the symlink will be rejected since it |
| // points to the bad file. |
| base::FilePath bad_symlink = good_dir.AppendASCII("bad_symlink"); |
| ASSERT_TRUE(base::CreateSymbolicLink(bad_file, bad_symlink)); |
| GURL bad_file_url = FilePathToFileURL(bad_symlink); |
| |
| CookieBlockingNetworkDelegate network_delegate; |
| network_delegate.AddToWhitelist(real_good_dir); |
| { |
| TestDelegate d; |
| default_context().set_network_delegate(&network_delegate); |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| good_file_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| r->Start(); |
| d.RunUntilComplete(); |
| // good_file_url should be allowed. |
| EXPECT_FALSE(d.request_failed()); |
| EXPECT_EQ(good_data, d.data_received()); |
| } |
| |
| { |
| TestDelegate d; |
| default_context().set_network_delegate(&network_delegate); |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| bad_file_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| r->Start(); |
| d.RunUntilComplete(); |
| // bad_file_url should be rejected. |
| EXPECT_TRUE(d.request_failed()); |
| EXPECT_EQ("", d.data_received()); |
| EXPECT_EQ(ERR_ACCESS_DENIED, d.request_status()); |
| } |
| } |
| |
| TEST_F(URLRequestTest, SymlinksToDirs) { |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| // Get an absolute path since temp_dir can contain a symbolic link. |
| base::FilePath absolute_temp_dir = |
| base::MakeAbsoluteFilePath(temp_dir_.GetPath()); |
| |
| // Create a good directory (will be whitelisted). |
| base::FilePath good_dir = absolute_temp_dir.AppendASCII("good"); |
| ASSERT_TRUE(base::CreateDirectory(good_dir)); |
| |
| // Create a bad directory (will not be whitelisted). |
| base::FilePath bad_dir = absolute_temp_dir.AppendASCII("bad"); |
| ASSERT_TRUE(base::CreateDirectory(bad_dir)); |
| |
| // This symlink will point to the good directory. Access to the symlink |
| // will be allowed as the symlink is in the good dir that'll be white |
| // listed. |
| base::FilePath good_symlink = good_dir.AppendASCII("good_symlink"); |
| ASSERT_TRUE(base::CreateSymbolicLink(good_dir, good_symlink)); |
| GURL good_file_url = FilePathToFileURL(good_symlink); |
| // This symlink will point to the bad directory. Even though the symlink is |
| // in the good directory, access to the symlink will be rejected since it |
| // points to the bad directory. |
| base::FilePath bad_symlink = good_dir.AppendASCII("bad_symlink"); |
| ASSERT_TRUE(base::CreateSymbolicLink(bad_dir, bad_symlink)); |
| GURL bad_file_url = FilePathToFileURL(bad_symlink); |
| |
| CookieBlockingNetworkDelegate network_delegate; |
| network_delegate.AddToWhitelist(good_dir); |
| { |
| TestDelegate d; |
| default_context().set_network_delegate(&network_delegate); |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| good_file_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| r->Start(); |
| d.RunUntilComplete(); |
| // good_file_url should be allowed. |
| EXPECT_FALSE(d.request_failed()); |
| ASSERT_NE(d.data_received().find("good_symlink"), std::string::npos); |
| } |
| |
| { |
| TestDelegate d; |
| default_context().set_network_delegate(&network_delegate); |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| bad_file_url, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| r->Start(); |
| d.RunUntilComplete(); |
| // bad_file_url should be rejected. |
| EXPECT_TRUE(d.request_failed()); |
| EXPECT_EQ("", d.data_received()); |
| EXPECT_EQ(ERR_ACCESS_DENIED, d.request_status()); |
| } |
| } |
| |
| #endif // defined(OS_POSIX) |
| |
| TEST_F(URLRequestTest, FileDirCancelTest) { |
| // Put in mock resource provider. |
| NetModule::SetResourceProvider(TestNetResourceProvider); |
| |
| TestDelegate d; |
| { |
| base::FilePath file_path; |
| base::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")); |
| |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| FilePathToFileURL(file_path), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| EXPECT_TRUE(req->is_pending()); |
| |
| d.set_cancel_in_received_data_pending(true); |
| |
| d.RunUntilComplete(); |
| } |
| |
| // Take out mock resource provider. |
| NetModule::SetResourceProvider(NULL); |
| } |
| |
| #if !defined(STARBOARD) |
| // Starboard does not support url_request_file_dir_job. |
| TEST_F(URLRequestTest, FileDirOutputSanity) { |
| // Verify the general sanity of the the output of the file: |
| // directory lister by checking for the output of a known existing |
| // file. |
| const char sentinel_name[] = "filedir-sentinel"; |
| |
| base::FilePath path; |
| base::PathService::Get(base::DIR_TEST_DATA, &path); |
| path = path.Append(kTestFilePath); |
| |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req( |
| default_context().CreateRequest(FilePathToFileURL(path), DEFAULT_PRIORITY, |
| &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| // Generate entry for the sentinel file. |
| base::FilePath sentinel_path = path.AppendASCII(sentinel_name); |
| |
| base::File::Info info; |
| EXPECT_TRUE(base::GetFileInfo(sentinel_path, &info)); |
| EXPECT_GT(info.size, 0); |
| std::string sentinel_output = GetDirectoryListingEntry( |
| base::string16(sentinel_name, |
| sentinel_name + strlen(sentinel_name)), |
| std::string(sentinel_name), false /* is_dir */, info.size, |
| |
| info.last_modified); |
| |
| ASSERT_LT(0, d.bytes_received()); |
| ASSERT_FALSE(d.request_failed()); |
| EXPECT_EQ(OK, d.request_status()); |
| // Check for the entry generated for the "sentinel" file. |
| const std::string& data = d.data_received(); |
| ASSERT_NE(data.find(sentinel_output), std::string::npos); |
| } |
| |
| 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. |
| |
| base::FilePath path; |
| base::PathService::Get(base::DIR_TEST_DATA, &path); |
| path = path.Append(kTestFilePath); |
| |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req( |
| default_context().CreateRequest(FilePathToFileURL(path), DEFAULT_PRIORITY, |
| &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| ASSERT_EQ(1, d.received_redirect_count()); |
| ASSERT_LT(0, d.bytes_received()); |
| ASSERT_FALSE(d.request_failed()); |
| EXPECT_EQ(OK, d.request_status()); |
| } |
| #endif |
| |
| #if defined(OS_WIN) |
| // Don't accept the url "file:///" on windows. See http://crbug.com/1474. |
| TEST_F(URLRequestTest, FileDirRedirectSingleSlash) { |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("file:///"), DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| ASSERT_EQ(1, d.received_redirect_count()); |
| EXPECT_NE(OK, d.request_status()); |
| } |
| #endif // defined(OS_WIN) |
| |
| #endif // !BUILDFLAG(DISABLE_FILE_SUPPORT) |
| |
| TEST_F(URLRequestTest, InvalidUrlTest) { |
| TestDelegate d; |
| { |
| std::unique_ptr<URLRequest> r( |
| default_context().CreateRequest(GURL("invalid url"), DEFAULT_PRIORITY, |
| &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| r->Start(); |
| EXPECT_TRUE(r->is_pending()); |
| |
| d.RunUntilComplete(); |
| EXPECT_TRUE(d.request_failed()); |
| } |
| } |
| |
| TEST_F(URLRequestTest, InvalidReferrerTest) { |
| TestURLRequestContext context; |
| TestNetworkDelegate network_delegate; |
| network_delegate.set_cancel_request_with_policy_violating_referrer(true); |
| context.set_network_delegate(&network_delegate); |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req( |
| context.CreateRequest(GURL("http://localhost/"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->SetReferrer("https://somewhere.com/"); |
| |
| req->Start(); |
| d.RunUntilComplete(); |
| EXPECT_TRUE(d.request_failed()); |
| } |
| |
| #if defined(OS_WIN) |
| TEST_F(URLRequestTest, ResolveShortcutTest) { |
| base::FilePath app_path; |
| base::PathService::Get(base::DIR_TEST_DATA, &app_path); |
| app_path = app_path.Append(kTestFilePath); |
| 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 |
| { |
| Microsoft::WRL::ComPtr<IShellLink> shell; |
| ASSERT_TRUE(SUCCEEDED(::CoCreateInstance( |
| CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shell)))); |
| Microsoft::WRL::ComPtr<IPersistFile> persist; |
| ASSERT_TRUE(SUCCEEDED(shell.CopyTo(persist.GetAddressOf()))); |
| 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))); |
| } |
| |
| TestDelegate d; |
| { |
| std::unique_ptr<URLRequest> r(default_context().CreateRequest( |
| FilePathToFileURL(base::FilePath(lnk_path)), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| r->Start(); |
| EXPECT_TRUE(r->is_pending()); |
| |
| d.RunUntilComplete(); |
| |
| 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); |
| std::unique_ptr<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) |
| |
| // Custom URLRequestJobs for use with interceptor tests |
| class RestartTestJob : public URLRequestTestJob { |
| public: |
| RestartTestJob(URLRequest* request, NetworkDelegate* network_delegate) |
| : URLRequestTestJob(request, network_delegate, true) {} |
| protected: |
| void StartAsync() override { this->NotifyRestartRequired(); } |
| private: |
| ~RestartTestJob() override = default; |
| }; |
| |
| class CancelTestJob : public URLRequestTestJob { |
| public: |
| explicit CancelTestJob(URLRequest* request, NetworkDelegate* network_delegate) |
| : URLRequestTestJob(request, network_delegate, true) {} |
| protected: |
| void StartAsync() override { request_->Cancel(); } |
| private: |
| ~CancelTestJob() override = default; |
| }; |
| |
| class CancelThenRestartTestJob : public URLRequestTestJob { |
| public: |
| explicit CancelThenRestartTestJob(URLRequest* request, |
| NetworkDelegate* network_delegate) |
| : URLRequestTestJob(request, network_delegate, true) { |
| } |
| protected: |
| void StartAsync() override { |
| request_->Cancel(); |
| this->NotifyRestartRequired(); |
| } |
| private: |
| ~CancelThenRestartTestJob() override = default; |
| }; |
| |
| // An Interceptor for use with interceptor tests. |
| class MockURLRequestInterceptor : public URLRequestInterceptor { |
| public: |
| // 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(); |
| } |
| |
| MockURLRequestInterceptor() |
| : 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), |
| use_url_request_http_job_(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) { |
| } |
| |
| ~MockURLRequestInterceptor() override = default; |
| |
| // URLRequestInterceptor implementation: |
| URLRequestJob* MaybeInterceptRequest( |
| URLRequest* request, |
| NetworkDelegate* network_delegate) const override { |
| 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; |
| if (use_url_request_http_job_) { |
| return URLRequestHttpJob::Factory(request, network_delegate, "http"); |
| } |
| // This job will result in error since the requested URL is not one of the |
| // URLs supported by these tests. |
| return new URLRequestTestJob(request, network_delegate, true); |
| } |
| if (!intercept_main_request_) |
| return nullptr; |
| intercept_main_request_ = false; |
| did_intercept_main_ = true; |
| URLRequestTestJob* job = new URLRequestTestJob(request, |
| network_delegate, |
| main_headers_, |
| main_data_, |
| true); |
| job->set_load_timing_info(main_request_load_timing_info_); |
| return job; |
| } |
| |
| URLRequestJob* MaybeInterceptRedirect(URLRequest* request, |
| NetworkDelegate* network_delegate, |
| const GURL& location) const override { |
| if (cancel_redirect_request_) { |
| cancel_redirect_request_ = false; |
| did_cancel_redirect_ = true; |
| return new CancelTestJob(request, network_delegate); |
| } |
| if (!intercept_redirect_) |
| return nullptr; |
| intercept_redirect_ = false; |
| did_intercept_redirect_ = true; |
| if (use_url_request_http_job_) { |
| return URLRequestHttpJob::Factory(request, network_delegate, "http"); |
| } |
| return new URLRequestTestJob(request, |
| network_delegate, |
| redirect_headers_, |
| redirect_data_, |
| true); |
| } |
| |
| URLRequestJob* MaybeInterceptResponse( |
| URLRequest* request, |
| NetworkDelegate* network_delegate) const override { |
| if (cancel_final_request_) { |
| cancel_final_request_ = false; |
| did_cancel_final_ = true; |
| return new CancelTestJob(request, network_delegate); |
| } |
| if (!intercept_final_response_) |
| return nullptr; |
| intercept_final_response_ = false; |
| did_intercept_final_ = true; |
| if (use_url_request_http_job_) { |
| return URLRequestHttpJob::Factory(request, network_delegate, "http"); |
| } |
| return new URLRequestTestJob(request, |
| network_delegate, |
| final_headers_, |
| final_data_, |
| true); |
| } |
| |
| void set_intercept_main_request(bool intercept_main_request) { |
| intercept_main_request_ = intercept_main_request; |
| } |
| |
| void set_main_headers(const std::string& main_headers) { |
| main_headers_ = main_headers; |
| } |
| |
| void set_main_data(const std::string& main_data) { |
| main_data_ = main_data; |
| } |
| |
| void set_main_request_load_timing_info( |
| const LoadTimingInfo& main_request_load_timing_info) { |
| main_request_load_timing_info_ = main_request_load_timing_info; |
| } |
| |
| void set_restart_main_request(bool restart_main_request) { |
| restart_main_request_ = restart_main_request; |
| } |
| |
| void set_cancel_main_request(bool cancel_main_request) { |
| cancel_main_request_ = cancel_main_request; |
| } |
| |
| void set_cancel_then_restart_main_request( |
| bool cancel_then_restart_main_request) { |
| cancel_then_restart_main_request_ = cancel_then_restart_main_request; |
| } |
| |
| void set_simulate_main_network_error(bool simulate_main_network_error) { |
| simulate_main_network_error_ = simulate_main_network_error; |
| } |
| |
| void set_intercept_redirect(bool intercept_redirect) { |
| intercept_redirect_ = intercept_redirect; |
| } |
| |
| void set_redirect_headers(const std::string& redirect_headers) { |
| redirect_headers_ = redirect_headers; |
| } |
| |
| void set_redirect_data(const std::string& redirect_data) { |
| redirect_data_ = redirect_data; |
| } |
| |
| void set_cancel_redirect_request(bool cancel_redirect_request) { |
| cancel_redirect_request_ = cancel_redirect_request; |
| } |
| |
| void set_intercept_final_response(bool intercept_final_response) { |
| intercept_final_response_ = intercept_final_response; |
| } |
| |
| void set_final_headers(const std::string& final_headers) { |
| final_headers_ = final_headers; |
| } |
| |
| void set_final_data(const std::string& final_data) { |
| final_data_ = final_data; |
| } |
| |
| void set_cancel_final_request(bool cancel_final_request) { |
| cancel_final_request_ = cancel_final_request; |
| } |
| |
| void set_use_url_request_http_job(bool use_url_request_http_job) { |
| use_url_request_http_job_ = use_url_request_http_job; |
| } |
| |
| bool did_intercept_main() const { |
| return did_intercept_main_; |
| } |
| |
| bool did_restart_main() const { |
| return did_restart_main_; |
| } |
| |
| bool did_cancel_main() const { |
| return did_cancel_main_; |
| } |
| |
| bool did_cancel_then_restart_main() const { |
| return did_cancel_then_restart_main_; |
| } |
| |
| bool did_simulate_error_main() const { |
| return did_simulate_error_main_; |
| } |
| |
| bool did_intercept_redirect() const { |
| return did_intercept_redirect_; |
| } |
| |
| bool did_cancel_redirect() const { |
| return did_cancel_redirect_; |
| } |
| |
| bool did_intercept_final() const { |
| return did_intercept_final_; |
| } |
| |
| bool did_cancel_final() const { |
| return did_cancel_final_; |
| } |
| |
| private: |
| // Indicate whether to intercept the main request, and if so specify the |
| // response to return and the LoadTimingInfo to use. |
| mutable bool intercept_main_request_; |
| mutable std::string main_headers_; |
| mutable std::string main_data_; |
| mutable LoadTimingInfo main_request_load_timing_info_; |
| |
| // These indicate actions that can be taken within MaybeInterceptRequest. |
| mutable bool restart_main_request_; |
| mutable bool cancel_main_request_; |
| mutable bool cancel_then_restart_main_request_; |
| mutable bool simulate_main_network_error_; |
| |
| // Indicate whether to intercept redirects, and if so specify the response to |
| // return. |
| mutable bool intercept_redirect_; |
| mutable std::string redirect_headers_; |
| mutable std::string redirect_data_; |
| |
| // Cancel the request within MaybeInterceptRedirect. |
| mutable bool cancel_redirect_request_; |
| |
| // Indicate whether to intercept the final response, and if so specify the |
| // response to return. |
| mutable bool intercept_final_response_; |
| mutable std::string final_headers_; |
| mutable std::string final_data_; |
| |
| // Cancel the final request within MaybeInterceptResponse. |
| mutable bool cancel_final_request_; |
| |
| // Instruct the interceptor to use a real URLRequestHTTPJob. |
| mutable bool use_url_request_http_job_; |
| |
| // These indicate if the interceptor did something or not. |
| mutable bool did_intercept_main_; |
| mutable bool did_restart_main_; |
| mutable bool did_cancel_main_; |
| mutable bool did_cancel_then_restart_main_; |
| mutable bool did_simulate_error_main_; |
| mutable bool did_intercept_redirect_; |
| mutable bool did_cancel_redirect_; |
| mutable bool did_intercept_final_; |
| mutable bool did_cancel_final_; |
| }; |
| |
| // Inherit PlatformTest since we require the autorelease pool on Mac OS X. |
| class URLRequestInterceptorTest : public URLRequestTest { |
| public: |
| URLRequestInterceptorTest() : URLRequestTest(), interceptor_(NULL) { |
| } |
| |
| ~URLRequestInterceptorTest() override { |
| // URLRequestJobs may post clean-up tasks on destruction. |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| void SetUpFactory() override { |
| interceptor_ = new MockURLRequestInterceptor(); |
| job_factory_.reset(new URLRequestInterceptingJobFactory( |
| std::move(job_factory_), base::WrapUnique(interceptor_))); |
| } |
| |
| MockURLRequestInterceptor* interceptor() const { |
| return interceptor_; |
| } |
| |
| private: |
| MockURLRequestInterceptor* interceptor_; |
| }; |
| |
| TEST_F(URLRequestInterceptorTest, Intercept) { |
| // Intercept the main request and respond with a simple response. |
| interceptor()->set_intercept_main_request(true); |
| interceptor()->set_main_headers(MockURLRequestInterceptor::ok_headers()); |
| interceptor()->set_main_data(MockURLRequestInterceptor::ok_data()); |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| 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(&user_data0, base::WrapUnique(user_data0)); |
| req->SetUserData(&user_data1, base::WrapUnique(user_data1)); |
| req->SetUserData(&user_data2, base::WrapUnique(user_data2)); |
| req->set_method("GET"); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| // Make sure we can retrieve our specific user data. |
| EXPECT_EQ(user_data0, req->GetUserData(&user_data0)); |
| EXPECT_EQ(user_data1, req->GetUserData(&user_data1)); |
| EXPECT_EQ(user_data2, req->GetUserData(&user_data2)); |
| |
| // Check that we got one good response. |
| EXPECT_EQ(OK, d.request_status()); |
| EXPECT_EQ(200, req->response_headers()->response_code()); |
| EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received()); |
| EXPECT_EQ(1, d.response_started_count()); |
| EXPECT_EQ(0, d.received_redirect_count()); |
| } |
| |
| TEST_F(URLRequestInterceptorTest, InterceptRedirect) { |
| // Intercept the main request and respond with a redirect. |
| interceptor()->set_intercept_main_request(true); |
| interceptor()->set_main_headers( |
| MockURLRequestInterceptor::redirect_headers()); |
| interceptor()->set_main_data(MockURLRequestInterceptor::redirect_data()); |
| |
| // Intercept that redirect and respond with a final OK response. |
| interceptor()->set_intercept_redirect(true); |
| interceptor()->set_redirect_headers(MockURLRequestInterceptor::ok_headers()); |
| interceptor()->set_redirect_data(MockURLRequestInterceptor::ok_data()); |
| |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->set_method("GET"); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| // Check that the interceptor got called as expected. |
| EXPECT_TRUE(interceptor()->did_intercept_main()); |
| EXPECT_TRUE(interceptor()->did_intercept_redirect()); |
| |
| // Check that we got one good response. |
| int status = d.request_status(); |
| EXPECT_EQ(OK, status); |
| if (status == OK) |
| EXPECT_EQ(200, req->response_headers()->response_code()); |
| |
| EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received()); |
| EXPECT_EQ(1, d.response_started_count()); |
| EXPECT_EQ(0, d.received_redirect_count()); |
| } |
| |
| TEST_F(URLRequestInterceptorTest, InterceptServerError) { |
| // Intercept the main request to generate a server error response. |
| interceptor()->set_intercept_main_request(true); |
| interceptor()->set_main_headers(MockURLRequestInterceptor::error_headers()); |
| interceptor()->set_main_data(MockURLRequestInterceptor::error_data()); |
| |
| // Intercept that error and respond with an OK response. |
| interceptor()->set_intercept_final_response(true); |
| interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers()); |
| interceptor()->set_final_data(MockURLRequestInterceptor::ok_data()); |
| |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->set_method("GET"); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| // Check that the interceptor got called as expected. |
| EXPECT_TRUE(interceptor()->did_intercept_main()); |
| EXPECT_TRUE(interceptor()->did_intercept_final()); |
| |
| // Check that we got one good response. |
| EXPECT_EQ(OK, d.request_status()); |
| EXPECT_EQ(200, req->response_headers()->response_code()); |
| EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received()); |
| EXPECT_EQ(1, d.response_started_count()); |
| EXPECT_EQ(0, d.received_redirect_count()); |
| } |
| |
| TEST_F(URLRequestInterceptorTest, InterceptNetworkError) { |
| // Intercept the main request to simulate a network error. |
| interceptor()->set_simulate_main_network_error(true); |
| |
| // Intercept that error and respond with an OK response. |
| interceptor()->set_intercept_final_response(true); |
| interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers()); |
| interceptor()->set_final_data(MockURLRequestInterceptor::ok_data()); |
| |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->set_method("GET"); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| // Check that the interceptor got called as expected. |
| EXPECT_TRUE(interceptor()->did_simulate_error_main()); |
| EXPECT_TRUE(interceptor()->did_intercept_final()); |
| |
| // Check that we received one good response. |
| EXPECT_EQ(OK, d.request_status()); |
| EXPECT_EQ(200, req->response_headers()->response_code()); |
| EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received()); |
| EXPECT_EQ(1, d.response_started_count()); |
| EXPECT_EQ(0, d.received_redirect_count()); |
| } |
| |
| TEST_F(URLRequestInterceptorTest, InterceptRestartRequired) { |
| // Restart the main request. |
| interceptor()->set_restart_main_request(true); |
| |
| // then intercept the new main request and respond with an OK response |
| interceptor()->set_intercept_main_request(true); |
| interceptor()->set_main_headers(MockURLRequestInterceptor::ok_headers()); |
| interceptor()->set_main_data(MockURLRequestInterceptor::ok_data()); |
| |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->set_method("GET"); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| // Check that the interceptor got called as expected. |
| EXPECT_TRUE(interceptor()->did_restart_main()); |
| EXPECT_TRUE(interceptor()->did_intercept_main()); |
| |
| // Check that we received one good response. |
| int status = d.request_status(); |
| EXPECT_EQ(OK, status); |
| if (status == OK) |
| EXPECT_EQ(200, req->response_headers()->response_code()); |
| |
| EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received()); |
| EXPECT_EQ(1, d.response_started_count()); |
| EXPECT_EQ(0, d.received_redirect_count()); |
| } |
| |
| TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelMain) { |
| // Intercept the main request and cancel from within the restarted job. |
| interceptor()->set_cancel_main_request(true); |
| |
| // Set up to intercept the final response and override it with an OK response. |
| interceptor()->set_intercept_final_response(true); |
| interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers()); |
| interceptor()->set_final_data(MockURLRequestInterceptor::ok_data()); |
| |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->set_method("GET"); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| // Check that the interceptor got called as expected. |
| EXPECT_TRUE(interceptor()->did_cancel_main()); |
| EXPECT_FALSE(interceptor()->did_intercept_final()); |
| |
| // Check that we see a canceled request. |
| EXPECT_EQ(ERR_ABORTED, d.request_status()); |
| } |
| |
| TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelRedirect) { |
| // Intercept the main request and respond with a redirect. |
| interceptor()->set_intercept_main_request(true); |
| interceptor()->set_main_headers( |
| MockURLRequestInterceptor::redirect_headers()); |
| interceptor()->set_main_data(MockURLRequestInterceptor::redirect_data()); |
| |
| // Intercept the redirect and cancel from within that job. |
| interceptor()->set_cancel_redirect_request(true); |
| |
| // Set up to intercept the final response and override it with an OK response. |
| interceptor()->set_intercept_final_response(true); |
| interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers()); |
| interceptor()->set_final_data(MockURLRequestInterceptor::ok_data()); |
| |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->set_method("GET"); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| // Check that 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 that we see a canceled request. |
| EXPECT_EQ(ERR_ABORTED, d.request_status()); |
| } |
| |
| TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelFinal) { |
| // Intercept the main request to simulate a network error. |
| interceptor()->set_simulate_main_network_error(true); |
| |
| // Set up to intercept final the response and cancel from within that job. |
| interceptor()->set_cancel_final_request(true); |
| |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->set_method("GET"); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| // Check that the interceptor got called as expected. |
| EXPECT_TRUE(interceptor()->did_simulate_error_main()); |
| EXPECT_TRUE(interceptor()->did_cancel_final()); |
| |
| // Check that we see a canceled request. |
| EXPECT_EQ(ERR_ABORTED, d.request_status()); |
| } |
| |
| TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelInRestart) { |
| // Intercept the main request and cancel then restart from within that job. |
| interceptor()->set_cancel_then_restart_main_request(true); |
| |
| // Set up to intercept the final response and override it with an OK response. |
| interceptor()->set_intercept_final_response(true); |
| interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers()); |
| interceptor()->set_final_data(MockURLRequestInterceptor::ok_data()); |
| |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->set_method("GET"); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| // Check that the interceptor got called as expected. |
| EXPECT_TRUE(interceptor()->did_cancel_then_restart_main()); |
| EXPECT_FALSE(interceptor()->did_intercept_final()); |
| |
| // Check that we see a canceled request. |
| EXPECT_EQ(ERR_ABORTED, d.request_status()); |
| } |
| |
| // "Normal" LoadTimingInfo as returned by a job. Everything is in order, not |
| // reused. |connect_time_flags| is used to indicate if there should be dns |
| // or SSL times, and |used_proxy| is used for proxy times. |
| LoadTimingInfo NormalLoadTimingInfo(base::TimeTicks now, |
| int connect_time_flags, |
| bool used_proxy) { |
| LoadTimingInfo load_timing; |
| load_timing.socket_log_id = 1; |
| |
| if (used_proxy) { |
| load_timing.proxy_resolve_start = now + base::TimeDelta::FromDays(1); |
| load_timing.proxy_resolve_end = now + base::TimeDelta::FromDays(2); |
| } |
| |
| LoadTimingInfo::ConnectTiming& connect_timing = load_timing.connect_timing; |
| if (connect_time_flags & CONNECT_TIMING_HAS_DNS_TIMES) { |
| connect_timing.dns_start = now + base::TimeDelta::FromDays(3); |
| connect_timing.dns_end = now + base::TimeDelta::FromDays(4); |
| } |
| connect_timing.connect_start = now + base::TimeDelta::FromDays(5); |
| if (connect_time_flags & CONNECT_TIMING_HAS_SSL_TIMES) { |
| connect_timing.ssl_start = now + base::TimeDelta::FromDays(6); |
| connect_timing.ssl_end = now + base::TimeDelta::FromDays(7); |
| } |
| connect_timing.connect_end = now + base::TimeDelta::FromDays(8); |
| |
| load_timing.send_start = now + base::TimeDelta::FromDays(9); |
| load_timing.send_end = now + base::TimeDelta::FromDays(10); |
| load_timing.receive_headers_end = now + base::TimeDelta::FromDays(11); |
| return load_timing; |
| } |
| |
| // Same as above, but in the case of a reused socket. |
| LoadTimingInfo NormalLoadTimingInfoReused(base::TimeTicks now, |
| bool used_proxy) { |
| LoadTimingInfo load_timing; |
| load_timing.socket_log_id = 1; |
| load_timing.socket_reused = true; |
| |
| if (used_proxy) { |
| load_timing.proxy_resolve_start = now + base::TimeDelta::FromDays(1); |
| load_timing.proxy_resolve_end = now + base::TimeDelta::FromDays(2); |
| } |
| |
| load_timing.send_start = now + base::TimeDelta::FromDays(9); |
| load_timing.send_end = now + base::TimeDelta::FromDays(10); |
| load_timing.receive_headers_end = now + base::TimeDelta::FromDays(11); |
| return load_timing; |
| } |
| |
| LoadTimingInfo RunURLRequestInterceptorLoadTimingTest( |
| const LoadTimingInfo& job_load_timing, |
| const URLRequestContext& context, |
| MockURLRequestInterceptor* interceptor) { |
| interceptor->set_intercept_main_request(true); |
| interceptor->set_main_request_load_timing_info(job_load_timing); |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req( |
| context.CreateRequest(GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, |
| &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| LoadTimingInfo resulting_load_timing; |
| req->GetLoadTimingInfo(&resulting_load_timing); |
| |
| // None of these should be modified by the URLRequest. |
| EXPECT_EQ(job_load_timing.socket_reused, resulting_load_timing.socket_reused); |
| EXPECT_EQ(job_load_timing.socket_log_id, resulting_load_timing.socket_log_id); |
| EXPECT_EQ(job_load_timing.send_start, resulting_load_timing.send_start); |
| EXPECT_EQ(job_load_timing.send_end, resulting_load_timing.send_end); |
| EXPECT_EQ(job_load_timing.receive_headers_end, |
| resulting_load_timing.receive_headers_end); |
| EXPECT_EQ(job_load_timing.push_start, resulting_load_timing.push_start); |
| EXPECT_EQ(job_load_timing.push_end, resulting_load_timing.push_end); |
| |
| return resulting_load_timing; |
| } |
| |
| // Basic test that the intercept + load timing tests work. |
| TEST_F(URLRequestInterceptorTest, InterceptLoadTiming) { |
| base::TimeTicks now = base::TimeTicks::Now(); |
| LoadTimingInfo job_load_timing = |
| NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_DNS_TIMES, false); |
| |
| LoadTimingInfo load_timing_result = |
| RunURLRequestInterceptorLoadTimingTest( |
| job_load_timing, default_context(), interceptor()); |
| |
| // Nothing should have been changed by the URLRequest. |
| EXPECT_EQ(job_load_timing.proxy_resolve_start, |
| load_timing_result.proxy_resolve_start); |
| EXPECT_EQ(job_load_timing.proxy_resolve_end, |
| load_timing_result.proxy_resolve_end); |
| EXPECT_EQ(job_load_timing.connect_timing.dns_start, |
| load_timing_result.connect_timing.dns_start); |
| EXPECT_EQ(job_load_timing.connect_timing.dns_end, |
| load_timing_result.connect_timing.dns_end); |
| EXPECT_EQ(job_load_timing.connect_timing.connect_start, |
| load_timing_result.connect_timing.connect_start); |
| EXPECT_EQ(job_load_timing.connect_timing.connect_end, |
| load_timing_result.connect_timing.connect_end); |
| EXPECT_EQ(job_load_timing.connect_timing.ssl_start, |
| load_timing_result.connect_timing.ssl_start); |
| EXPECT_EQ(job_load_timing.connect_timing.ssl_end, |
| load_timing_result.connect_timing.ssl_end); |
| |
| // Redundant sanity check. |
| TestLoadTimingNotReused(load_timing_result, CONNECT_TIMING_HAS_DNS_TIMES); |
| } |
| |
| // Another basic test, with proxy and SSL times, but no DNS times. |
| TEST_F(URLRequestInterceptorTest, InterceptLoadTimingProxy) { |
| base::TimeTicks now = base::TimeTicks::Now(); |
| LoadTimingInfo job_load_timing = |
| NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_SSL_TIMES, true); |
| |
| LoadTimingInfo load_timing_result = |
| RunURLRequestInterceptorLoadTimingTest( |
| job_load_timing, default_context(), interceptor()); |
| |
| // Nothing should have been changed by the URLRequest. |
| EXPECT_EQ(job_load_timing.proxy_resolve_start, |
| load_timing_result.proxy_resolve_start); |
| EXPECT_EQ(job_load_timing.proxy_resolve_end, |
| load_timing_result.proxy_resolve_end); |
| EXPECT_EQ(job_load_timing.connect_timing.dns_start, |
| load_timing_result.connect_timing.dns_start); |
| EXPECT_EQ(job_load_timing.connect_timing.dns_end, |
| load_timing_result.connect_timing.dns_end); |
| EXPECT_EQ(job_load_timing.connect_timing.connect_start, |
| load_timing_result.connect_timing.connect_start); |
| EXPECT_EQ(job_load_timing.connect_timing.connect_end, |
| load_timing_result.connect_timing.connect_end); |
| EXPECT_EQ(job_load_timing.connect_timing.ssl_start, |
| load_timing_result.connect_timing.ssl_start); |
| EXPECT_EQ(job_load_timing.connect_timing.ssl_end, |
| load_timing_result.connect_timing.ssl_end); |
| |
| // Redundant sanity check. |
| TestLoadTimingNotReusedWithProxy(load_timing_result, |
| CONNECT_TIMING_HAS_SSL_TIMES); |
| } |
| |
| // Make sure that URLRequest correctly adjusts proxy times when they're before |
| // |request_start|, due to already having a connected socket. This happens in |
| // the case of reusing a SPDY session. The connected socket is not considered |
| // reused in this test (May be a preconnect). |
| // |
| // To mix things up from the test above, assumes DNS times but no SSL times. |
| TEST_F(URLRequestInterceptorTest, InterceptLoadTimingEarlyProxyResolution) { |
| base::TimeTicks now = base::TimeTicks::Now(); |
| LoadTimingInfo job_load_timing = |
| NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_DNS_TIMES, true); |
| job_load_timing.proxy_resolve_start = now - base::TimeDelta::FromDays(6); |
| job_load_timing.proxy_resolve_end = now - base::TimeDelta::FromDays(5); |
| job_load_timing.connect_timing.dns_start = now - base::TimeDelta::FromDays(4); |
| job_load_timing.connect_timing.dns_end = now - base::TimeDelta::FromDays(3); |
| job_load_timing.connect_timing.connect_start = |
| now - base::TimeDelta::FromDays(2); |
| job_load_timing.connect_timing.connect_end = |
| now - base::TimeDelta::FromDays(1); |
| |
| LoadTimingInfo load_timing_result = |
| RunURLRequestInterceptorLoadTimingTest( |
| job_load_timing, default_context(), interceptor()); |
| |
| // Proxy times, connect times, and DNS times should all be replaced with |
| // request_start. |
| EXPECT_EQ(load_timing_result.request_start, |
| load_timing_result.proxy_resolve_start); |
| EXPECT_EQ(load_timing_result.request_start, |
| load_timing_result.proxy_resolve_end); |
| EXPECT_EQ(load_timing_result.request_start, |
| load_timing_result.connect_timing.dns_start); |
| EXPECT_EQ(load_timing_result.request_start, |
| load_timing_result.connect_timing.dns_end); |
| EXPECT_EQ(load_timing_result.request_start, |
| load_timing_result.connect_timing.connect_start); |
| EXPECT_EQ(load_timing_result.request_start, |
| load_timing_result.connect_timing.connect_end); |
| |
| // Other times should have been left null. |
| TestLoadTimingNotReusedWithProxy(load_timing_result, |
| CONNECT_TIMING_HAS_DNS_TIMES); |
| } |
| |
| // Same as above, but in the reused case. |
| TEST_F(URLRequestInterceptorTest, |
| InterceptLoadTimingEarlyProxyResolutionReused) { |
| base::TimeTicks now = base::TimeTicks::Now(); |
| LoadTimingInfo job_load_timing = NormalLoadTimingInfoReused(now, true); |
| job_load_timing.proxy_resolve_start = now - base::TimeDelta::FromDays(4); |
| job_load_timing.proxy_resolve_end = now - base::TimeDelta::FromDays(3); |
| |
| LoadTimingInfo load_timing_result = |
| RunURLRequestInterceptorLoadTimingTest( |
| job_load_timing, default_context(), interceptor()); |
| |
| // Proxy times and connect times should all be replaced with request_start. |
| EXPECT_EQ(load_timing_result.request_start, |
| load_timing_result.proxy_resolve_start); |
| EXPECT_EQ(load_timing_result.request_start, |
| load_timing_result.proxy_resolve_end); |
| |
| // Other times should have been left null. |
| TestLoadTimingReusedWithProxy(load_timing_result); |
| } |
| |
| // Make sure that URLRequest correctly adjusts connect times when they're before |
| // |request_start|, due to reusing a connected socket. The connected socket is |
| // not considered reused in this test (May be a preconnect). |
| // |
| // To mix things up, the request has SSL times, but no DNS times. |
| TEST_F(URLRequestInterceptorTest, InterceptLoadTimingEarlyConnect) { |
| base::TimeTicks now = base::TimeTicks::Now(); |
| LoadTimingInfo job_load_timing = |
| NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_SSL_TIMES, false); |
| job_load_timing.connect_timing.connect_start = |
| now - base::TimeDelta::FromDays(1); |
| job_load_timing.connect_timing.ssl_start = now - base::TimeDelta::FromDays(2); |
| job_load_timing.connect_timing.ssl_end = now - base::TimeDelta::FromDays(3); |
| job_load_timing.connect_timing.connect_end = |
| now - base::TimeDelta::FromDays(4); |
| |
| LoadTimingInfo load_timing_result = |
| RunURLRequestInterceptorLoadTimingTest( |
| job_load_timing, default_context(), interceptor()); |
| |
| // Connect times, and SSL times should be replaced with request_start. |
| EXPECT_EQ(load_timing_result.request_start, |
| load_timing_result.connect_timing.connect_start); |
| EXPECT_EQ(load_timing_result.request_start, |
| load_timing_result.connect_timing.ssl_start); |
| EXPECT_EQ(load_timing_result.request_start, |
| load_timing_result.connect_timing.ssl_end); |
| EXPECT_EQ(load_timing_result.request_start, |
| load_timing_result.connect_timing.connect_end); |
| |
| // Other times should have been left null. |
| TestLoadTimingNotReused(load_timing_result, CONNECT_TIMING_HAS_SSL_TIMES); |
| } |
| |
| // Make sure that URLRequest correctly adjusts connect times when they're before |
| // |request_start|, due to reusing a connected socket in the case that there |
| // are also proxy times. The connected socket is not considered reused in this |
| // test (May be a preconnect). |
| // |
| // In this test, there are no SSL or DNS times. |
| TEST_F(URLRequestInterceptorTest, InterceptLoadTimingEarlyConnectWithProxy) { |
| base::TimeTicks now = base::TimeTicks::Now(); |
| LoadTimingInfo job_load_timing = |
| NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY, true); |
| job_load_timing.connect_timing.connect_start = |
| now - base::TimeDelta::FromDays(1); |
| job_load_timing.connect_timing.connect_end = |
| now - base::TimeDelta::FromDays(2); |
| |
| LoadTimingInfo load_timing_result = |
| RunURLRequestInterceptorLoadTimingTest( |
| job_load_timing, default_context(), interceptor()); |
| |
| // Connect times should be replaced with proxy_resolve_end. |
| EXPECT_EQ(load_timing_result.proxy_resolve_end, |
| load_timing_result.connect_timing.connect_start); |
| EXPECT_EQ(load_timing_result.proxy_resolve_end, |
| load_timing_result.connect_timing.connect_end); |
| |
| // Other times should have been left null. |
| TestLoadTimingNotReusedWithProxy(load_timing_result, |
| CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY); |
| } |
| |
| // Check that two different URL requests have different identifiers. |
| TEST_F(URLRequestTest, Identifiers) { |
| TestDelegate d; |
| TestURLRequestContext context; |
| std::unique_ptr<URLRequest> req( |
| context.CreateRequest(GURL("http://example.com"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| std::unique_ptr<URLRequest> other_req( |
| context.CreateRequest(GURL("http://example.com"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| ASSERT_NE(req->identifier(), other_req->identifier()); |
| } |
| |
| #if defined(OS_IOS) |
| // TODO(droger): Check that a failure to connect to the proxy is reported to |
| // the network delegate. crbug.com/496743 |
| #define MAYBE_NetworkDelegateProxyError DISABLED_NetworkDelegateProxyError |
| #else |
| #define MAYBE_NetworkDelegateProxyError NetworkDelegateProxyError |
| #endif |
| TEST_F(URLRequestTest, MAYBE_NetworkDelegateProxyError) { |
| MockHostResolver host_resolver; |
| host_resolver.rules()->AddSimulatedFailure("*"); |
| |
| TestNetworkDelegate network_delegate; // Must outlive URLRequests. |
| TestURLRequestContextWithProxy context("myproxy:70", &network_delegate); |
| |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req( |
| context.CreateRequest(GURL("http://example.com"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->set_method("GET"); |
| |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| // Check we see a failed request. |
| // The proxy server is not set before failure. |
| EXPECT_FALSE(req->proxy_server().is_valid()); |
| EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, d.request_status()); |
| |
| EXPECT_EQ(1, network_delegate.error_count()); |
| EXPECT_THAT(network_delegate.last_error(), |
| IsError(ERR_PROXY_CONNECTION_FAILED)); |
| EXPECT_EQ(1, network_delegate.completed_requests()); |
| } |
| |
| // Make sure that NetworkDelegate::NotifyCompleted is called if |
| // content is empty. |
| TEST_F(URLRequestTest, RequestCompletionForEmptyResponse) { |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("data:,"), DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| EXPECT_EQ("", d.data_received()); |
| EXPECT_EQ(1, default_network_delegate_.completed_requests()); |
| } |
| |
| // Make sure that SetPriority actually sets the URLRequest's priority |
| // correctly, both before and after start. |
| TEST_F(URLRequestTest, SetPriorityBasic) { |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| EXPECT_EQ(DEFAULT_PRIORITY, req->priority()); |
| |
| req->SetPriority(LOW); |
| EXPECT_EQ(LOW, req->priority()); |
| |
| req->Start(); |
| EXPECT_EQ(LOW, req->priority()); |
| |
| req->SetPriority(MEDIUM); |
| EXPECT_EQ(MEDIUM, req->priority()); |
| } |
| |
| // Make sure that URLRequest calls SetPriority on a job before calling |
| // Start on it. |
| TEST_F(URLRequestTest, SetJobPriorityBeforeJobStart) { |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| EXPECT_EQ(DEFAULT_PRIORITY, req->priority()); |
| |
| RequestPriority job_priority; |
| std::unique_ptr<URLRequestJob> job(new PriorityMonitoringURLRequestJob( |
| req.get(), &default_network_delegate_, &job_priority)); |
| AddTestInterceptor()->set_main_intercept_job(std::move(job)); |
| EXPECT_EQ(DEFAULT_PRIORITY, job_priority); |
| |
| req->SetPriority(LOW); |
| |
| req->Start(); |
| EXPECT_EQ(LOW, job_priority); |
| } |
| |
| // Make sure that URLRequest passes on its priority updates to its |
| // job. |
| TEST_F(URLRequestTest, SetJobPriority) { |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| RequestPriority job_priority; |
| std::unique_ptr<URLRequestJob> job(new PriorityMonitoringURLRequestJob( |
| req.get(), &default_network_delegate_, &job_priority)); |
| AddTestInterceptor()->set_main_intercept_job(std::move(job)); |
| |
| req->SetPriority(LOW); |
| req->Start(); |
| EXPECT_EQ(LOW, job_priority); |
| |
| req->SetPriority(MEDIUM); |
| EXPECT_EQ(MEDIUM, req->priority()); |
| EXPECT_EQ(MEDIUM, job_priority); |
| } |
| |
| // Setting the IGNORE_LIMITS load flag should be okay if the priority |
| // is MAXIMUM_PRIORITY. |
| TEST_F(URLRequestTest, PriorityIgnoreLimits) { |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| GURL("http://test_intercept/foo"), MAXIMUM_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| EXPECT_EQ(MAXIMUM_PRIORITY, req->priority()); |
| |
| RequestPriority job_priority; |
| std::unique_ptr<URLRequestJob> job(new PriorityMonitoringURLRequestJob( |
| req.get(), &default_network_delegate_, &job_priority)); |
| AddTestInterceptor()->set_main_intercept_job(std::move(job)); |
| |
| req->SetLoadFlags(LOAD_IGNORE_LIMITS); |
| EXPECT_EQ(MAXIMUM_PRIORITY, req->priority()); |
| |
| req->SetPriority(MAXIMUM_PRIORITY); |
| EXPECT_EQ(MAXIMUM_PRIORITY, req->priority()); |
| |
| req->Start(); |
| EXPECT_EQ(MAXIMUM_PRIORITY, req->priority()); |
| EXPECT_EQ(MAXIMUM_PRIORITY, job_priority); |
| } |
| |
| namespace { |
| |
| // Less verbose way of running a simple testserver for the tests below. |
| class HttpTestServer : public EmbeddedTestServer { |
| public: |
| explicit HttpTestServer(const base::FilePath& document_root) { |
| AddDefaultHandlers(document_root); |
| } |
| |
| HttpTestServer() { AddDefaultHandlers(base::FilePath()); } |
| }; |
| |
| } // namespace |
| |
| TEST_F(URLRequestTest, DelayedCookieCallback) { |
| HttpTestServer test_server; |
| ASSERT_TRUE(test_server.Start()); |
| |
| TestURLRequestContext context; |
| std::unique_ptr<DelayedCookieMonster> delayed_cm(new DelayedCookieMonster()); |
| context.set_cookie_store(delayed_cm.get()); |
| |
| // Set up a cookie. |
| { |
| TestNetworkDelegate network_delegate; |
| context.set_network_delegate(&network_delegate); |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(context.CreateRequest( |
| test_server.GetURL("/set-cookie?CookieToNotSend=1"), DEFAULT_PRIORITY, |
| &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| 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; |
| std::unique_ptr<URLRequest> req(context.CreateRequest( |
| test_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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) { |
| HttpTestServer test_server; |
| ASSERT_TRUE(test_server.Start()); |
| |
| // Set up a cookie. |
| { |
| TestNetworkDelegate network_delegate; |
| default_context().set_network_delegate(&network_delegate); |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/set-cookie?CookieToNotSend=1"), DEFAULT_PRIORITY, |
| &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| 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; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->SetLoadFlags(LOAD_DO_NOT_SEND_COOKIES); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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) { |
| HttpTestServer test_server; |
| ASSERT_TRUE(test_server.Start()); |
| |
| // Set up a cookie. |
| { |
| TestNetworkDelegate network_delegate; |
| default_context().set_network_delegate(&network_delegate); |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/set-cookie?CookieToNotUpdate=2"), DEFAULT_PRIORITY, |
| &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/set-cookie?CookieToNotSave=1&CookieToNotUpdate=1"), |
| DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->SetLoadFlags(LOAD_DO_NOT_SAVE_COOKIES); |
| req->Start(); |
| |
| d.RunUntilComplete(); |
| |
| // 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; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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) { |
| HttpTestServer test_server; |
| ASSERT_TRUE(test_server.Start()); |
| |
| // Set up a cookie. |
| { |
| TestNetworkDelegate network_delegate; |
| default_context().set_network_delegate(&network_delegate); |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/set-cookie?CookieToNotSend=1"), DEFAULT_PRIORITY, |
| &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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()); |
| TestNetLogEntry::List entries; |
| net_log_.GetEntries(&entries); |
| for (const auto& entry : entries) { |
| EXPECT_NE(entry.type, |
| NetLogEventType::COOKIE_GET_BLOCKED_BY_NETWORK_DELEGATE); |
| } |
| } |
| |
| // 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); |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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()); |
| TestNetLogEntry::List entries; |
| net_log_.GetEntries(&entries); |
| ExpectLogContainsSomewhereAfter( |
| entries, 0, NetLogEventType::COOKIE_GET_BLOCKED_BY_NETWORK_DELEGATE, |
| NetLogEventPhase::NONE); |
| } |
| } |
| |
| // TODO(crbug.com/564656) This test is flaky on iOS. |
| #if defined(OS_IOS) |
| #define MAYBE_DoNotSaveCookies_ViaPolicy FLAKY_DoNotSaveCookies_ViaPolicy |
| #else |
| #define MAYBE_DoNotSaveCookies_ViaPolicy DoNotSaveCookies_ViaPolicy |
| #endif |
| TEST_F(URLRequestTest, DoNotSaveCookies_ViaPolicy) { |
| HttpTestServer test_server; |
| ASSERT_TRUE(test_server.Start()); |
| |
| // Set up a cookie. |
| { |
| TestNetworkDelegate network_delegate; |
| default_context().set_network_delegate(&network_delegate); |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/set-cookie?CookieToNotUpdate=2"), DEFAULT_PRIORITY, |
| &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| EXPECT_EQ(0, network_delegate.blocked_get_cookies_count()); |
| EXPECT_EQ(0, network_delegate.blocked_set_cookie_count()); |
| TestNetLogEntry::List entries; |
| net_log_.GetEntries(&entries); |
| for (const auto& entry : entries) { |
| EXPECT_NE(entry.type, |
| NetLogEventType::COOKIE_SET_BLOCKED_BY_NETWORK_DELEGATE); |
| } |
| } |
| |
| // 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); |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/set-cookie?CookieToNotSave=1&CookieToNotUpdate=1"), |
| DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| |
| d.RunUntilComplete(); |
| |
| EXPECT_EQ(0, network_delegate.blocked_get_cookies_count()); |
| EXPECT_EQ(2, network_delegate.blocked_set_cookie_count()); |
| TestNetLogEntry::List entries; |
| net_log_.GetEntries(&entries); |
| ExpectLogContainsSomewhereAfter( |
| entries, 0, NetLogEventType::COOKIE_SET_BLOCKED_BY_NETWORK_DELEGATE, |
| NetLogEventPhase::NONE); |
| } |
| |
| // Verify the cookies weren't saved or updated. |
| { |
| TestNetworkDelegate network_delegate; |
| default_context().set_network_delegate(&network_delegate); |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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) { |
| HttpTestServer test_server; |
| ASSERT_TRUE(test_server.Start()); |
| |
| // Set up an empty cookie. |
| { |
| TestNetworkDelegate network_delegate; |
| default_context().set_network_delegate(&network_delegate); |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/set-cookie"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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) { |
| HttpTestServer test_server; |
| ASSERT_TRUE(test_server.Start()); |
| |
| // Set up a cookie. |
| { |
| TestNetworkDelegate network_delegate; |
| default_context().set_network_delegate(&network_delegate); |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/set-cookie?CookieToNotSend=1"), DEFAULT_PRIORITY, |
| &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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); |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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) { |
| HttpTestServer test_server; |
| ASSERT_TRUE(test_server.Start()); |
| |
| // Set up a cookie. |
| { |
| TestNetworkDelegate network_delegate; |
| default_context().set_network_delegate(&network_delegate); |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/set-cookie?CookieToNotUpdate=2"), DEFAULT_PRIORITY, |
| &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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); |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/set-cookie?CookieToNotSave=1&CookieToNotUpdate=1"), |
| DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| |
| d.RunUntilComplete(); |
| |
| 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; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL("/echoheader?Cookie"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| |
| 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, SameSiteCookies) { |
| HttpTestServer test_server; |
| ASSERT_TRUE(test_server.Start()); |
| |
| TestNetworkDelegate network_delegate; |
| default_context().set_network_delegate(&network_delegate); |
| |
| const std::string kHost = "example.test"; |
| const std::string kSubHost = "subdomain.example.test"; |
| const std::string kCrossHost = "cross-origin.test"; |
| |
| // Set up two 'SameSite' cookies on 'example.test' |
| { |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL(kHost, |
| "/set-cookie?StrictSameSiteCookie=1;SameSite=Strict&" |
| "LaxSameSiteCookie=1;SameSite=Lax"), |
| DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->Start(); |
| d.RunUntilComplete(); |
| EXPECT_EQ(0, network_delegate.blocked_get_cookies_count()); |
| EXPECT_EQ(0, network_delegate.blocked_set_cookie_count()); |
| EXPECT_EQ(2, network_delegate.set_cookie_count()); |
| } |
| |
| // Verify that both cookies are sent for same-site requests. |
| { |
| TestDelegate d; |
| std::unique_ptr<URLRequest> req(default_context().CreateRequest( |
| test_server.GetURL(kHost, "/echoheader?Cookie"), DEFAULT_PRIORITY, &d, |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| req->set_site_for_cookies(test_server.GetURL(kHost, "/")); |
| req->set_initiator(url::Origin::Create(test_server.GetURL(kHost, "/"))); |
| req->Start(); |
| d.RunUntilComplete(); |
| |