diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-06-18 14:10:49 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> | 2015-06-18 13:53:24 +0000 |
commit | 813fbf95af77a531c57a8c497345ad2c61d475b3 (patch) | |
tree | 821b2c8de8365f21b6c9ba17a236fb3006a1d506 /chromium/net/test | |
parent | af6588f8d723931a298c995fa97259bb7f7deb55 (diff) | |
download | qtwebengine-chromium-813fbf95af77a531c57a8c497345ad2c61d475b3.tar.gz |
BASELINE: Update chromium to 44.0.2403.47
Change-Id: Ie056fedba95cf5e5c76b30c4b2c80fca4764aa2f
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/net/test')
35 files changed, 1222 insertions, 643 deletions
diff --git a/chromium/net/test/cert_test_util.h b/chromium/net/test/cert_test_util.h index 6334dd7edd8..219ccd87257 100644 --- a/chromium/net/test/cert_test_util.h +++ b/chromium/net/test/cert_test_util.h @@ -11,9 +11,7 @@ #include "net/cert/x509_cert_types.h" #include "net/cert/x509_certificate.h" -#if defined(USE_NSS) -#include "base/memory/scoped_ptr.h" - +#if defined(USE_NSS_CERTS) // From <pk11pub.h> typedef struct PK11SlotInfoStr PK11SlotInfo; #endif @@ -30,14 +28,13 @@ namespace net { class EVRootCAMetadata; -#if defined(USE_NSS) -// Imports a private key from file |key_filename| in |dir|. The file must -// contain a PKCS#8 PrivateKeyInfo in DER encoding. The key is imported to -// |slot|. -scoped_ptr<crypto::RSAPrivateKey> ImportSensitiveKeyFromFile( - const base::FilePath& dir, - const std::string& key_filename, - PK11SlotInfo* slot); +#if defined(USE_NSS_CERTS) +// Imports a private key from file |key_filename| in |dir| into |slot|. The file +// must contain a PKCS#8 PrivateKeyInfo in DER encoding. Returns true on success +// and false on failure. +bool ImportSensitiveKeyFromFile(const base::FilePath& dir, + const std::string& key_filename, + PK11SlotInfo* slot); bool ImportClientCertToSlot(const scoped_refptr<X509Certificate>& cert, PK11SlotInfo* slot); diff --git a/chromium/net/test/cert_test_util_nss.cc b/chromium/net/test/cert_test_util_nss.cc index ee929e5a41f..4427cebe117 100644 --- a/chromium/net/test/cert_test_util_nss.cc +++ b/chromium/net/test/cert_test_util_nss.cc @@ -9,22 +9,22 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "crypto/nss_key_util.h" #include "crypto/nss_util.h" -#include "crypto/rsa_private_key.h" +#include "crypto/scoped_nss_types.h" #include "net/cert/cert_type.h" namespace net { -scoped_ptr<crypto::RSAPrivateKey> ImportSensitiveKeyFromFile( - const base::FilePath& dir, - const std::string& key_filename, - PK11SlotInfo* slot) { +bool ImportSensitiveKeyFromFile(const base::FilePath& dir, + const std::string& key_filename, + PK11SlotInfo* slot) { base::FilePath key_path = dir.AppendASCII(key_filename); std::string key_pkcs8; bool success = base::ReadFileToString(key_path, &key_pkcs8); if (!success) { LOG(ERROR) << "Failed to read file " << key_path.value(); - return scoped_ptr<crypto::RSAPrivateKey>(); + return false; } const uint8* key_pkcs8_begin = @@ -32,12 +32,12 @@ scoped_ptr<crypto::RSAPrivateKey> ImportSensitiveKeyFromFile( std::vector<uint8> key_vector(key_pkcs8_begin, key_pkcs8_begin + key_pkcs8.length()); - scoped_ptr<crypto::RSAPrivateKey> private_key( - crypto::RSAPrivateKey::CreateSensitiveFromPrivateKeyInfo(slot, - key_vector)); + crypto::ScopedSECKEYPrivateKey private_key( + crypto::ImportNSSKeyFromPrivateKeyInfo(slot, key_vector, + true /* permanent */)); LOG_IF(ERROR, !private_key) << "Could not create key from file " << key_path.value(); - return private_key.Pass(); + return private_key; } bool ImportClientCertToSlot(const scoped_refptr<X509Certificate>& cert, diff --git a/chromium/net/test/embedded_test_server/embedded_test_server.cc b/chromium/net/test/embedded_test_server/embedded_test_server.cc index 7ac764fb708..ac7d3bc14ac 100644 --- a/chromium/net/test/embedded_test_server/embedded_test_server.cc +++ b/chromium/net/test/embedded_test_server/embedded_test_server.cc @@ -49,8 +49,15 @@ scoped_ptr<HttpResponse> HandleFileRequest( // This is a test-only server. Ignore I/O thread restrictions. base::ThreadRestrictions::ScopedAllowIO allow_io; + std::string relative_url(request.relative_url); + // A proxy request will have an absolute path. Simulate the proxy by stripping + // the scheme, host, and port. + GURL relative_gurl(relative_url); + if (relative_gurl.is_valid()) + relative_url = relative_gurl.PathForRequest(); + // Trim the first byte ('/'). - std::string request_path(request.relative_url.substr(1)); + std::string request_path = relative_url.substr(1); // Remove the query string if present. size_t query_pos = request_path.find('?'); @@ -115,7 +122,7 @@ void HttpListenSocket::DetachFromThread() { } EmbeddedTestServer::EmbeddedTestServer() - : port_(-1), + : port_(0), weak_factory_(this) { DCHECK(thread_checker_.CalledOnValidThread()); } diff --git a/chromium/net/test/embedded_test_server/embedded_test_server.h b/chromium/net/test/embedded_test_server/embedded_test_server.h index 24ff8d7a7b9..8746f0d9a26 100644 --- a/chromium/net/test/embedded_test_server/embedded_test_server.h +++ b/chromium/net/test/embedded_test_server/embedded_test_server.h @@ -71,7 +71,7 @@ class HttpListenSocket : public TCPListenSocket { // if (absolute_url.path() != "/test") // return scoped_ptr<HttpResponse>(); // -// scoped_ptr<HttpResponse> http_response(new HttpResponse()); +// scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse()); // http_response->set_code(test_server::SUCCESS); // http_response->set_content("hello"); // http_response->set_content_type("text/plain"); @@ -136,7 +136,7 @@ class EmbeddedTestServer : public StreamListenSocket::Delegate { const std::string& relative_url) const; // Returns the port number used by the server. - int port() const { return port_; } + uint16 port() const { return port_; } // Registers request handler which serves files from |directory|. // For instance, a request to "/foo.html" is served by "foo.html" under @@ -188,7 +188,7 @@ class EmbeddedTestServer : public StreamListenSocket::Delegate { scoped_ptr<base::Thread> io_thread_; scoped_ptr<HttpListenSocket> listen_socket_; - int port_; + uint16 port_; GURL base_url_; // Owns the HttpConnection objects. diff --git a/chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc b/chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc index 28d909e6ce8..b5d72f2a1e6 100644 --- a/chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc +++ b/chromium/net/test/embedded_test_server/embedded_test_server_unittest.cc @@ -112,12 +112,12 @@ class EmbeddedTestServerTest: public testing::Test, }; TEST_F(EmbeddedTestServerTest, GetBaseURL) { - EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%d/", server_->port()), + EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%u/", server_->port()), server_->base_url().spec()); } TEST_F(EmbeddedTestServerTest, GetURL) { - EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%d/path?query=foo", + EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%u/path?query=foo", server_->port()), server_->GetURL("/path?query=foo").spec()); } @@ -137,10 +137,8 @@ TEST_F(EmbeddedTestServerTest, RegisterRequestHandler) { "text/html", HTTP_OK)); - scoped_ptr<URLFetcher> fetcher( - URLFetcher::Create(server_->GetURL("/test?q=foo"), - URLFetcher::GET, - this)); + scoped_ptr<URLFetcher> fetcher = + URLFetcher::Create(server_->GetURL("/test?q=foo"), URLFetcher::GET, this); fetcher->SetRequestContext(request_context_getter_.get()); fetcher->Start(); WaitForResponses(1); @@ -159,10 +157,8 @@ TEST_F(EmbeddedTestServerTest, ServeFilesFromDirectory) { server_->ServeFilesFromDirectory( src_dir.AppendASCII("net").AppendASCII("data")); - scoped_ptr<URLFetcher> fetcher( - URLFetcher::Create(server_->GetURL("/test.html"), - URLFetcher::GET, - this)); + scoped_ptr<URLFetcher> fetcher = + URLFetcher::Create(server_->GetURL("/test.html"), URLFetcher::GET, this); fetcher->SetRequestContext(request_context_getter_.get()); fetcher->Start(); WaitForResponses(1); @@ -174,10 +170,8 @@ TEST_F(EmbeddedTestServerTest, ServeFilesFromDirectory) { } TEST_F(EmbeddedTestServerTest, DefaultNotFoundResponse) { - scoped_ptr<URLFetcher> fetcher( - URLFetcher::Create(server_->GetURL("/non-existent"), - URLFetcher::GET, - this)); + scoped_ptr<URLFetcher> fetcher = URLFetcher::Create( + server_->GetURL("/non-existent"), URLFetcher::GET, this); fetcher->SetRequestContext(request_context_getter_.get()); fetcher->Start(); @@ -209,20 +203,14 @@ TEST_F(EmbeddedTestServerTest, ConcurrentFetches) { "text/plain", HTTP_NOT_FOUND)); - scoped_ptr<URLFetcher> fetcher1 = scoped_ptr<URLFetcher>( - URLFetcher::Create(server_->GetURL("/test1"), - URLFetcher::GET, - this)); + scoped_ptr<URLFetcher> fetcher1 = + URLFetcher::Create(server_->GetURL("/test1"), URLFetcher::GET, this); fetcher1->SetRequestContext(request_context_getter_.get()); - scoped_ptr<URLFetcher> fetcher2 = scoped_ptr<URLFetcher>( - URLFetcher::Create(server_->GetURL("/test2"), - URLFetcher::GET, - this)); + scoped_ptr<URLFetcher> fetcher2 = + URLFetcher::Create(server_->GetURL("/test2"), URLFetcher::GET, this); fetcher2->SetRequestContext(request_context_getter_.get()); - scoped_ptr<URLFetcher> fetcher3 = scoped_ptr<URLFetcher>( - URLFetcher::Create(server_->GetURL("/test3"), - URLFetcher::GET, - this)); + scoped_ptr<URLFetcher> fetcher3 = + URLFetcher::Create(server_->GetURL("/test3"), URLFetcher::GET, this); fetcher3->SetRequestContext(request_context_getter_.get()); // Fetch the three URLs concurrently. @@ -289,8 +277,8 @@ class EmbeddedTestServerThreadingTestDelegate if (!loop) loop.reset(new base::MessageLoopForIO); - scoped_ptr<URLFetcher> fetcher(URLFetcher::Create( - server.GetURL("/test?q=foo"), URLFetcher::GET, this)); + scoped_ptr<URLFetcher> fetcher = + URLFetcher::Create(server.GetURL("/test?q=foo"), URLFetcher::GET, this); fetcher->SetRequestContext( new TestURLRequestContextGetter(loop->message_loop_proxy())); fetcher->Start(); diff --git a/chromium/net/test/embedded_test_server/http_request.cc b/chromium/net/test/embedded_test_server/http_request.cc index 3acb550292f..51d6f064694 100644 --- a/chromium/net/test/embedded_test_server/http_request.cc +++ b/chromium/net/test/embedded_test_server/http_request.cc @@ -10,6 +10,7 @@ #include "base/strings/string_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" +#include "net/http/http_chunked_decoder.h" namespace net { namespace test_server { @@ -83,8 +84,10 @@ HttpRequestParser::ParseResult HttpRequestParser::ParseHeaders() { // Parse request's the first header line. // Request main main header, eg. GET /foobar.html HTTP/1.1 + std::string request_headers; { const std::string header_line = ShiftLine(); + http_request_->all_headers += header_line + "\r\n"; std::vector<std::string> header_line_tokens; base::SplitString(header_line, ' ', &header_line_tokens); DCHECK_EQ(3u, header_line_tokens.size()); @@ -111,6 +114,7 @@ HttpRequestParser::ParseResult HttpRequestParser::ParseHeaders() { if (header_line.empty()) break; + http_request_->all_headers += header_line + "\r\n"; if (header_line[0] == ' ' || header_line[0] == '\t') { // Continuation of the previous multi-line header. std::string header_value = @@ -137,6 +141,13 @@ HttpRequestParser::ParseResult HttpRequestParser::ParseHeaders() { http_request_->headers["Content-Length"], &declared_content_length_); DCHECK(success) << "Malformed Content-Length header's value."; + } else if (http_request_->headers.count("Transfer-Encoding") > 0) { + if (http_request_->headers["Transfer-Encoding"] == "chunked") { + http_request_->has_content = true; + chunked_decoder_.reset(new HttpChunkedDecoder()); + state_ = STATE_CONTENT; + return WAITING; + } } if (declared_content_length_ == 0) { // No content data, so parsing is finished. @@ -152,6 +163,25 @@ HttpRequestParser::ParseResult HttpRequestParser::ParseHeaders() { HttpRequestParser::ParseResult HttpRequestParser::ParseContent() { const size_t available_bytes = buffer_.size() - buffer_position_; + if (chunked_decoder_.get()) { + int bytes_written = chunked_decoder_->FilterBuf( + const_cast<char*>(buffer_.data()) + buffer_position_, available_bytes); + http_request_->content.append(buffer_.data() + buffer_position_, + bytes_written); + + if (chunked_decoder_->reached_eof()) { + buffer_ = + buffer_.substr(buffer_.size() - chunked_decoder_->bytes_after_eof()); + buffer_position_ = 0; + state_ = STATE_ACCEPTED; + return ACCEPTED; + } + buffer_ = ""; + buffer_position_ = 0; + state_ = STATE_CONTENT; + return WAITING; + } + const size_t fetch_bytes = std::min( available_bytes, declared_content_length_ - http_request_->content.size()); diff --git a/chromium/net/test/embedded_test_server/http_request.h b/chromium/net/test/embedded_test_server/http_request.h index cb9144b1449..c2993785664 100644 --- a/chromium/net/test/embedded_test_server/http_request.h +++ b/chromium/net/test/embedded_test_server/http_request.h @@ -13,6 +13,9 @@ #include "base/strings/string_piece.h" namespace net { + +class HttpChunkedDecoder; + namespace test_server { // Methods of HTTP requests supported by the test HTTP server. @@ -36,6 +39,7 @@ struct HttpRequest { std::string relative_url; // Starts with '/'. Example: "/test?query=foo" HttpMethod method; std::string method_string; + std::string all_headers; std::map<std::string, std::string> headers; std::string content; bool has_content; @@ -92,7 +96,7 @@ class HttpRequestParser { ParseResult ParseHeaders(); // Parses request's content data and returns ACCEPTED if all of it have been - // processed. Chunked Transfer Encoding *is not* supported. + // processed. Chunked Transfer Encoding is supported. ParseResult ParseContent(); // Fetches the next line from the buffer. Result does not contain \r\n. @@ -107,6 +111,8 @@ class HttpRequestParser { // Content length of the request currently being parsed. size_t declared_content_length_; + scoped_ptr<HttpChunkedDecoder> chunked_decoder_; + DISALLOW_COPY_AND_ASSIGN(HttpRequestParser); }; diff --git a/chromium/net/test/embedded_test_server/http_request_unittest.cc b/chromium/net/test/embedded_test_server/http_request_unittest.cc index 1006e4ede90..ff2ae3cf968 100644 --- a/chromium/net/test/embedded_test_server/http_request_unittest.cc +++ b/chromium/net/test/embedded_test_server/http_request_unittest.cc @@ -4,6 +4,7 @@ #include "net/test/embedded_test_server/http_request.h" +#include "base/memory/scoped_ptr.h" #include "testing/gtest/include/gtest/gtest.h" namespace net { @@ -44,6 +45,14 @@ TEST(HttpRequestTest, ParseRequest) { EXPECT_EQ(1u, request->headers.count("Multi-line-header")); EXPECT_EQ(1u, request->headers.count("Content-Length")); + const char kExpectedAllHeaders[] = + "POST /foobar.html HTTP/1.1\r\n" + "Host: localhost:1234\r\n" + "Multi-line-header: abcd\r\n" + " efgh\r\n" + " ijkl\r\n" + "Content-Length: 10\r\n"; + EXPECT_EQ(kExpectedAllHeaders, request->all_headers); EXPECT_EQ("localhost:1234", request->headers["Host"]); EXPECT_EQ("abcd efgh ijkl", request->headers["Multi-line-header"]); EXPECT_EQ("10", request->headers["Content-Length"]); @@ -68,6 +77,48 @@ TEST(HttpRequestTest, ParseRequestWithEmptyBody) { EXPECT_EQ("0", request->headers["Content-Length"]); } +TEST(HttpRequestTest, ParseRequestWithChunkedBody) { + HttpRequestParser parser; + + parser.ProcessChunk("POST /foobar.html HTTP/1.1\r\n"); + parser.ProcessChunk("Transfer-Encoding: chunked\r\n\r\n"); + parser.ProcessChunk("5\r\nhello\r\n"); + parser.ProcessChunk("1\r\n \r\n"); + parser.ProcessChunk("5\r\nworld\r\n"); + parser.ProcessChunk("0\r\n\r\n"); + ASSERT_EQ(HttpRequestParser::ACCEPTED, parser.ParseRequest()); + + scoped_ptr<HttpRequest> request = parser.GetRequest(); + EXPECT_EQ("hello world", request->content); + EXPECT_TRUE(request->has_content); + EXPECT_EQ(1u, request->headers.count("Transfer-Encoding")); + EXPECT_EQ("chunked", request->headers["Transfer-Encoding"]); +} + +TEST(HttpRequestTest, ParseRequestWithChunkedBodySlow) { + HttpRequestParser parser; + + parser.ProcessChunk("POST /foobar.html HTTP/1.1\r\n"); + parser.ProcessChunk("Transfer-Encoding: chunked\r\n\r\n"); + std::string chunked_body = "5\r\nhello\r\n0\r\n\r\n"; + + // Send one character at a time, and make the parser parse the request. + for (size_t i = 0; i < chunked_body.size(); i++) { + parser.ProcessChunk(chunked_body.substr(i, 1)); + // Except for the last pass, ParseRequest() should give WAITING. + if (i != chunked_body.size() - 1) { + ASSERT_EQ(HttpRequestParser::WAITING, parser.ParseRequest()); + } + } + // All chunked data has been sent, the last ParseRequest should give ACCEPTED. + ASSERT_EQ(HttpRequestParser::ACCEPTED, parser.ParseRequest()); + scoped_ptr<HttpRequest> request = parser.GetRequest(); + EXPECT_EQ("hello", request->content); + EXPECT_TRUE(request->has_content); + EXPECT_EQ(1u, request->headers.count("Transfer-Encoding")); + EXPECT_EQ("chunked", request->headers["Transfer-Encoding"]); +} + TEST(HttpRequestTest, ParseRequestWithoutBody) { HttpRequestParser parser; diff --git a/chromium/net/test/embedded_test_server/http_response.h b/chromium/net/test/embedded_test_server/http_response.h index 821c02757dc..d4df75b5b85 100644 --- a/chromium/net/test/embedded_test_server/http_response.h +++ b/chromium/net/test/embedded_test_server/http_response.h @@ -7,10 +7,10 @@ #include <map> #include <string> -#include <vector> #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/strings/string_split.h" #include "net/http/http_status_code.h" namespace net { @@ -60,7 +60,7 @@ class BasicHttpResponse : public HttpResponse { HttpStatusCode code_; std::string content_; std::string content_type_; - std::vector<std::pair<std::string, std::string> > custom_headers_; + base::StringPairs custom_headers_; DISALLOW_COPY_AND_ASSIGN(BasicHttpResponse); }; diff --git a/chromium/net/test/event_waiter.h b/chromium/net/test/event_waiter.h new file mode 100644 index 00000000000..618b8ede462 --- /dev/null +++ b/chromium/net/test/event_waiter.h @@ -0,0 +1,40 @@ +// Copyright 2015 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. + +#ifndef NET_TEST_EVENT_WAITER_H_ +#define NET_TEST_EVENT_WAITER_H_ + +#include "base/run_loop.h" + +namespace net { + +// Helper class to run a RunLoop until an expected event is reported. +template <typename Event> +class EventWaiter { + public: + // Runs a RunLoop until NotifyEvent() is called with |event|. + void WaitForEvent(Event event) { + expected_event_ = event; + base::RunLoop run_loop; + quit_closure_ = run_loop.QuitClosure(); + run_loop.Run(); + } + + // Unblocks a WaitForEvent() call if it was called with |event|. Otherwise, + // has no effect. + void NotifyEvent(Event event) { + if (event == expected_event_ && !quit_closure_.is_null()) { + quit_closure_.Run(); + quit_closure_.Reset(); + } + } + + private: + Event expected_event_; + base::Closure quit_closure_; +}; + +} // namespace net + +#endif // NET_TEST_EVENT_WAITER_H_ diff --git a/chromium/net/test/gtest_util.h b/chromium/net/test/gtest_util.h index 14492c2a780..1d6708774ff 100644 --- a/chromium/net/test/gtest_util.h +++ b/chromium/net/test/gtest_util.h @@ -7,8 +7,8 @@ #ifndef NET_QUIC_TEST_TOOLS_GTEST_UTIL_H_ #define NET_QUIC_TEST_TOOLS_GTEST_UTIL_H_ +#include "base/test/mock_log.h" #include "net/test/scoped_disable_exit_on_dfatal.h" -#include "net/test/scoped_mock_log.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -17,26 +17,25 @@ namespace test { // Internal implementation for the EXPECT_DFATAL and ASSERT_DFATAL // macros. Do not use this directly. -#define GTEST_DFATAL_(statement, matcher, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (true) { \ - ::net::test::ScopedMockLog gtest_log; \ - ::net::test::ScopedDisableExitOnDFatal gtest_disable_exit; \ - using ::testing::_; \ - EXPECT_CALL(gtest_log, Log(_, _, _, _, _)) \ - .WillRepeatedly(::testing::Return(false)); \ - EXPECT_CALL(gtest_log, Log(logging::LOG_DFATAL, _, _, _, matcher)) \ - .Times(::testing::AtLeast(1)) \ - .WillOnce(::testing::Return(false)); \ - gtest_log.StartCapturingLogs(); \ - { statement; } \ - gtest_log.StopCapturingLogs(); \ - if (!testing::Mock::VerifyAndClear(>est_log)) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_dfatal_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_dfatal_, __LINE__): \ - fail("") +#define GTEST_DFATAL_(statement, matcher, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (true) { \ + ::base::test::MockLog gtest_log; \ + ::net::test::ScopedDisableExitOnDFatal gtest_disable_exit; \ + using ::testing::_; \ + EXPECT_CALL(gtest_log, Log(_, _, _, _, _)) \ + .WillRepeatedly(::testing::Return(false)); \ + EXPECT_CALL(gtest_log, Log(logging::LOG_DFATAL, _, _, _, matcher)) \ + .Times(::testing::AtLeast(1)) \ + .WillOnce(::testing::Return(false)); \ + gtest_log.StartCapturingLogs(); \ + { statement; } \ + gtest_log.StopCapturingLogs(); \ + if (!testing::Mock::VerifyAndClear(>est_log)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_dfatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_dfatal_, __LINE__) : fail("") // The EXPECT_DFATAL and ASSERT_DFATAL macros are lightweight // alternatives to EXPECT_DEBUG_DEATH and ASSERT_DEBUG_DEATH. They diff --git a/chromium/net/test/net_test_suite.cc b/chromium/net/test/net_test_suite.cc index ed8a103ac1e..b14e3fea536 100644 --- a/chromium/net/test/net_test_suite.cc +++ b/chromium/net/test/net_test_suite.cc @@ -10,12 +10,12 @@ #include "net/spdy/spdy_session.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(USE_NSS) || defined(OS_IOS) -#include "net/ocsp/nss_ocsp.h" +#if defined(USE_NSS_CERTS) || defined(OS_IOS) +#include "net/cert_net/nss_ocsp.h" #endif class StaticReset : public ::testing::EmptyTestEventListener { - virtual void OnTestStart(const ::testing::TestInfo& test_info) override { + void OnTestStart(const ::testing::TestInfo& test_info) override { net::HttpStreamFactory::ResetStaticSettingsToInit(); } }; @@ -38,7 +38,7 @@ void NetTestSuite::Initialize() { } void NetTestSuite::Shutdown() { -#if defined(USE_NSS) || defined(OS_IOS) +#if defined(USE_NSS_CERTS) || defined(OS_IOS) net::ShutdownNSSHttpIO(); #endif diff --git a/chromium/net/test/python_utils.cc b/chromium/net/test/python_utils.cc index 7e40faefe83..7d137b7c411 100644 --- a/chromium/net/test/python_utils.cc +++ b/chromium/net/test/python_utils.cc @@ -9,11 +9,18 @@ #include "base/environment.h" #include "base/files/file_path.h" #include "base/files/file_util.h" +#include "base/lazy_instance.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/path_service.h" +#include "base/process/launch.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#if defined(OS_MACOSX) +#include "base/mac/foundation_util.h" +#endif + const char kPythonPathEnv[] = "PYTHONPATH"; void AppendToPythonPath(const base::FilePath& dir) { @@ -39,31 +46,6 @@ void AppendToPythonPath(const base::FilePath& dir) { } } -namespace { - -#if defined(OS_MACOSX) || defined(OS_CHROMEOS) -// Search for |to_try|, rolling up the directory tree from -// |start_dir|. If found, return true and put the path to |to_try| in -// |out_dir|. If not, return false and leave |out_dir| untouched. -bool TryRelativeToDir(const base::FilePath& start_dir, - const base::FilePath& to_try, - base::FilePath* out_dir) { - base::FilePath dir(start_dir); - while (!base::DirectoryExists(dir.Append(to_try))) { - base::FilePath parent = dir.DirName(); - if (parent == dir) { - // We hit the root directory. - return false; - } - dir = parent; - } - *out_dir = dir; - return true; -} -#endif // defined(OS_MACOSX) || defined(OS_CHROMEOS) - -} // namespace - bool GetPyProtoPath(base::FilePath* dir) { // Locate the Python code generated by the protocol buffers compiler. base::FilePath generated_code_dir; @@ -72,44 +54,62 @@ bool GetPyProtoPath(base::FilePath* dir) { return false; } +#if defined(OS_MACOSX) + if (base::mac::AmIBundled()) + generated_code_dir = generated_code_dir.DirName().DirName().DirName(); +#endif + + // Used for GYP. TODO(jam): remove after GN conversion. const base::FilePath kPyProto(FILE_PATH_LITERAL("pyproto")); + if (base::DirectoryExists(generated_code_dir.Append(kPyProto))) { + *dir = generated_code_dir.Append(kPyProto); + return true; + } -#if defined(OS_MACOSX) || defined(OS_CHROMEOS) - base::FilePath source_dir; - if (!PathService::Get(base::DIR_SOURCE_ROOT, &source_dir)) { - LOG(ERROR) << "Can't find " << source_dir.value(); - return false; + // Used for GN. + const base::FilePath kGen(FILE_PATH_LITERAL("gen")); + if (base::DirectoryExists(generated_code_dir.Append(kGen))) { + *dir = generated_code_dir.Append(kGen); + return true; } - // On Mac, and possibly Chrome OS, DIR_EXE might be pointing deep - // into the Release/ (or Debug/) directory and we can't depend on - // how far down it goes. So we walk upwards from DIR_EXE until we - // find a likely looking spot. - if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) { - LOG(WARNING) << "Can't find " << kPyProto.value() - << " next to " << generated_code_dir.value(); - // On Chrome OS, we may have installed the test binaries and support tools - // in a wholly separate location, relative to DIR_SOURCE_ROOT. We'll want - // to do a similar investigation from that point as well. - generated_code_dir = source_dir - .Append(FILE_PATH_LITERAL("out")) - .Append(FILE_PATH_LITERAL("Release")); - if (!TryRelativeToDir(generated_code_dir, kPyProto, dir)) { - LOG(WARNING) << "Can't find " << kPyProto.value() - << " next to " << generated_code_dir.value(); - return false; - } + + return false; +} + +#if defined(OS_WIN) +struct PythonExePath { + PythonExePath() { + // This is test-only code, so CHECK with a subprocess invocation is ok. + base::CommandLine command(base::FilePath(FILE_PATH_LITERAL("cmd"))); + command.AppendArg("/c"); + command.AppendArg("python"); + command.AppendArg("-c"); + command.AppendArg("import sys; print sys.executable"); + std::string output; + CHECK(GetAppOutput(command, &output)); + // This does only work if cmd.exe doesn't use a non-US codepage. + path_ = base::ASCIIToUTF16(output); + TrimWhitespace(path_, base::TRIM_ALL, &path_); } - generated_code_dir = *dir; + base::string16 path_; +}; +static base::LazyInstance<PythonExePath>::Leaky g_python_path; #endif - *dir = generated_code_dir.Append(kPyProto); - VLOG(2) << "Found " << kPyProto.value() << " in " << dir->value(); - return true; -} bool GetPythonCommand(base::CommandLine* python_cmd) { DCHECK(python_cmd); +#if defined(OS_WIN) + // Most developers have depot_tools in their path, which only has a + // python.bat, not a python.exe. Go through cmd to find the path to + // the python executable. + // (Don't just return a a "cmd /c python" command line, because then tests + // that try to kill the python process will kill the cmd process instead, + // which can cause flakiness.) + python_cmd->SetProgram(base::FilePath(g_python_path.Get().path_)); +#else python_cmd->SetProgram(base::FilePath(FILE_PATH_LITERAL("python"))); +#endif // Launch python in unbuffered mode, so that python output doesn't mix with // gtest output in buildbot log files. See http://crbug.com/147368. diff --git a/chromium/net/test/run_all_unittests.cc b/chromium/net/test/run_all_unittests.cc index e86487e6fed..25016ca589c 100644 --- a/chromium/net/test/run_all_unittests.cc +++ b/chromium/net/test/run_all_unittests.cc @@ -19,12 +19,8 @@ #include "url/android/url_jni_registrar.h" #endif -#if !defined(OS_IOS) -#include "net/proxy/proxy_resolver_v8.h" -#endif - -#ifdef V8_USE_EXTERNAL_STARTUP_DATA -#include "gin/public/isolate_holder.h" +#if !defined(OS_ANDROID) && !defined(OS_IOS) +#include "third_party/mojo/src/mojo/edk/embedder/test_embedder.h" #endif using net::internal::ClientSocketPoolBaseHelper; @@ -61,12 +57,8 @@ int main(int argc, char** argv) { // single-threaded. net::EnableSSLServerSockets(); -#ifdef V8_USE_EXTERNAL_STARTUP_DATA - gin::IsolateHolder::LoadV8Snapshot(); -#endif - -#if !defined(OS_IOS) - net::ProxyResolverV8::EnsureIsolateCreated(); +#if !defined(OS_ANDROID) && !defined(OS_IOS) + mojo::embedder::test::InitWithSimplePlatformSupport(); #endif return base::LaunchUnitTests( diff --git a/chromium/net/test/scoped_mock_log.cc b/chromium/net/test/scoped_mock_log.cc deleted file mode 100644 index 3bc99cb3d42..00000000000 --- a/chromium/net/test/scoped_mock_log.cc +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2014 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 "net/test/scoped_mock_log.h" - -#include "base/logging.h" - -namespace net { -namespace test { - -// static -ScopedMockLog* ScopedMockLog::g_instance_ = NULL; - -ScopedMockLog::ScopedMockLog() : is_capturing_logs_(false) {} - -ScopedMockLog::~ScopedMockLog() { - if (is_capturing_logs_) { - StopCapturingLogs(); - } -} - -void ScopedMockLog::StartCapturingLogs() { - // We don't use CHECK(), which can generate a new LOG message, and - // thus can confuse ScopedMockLog objects or other registered - // LogSinks. - RAW_CHECK(!is_capturing_logs_); - RAW_CHECK(!g_instance_); - - is_capturing_logs_ = true; - g_instance_ = this; - previous_handler_ = logging::GetLogMessageHandler(); - logging::SetLogMessageHandler(LogMessageHandler); -} - -void ScopedMockLog::StopCapturingLogs() { - // We don't use CHECK(), which can generate a new LOG message, and - // thus can confuse ScopedMockLog objects or other registered - // LogSinks. - RAW_CHECK(is_capturing_logs_); - RAW_CHECK(g_instance_ == this); - - is_capturing_logs_ = false; - logging::SetLogMessageHandler(previous_handler_); - g_instance_ = NULL; -} - -// static -bool ScopedMockLog::LogMessageHandler(int severity, - const char* file, - int line, - size_t message_start, - const std::string& str) { - return g_instance_->Log(severity, file, line, message_start, str); -} - -} // namespace test -} // namespace net diff --git a/chromium/net/test/scoped_mock_log.h b/chromium/net/test/scoped_mock_log.h deleted file mode 100644 index e1edfcccde8..00000000000 --- a/chromium/net/test/scoped_mock_log.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2014 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. - -#ifndef NET_QUIC_TEST_TOOLS_SCOPED_MOCK_LOG_H_ -#define NET_QUIC_TEST_TOOLS_SCOPED_MOCK_LOG_H_ - -#include "base/logging.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { -namespace test { - -// A ScopedMockLog object intercepts LOG() messages issued during its -// lifespan. Using this together with gMock, it's very easy to test -// how a piece of code calls LOG(). The typical usage: -// -// TEST(FooTest, LogsCorrectly) { -// ScopedMockLog log; -// -// // We expect the WARNING "Something bad!" exactly twice. -// EXPECT_CALL(log, Log(WARNING, _, "Something bad!")) -// .Times(2); -// -// // We allow foo.cc to call LOG(INFO) any number of times. -// EXPECT_CALL(log, Log(INFO, HasSubstr("/foo.cc"), _)) -// .Times(AnyNumber()); -// -// log.StartCapturingLogs(); // Call this after done setting expectations. -// Foo(); // Exercises the code under test. -// } -// -// CAVEAT: base/logging does not allow a thread to call LOG() again -// when it's already inside a LOG() call. Doing so will cause a -// deadlock. Therefore, it's the user's responsibility to not call -// LOG() in an action triggered by ScopedMockLog::Log(). You may call -// RAW_LOG() instead. -class ScopedMockLog { - public: - // Creates a ScopedMockLog object that is not capturing logs. - // If it were to start to capture logs, it could be a problem if - // some other threads already exist and are logging, as the user - // hasn't had a chance to set up expectation on this object yet - // (calling a mock method before setting the expectation is - // UNDEFINED behavior). - ScopedMockLog(); - - // When the object is destructed, it stops intercepting logs. - ~ScopedMockLog(); - - // Starts log capturing if the object isn't already doing so. - // Otherwise crashes. Usually this method is called in the same - // thread that created this object. It is the user's responsibility - // to not call this method if another thread may be calling it or - // StopCapturingLogs() at the same time. - void StartCapturingLogs(); - - // Stops log capturing if the object is capturing logs. Otherwise - // crashes. Usually this method is called in the same thread that - // created this object. It is the user's responsibility to not call - // this method if another thread may be calling it or - // StartCapturingLogs() at the same time. - void StopCapturingLogs(); - - // Sets the Log Message Handler that gets passed every log message before - // it's sent to other log destinations (if any). - // Returns true to signal that it handled the message and the message - // should not be sent to other log destinations. - MOCK_METHOD5(Log, bool(int severity, - const char* file, - int line, - size_t message_start, - const std::string& str)); - - private: - // The currently active scoped mock log. - static ScopedMockLog* g_instance_; - - // Static function which is set as the logging message handler. - // Called once for each message. - static bool LogMessageHandler(int severity, - const char* file, - int line, - size_t message_start, - const std::string& str); - - // True if this object is currently capturing logs. - bool is_capturing_logs_; - - // The previous handler to restore when the ScopedMockLog is destroyed. - logging::LogMessageHandlerFunction previous_handler_; -}; - -} // namespace test -} // namespace net - -#endif // NET_QUIC_TEST_TOOLS_SCOPED_MOCK_LOG_H_ diff --git a/chromium/net/test/spawned_test_server/base_test_server.cc b/chromium/net/test/spawned_test_server/base_test_server.cc index 0e23c7a3b55..5d97f8dd6bc 100644 --- a/chromium/net/test/spawned_test_server/base_test_server.cc +++ b/chromium/net/test/spawned_test_server/base_test_server.cc @@ -16,11 +16,11 @@ #include "net/base/address_list.h" #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" -#include "net/base/net_log.h" #include "net/base/net_util.h" #include "net/base/test_completion_callback.h" #include "net/cert/test_root_certs.h" #include "net/dns/host_resolver.h" +#include "net/log/net_log.h" #include "url/gurl.h" namespace net { @@ -29,11 +29,17 @@ namespace { std::string GetHostname(BaseTestServer::Type type, const BaseTestServer::SSLOptions& options) { - if (BaseTestServer::UsingSSL(type) && - options.server_certificate == - BaseTestServer::SSLOptions::CERT_MISMATCHED_NAME) { - // Return a different hostname string that resolves to the same hostname. - return "localhost"; + if (BaseTestServer::UsingSSL(type)) { + if (options.server_certificate == + BaseTestServer::SSLOptions::CERT_MISMATCHED_NAME || + options.server_certificate == + BaseTestServer::SSLOptions::CERT_COMMON_NAME_IS_DOMAIN) { + // For |CERT_MISMATCHED_NAME|, return a different hostname string + // that resolves to the same hostname. For + // |CERT_COMMON_NAME_IS_DOMAIN|, the certificate is issued for + // "localhost" instead of "127.0.0.1". + return "localhost"; + } } // Use the 127.0.0.1 as default. @@ -44,8 +50,6 @@ std::string GetClientCertType(SSLClientCertType type) { switch (type) { case CLIENT_CERT_RSA_SIGN: return "rsa_sign"; - case CLIENT_CERT_DSS_SIGN: - return "dss_sign"; case CLIENT_CERT_ECDSA_SIGN: return "ecdsa_sign"; default: @@ -59,6 +63,8 @@ void GetKeyExchangesList(int key_exchange, base::ListValue* values) { values->Append(new base::StringValue("rsa")); if (key_exchange & BaseTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA) values->Append(new base::StringValue("dhe_rsa")); + if (key_exchange & BaseTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA) + values->Append(new base::StringValue("ecdhe_rsa")); } void GetCiphersList(int cipher, base::ListValue* values) { @@ -70,6 +76,8 @@ void GetCiphersList(int cipher, base::ListValue* values) { values->Append(new base::StringValue("aes256")); if (cipher & BaseTestServer::SSLOptions::BULK_CIPHER_3DES) values->Append(new base::StringValue("3des")); + if (cipher & BaseTestServer::SSLOptions::BULK_CIPHER_AES128GCM) + values->Append(new base::StringValue("aes128gcm")); } base::StringValue* GetTLSIntoleranceType( @@ -101,8 +109,9 @@ BaseTestServer::SSLOptions::SSLOptions() tls_intolerance_type(TLS_INTOLERANCE_ALERT), fallback_scsv_enabled(false), staple_ocsp_response(false), + ocsp_server_unavailable(false), enable_npn(false), - disable_session_cache(false) { + alert_after_handshake(false) { } BaseTestServer::SSLOptions::SSLOptions( @@ -118,8 +127,9 @@ BaseTestServer::SSLOptions::SSLOptions( tls_intolerance_type(TLS_INTOLERANCE_ALERT), fallback_scsv_enabled(false), staple_ocsp_response(false), + ocsp_server_unavailable(false), enable_npn(false), - disable_session_cache(false) { + alert_after_handshake(false) { } BaseTestServer::SSLOptions::~SSLOptions() {} @@ -129,6 +139,8 @@ base::FilePath BaseTestServer::SSLOptions::GetCertificateFile() const { case CERT_OK: case CERT_MISMATCHED_NAME: return base::FilePath(FILE_PATH_LITERAL("ok_cert.pem")); + case CERT_COMMON_NAME_IS_DOMAIN: + return base::FilePath(FILE_PATH_LITERAL("localhost_cert.pem")); case CERT_EXPIRED: return base::FilePath(FILE_PATH_LITERAL("expired_cert.pem")); case CERT_CHAIN_WRONG_ROOT: @@ -170,7 +182,8 @@ BaseTestServer::BaseTestServer(Type type, const std::string& host) : type_(type), started_(false), log_to_console_(false), - ws_basic_auth_(false) { + ws_basic_auth_(false), + no_anonymous_ftp_user_(false) { Init(host); } @@ -179,7 +192,8 @@ BaseTestServer::BaseTestServer(Type type, const SSLOptions& ssl_options) type_(type), started_(false), log_to_console_(false), - ws_basic_auth_(false) { + ws_basic_auth_(false), + no_anonymous_ftp_user_(false) { DCHECK(UsingSSL(type)); Init(GetHostname(type, ssl_options)); } @@ -231,7 +245,7 @@ bool BaseTestServer::GetAddressList(AddressList* address_list) const { BoundNetLog()); if (rv == ERR_IO_PENDING) rv = callback.WaitForResult(); - if (rv != net::OK) { + if (rv != OK) { LOG(ERROR) << "Failed to resolve hostname: " << host_port_pair_.host(); return false; } @@ -296,6 +310,24 @@ bool BaseTestServer::GetFilePathWithReplacements( return true; } +bool BaseTestServer::LoadTestRootCert() const { + TestRootCerts* root_certs = TestRootCerts::GetInstance(); + if (!root_certs) + return false; + + // Should always use absolute path to load the root certificate. + base::FilePath root_certificate_path = certificates_dir_; + if (!certificates_dir_.IsAbsolute()) { + base::FilePath src_dir; + if (!PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)) + return false; + root_certificate_path = src_dir.Append(certificates_dir_); + } + + return root_certs->AddFromFile( + root_certificate_path.AppendASCII("root_ca_cert.pem")); +} + void BaseTestServer::Init(const std::string& host) { host_port_pair_ = HostPortPair(host, 0); @@ -338,24 +370,6 @@ bool BaseTestServer::ParseServerData(const std::string& server_data) { return true; } -bool BaseTestServer::LoadTestRootCert() const { - TestRootCerts* root_certs = TestRootCerts::GetInstance(); - if (!root_certs) - return false; - - // Should always use absolute path to load the root certificate. - base::FilePath root_certificate_path = certificates_dir_; - if (!certificates_dir_.IsAbsolute()) { - base::FilePath src_dir; - if (!PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)) - return false; - root_certificate_path = src_dir.Append(certificates_dir_); - } - - return root_certs->AddFromFile( - root_certificate_path.AppendASCII("root_ca_cert.pem")); -} - bool BaseTestServer::SetupWhenServerStarted() { DCHECK(host_port_pair_.port()); @@ -395,6 +409,11 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const { arguments->Set("ws-basic-auth", base::Value::CreateNullValue()); } + if (no_anonymous_ftp_user_) { + DCHECK_EQ(TYPE_FTP, type_); + arguments->Set("no-anonymous-ftp-user", base::Value::CreateNullValue()); + } + if (UsingSSL(type_)) { // Check the certificate arguments of the HTTPS server. base::FilePath certificate_path(certificates_dir_); @@ -476,10 +495,14 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const { } if (ssl_options_.staple_ocsp_response) arguments->Set("staple-ocsp-response", base::Value::CreateNullValue()); + if (ssl_options_.ocsp_server_unavailable) { + arguments->Set("ocsp-server-unavailable", + base::Value::CreateNullValue()); + } if (ssl_options_.enable_npn) arguments->Set("enable-npn", base::Value::CreateNullValue()); - if (ssl_options_.disable_session_cache) - arguments->Set("disable-session-cache", base::Value::CreateNullValue()); + if (ssl_options_.alert_after_handshake) + arguments->Set("alert-after-handshake", base::Value::CreateNullValue()); } return GenerateAdditionalArguments(arguments); diff --git a/chromium/net/test/spawned_test_server/base_test_server.h b/chromium/net/test/spawned_test_server/base_test_server.h index 45ea1cecffa..b72e5d3e05a 100644 --- a/chromium/net/test/spawned_test_server/base_test_server.h +++ b/chromium/net/test/spawned_test_server/base_test_server.h @@ -61,6 +61,10 @@ class BaseTestServer { // TestRootStore) is expected to have a self-signed version of the // intermediate. CERT_CHAIN_WRONG_ROOT, + + // Causes the testserver to use a hostname that is a domain + // instead of an IP. + CERT_COMMON_NAME_IS_DOMAIN, }; // OCSPStatus enumerates the types of OCSP response that the testserver @@ -79,10 +83,11 @@ class BaseTestServer { // Special value used to indicate that any algorithm the server supports // is acceptable. Preferred over explicitly OR-ing all key exchange // algorithms. - KEY_EXCHANGE_ANY = 0, + KEY_EXCHANGE_ANY = 0, - KEY_EXCHANGE_RSA = (1 << 0), + KEY_EXCHANGE_RSA = (1 << 0), KEY_EXCHANGE_DHE_RSA = (1 << 1), + KEY_EXCHANGE_ECDHE_RSA = (1 << 2), }; // Bitmask of bulk encryption algorithms that the test server supports @@ -90,16 +95,18 @@ class BaseTestServer { enum BulkCipher { // Special value used to indicate that any algorithm the server supports // is acceptable. Preferred over explicitly OR-ing all ciphers. - BULK_CIPHER_ANY = 0, + BULK_CIPHER_ANY = 0, - BULK_CIPHER_RC4 = (1 << 0), + BULK_CIPHER_RC4 = (1 << 0), BULK_CIPHER_AES128 = (1 << 1), BULK_CIPHER_AES256 = (1 << 2), // NOTE: 3DES support in the Python test server has external // dependencies and not be available on all machines. Clients may not // be able to connect if only 3DES is specified. - BULK_CIPHER_3DES = (1 << 3), + BULK_CIPHER_3DES = (1 << 3), + + BULK_CIPHER_AES128GCM = (1 << 4), }; // NOTE: the values of these enumerators are passed to the the Python test @@ -201,13 +208,15 @@ class BaseTestServer { // Whether to staple the OCSP response. bool staple_ocsp_response; + // Whether to make the OCSP server unavailable. This does not affect the + // stapled OCSP response. + bool ocsp_server_unavailable; + // Whether to enable NPN support. bool enable_npn; - // Whether to disable TLS session caching. When session caching is - // disabled, the server will use an empty session ID in the - // ServerHello. - bool disable_session_cache; + // Whether to send a fatal alert immediately after completing the handshake. + bool alert_after_handshake; }; // Pass as the 'host' parameter during construction to server on 127.0.0.1 @@ -253,6 +262,15 @@ class BaseTestServer { ws_basic_auth_ = ws_basic_auth; } + // Disable creation of anonymous FTP user. + void set_no_anonymous_ftp_user(bool no_anonymous_ftp_user) { + no_anonymous_ftp_user_ = no_anonymous_ftp_user; + } + + // Marks the root certificate of an HTTPS test server as trusted for + // the duration of tests. + bool LoadTestRootCert() const WARN_UNUSED_RESULT; + protected: virtual ~BaseTestServer(); Type type() const { return type_; } @@ -291,10 +309,6 @@ class BaseTestServer { private: void Init(const std::string& host); - // Marks the root certificate of an HTTPS test server as trusted for - // the duration of tests. - bool LoadTestRootCert() const WARN_UNUSED_RESULT; - // Document root of the test server. base::FilePath document_root_; @@ -322,6 +336,9 @@ class BaseTestServer { // Is WebSocket basic HTTP authentication enabled? bool ws_basic_auth_; + // Disable creation of anonymous FTP user? + bool no_anonymous_ftp_user_; + scoped_ptr<ScopedPortException> allowed_port_; DISALLOW_COPY_AND_ASSIGN(BaseTestServer); diff --git a/chromium/net/test/spawned_test_server/local_test_server.cc b/chromium/net/test/spawned_test_server/local_test_server.cc index c85e05a8dec..77630b175ae 100644 --- a/chromium/net/test/spawned_test_server/local_test_server.cc +++ b/chromium/net/test/spawned_test_server/local_test_server.cc @@ -8,7 +8,6 @@ #include "base/json/json_reader.h" #include "base/logging.h" #include "base/path_service.h" -#include "base/process/kill.h" #include "base/strings/string_number_conversions.h" #include "base/values.h" #include "net/base/host_port_pair.h" @@ -121,21 +120,19 @@ bool LocalTestServer::BlockUntilStarted() { bool LocalTestServer::Stop() { CleanUpWhenStoppingServer(); - if (!process_handle_) + if (!process_.IsValid()) return true; // First check if the process has already terminated. - bool ret = base::WaitForSingleProcess(process_handle_, base::TimeDelta()); - if (!ret) { - ret = base::KillProcess(process_handle_, 1, true); - } - - if (ret) { - base::CloseProcessHandle(process_handle_); - process_handle_ = base::kNullProcessHandle; - } else { + int exit_code; + bool ret = process_.WaitForExitWithTimeout(base::TimeDelta(), &exit_code); + if (!ret) + ret = process_.Terminate(1, true); + + if (ret) + process_.Close(); + else VLOG(1) << "Kill failed?"; - } return ret; } @@ -149,7 +146,6 @@ bool LocalTestServer::Init(const base::FilePath& document_root) { // number out over a pipe that this TestServer object will read from. Once // that is complete, the host port pair will contain the actual port. DCHECK(!GetPort()); - process_handle_ = base::kNullProcessHandle; base::FilePath src_dir; if (!PathService::Get(base::DIR_SOURCE_ROOT, &src_dir)) diff --git a/chromium/net/test/spawned_test_server/local_test_server.h b/chromium/net/test/spawned_test_server/local_test_server.h index 37b118588a5..785d7267056 100644 --- a/chromium/net/test/spawned_test_server/local_test_server.h +++ b/chromium/net/test/spawned_test_server/local_test_server.h @@ -9,7 +9,7 @@ #include "base/files/file_util.h" #include "base/files/scoped_file.h" -#include "base/process/process_handle.h" +#include "base/process/process.h" #include "net/test/spawned_test_server/base_test_server.h" #if defined(OS_WIN) @@ -92,8 +92,8 @@ class LocalTestServer : public BaseTestServer { // Waits for the server to start. Returns true on success. bool WaitToStart() WARN_UNUSED_RESULT; - // Handle of the Python process running the test server. - base::ProcessHandle process_handle_; + // The Python process running the test server. + base::Process process_; #if defined(OS_WIN) // The pipe file handle we read from. diff --git a/chromium/net/test/spawned_test_server/local_test_server_posix.cc b/chromium/net/test/spawned_test_server/local_test_server_posix.cc index 0edbedf1e42..c770152ea6b 100644 --- a/chromium/net/test/spawned_test_server/local_test_server_posix.cc +++ b/chromium/net/test/spawned_test_server/local_test_server_posix.cc @@ -139,7 +139,8 @@ bool LocalTestServer::LaunchPython(const base::FilePath& testserver_path) { base::LaunchOptions options; options.fds_to_remap = &map_write_fd; - if (!base::LaunchProcess(python_command, options, &process_handle_)) { + process_ = base::LaunchProcess(python_command, options); + if (!process_.IsValid()) { LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString(); return false; } diff --git a/chromium/net/test/spawned_test_server/local_test_server_win.cc b/chromium/net/test/spawned_test_server/local_test_server_win.cc index 412e4e10c80..0476b907caf 100644 --- a/chromium/net/test/spawned_test_server/local_test_server_win.cc +++ b/chromium/net/test/spawned_test_server/local_test_server_win.cc @@ -78,60 +78,6 @@ bool ReadData(HANDLE read_fd, HANDLE write_fd, return true; } -// Class that sets up a temporary path that includes the supplied path -// at the end. -// -// TODO(bratell): By making this more generic we can possibly reuse -// it at other places such as -// chrome/common/multi_process_lock_unittest.cc. -class ScopedPath { - public: - // Constructor which sets up the environment to include the path to - // |path_to_add|. - explicit ScopedPath(const base::FilePath& path_to_add); - - // Destructor that restores the path that were active when the - // object was constructed. - ~ScopedPath(); - - private: - // The PATH environment variable before it was changed or an empty - // string if there was no PATH environment variable. - std::string old_path_; - - // The helper object that allows us to read and set environment - // variables more easily. - scoped_ptr<base::Environment> environment_; - - // A flag saying if we have actually modified the environment. - bool path_modified_; - - DISALLOW_COPY_AND_ASSIGN(ScopedPath); -}; - -ScopedPath::ScopedPath(const base::FilePath& path_to_add) - : environment_(base::Environment::Create()), - path_modified_(false) { - environment_->GetVar("PATH", &old_path_); - - std::string new_value = old_path_; - if (!new_value.empty()) - new_value += ";"; - - new_value += base::WideToUTF8(path_to_add.value()); - - path_modified_ = environment_->SetVar("PATH", new_value); -} - -ScopedPath::~ScopedPath() { - if (!path_modified_) - return; - if (old_path_.empty()) - environment_->UnSetVar("PATH"); - else - environment_->SetVar("PATH", old_path_); -} - } // namespace namespace net { @@ -155,8 +101,9 @@ bool LocalTestServer::LaunchPython(const base::FilePath& testserver_path) { child_write_fd_.Set(child_write); // Have the child inherit the write half. - if (!SetHandleInformation(child_write, HANDLE_FLAG_INHERIT, - HANDLE_FLAG_INHERIT)) { + if (!::DuplicateHandle(::GetCurrentProcess(), child_write, + ::GetCurrentProcess(), &child_write, 0, TRUE, + DUPLICATE_SAME_ACCESS)) { PLOG(ERROR) << "Failed to enable pipe inheritance"; return false; } @@ -176,11 +123,14 @@ bool LocalTestServer::LaunchPython(const base::FilePath& testserver_path) { base::LaunchOptions launch_options; launch_options.inherit_handles = true; - if (!base::LaunchProcess(python_command, launch_options, &process_handle_)) { + process_ = base::LaunchProcess(python_command, launch_options); + if (!process_.IsValid()) { LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString(); + ::CloseHandle(child_write); return false; } + ::CloseHandle(child_write); return true; } diff --git a/chromium/net/test/spawned_test_server/remote_test_server.cc b/chromium/net/test/spawned_test_server/remote_test_server.cc index 6d098c8f49c..1d1481b9d16 100644 --- a/chromium/net/test/spawned_test_server/remote_test_server.cc +++ b/chromium/net/test/spawned_test_server/remote_test_server.cc @@ -95,6 +95,8 @@ bool RemoteTestServer::Start() { if (!GenerateArguments(&arguments_dict)) return false; + arguments_dict.Set("on-remote-server", base::Value::CreateNullValue()); + // Append the 'server-type' argument which is used by spawner server to // pass right server type to Python test server. arguments_dict.SetString("server-type", GetServerTypeString(type())); diff --git a/chromium/net/test/spawned_test_server/remote_test_server.h b/chromium/net/test/spawned_test_server/remote_test_server.h index de12e4ebe44..a8b8bb2c235 100644 --- a/chromium/net/test/spawned_test_server/remote_test_server.h +++ b/chromium/net/test/spawned_test_server/remote_test_server.h @@ -29,7 +29,7 @@ class RemoteTestServer : public BaseTestServer { const SSLOptions& ssl_options, const base::FilePath& document_root); - virtual ~RemoteTestServer(); + ~RemoteTestServer() override; // Starts the Python test server on the host, instead of on the device, and // blocks until the server is ready. diff --git a/chromium/net/test/spawned_test_server/spawner_communicator.cc b/chromium/net/test/spawned_test_server/spawner_communicator.cc index 53484ead585..d16e57a6cdb 100644 --- a/chromium/net/test/spawned_test_server/spawner_communicator.cc +++ b/chromium/net/test/spawned_test_server/spawner_communicator.cc @@ -47,7 +47,7 @@ class SpawnerRequestData : public base::SupportsUserData::Data { data_received_->clear(); } - virtual ~SpawnerRequestData() {} + ~SpawnerRequestData() override {} bool DoesRequestIdMatch(int request_id) const { return request_id_ == request_id; @@ -173,7 +173,7 @@ void SpawnerCommunicator::SendCommandAndWaitForResultOnIOThread( DCHECK(!cur_request_.get()); context_.reset(new TestURLRequestContext); cur_request_ = context_->CreateRequest( - GenerateSpawnerCommandURL(command, port_), DEFAULT_PRIORITY, this, NULL); + GenerateSpawnerCommandURL(command, port_), DEFAULT_PRIORITY, this); DCHECK(cur_request_); int current_request_id = ++next_id_; SpawnerRequestData* data = new SpawnerRequestData(current_request_id, diff --git a/chromium/net/test/spawned_test_server/spawner_communicator.h b/chromium/net/test/spawned_test_server/spawner_communicator.h index 549ad9158c5..15ae0c5e1c3 100644 --- a/chromium/net/test/spawned_test_server/spawner_communicator.h +++ b/chromium/net/test/spawned_test_server/spawner_communicator.h @@ -29,7 +29,7 @@ class ScopedPortException; // themselves continue running on the device. To control the test server on the // host machine, a second HTTP server is started, the spawner server, which // controls the life cycle of remote test servers. Calls to start/kill the -// net::SpawnedTestServer are then redirected to the spawner server via +// SpawnedTestServer are then redirected to the spawner server via // this spawner communicator. // // Currently only three commands are supported by spawner. @@ -58,10 +58,10 @@ class ScopedPortException; // The internal I/O thread is required by net stack to perform net I/O. // The Start/StopServer methods block the caller thread until result is // fetched from spawner server or timed-out. -class SpawnerCommunicator : public net::URLRequest::Delegate { +class SpawnerCommunicator : public URLRequest::Delegate { public: explicit SpawnerCommunicator(uint16 port); - virtual ~SpawnerCommunicator(); + ~SpawnerCommunicator() override; // Starts an instance of the Python test server on the host/ machine. // If successfully started, returns true, setting |*port| to the port @@ -100,8 +100,8 @@ class SpawnerCommunicator : public net::URLRequest::Delegate { std::string* data_received); // URLRequest::Delegate methods. Called on the IO thread. - virtual void OnResponseStarted(URLRequest* request) override; - virtual void OnReadCompleted(URLRequest* request, int num_bytes) override; + void OnResponseStarted(URLRequest* request) override; + void OnReadCompleted(URLRequest* request, int num_bytes) override; // Reads Result from the response. Called on the IO thread. void ReadResult(URLRequest* request); diff --git a/chromium/net/test/test_certificate_data.h b/chromium/net/test/test_certificate_data.h index 3ccda5e34cb..b5346b4d9d1 100644 --- a/chromium/net/test/test_certificate_data.h +++ b/chromium/net/test/test_certificate_data.h @@ -9,22 +9,26 @@ static const char kNistSPKIHash[] = "\x15\x60\xde\x65\x4e\x03\x9f\xd0\x08\x82" "\xa9\x6a\xc4\x65\x8e\x6f\x92\x06\x84\x35"; -// kSatvedaSPKIs contains the SHA1 hashes of the SPKIs of the satveda.pem +// kTwitterSPKIs contains the SHA1 hashes of the SPKIs of the twitter-chain.pem // certificate chain, in order. -static const char kSatvedaSPKIs[2][21] = { - "\xd6\x2d\x7a\x12\x02\x7f\x9b\x8e\x4f\x2b" - "\x07\xc5\xfb\xf9\x2a\x2e\x9a\xcc\x0e\xe3", - "\xba\x2e\xb5\xa8\x3e\x13\x23\xd9\x53\x4b" - "\x5e\x65\xbc\xe7\xa3\x13\x5d\xd0\xa9\x96", +static const char kTwitterSPKIs[3][21] = { + "\x26\x9a\x19\xa3\x88\x28\xc1\xdd\x70\x1b" + "\xa0\xca\x2c\x98\xdb\xc6\xe1\x4f\x37\x3e", + "\x47\x49\xdf\x16\x57\xf4\x6c\x8b\xd2\x8c" + "\x79\x1b\x99\xfb\x9f\x28\x81\x2a\x60\xe0", + "\xb1\x81\x08\x1a\x19\xa4\xc0\x94\x1f\xfa" + "\xe8\x95\x28\xc1\x24\xc9\x9b\x34\xac\xc7", }; -// kSatvedaSPKIsSHA256 contains the SHA256 hashes of the SPKIs of the -// satveda.pem certificate chain, in order. -static const char kSatvedaSPKIsSHA256[2][33] = { - "\xb9\x42\xab\xf2\x08\x63\xef\x81\x70\x88\x45\xc4\x39\xa2\x6e\x9c" - "\x2f\x9a\xf9\xf4\xcb\x23\x61\xd4\x83\x97\x61\x6d\xf2\x5b\x27\xa8", - "\x32\xb6\x4b\x66\x72\x7a\x20\x63\xe4\x06\x6f\x3b\x95\x8c\xb0\xaa" - "\xee\x57\x6a\x5e\xce\xfd\x95\x33\x99\xbb\x88\x74\x73\x1d\x95\x87", +// kTwitterSPKIsSHA256 contains the SHA256 hashes of the SPKIs of the +// twitter-chain.pem certificate chain, in order. +static const char kTwitterSPKIsSHA256[3][33] = { + "\x20\xec\x5d\x0a\xfb\xc6\xc0\xe2\xe1\x95\x56\xc5\x35\x2b\x3c\x60" + "\x78\xa6\xed\x95\x55\xc2\xfa\x86\x82\x40\x4f\xdb\x55\x29\xd3\xad", + "\x80\xcc\x56\x3a\xb5\xf8\x3c\xc4\x1e\xb0\xaf\x6a\x14\xd6\xd8\x07" + "\x18\xc1\x7e\x35\x2f\x96\x49\xff\xbc\xdd\x67\xf8\xbf\x65\x13\x91", + "\x25\xb4\x1b\x50\x6e\x49\x30\x95\x28\x23\xa6\xeb\x9f\x1d\x31\xde" + "\xf6\x45\xea\x38\xa5\xc6\xc6\xa9\x6d\x71\x95\x7e\x38\x4d\xf0\x58", }; // Certificates for test data. They're obtained with: diff --git a/chromium/net/test/url_request/url_request_failed_job.cc b/chromium/net/test/url_request/url_request_failed_job.cc index c13c3c8c443..ce7ecb332e7 100644 --- a/chromium/net/test/url_request/url_request_failed_job.cc +++ b/chromium/net/test/url_request/url_request_failed_job.cc @@ -6,53 +6,140 @@ #include "base/bind.h" #include "base/logging.h" +#include "base/macros.h" #include "base/message_loop/message_loop.h" #include "base/strings/string_number_conversions.h" #include "net/base/net_errors.h" +#include "net/base/url_util.h" +#include "net/http/http_response_headers.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_filter.h" +#include "net/url_request/url_request_interceptor.h" namespace net { + namespace { const char kMockHostname[] = "mock.failed.request"; -// Gets the numeric net error code from URL of the form: -// scheme://kMockHostname/error_code. The error code must be a valid -// net error code, and not net::OK or net::ERR_IO_PENDING. -int GetErrorCode(net::URLRequest* request) { - int net_error; - std::string path = request->url().path(); - if (path[0] == '/' && base::StringToInt(path.c_str() + 1, &net_error)) { - CHECK_LT(net_error, 0); - CHECK_NE(net_error, net::ERR_IO_PENDING); - return net_error; +// String names of failure phases matching FailurePhase enum. +const char* kFailurePhase[]{ + "start", // START + "readsync", // READ_SYNC + "readasync", // READ_ASYNC +}; + +static_assert(arraysize(kFailurePhase) == + URLRequestFailedJob::FailurePhase::MAX_FAILURE_PHASE, + "kFailurePhase must match FailurePhase enum"); + +class MockJobInterceptor : public URLRequestInterceptor { + public: + MockJobInterceptor() {} + ~MockJobInterceptor() override {} + + // URLRequestJobFactory::ProtocolHandler implementation: + URLRequestJob* MaybeInterceptRequest( + URLRequest* request, + NetworkDelegate* network_delegate) const override { + int net_error = OK; + URLRequestFailedJob::FailurePhase phase = + URLRequestFailedJob::FailurePhase::MAX_FAILURE_PHASE; + for (size_t i = 0; i < arraysize(kFailurePhase); i++) { + std::string phase_error_string; + if (GetValueForKeyInQuery(request->url(), kFailurePhase[i], + &phase_error_string)) { + if (base::StringToInt(phase_error_string, &net_error)) { + phase = static_cast<URLRequestFailedJob::FailurePhase>(i); + break; + } + } + } + return new URLRequestFailedJob(request, network_delegate, phase, net_error); } - NOTREACHED(); - return net::ERR_UNEXPECTED; -} + + private: + DISALLOW_COPY_AND_ASSIGN(MockJobInterceptor); +}; GURL GetMockUrl(const std::string& scheme, const std::string& hostname, + URLRequestFailedJob::FailurePhase phase, int net_error) { - CHECK_LT(net_error, 0); - CHECK_NE(net_error, net::ERR_IO_PENDING); - return GURL(scheme + "://" + hostname + "/" + base::IntToString(net_error)); + CHECK_GE(phase, URLRequestFailedJob::FailurePhase::START); + CHECK_LE(phase, URLRequestFailedJob::FailurePhase::READ_ASYNC); + CHECK_LT(net_error, OK); + return GURL(scheme + "://" + hostname + "/error?" + kFailurePhase[phase] + + "=" + base::IntToString(net_error)); } } // namespace -URLRequestFailedJob::URLRequestFailedJob(net::URLRequest* request, - net::NetworkDelegate* network_delegate, +URLRequestFailedJob::URLRequestFailedJob(URLRequest* request, + NetworkDelegate* network_delegate, + FailurePhase phase, int net_error) - : net::URLRequestJob(request, network_delegate), + : URLRequestJob(request, network_delegate), + phase_(phase), net_error_(net_error), - weak_factory_(this) {} + weak_factory_(this) { + CHECK_GE(phase, URLRequestFailedJob::FailurePhase::START); + CHECK_LE(phase, URLRequestFailedJob::FailurePhase::READ_ASYNC); + CHECK_LT(net_error, OK); +} + +URLRequestFailedJob::URLRequestFailedJob(URLRequest* request, + NetworkDelegate* network_delegate, + int net_error) + : URLRequestFailedJob(request, network_delegate, START, net_error) { +} void URLRequestFailedJob::Start() { - base::MessageLoop::current()->PostTask( + if (phase_ == START) { + if (net_error_ != ERR_IO_PENDING) { + NotifyStartError(URLRequestStatus(URLRequestStatus::FAILED, net_error_)); + return; + } + SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); + return; + } + response_info_.headers = new net::HttpResponseHeaders("HTTP/1.1 200 OK"); + NotifyHeadersComplete(); +} + +bool URLRequestFailedJob::ReadRawData(IOBuffer* buf, + int buf_size, + int* bytes_read) { + CHECK(phase_ == READ_SYNC || phase_ == READ_ASYNC); + if (net_error_ != ERR_IO_PENDING && phase_ == READ_SYNC) { + NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, net_error_)); + return false; + } + + SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); + + if (net_error_ == ERR_IO_PENDING) + return false; + + DCHECK_EQ(READ_ASYNC, phase_); + DCHECK_NE(ERR_IO_PENDING, net_error_); + + base::MessageLoopProxy::current()->PostTask( FROM_HERE, - base::Bind(&URLRequestFailedJob::StartAsync, weak_factory_.GetWeakPtr())); + base::Bind(&URLRequestFailedJob::NotifyDone, weak_factory_.GetWeakPtr(), + URLRequestStatus(URLRequestStatus::FAILED, net_error_))); + return false; +} + +int URLRequestFailedJob::GetResponseCode() const { + // If we have headers, get the response code from them. + if (response_info_.headers) + return response_info_.headers->response_code(); + return URLRequestJob::GetResponseCode(); +} + +void URLRequestFailedJob::GetResponseInfo(HttpResponseInfo* info) { + *info = response_info_; } // static @@ -63,10 +150,14 @@ void URLRequestFailedJob::AddUrlHandler() { // static void URLRequestFailedJob::AddUrlHandlerForHostname( const std::string& hostname) { - // Add |hostname| to net::URLRequestFilter for HTTP and HTTPS. - net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); - filter->AddHostnameHandler("http", hostname, URLRequestFailedJob::Factory); - filter->AddHostnameHandler("https", hostname, URLRequestFailedJob::Factory); + URLRequestFilter* filter = URLRequestFilter::GetInstance(); + // Add |hostname| to URLRequestFilter for HTTP and HTTPS. + filter->AddHostnameInterceptor( + "http", hostname, + scoped_ptr<URLRequestInterceptor>(new MockJobInterceptor())); + filter->AddHostnameInterceptor( + "https", hostname, + scoped_ptr<URLRequestInterceptor>(new MockJobInterceptor())); } // static @@ -80,31 +171,26 @@ GURL URLRequestFailedJob::GetMockHttpsUrl(int net_error) { } // static -GURL URLRequestFailedJob::GetMockHttpUrlForHostname( - int net_error, const std::string& hostname) { - return GetMockUrl("http", hostname, net_error); +GURL URLRequestFailedJob::GetMockHttpUrlWithFailurePhase(FailurePhase phase, + int net_error) { + return GetMockUrl("http", kMockHostname, phase, net_error); } // static -GURL URLRequestFailedJob::GetMockHttpsUrlForHostname( - int net_error, const std::string& hostname) { - return GetMockUrl("https", hostname, net_error); +GURL URLRequestFailedJob::GetMockHttpUrlForHostname( + int net_error, + const std::string& hostname) { + return GetMockUrl("http", hostname, START, net_error); } -URLRequestFailedJob::~URLRequestFailedJob() {} - // static -net::URLRequestJob* URLRequestFailedJob::Factory( - net::URLRequest* request, - net::NetworkDelegate* network_delegate, - const std::string& scheme) { - return new URLRequestFailedJob( - request, network_delegate, GetErrorCode(request)); +GURL URLRequestFailedJob::GetMockHttpsUrlForHostname( + int net_error, + const std::string& hostname) { + return GetMockUrl("https", hostname, START, net_error); } -void URLRequestFailedJob::StartAsync() { - NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED, - net_error_)); +URLRequestFailedJob::~URLRequestFailedJob() { } } // namespace net diff --git a/chromium/net/test/url_request/url_request_failed_job.h b/chromium/net/test/url_request/url_request_failed_job.h index 4307f91b80b..0413111c87c 100644 --- a/chromium/net/test/url_request/url_request_failed_job.h +++ b/chromium/net/test/url_request/url_request_failed_job.h @@ -14,28 +14,56 @@ namespace net { -// This class simulates a URLRequestJob failing with a given error code while -// trying to connect. +// This class simulates a URLRequestJob failing with a given error code at +// a particular phase while trying to connect. class URLRequestFailedJob : public URLRequestJob { public: + // A Java counterpart will be generated for this enum. + // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net.test + enum FailurePhase { + START = 0, + READ_SYNC = 1, + READ_ASYNC = 2, + MAX_FAILURE_PHASE = 3, + }; + + URLRequestFailedJob(URLRequest* request, + NetworkDelegate* network_delegate, + FailurePhase phase, + int net_error); + + // Same as above, except that the job fails at FailurePhase.START. URLRequestFailedJob(URLRequest* request, NetworkDelegate* network_delegate, int net_error); + // URLRequestJob implementation: void Start() override; + bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override; + int GetResponseCode() const override; + void GetResponseInfo(HttpResponseInfo* info) override; // Adds the testing URLs to the URLRequestFilter. static void AddUrlHandler(); static void AddUrlHandlerForHostname(const std::string& hostname); // Given a net error code, constructs a mock URL that will return that error - // asynchronously when started. |net_error| must be a valid net error code - // other than net::OK and net::ERR_IO_PENDING. + // asynchronously when started. |net_error| must be a valid net error code + // other than net::OK. Passing net::ERR_IO_PENDING for |net_error| causes the + // resulting request to hang. static GURL GetMockHttpUrl(int net_error); static GURL GetMockHttpsUrl(int net_error); - // URLRequestFailedJob must be added as a handler for |hostname| for - // the returned URL to return |net_error|. + // Constructs a mock URL that reports |net_error| at given |phase| of the + // request. |net_error| must be a valid net error code other than net::OK. + // Passing net::ERR_IO_PENDING for |net_error| causes the resulting request to + // hang. + static GURL GetMockHttpUrlWithFailurePhase(FailurePhase phase, int net_error); + + // Given a net error code and a host name, constructs a mock URL that will + // return that error asynchronously when started. |net_error| must be a valid + // net error code other than net::OK. Passing net::ERR_IO_PENDING for + // |net_error| causes the resulting request to hang. static GURL GetMockHttpUrlForHostname(int net_error, const std::string& hostname); static GURL GetMockHttpsUrlForHostname(int net_error, @@ -45,13 +73,8 @@ class URLRequestFailedJob : public URLRequestJob { ~URLRequestFailedJob() override; private: - static URLRequestJob* Factory(URLRequest* request, - NetworkDelegate* network_delegate, - const std::string& scheme); - - // Simulate a failure. - void StartAsync(); - + HttpResponseInfo response_info_; + const FailurePhase phase_; const int net_error_; base::WeakPtrFactory<URLRequestFailedJob> weak_factory_; diff --git a/chromium/net/test/url_request/url_request_mock_data_job.cc b/chromium/net/test/url_request/url_request_mock_data_job.cc new file mode 100644 index 00000000000..5425816bb05 --- /dev/null +++ b/chromium/net/test/url_request/url_request_mock_data_job.cc @@ -0,0 +1,193 @@ +// Copyright 2014 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 "net/test/url_request/url_request_mock_data_job.h" + +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" +#include "net/base/io_buffer.h" +#include "net/base/url_util.h" +#include "net/http/http_request_headers.h" +#include "net/http/http_response_headers.h" +#include "net/http/http_util.h" +#include "net/url_request/url_request_filter.h" + +namespace net { +namespace { + +const char kMockHostname[] = "mock.data"; + +// Gets the data from URL of the form: +// scheme://kMockHostname/?data=abc&repeat_count=nnn. +std::string GetDataFromRequest(const URLRequest& request) { + std::string value; + if (!GetValueForKeyInQuery(request.url(), "data", &value)) + return "default_data"; + return value; +} + +// Gets the numeric repeat count from URL of the form: +// scheme://kMockHostname/?data=abc&repeat_count=nnn. +int GetRepeatCountFromRequest(const URLRequest& request) { + std::string value; + if (!GetValueForKeyInQuery(request.url(), "repeat", &value)) + return 1; + + int repeat_count; + if (!base::StringToInt(value, &repeat_count)) + return 1; + + DCHECK_GT(repeat_count, 0); + + return repeat_count; +} + +GURL GetMockUrl(const std::string& scheme, + const std::string& hostname, + const std::string& data, + int data_repeat_count) { + DCHECK_GT(data_repeat_count, 0); + std::string url(scheme + "://" + hostname + "/"); + url.append("?data="); + url.append(data); + url.append("&repeat="); + url.append(base::IntToString(data_repeat_count)); + return GURL(url); +} + +class MockJobInterceptor : public URLRequestInterceptor { + public: + MockJobInterceptor() {} + ~MockJobInterceptor() override {} + + // URLRequestInterceptor implementation + URLRequestJob* MaybeInterceptRequest( + URLRequest* request, + NetworkDelegate* network_delegate) const override { + return new URLRequestMockDataJob(request, network_delegate, + GetDataFromRequest(*request), + GetRepeatCountFromRequest(*request)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MockJobInterceptor); +}; + +} // namespace + +URLRequestMockDataJob::URLRequestMockDataJob(URLRequest* request, + NetworkDelegate* network_delegate, + const std::string& data, + int data_repeat_count) + : URLRequestJob(request, network_delegate), + data_offset_(0), + weak_factory_(this) { + DCHECK_GT(data_repeat_count, 0); + for (int i = 0; i < data_repeat_count; ++i) { + data_.append(data); + } +} + +void URLRequestMockDataJob::Start() { + // Start reading asynchronously so that all error reporting and data + // callbacks happen as they would for network requests. + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(&URLRequestMockDataJob::StartAsync, + weak_factory_.GetWeakPtr())); +} + +URLRequestMockDataJob::~URLRequestMockDataJob() { +} + +bool URLRequestMockDataJob::ReadRawData(IOBuffer* buf, + int buf_size, + int* bytes_read) { + DCHECK(bytes_read); + *bytes_read = static_cast<int>( + std::min(static_cast<size_t>(buf_size), data_.length() - data_offset_)); + memcpy(buf->data(), data_.c_str() + data_offset_, *bytes_read); + data_offset_ += *bytes_read; + return true; +} + +int URLRequestMockDataJob::GetResponseCode() const { + HttpResponseInfo info; + GetResponseInfoConst(&info); + return info.headers->response_code(); +} + +// Public virtual version. +void URLRequestMockDataJob::GetResponseInfo(HttpResponseInfo* info) { + // Forward to private const version. + GetResponseInfoConst(info); +} + +// Private const version. +void URLRequestMockDataJob::GetResponseInfoConst(HttpResponseInfo* info) const { + // Send back mock headers. + std::string raw_headers; + raw_headers.append( + "HTTP/1.1 200 OK\n" + "Content-type: text/plain\n"); + raw_headers.append(base::StringPrintf("Content-Length: %1d\n", + static_cast<int>(data_.length()))); + info->headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders( + raw_headers.c_str(), static_cast<int>(raw_headers.length()))); +} + +void URLRequestMockDataJob::StartAsync() { + if (!request_) + return; + + set_expected_content_size(data_.length()); + NotifyHeadersComplete(); +} + +// static +void URLRequestMockDataJob::AddUrlHandler() { + return AddUrlHandlerForHostname(kMockHostname); +} + +// static +void URLRequestMockDataJob::AddUrlHandlerForHostname( + const std::string& hostname) { + // Add |hostname| to URLRequestFilter for HTTP and HTTPS. + URLRequestFilter* filter = URLRequestFilter::GetInstance(); + filter->AddHostnameInterceptor("http", hostname, + make_scoped_ptr(new MockJobInterceptor())); + filter->AddHostnameInterceptor("https", hostname, + make_scoped_ptr(new MockJobInterceptor())); +} + +// static +GURL URLRequestMockDataJob::GetMockHttpUrl(const std::string& data, + int repeat_count) { + return GetMockHttpUrlForHostname(kMockHostname, data, repeat_count); +} + +// static +GURL URLRequestMockDataJob::GetMockHttpsUrl(const std::string& data, + int repeat_count) { + return GetMockHttpsUrlForHostname(kMockHostname, data, repeat_count); +} + +// static +GURL URLRequestMockDataJob::GetMockHttpUrlForHostname( + const std::string& hostname, + const std::string& data, + int repeat_count) { + return GetMockUrl("http", hostname, data, repeat_count); +} + +// static +GURL URLRequestMockDataJob::GetMockHttpsUrlForHostname( + const std::string& hostname, + const std::string& data, + int repeat_count) { + return GetMockUrl("https", hostname, data, repeat_count); +} + +} // namespace net diff --git a/chromium/net/test/url_request/url_request_mock_data_job.h b/chromium/net/test/url_request/url_request_mock_data_job.h new file mode 100644 index 00000000000..3d84e371c35 --- /dev/null +++ b/chromium/net/test/url_request/url_request_mock_data_job.h @@ -0,0 +1,63 @@ +// Copyright 2014 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. + +#ifndef NET_URL_REQUEST_URL_REQUEST_MOCK_DATA_JOB_H_ +#define NET_URL_REQUEST_URL_REQUEST_MOCK_DATA_JOB_H_ + +#include <string> + +#include "base/memory/weak_ptr.h" +#include "net/base/net_export.h" +#include "net/url_request/url_request_job.h" + +namespace net { + +class URLRequest; + +// Mock data job, which synchronously returns data repeated multiple times. +class URLRequestMockDataJob : public URLRequestJob { + public: + URLRequestMockDataJob(URLRequest* request, + NetworkDelegate* network_delegate, + const std::string& data, + int data_repeat_count); + + void Start() override; + bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override; + int GetResponseCode() const override; + void GetResponseInfo(HttpResponseInfo* info) override; + + // Adds the testing URLs to the URLRequestFilter. + static void AddUrlHandler(); + static void AddUrlHandlerForHostname(const std::string& hostname); + + // Given data and repeat cound, constructs a mock URL that will return that + // data repeated |repeat_count| times when started. |data| must be safe for + // URL. + static GURL GetMockHttpUrl(const std::string& data, int repeat_count); + static GURL GetMockHttpsUrl(const std::string& data, int repeat_count); + + // URLRequestFailedJob must be added as a handler for |hostname| for + // the returned URL to return |net_error|. + static GURL GetMockHttpUrlForHostname(const std::string& hostname, + const std::string& data, + int repeat_count); + static GURL GetMockHttpsUrlForHostname(const std::string& hostname, + const std::string& data, + int repeat_count); + + private: + void GetResponseInfoConst(HttpResponseInfo* info) const; + ~URLRequestMockDataJob() override; + + void StartAsync(); + + std::string data_; + size_t data_offset_; + base::WeakPtrFactory<URLRequestMockDataJob> weak_factory_; +}; + +} // namespace net + +#endif // NET_URL_REQUEST_URL_REQUEST_SIMPLE_JOB_H_ diff --git a/chromium/net/test/url_request/url_request_mock_http_job.cc b/chromium/net/test/url_request/url_request_mock_http_job.cc index ede87cfeabd..b7b4cdbf619 100644 --- a/chromium/net/test/url_request/url_request_mock_http_job.cc +++ b/chromium/net/test/url_request/url_request_mock_http_job.cc @@ -28,14 +28,7 @@ const char kMockHostname[] = "mock.http"; const base::FilePath::CharType kMockHeaderFileSuffix[] = FILE_PATH_LITERAL(".mock-http-headers"); -// String names of failure phases matching FailurePhase enum. -const char* kFailurePhase[] { - "start", // START - "readasync", // READ_ASYNC - "readsync", // READ_SYNC -}; - -class MockJobInterceptor : public net::URLRequestInterceptor { +class MockJobInterceptor : public URLRequestInterceptor { public: // When |map_all_requests_to_base_path| is true, all request should return the // contents of the file at |base_path|. When |map_all_requests_to_base_path| @@ -50,10 +43,10 @@ class MockJobInterceptor : public net::URLRequestInterceptor { worker_pool_(worker_pool) {} ~MockJobInterceptor() override {} - // net::URLRequestJobFactory::ProtocolHandler implementation - net::URLRequestJob* MaybeInterceptRequest( - net::URLRequest* request, - net::NetworkDelegate* network_delegate) const override { + // URLRequestJobFactory::ProtocolHandler implementation + URLRequestJob* MaybeInterceptRequest( + URLRequest* request, + NetworkDelegate* network_delegate) const override { return new URLRequestMockHTTPJob( request, network_delegate, @@ -63,15 +56,15 @@ class MockJobInterceptor : public net::URLRequestInterceptor { } private: - base::FilePath GetOnDiskPath(net::URLRequest* request) const { + base::FilePath GetOnDiskPath(URLRequest* request) const { // Conceptually we just want to "return base_path_ + request->url().path()". // But path in the request URL is in URL space (i.e. %-encoded spaces). // So first we convert base FilePath to a URL, then append the URL // path to that, and convert the final URL back to a FilePath. - GURL file_url(net::FilePathToFileURL(base_path_)); + GURL file_url(FilePathToFileURL(base_path_)); std::string url = file_url.spec() + request->url().path(); base::FilePath file_path; - net::FileURLToFilePath(GURL(url), &file_path); + FileURLToFilePath(GURL(url), &file_path); return file_path; } @@ -96,78 +89,64 @@ std::string DoFileIO(const base::FilePath& file_path) { return raw_headers; } +// For a given file |path| and |scheme|, return the URL served by the +// URlRequestMockHTTPJob. +GURL GetMockUrlForScheme(const base::FilePath& path, + const std::string& scheme) { + std::string url = scheme + "://" + kMockHostname + "/"; + std::string path_str = path.MaybeAsASCII(); + DCHECK(!path_str.empty()); // We only expect ASCII paths in tests. + url.append(path_str); + return GURL(url); +} + } // namespace // static -void URLRequestMockHTTPJob::AddUrlHandler( +void URLRequestMockHTTPJob::AddUrlHandlers( const base::FilePath& base_path, const scoped_refptr<base::SequencedWorkerPool>& worker_pool) { - // Add kMockHostname to net::URLRequestFilter. - net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); + // Add kMockHostname to URLRequestFilter, for both HTTP and HTTPS. + URLRequestFilter* filter = URLRequestFilter::GetInstance(); filter->AddHostnameInterceptor( "http", kMockHostname, CreateInterceptor(base_path, worker_pool)); -} - -// static -void URLRequestMockHTTPJob::AddHostnameToFileHandler( - const std::string& hostname, - const base::FilePath& file, - const scoped_refptr<base::SequencedWorkerPool>& worker_pool) { - net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); - filter->AddHostnameInterceptor( - "http", hostname, CreateInterceptorForSingleFile(file, worker_pool)); + filter->AddHostnameInterceptor("https", kMockHostname, + CreateInterceptor(base_path, worker_pool)); } // static GURL URLRequestMockHTTPJob::GetMockUrl(const base::FilePath& path) { - std::string url = "http://"; - url.append(kMockHostname); - url.append("/"); - std::string path_str = path.MaybeAsASCII(); - DCHECK(!path_str.empty()); // We only expect ASCII paths in tests. - url.append(path_str); - return GURL(url); + return GetMockUrlForScheme(path, "http"); } // static -GURL URLRequestMockHTTPJob::GetMockUrlWithFailure(const base::FilePath& path, - FailurePhase phase, - int net_error) { - COMPILE_ASSERT(arraysize(kFailurePhase) == MAX_FAILURE_PHASE, - kFailurePhase_must_match_FailurePhase_enum); - DCHECK_GE(phase, START); - DCHECK_LE(phase, READ_SYNC); - std::string url(GetMockUrl(path).spec()); - url.append("?"); - url.append(kFailurePhase[phase]); - url.append("="); - url.append(base::IntToString(net_error)); - return GURL(url); +GURL URLRequestMockHTTPJob::GetMockHttpsUrl(const base::FilePath& path) { + return GetMockUrlForScheme(path, "https"); } // static -scoped_ptr<net::URLRequestInterceptor> URLRequestMockHTTPJob::CreateInterceptor( +scoped_ptr<URLRequestInterceptor> URLRequestMockHTTPJob::CreateInterceptor( const base::FilePath& base_path, const scoped_refptr<base::SequencedWorkerPool>& worker_pool) { - return scoped_ptr<net::URLRequestInterceptor>( + return scoped_ptr<URLRequestInterceptor>( new MockJobInterceptor(base_path, false, worker_pool)); } // static -scoped_ptr<net::URLRequestInterceptor> +scoped_ptr<URLRequestInterceptor> URLRequestMockHTTPJob::CreateInterceptorForSingleFile( const base::FilePath& file, const scoped_refptr<base::SequencedWorkerPool>& worker_pool) { - return scoped_ptr<net::URLRequestInterceptor>( + return scoped_ptr<URLRequestInterceptor>( new MockJobInterceptor(file, true, worker_pool)); } URLRequestMockHTTPJob::URLRequestMockHTTPJob( - net::URLRequest* request, - net::NetworkDelegate* network_delegate, + URLRequest* request, + NetworkDelegate* network_delegate, const base::FilePath& file_path, const scoped_refptr<base::TaskRunner>& task_runner) - : net::URLRequestFileJob(request, network_delegate, file_path, task_runner), + : URLRequestFileJob(request, network_delegate, file_path, task_runner), task_runner_(task_runner), weak_ptr_factory_(this) { } @@ -176,22 +155,20 @@ URLRequestMockHTTPJob::~URLRequestMockHTTPJob() { } // Public virtual version. -void URLRequestMockHTTPJob::GetResponseInfo(net::HttpResponseInfo* info) { +void URLRequestMockHTTPJob::GetResponseInfo(HttpResponseInfo* info) { // Forward to private const version. GetResponseInfoConst(info); } bool URLRequestMockHTTPJob::IsRedirectResponse(GURL* location, int* http_status_code) { - // Override the net::URLRequestFileJob implementation to invoke the default + // Override the URLRequestFileJob implementation to invoke the default // one based on HttpResponseInfo. - return net::URLRequestJob::IsRedirectResponse(location, http_status_code); + return URLRequestJob::IsRedirectResponse(location, http_status_code); } // Public virtual version. void URLRequestMockHTTPJob::Start() { - if (MaybeReportErrorOnPhase(START)) - return; base::PostTaskAndReplyWithResult( task_runner_.get(), FROM_HERE, @@ -200,20 +177,7 @@ void URLRequestMockHTTPJob::Start() { weak_ptr_factory_.GetWeakPtr())); } -// Public virtual version. -bool URLRequestMockHTTPJob::ReadRawData(IOBuffer* buf, - int buf_size, - int* bytes_read) { - if (MaybeReportErrorOnPhase(READ_SYNC)) - return false; - if (MaybeReportErrorOnPhase(READ_ASYNC)) - return false; - return URLRequestFileJob::ReadRawData(buf, buf_size, bytes_read); -} - void URLRequestMockHTTPJob::SetHeadersAndStart(const std::string& raw_headers) { - if (MaybeReportErrorOnPhase(START)) - return; raw_headers_ = raw_headers; // Handle CRLF line-endings. ReplaceSubstringsAfterOffset(&raw_headers_, 0, "\r\n", "\n"); @@ -222,63 +186,28 @@ void URLRequestMockHTTPJob::SetHeadersAndStart(const std::string& raw_headers) { URLRequestFileJob::Start(); } -bool URLRequestMockHTTPJob::MaybeReportErrorOnPhase( - FailurePhase current_phase) { - DCHECK_GE(current_phase, START); - DCHECK_LE(current_phase, READ_SYNC); - std::string phase_key(kFailurePhase[current_phase]); - std::string phase_error_string; - if (!GetValueForKeyInQuery(request_->url(), phase_key, &phase_error_string)) - return false; - - int net_error; - if (!base::StringToInt(phase_error_string, &net_error)) - return false; - - if (net_error != net::ERR_IO_PENDING && - (current_phase == START || current_phase == READ_SYNC)) { - NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, net_error)); - return true; - } - - SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); - - if (current_phase != READ_ASYNC) - return true; - - base::MessageLoopProxy::current()->PostTask( - FROM_HERE, - base::Bind( - &URLRequestMockHTTPJob::NotifyDone, - weak_ptr_factory_.GetWeakPtr(), - net::URLRequestStatus(net::URLRequestStatus::FAILED, net_error))); - - return true; -} - // Private const version. -void URLRequestMockHTTPJob::GetResponseInfoConst( - net::HttpResponseInfo* info) const { - info->headers = new net::HttpResponseHeaders(raw_headers_); +void URLRequestMockHTTPJob::GetResponseInfoConst(HttpResponseInfo* info) const { + info->headers = new HttpResponseHeaders(raw_headers_); } bool URLRequestMockHTTPJob::GetMimeType(std::string* mime_type) const { - net::HttpResponseInfo info; + HttpResponseInfo info; GetResponseInfoConst(&info); return info.headers.get() && info.headers->GetMimeType(mime_type); } int URLRequestMockHTTPJob::GetResponseCode() const { - net::HttpResponseInfo info; + HttpResponseInfo info; GetResponseInfoConst(&info); // If we have headers, get the response code from them. if (info.headers.get()) return info.headers->response_code(); - return net::URLRequestJob::GetResponseCode(); + return URLRequestJob::GetResponseCode(); } bool URLRequestMockHTTPJob::GetCharset(std::string* charset) { - net::HttpResponseInfo info; + HttpResponseInfo info; GetResponseInfo(&info); return info.headers.get() && info.headers->GetCharset(charset); } diff --git a/chromium/net/test/url_request/url_request_mock_http_job.h b/chromium/net/test/url_request/url_request_mock_http_job.h index 6eb3c72b861..06c31009c8b 100644 --- a/chromium/net/test/url_request/url_request_mock_http_job.h +++ b/chromium/net/test/url_request/url_request_mock_http_job.h @@ -28,13 +28,6 @@ namespace net { class URLRequestMockHTTPJob : public URLRequestFileJob { public: - enum FailurePhase { - START = 0, - READ_ASYNC = 1, - READ_SYNC = 2, - MAX_FAILURE_PHASE = 3, - }; - // Note that all file IO is done using |worker_pool|. URLRequestMockHTTPJob(URLRequest* request, NetworkDelegate* network_delegate, @@ -42,35 +35,21 @@ class URLRequestMockHTTPJob : public URLRequestFileJob { const scoped_refptr<base::TaskRunner>& task_runner); void Start() override; - bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override; bool GetMimeType(std::string* mime_type) const override; int GetResponseCode() const override; bool GetCharset(std::string* charset) override; void GetResponseInfo(HttpResponseInfo* info) override; bool IsRedirectResponse(GURL* location, int* http_status_code) override; - // Adds the testing URLs to the URLRequestFilter. - static void AddUrlHandler( + // Adds the testing URLs to the URLRequestFilter, both under HTTP and HTTPS. + static void AddUrlHandlers( const base::FilePath& base_path, const scoped_refptr<base::SequencedWorkerPool>& worker_pool); - // Respond to all HTTP requests of |hostname| with contents of the file - // located at |file_path|. - static void AddHostnameToFileHandler( - const std::string& hostname, - const base::FilePath& file, - const scoped_refptr<base::SequencedWorkerPool>& worker_pool); - // Given the path to a file relative to the path passed to AddUrlHandler(), // construct a mock URL. static GURL GetMockUrl(const base::FilePath& path); - - // Given the path to a file relative to the path passed to AddUrlHandler(), - // construct a mock URL that reports |net_error| at given |phase| of the - // request. Reporting |net_error| ERR_IO_PENDING results in a hung request. - static GURL GetMockUrlWithFailure(const base::FilePath& path, - FailurePhase phase, - int net_error); + static GURL GetMockHttpsUrl(const base::FilePath& path); // Returns a URLRequestJobFactory::ProtocolHandler that serves // URLRequestMockHTTPJob's responding like an HTTP server. |base_path| is the @@ -93,11 +72,6 @@ class URLRequestMockHTTPJob : public URLRequestFileJob { private: void GetResponseInfoConst(HttpResponseInfo* info) const; void SetHeadersAndStart(const std::string& raw_headers); - // Checks query part of request url, and reports an error if it matches. - // Error is parsed out from the query and is reported synchronously. - // Reporting ERR_IO_PENDING results in a hung request. - // The "readasync" error is posted asynchronously. - bool MaybeReportErrorOnPhase(FailurePhase phase); std::string raw_headers_; const scoped_refptr<base::TaskRunner> task_runner_; diff --git a/chromium/net/test/url_request/url_request_slow_download_job.cc b/chromium/net/test/url_request/url_request_slow_download_job.cc new file mode 100644 index 00000000000..718a9f05502 --- /dev/null +++ b/chromium/net/test/url_request/url_request_slow_download_job.cc @@ -0,0 +1,265 @@ +// 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 "net/test/url_request/url_request_slow_download_job.h" + +#include "base/bind.h" +#include "base/compiler_specific.h" +#include "base/logging.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" +#include "net/http/http_response_headers.h" +#include "net/url_request/url_request.h" +#include "net/url_request/url_request_filter.h" +#include "url/gurl.h" + +namespace net { + +const char URLRequestSlowDownloadJob::kUnknownSizeUrl[] = + "http://url.handled.by.slow.download/download-unknown-size"; +const char URLRequestSlowDownloadJob::kKnownSizeUrl[] = + "http://url.handled.by.slow.download/download-known-size"; +const char URLRequestSlowDownloadJob::kFinishDownloadUrl[] = + "http://url.handled.by.slow.download/download-finish"; +const char URLRequestSlowDownloadJob::kErrorDownloadUrl[] = + "http://url.handled.by.slow.download/download-error"; + +const int URLRequestSlowDownloadJob::kFirstDownloadSize = 1024 * 35; +const int URLRequestSlowDownloadJob::kSecondDownloadSize = 1024 * 10; + +// static +base::LazyInstance<URLRequestSlowDownloadJob::SlowJobsSet>::Leaky + URLRequestSlowDownloadJob::pending_requests_ = LAZY_INSTANCE_INITIALIZER; + +void URLRequestSlowDownloadJob::Start() { + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(&URLRequestSlowDownloadJob::StartAsync, + weak_factory_.GetWeakPtr())); +} + +// static +void URLRequestSlowDownloadJob::AddUrlHandler() { + URLRequestFilter* filter = URLRequestFilter::GetInstance(); + filter->AddUrlHandler(GURL(kUnknownSizeUrl), + &URLRequestSlowDownloadJob::Factory); + filter->AddUrlHandler(GURL(kKnownSizeUrl), + &URLRequestSlowDownloadJob::Factory); + filter->AddUrlHandler(GURL(kFinishDownloadUrl), + &URLRequestSlowDownloadJob::Factory); + filter->AddUrlHandler(GURL(kErrorDownloadUrl), + &URLRequestSlowDownloadJob::Factory); +} + +// static +URLRequestJob* URLRequestSlowDownloadJob::Factory( + URLRequest* request, + NetworkDelegate* network_delegate, + const std::string& scheme) { + URLRequestSlowDownloadJob* job = + new URLRequestSlowDownloadJob(request, network_delegate); + if (request->url().spec() != kFinishDownloadUrl && + request->url().spec() != kErrorDownloadUrl) + pending_requests_.Get().insert(job); + return job; +} + +// static +size_t URLRequestSlowDownloadJob::NumberOutstandingRequests() { + return pending_requests_.Get().size(); +} + +// static +void URLRequestSlowDownloadJob::FinishPendingRequests() { + typedef std::set<URLRequestSlowDownloadJob*> JobList; + for (JobList::iterator it = pending_requests_.Get().begin(); + it != pending_requests_.Get().end(); ++it) { + (*it)->set_should_finish_download(); + } +} + +void URLRequestSlowDownloadJob::ErrorPendingRequests() { + typedef std::set<URLRequestSlowDownloadJob*> JobList; + for (JobList::iterator it = pending_requests_.Get().begin(); + it != pending_requests_.Get().end(); ++it) { + (*it)->set_should_error_download(); + } +} + +URLRequestSlowDownloadJob::URLRequestSlowDownloadJob( + URLRequest* request, + NetworkDelegate* network_delegate) + : URLRequestJob(request, network_delegate), + bytes_already_sent_(0), + should_error_download_(false), + should_finish_download_(false), + buffer_size_(0), + weak_factory_(this) { +} + +void URLRequestSlowDownloadJob::StartAsync() { + if (LowerCaseEqualsASCII(kFinishDownloadUrl, request_->url().spec().c_str())) + URLRequestSlowDownloadJob::FinishPendingRequests(); + if (LowerCaseEqualsASCII(kErrorDownloadUrl, request_->url().spec().c_str())) + URLRequestSlowDownloadJob::ErrorPendingRequests(); + + NotifyHeadersComplete(); +} + +// ReadRawData and CheckDoneStatus together implement a state +// machine. ReadRawData may be called arbitrarily by the network stack. +// It responds by: +// * If there are bytes remaining in the first chunk, they are +// returned. +// [No bytes remaining in first chunk. ] +// * If should_finish_download_ is not set, it returns IO_PENDING, +// and starts calling CheckDoneStatus on a regular timer. +// [should_finish_download_ set.] +// * If there are bytes remaining in the second chunk, they are filled. +// * Otherwise, return *bytes_read = 0 to indicate end of request. +// CheckDoneStatus is called on a regular basis, in the specific +// case where we have transmitted all of the first chunk and none of the +// second. If should_finish_download_ becomes set, it will "complete" +// the ReadRawData call that spawned off the CheckDoneStatus() repeated call. +// +// FillBufferHelper is a helper function that does the actual work of figuring +// out where in the state machine we are and how we should fill the buffer. +// It returns an enum indicating the state of the read. +URLRequestSlowDownloadJob::ReadStatus +URLRequestSlowDownloadJob::FillBufferHelper(IOBuffer* buf, + int buf_size, + int* bytes_written) { + if (bytes_already_sent_ < kFirstDownloadSize) { + int bytes_to_write = + std::min(kFirstDownloadSize - bytes_already_sent_, buf_size); + for (int i = 0; i < bytes_to_write; ++i) { + buf->data()[i] = '*'; + } + *bytes_written = bytes_to_write; + bytes_already_sent_ += bytes_to_write; + return BUFFER_FILLED; + } + + if (!should_finish_download_) + return REQUEST_BLOCKED; + + if (bytes_already_sent_ < kFirstDownloadSize + kSecondDownloadSize) { + int bytes_to_write = + std::min(kFirstDownloadSize + kSecondDownloadSize - bytes_already_sent_, + buf_size); + for (int i = 0; i < bytes_to_write; ++i) { + buf->data()[i] = '*'; + } + *bytes_written = bytes_to_write; + bytes_already_sent_ += bytes_to_write; + return BUFFER_FILLED; + } + + return REQUEST_COMPLETE; +} + +bool URLRequestSlowDownloadJob::ReadRawData(IOBuffer* buf, + int buf_size, + int* bytes_read) { + if (LowerCaseEqualsASCII(kFinishDownloadUrl, + request_->url().spec().c_str()) || + LowerCaseEqualsASCII(kErrorDownloadUrl, request_->url().spec().c_str())) { + VLOG(10) << __FUNCTION__ << " called w/ kFinish/ErrorDownloadUrl."; + *bytes_read = 0; + return true; + } + + VLOG(10) << __FUNCTION__ << " called at position " << bytes_already_sent_ + << " in the stream."; + ReadStatus status = FillBufferHelper(buf, buf_size, bytes_read); + switch (status) { + case BUFFER_FILLED: + return true; + case REQUEST_BLOCKED: + buffer_ = buf; + buffer_size_ = buf_size; + SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, base::Bind(&URLRequestSlowDownloadJob::CheckDoneStatus, + weak_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(100)); + return false; + case REQUEST_COMPLETE: + *bytes_read = 0; + return true; + } + NOTREACHED(); + return true; +} + +void URLRequestSlowDownloadJob::CheckDoneStatus() { + if (should_finish_download_) { + VLOG(10) << __FUNCTION__ << " called w/ should_finish_download_ set."; + DCHECK(NULL != buffer_.get()); + int bytes_written = 0; + ReadStatus status = + FillBufferHelper(buffer_.get(), buffer_size_, &bytes_written); + DCHECK_EQ(BUFFER_FILLED, status); + buffer_ = NULL; // Release the reference. + SetStatus(URLRequestStatus()); + NotifyReadComplete(bytes_written); + } else if (should_error_download_) { + VLOG(10) << __FUNCTION__ << " called w/ should_finish_ownload_ set."; + NotifyDone( + URLRequestStatus(URLRequestStatus::FAILED, ERR_CONNECTION_RESET)); + } else { + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, base::Bind(&URLRequestSlowDownloadJob::CheckDoneStatus, + weak_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(100)); + } +} + +// Public virtual version. +void URLRequestSlowDownloadJob::GetResponseInfo(HttpResponseInfo* info) { + // Forward to private const version. + GetResponseInfoConst(info); +} + +URLRequestSlowDownloadJob::~URLRequestSlowDownloadJob() { + pending_requests_.Get().erase(this); +} + +// Private const version. +void URLRequestSlowDownloadJob::GetResponseInfoConst( + HttpResponseInfo* info) const { + // Send back mock headers. + std::string raw_headers; + if (LowerCaseEqualsASCII(kFinishDownloadUrl, + request_->url().spec().c_str()) || + LowerCaseEqualsASCII(kErrorDownloadUrl, request_->url().spec().c_str())) { + raw_headers.append( + "HTTP/1.1 200 OK\n" + "Content-type: text/plain\n"); + } else { + raw_headers.append( + "HTTP/1.1 200 OK\n" + "Content-type: application/octet-stream\n" + "Cache-Control: max-age=0\n"); + + if (LowerCaseEqualsASCII(kKnownSizeUrl, request_->url().spec().c_str())) { + raw_headers.append(base::StringPrintf( + "Content-Length: %d\n", kFirstDownloadSize + kSecondDownloadSize)); + } + } + + // ParseRawHeaders expects \0 to end each header line. + ReplaceSubstringsAfterOffset(&raw_headers, 0, "\n", std::string("\0", 1)); + info->headers = new HttpResponseHeaders(raw_headers); +} + +bool URLRequestSlowDownloadJob::GetMimeType(std::string* mime_type) const { + HttpResponseInfo info; + GetResponseInfoConst(&info); + return info.headers.get() && info.headers->GetMimeType(mime_type); +} + +} // namespace net diff --git a/chromium/net/test/url_request/url_request_slow_download_job.h b/chromium/net/test/url_request/url_request_slow_download_job.h new file mode 100644 index 00000000000..a264a84abdf --- /dev/null +++ b/chromium/net/test/url_request/url_request_slow_download_job.h @@ -0,0 +1,99 @@ +// 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. +// This class simulates a slow download. Requests to |kUnknownSizeUrl| and +// |kKnownSizeUrl| start downloads that pause after the first N bytes, to be +// completed by sending a request to |kFinishDownloadUrl|. + +#ifndef NET_TEST_URL_REQUEST_URL_REQUEST_SLOW_DOWNLOAD_JOB_H_ +#define NET_TEST_URL_REQUEST_URL_REQUEST_SLOW_DOWNLOAD_JOB_H_ + +#include <set> +#include <string> + +#include "base/lazy_instance.h" +#include "base/memory/weak_ptr.h" +#include "net/url_request/url_request_job.h" + +namespace net { + +class URLRequestSlowDownloadJob : public URLRequestJob { + public: + // Test URLs. + static const char kUnknownSizeUrl[]; + static const char kKnownSizeUrl[]; + static const char kFinishDownloadUrl[]; + static const char kErrorDownloadUrl[]; + + // Download sizes. + static const int kFirstDownloadSize; + static const int kSecondDownloadSize; + + // Timer callback, used to check to see if we should finish our download and + // send the second chunk. + void CheckDoneStatus(); + + // URLRequestJob methods + void Start() override; + bool GetMimeType(std::string* mime_type) const override; + void GetResponseInfo(HttpResponseInfo* info) override; + bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override; + + static URLRequestJob* Factory(URLRequest* request, + NetworkDelegate* network_delegate, + const std::string& scheme); + + // Returns the current number of URLRequestSlowDownloadJobs that have + // not yet completed. + static size_t NumberOutstandingRequests(); + + // Adds the testing URLs to the URLRequestFilter. + static void AddUrlHandler(); + + private: + URLRequestSlowDownloadJob(URLRequest* request, + NetworkDelegate* network_delegate); + ~URLRequestSlowDownloadJob() override; + + // Enum indicating where we are in the read after a call to + // FillBufferHelper. + enum ReadStatus { + // The buffer was filled with data and may be returned. + BUFFER_FILLED, + + // No data was added to the buffer because kFinishDownloadUrl has + // not yet been seen and we've already returned the first chunk. + REQUEST_BLOCKED, + + // No data was added to the buffer because we've already returned + // all the data. + REQUEST_COMPLETE + }; + ReadStatus FillBufferHelper(IOBuffer* buf, int buf_size, int* bytes_written); + + void GetResponseInfoConst(HttpResponseInfo* info) const; + + // Mark all pending requests to be finished. We keep track of pending + // requests in |pending_requests_|. + static void FinishPendingRequests(); + static void ErrorPendingRequests(); + typedef std::set<URLRequestSlowDownloadJob*> SlowJobsSet; + static base::LazyInstance<SlowJobsSet>::Leaky pending_requests_; + + void StartAsync(); + + void set_should_finish_download() { should_finish_download_ = true; } + void set_should_error_download() { should_error_download_ = true; } + + int bytes_already_sent_; + bool should_error_download_; + bool should_finish_download_; + scoped_refptr<IOBuffer> buffer_; + int buffer_size_; + + base::WeakPtrFactory<URLRequestSlowDownloadJob> weak_factory_; +}; + +} // namespace content + +#endif // NET_TEST_URL_REQUEST_URL_REQUEST_SLOW_DOWNLOAD_JOB_H_ |