diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-20 10:33:36 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-11-22 11:45:12 +0000 |
commit | be59a35641616a4cf23c4a13fa0632624b021c1b (patch) | |
tree | 9da183258bdf9cc413f7562079d25ace6955467f /chromium/net/test | |
parent | d702e4b6a64574e97fc7df8fe3238cde70242080 (diff) | |
download | qtwebengine-chromium-be59a35641616a4cf23c4a13fa0632624b021c1b.tar.gz |
BASELINE: Update Chromium to 62.0.3202.101
Change-Id: I2d5eca8117600df6d331f6166ab24d943d9814ac
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/net/test')
38 files changed, 1195 insertions, 496 deletions
diff --git a/chromium/net/test/OWNERS b/chromium/net/test/OWNERS deleted file mode 100644 index 66d66900859..00000000000 --- a/chromium/net/test/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -# General reviewer, except sync-specific bits. -phajdan.jr@chromium.org diff --git a/chromium/net/test/android/javatests/src/org/chromium/net/test/IConnectionListener.aidl b/chromium/net/test/android/javatests/src/org/chromium/net/test/IConnectionListener.aidl new file mode 100644 index 00000000000..7725d71c902 --- /dev/null +++ b/chromium/net/test/android/javatests/src/org/chromium/net/test/IConnectionListener.aidl @@ -0,0 +1,21 @@ +// Copyright 2017 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. + +package org.chromium.net.test; + +interface IConnectionListener { + /** + * When a new connection has been accepted by the server. + * + * @param socketId Unique as long as the socket is alive. + */ + oneway void acceptedSocket(long socketId); + + /** + * When data has been read on a socket. + * + * @param socketId Unique as long as the socket is alive. + */ + oneway void readFromSocket(long socketId); +} diff --git a/chromium/net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerImpl.aidl b/chromium/net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerImpl.aidl index 366210a1c78..7a6e2031ef9 100644 --- a/chromium/net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerImpl.aidl +++ b/chromium/net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerImpl.aidl @@ -4,10 +4,12 @@ package org.chromium.net.test; +import org.chromium.net.test.IConnectionListener; + interface IEmbeddedTestServerImpl { /** Initialize the native object. */ - boolean initializeNative(); + boolean initializeNative(boolean https); /** Start the server. * @@ -15,6 +17,12 @@ interface IEmbeddedTestServerImpl { */ boolean start(); + /** Get the path of the server's root certificate. + * + * @return The pathname of a PEM file containing the server's root certificate. + */ + String getRootCertPemPath(); + /** Add the default handlers and serve files from the provided directory relative to the * external storage directory. * @@ -23,6 +31,12 @@ interface IEmbeddedTestServerImpl { */ void addDefaultHandlers(String directoryPath); + /** Configure the server to use a particular type of SSL certificate. + * + * @param serverCertificate The type of certificate the server should use. + */ + void setSSLConfig(int serverCertificate); + /** Serve files from the provided directory. * * @param directoryPath The path of the directory from which files should be served. @@ -45,5 +59,6 @@ interface IEmbeddedTestServerImpl { /** Destroy the native object. */ void destroy(); + /** Set a connection listener. Must be called before {@link start()}. */ + void setConnectionListener(IConnectionListener callback); } - diff --git a/chromium/net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerInterface.aidl b/chromium/net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerInterface.aidl index 9cb0488697e..f50efde192a 100644 --- a/chromium/net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerInterface.aidl +++ b/chromium/net/test/android/javatests/src/org/chromium/net/test/IEmbeddedTestServerInterface.aidl @@ -3,3 +3,4 @@ // found in the LICENSE file. interface org.chromium.net.test.IEmbeddedTestServerImpl; +interface org.chromium.net.test.IConnectionListener; diff --git a/chromium/net/test/android/net_test_entry_point.cc b/chromium/net/test/android/net_test_entry_point.cc index fa324cbcdd6..1c030af4500 100644 --- a/chromium/net/test/android/net_test_entry_point.cc +++ b/chromium/net/test/android/net_test_entry_point.cc @@ -8,9 +8,7 @@ // This is called by the VM when the shared library is first loaded. JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { base::android::InitVM(vm); - JNIEnv* env = base::android::AttachCurrentThread(); - if (!net::test::OnJNIOnLoadRegisterJNI(env) || - !net::test::OnJNIOnLoadInit()) { + if (!net::test::OnJNIOnLoadInit()) { return -1; } return JNI_VERSION_1_4; diff --git a/chromium/net/test/cert_test_util.cc b/chromium/net/test/cert_test_util.cc index 2c22d84f29e..e3150954bbd 100644 --- a/chromium/net/test/cert_test_util.cc +++ b/chromium/net/test/cert_test_util.cc @@ -79,10 +79,9 @@ scoped_refptr<X509Certificate> ImportCertFromFile( } ScopedTestEVPolicy::ScopedTestEVPolicy(EVRootCAMetadata* ev_root_ca_metadata, - const SHA1HashValue& fingerprint, + const SHA256HashValue& fingerprint, const char* policy) - : fingerprint_(fingerprint), - ev_root_ca_metadata_(ev_root_ca_metadata) { + : fingerprint_(fingerprint), ev_root_ca_metadata_(ev_root_ca_metadata) { EXPECT_TRUE(ev_root_ca_metadata->AddEVCA(fingerprint, policy)); } diff --git a/chromium/net/test/cert_test_util.h b/chromium/net/test/cert_test_util.h index f5b104b1225..d6870ed6be4 100644 --- a/chromium/net/test/cert_test_util.h +++ b/chromium/net/test/cert_test_util.h @@ -13,8 +13,12 @@ #include "testing/gtest/include/gtest/gtest.h" #if defined(USE_NSS_CERTS) +#include "net/cert/scoped_nss_types.h" + // From <pk11pub.h> typedef struct PK11SlotInfoStr PK11SlotInfo; + +#include "net/cert/scoped_nss_types.h" #endif namespace base { @@ -33,14 +37,32 @@ bool ImportSensitiveKeyFromFile(const base::FilePath& dir, const std::string& key_filename, PK11SlotInfo* slot); -bool ImportClientCertToSlot(const scoped_refptr<X509Certificate>& cert, - PK11SlotInfo* slot); +bool ImportClientCertToSlot(CERTCertificate* cert, PK11SlotInfo* slot); + +ScopedCERTCertificate ImportClientCertToSlot( + const scoped_refptr<X509Certificate>& cert, + PK11SlotInfo* slot); scoped_refptr<X509Certificate> ImportClientCertAndKeyFromFile( const base::FilePath& dir, const std::string& cert_filename, const std::string& key_filename, + PK11SlotInfo* slot, + ScopedCERTCertificate* nss_cert); +scoped_refptr<X509Certificate> ImportClientCertAndKeyFromFile( + const base::FilePath& dir, + const std::string& cert_filename, + const std::string& key_filename, PK11SlotInfo* slot); + +ScopedCERTCertificate ImportCERTCertificateFromFile( + const base::FilePath& certs_dir, + const std::string& cert_file); + +ScopedCERTCertificateList CreateCERTCertificateListFromFile( + const base::FilePath& certs_dir, + const std::string& cert_file, + int format); #endif // Imports all of the certificates in |cert_file|, a file in |certs_dir|, into a @@ -80,12 +102,12 @@ scoped_refptr<X509Certificate> ImportCertFromFile(const base::FilePath& certs_di class ScopedTestEVPolicy { public: ScopedTestEVPolicy(EVRootCAMetadata* ev_root_ca_metadata, - const SHA1HashValue& fingerprint, + const SHA256HashValue& fingerprint, const char* policy); ~ScopedTestEVPolicy(); private: - SHA1HashValue fingerprint_; + SHA256HashValue fingerprint_; EVRootCAMetadata* const ev_root_ca_metadata_; }; diff --git a/chromium/net/test/cert_test_util_nss.cc b/chromium/net/test/cert_test_util_nss.cc index 4105e9b885a..b7197d1affd 100644 --- a/chromium/net/test/cert_test_util_nss.cc +++ b/chromium/net/test/cert_test_util_nss.cc @@ -13,6 +13,7 @@ #include "crypto/nss_util.h" #include "crypto/scoped_nss_types.h" #include "net/cert/cert_type.h" +#include "net/cert/x509_util_nss.h" namespace net { @@ -40,11 +41,11 @@ bool ImportSensitiveKeyFromFile(const base::FilePath& dir, return !!private_key; } -bool ImportClientCertToSlot(const scoped_refptr<X509Certificate>& cert, - PK11SlotInfo* slot) { - std::string nickname = cert->GetDefaultNickname(USER_CERT); - SECStatus rv = PK11_ImportCert(slot, cert->os_cert_handle(), - CK_INVALID_HANDLE, nickname.c_str(), PR_FALSE); +bool ImportClientCertToSlot(CERTCertificate* nss_cert, PK11SlotInfo* slot) { + std::string nickname = + x509_util::GetDefaultUniqueNickname(nss_cert, USER_CERT, slot); + SECStatus rv = PK11_ImportCert(slot, nss_cert, CK_INVALID_HANDLE, + nickname.c_str(), PR_FALSE); if (rv != SECSuccess) { LOG(ERROR) << "Could not import cert"; return false; @@ -52,11 +53,26 @@ bool ImportClientCertToSlot(const scoped_refptr<X509Certificate>& cert, return true; } +ScopedCERTCertificate ImportClientCertToSlot( + const scoped_refptr<X509Certificate>& cert, + PK11SlotInfo* slot) { + ScopedCERTCertificate nss_cert = + x509_util::CreateCERTCertificateFromX509Certificate(cert.get()); + if (!nss_cert) + return nullptr; + + if (!ImportClientCertToSlot(nss_cert.get(), slot)) + return nullptr; + + return nss_cert; +} + scoped_refptr<X509Certificate> ImportClientCertAndKeyFromFile( const base::FilePath& dir, const std::string& cert_filename, const std::string& key_filename, - PK11SlotInfo* slot) { + PK11SlotInfo* slot, + ScopedCERTCertificate* nss_cert) { if (!ImportSensitiveKeyFromFile(dir, key_filename, slot)) { LOG(ERROR) << "Could not import private key from file " << key_filename; return NULL; @@ -69,7 +85,8 @@ scoped_refptr<X509Certificate> ImportClientCertAndKeyFromFile( return NULL; } - if (!ImportClientCertToSlot(cert, slot)) + *nss_cert = ImportClientCertToSlot(cert, slot); + if (!*nss_cert) return NULL; // |cert| continues to point to the original X509Certificate before the @@ -78,4 +95,41 @@ scoped_refptr<X509Certificate> ImportClientCertAndKeyFromFile( return cert; } +scoped_refptr<X509Certificate> ImportClientCertAndKeyFromFile( + const base::FilePath& dir, + const std::string& cert_filename, + const std::string& key_filename, + PK11SlotInfo* slot) { + ScopedCERTCertificate nss_cert; + return ImportClientCertAndKeyFromFile(dir, cert_filename, key_filename, slot, + &nss_cert); +} + +ScopedCERTCertificate ImportCERTCertificateFromFile( + const base::FilePath& certs_dir, + const std::string& cert_file) { + scoped_refptr<X509Certificate> cert = + ImportCertFromFile(certs_dir, cert_file); + if (!cert) + return nullptr; + return x509_util::CreateCERTCertificateFromX509Certificate(cert.get()); +} + +ScopedCERTCertificateList CreateCERTCertificateListFromFile( + const base::FilePath& certs_dir, + const std::string& cert_file, + int format) { + CertificateList certs = + CreateCertificateListFromFile(certs_dir, cert_file, format); + ScopedCERTCertificateList nss_certs; + for (const auto& cert : certs) { + ScopedCERTCertificate nss_cert = + x509_util::CreateCERTCertificateFromX509Certificate(cert.get()); + if (!nss_cert) + return {}; + nss_certs.push_back(std::move(nss_cert)); + } + return nss_certs; +} + } // namespace net diff --git a/chromium/net/test/embedded_test_server/android/embedded_test_server_android.cc b/chromium/net/test/embedded_test_server/android/embedded_test_server_android.cc index fb492000680..6de29451eef 100644 --- a/chromium/net/test/embedded_test_server/android/embedded_test_server_android.cc +++ b/chromium/net/test/embedded_test_server/android/embedded_test_server_android.cc @@ -20,10 +20,32 @@ using base::android::ScopedJavaLocalRef; namespace net { namespace test_server { +EmbeddedTestServerAndroid::ConnectionListener::ConnectionListener( + EmbeddedTestServerAndroid* test_server_android) + : test_server_android_(test_server_android) {} + +EmbeddedTestServerAndroid::ConnectionListener::~ConnectionListener() = default; + +void EmbeddedTestServerAndroid::ConnectionListener::AcceptedSocket( + const StreamSocket& socket) { + test_server_android_->AcceptedSocket(static_cast<const void*>(&socket)); +} + +void EmbeddedTestServerAndroid::ConnectionListener::ReadFromSocket( + const StreamSocket& socket, + int rv) { + test_server_android_->ReadFromSocket(static_cast<const void*>(&socket)); +} + EmbeddedTestServerAndroid::EmbeddedTestServerAndroid( JNIEnv* env, - const JavaRef<jobject>& jobj) - : weak_java_server_(env, jobj), test_server_() { + const JavaRef<jobject>& jobj, + jboolean jhttps) + : weak_java_server_(env, jobj), + test_server_(jhttps ? EmbeddedTestServer::TYPE_HTTPS + : EmbeddedTestServer::TYPE_HTTP), + connection_listener_(this) { + test_server_.SetConnectionListener(&connection_listener_); Java_EmbeddedTestServerImpl_setNativePtr(env, jobj, reinterpret_cast<intptr_t>(this)); } @@ -38,6 +60,13 @@ jboolean EmbeddedTestServerAndroid::Start(JNIEnv* env, return test_server_.Start(); } +ScopedJavaLocalRef<jstring> EmbeddedTestServerAndroid::GetRootCertPemPath( + JNIEnv* env, + const JavaParamRef<jobject>& jobj) const { + return base::android::ConvertUTF8ToJavaString( + env, test_server_.GetRootCertPemPath().value()); +} + jboolean EmbeddedTestServerAndroid::ShutdownAndWaitUntilComplete( JNIEnv* env, const JavaParamRef<jobject>& jobj) { @@ -62,6 +91,13 @@ void EmbeddedTestServerAndroid::AddDefaultHandlers( test_server_.AddDefaultHandlers(directory); } +void EmbeddedTestServerAndroid::SetSSLConfig(JNIEnv* jenv, + const JavaParamRef<jobject>& jobj, + jint jserver_certificate) { + test_server_.SetSSLConfig( + static_cast<EmbeddedTestServer::ServerCertificate>(jserver_certificate)); +} + typedef std::unique_ptr<HttpResponse> (*HandleRequestPtr)( const HttpRequest& request); @@ -82,6 +118,18 @@ void EmbeddedTestServerAndroid::ServeFilesFromDirectory( test_server_.ServeFilesFromDirectory(directory); } +void EmbeddedTestServerAndroid::AcceptedSocket(const void* socket_id) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_EmbeddedTestServerImpl_acceptedSocket( + env, weak_java_server_.get(env), reinterpret_cast<intptr_t>(socket_id)); +} + +void EmbeddedTestServerAndroid::ReadFromSocket(const void* socket_id) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_EmbeddedTestServerImpl_readFromSocket( + env, weak_java_server_.get(env), reinterpret_cast<intptr_t>(socket_id)); +} + void EmbeddedTestServerAndroid::Destroy(JNIEnv* env, const JavaParamRef<jobject>& jobj) { delete this; @@ -89,17 +137,13 @@ void EmbeddedTestServerAndroid::Destroy(JNIEnv* env, static void Init(JNIEnv* env, const JavaParamRef<jobject>& jobj, - const JavaParamRef<jstring>& jtest_data_dir) { + const JavaParamRef<jstring>& jtest_data_dir, + jboolean jhttps) { TRACE_EVENT0("native", "EmbeddedTestServerAndroid::Init"); base::FilePath test_data_dir( base::android::ConvertJavaStringToUTF8(env, jtest_data_dir)); base::InitAndroidTestPaths(test_data_dir); - new EmbeddedTestServerAndroid(env, jobj); -} - -// static -bool EmbeddedTestServerAndroid::RegisterEmbeddedTestServerAndroid(JNIEnv* env) { - return RegisterNativesImpl(env); + new EmbeddedTestServerAndroid(env, jobj, jhttps); } } // namespace test_server diff --git a/chromium/net/test/embedded_test_server/android/embedded_test_server_android.h b/chromium/net/test/embedded_test_server/android/embedded_test_server_android.h index a0e7f25a1dc..6765237d2f4 100644 --- a/chromium/net/test/embedded_test_server/android/embedded_test_server_android.h +++ b/chromium/net/test/embedded_test_server/android/embedded_test_server_android.h @@ -11,6 +11,7 @@ #include "base/android/scoped_java_ref.h" #include "base/macros.h" #include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/embedded_test_server_connection_listener.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" @@ -21,13 +22,18 @@ namespace test_server { class EmbeddedTestServerAndroid { public: EmbeddedTestServerAndroid(JNIEnv* env, - const base::android::JavaRef<jobject>& obj); + const base::android::JavaRef<jobject>& obj, + jboolean jhttps); ~EmbeddedTestServerAndroid(); void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); jboolean Start(JNIEnv* env, const base::android::JavaParamRef<jobject>& jobj); + base::android::ScopedJavaLocalRef<jstring> GetRootCertPemPath( + JNIEnv* jenv, + const base::android::JavaParamRef<jobject>& jobj) const; + jboolean ShutdownAndWaitUntilComplete( JNIEnv* env, const base::android::JavaParamRef<jobject>& jobj); @@ -42,6 +48,10 @@ class EmbeddedTestServerAndroid { const base::android::JavaParamRef<jobject>& jobj, const base::android::JavaParamRef<jstring>& jdirectory_path); + void SetSSLConfig(JNIEnv* jenv, + const base::android::JavaParamRef<jobject>& jobj, + jint jserver_certificate); + void RegisterRequestHandler(JNIEnv* jenv, const base::android::JavaParamRef<jobject>& jobj, jlong handler); @@ -51,12 +61,28 @@ class EmbeddedTestServerAndroid { const base::android::JavaParamRef<jobject>& jobj, const base::android::JavaParamRef<jstring>& jdirectory_path); - static bool RegisterEmbeddedTestServerAndroid(JNIEnv* env); - private: + // Connection listener forwarding notifications to EmbeddedTestServerAndroid. + class ConnectionListener : public EmbeddedTestServerConnectionListener { + public: + ConnectionListener(EmbeddedTestServerAndroid* test_server_android); + ~ConnectionListener() override; + + void AcceptedSocket(const StreamSocket& socket) override; + void ReadFromSocket(const StreamSocket& socket, int rv) override; + + private: + EmbeddedTestServerAndroid* test_server_android_; + }; + + // Forwards notifications to Java. See EmbeddedTestServerConnectionListener. + void AcceptedSocket(const void* socket_id); + void ReadFromSocket(const void* socket_id); + JavaObjectWeakGlobalRef weak_java_server_; EmbeddedTestServer test_server_; + ConnectionListener connection_listener_; DISALLOW_COPY_AND_ASSIGN(EmbeddedTestServerAndroid); }; diff --git a/chromium/net/test/embedded_test_server/default_handlers.cc b/chromium/net/test/embedded_test_server/default_handlers.cc index fd304212382..38a8c3c1fa1 100644 --- a/chromium/net/test/embedded_test_server/default_handlers.cc +++ b/chromium/net/test/embedded_test_server/default_handlers.cc @@ -10,6 +10,7 @@ #include <sstream> #include <string> #include <utility> +#include <vector> #include "base/base64.h" #include "base/bind.h" @@ -28,6 +29,7 @@ #include "base/time/time.h" #include "net/base/escape.h" #include "net/base/url_util.h" +#include "net/filter/filter_source_stream_test_util.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" #include "net/test/embedded_test_server/request_handler_util.h" @@ -174,7 +176,7 @@ std::unique_ptr<HttpResponse> HandleEchoAll(const HttpRequest& request) { // /echo-raw // Returns the query string as the raw response (no HTTP headers). std::unique_ptr<HttpResponse> HandleEchoRaw(const HttpRequest& request) { - return base::MakeUnique<RawHttpResponse>("", request.GetURL().query()); + return std::make_unique<RawHttpResponse>("", request.GetURL().query()); } // /set-cookie?COOKIES @@ -616,7 +618,7 @@ class HungHttpResponse : public HttpResponse { // /hung // Never returns a response. std::unique_ptr<HttpResponse> HandleHungResponse(const HttpRequest& request) { - return base::MakeUnique<HungHttpResponse>(); + return std::make_unique<HungHttpResponse>(); } // Return headers, then hangs. @@ -637,7 +639,31 @@ class HungAfterHeadersHttpResponse : public HttpResponse { // Never returns a response. std::unique_ptr<HttpResponse> HandleHungAfterHeadersResponse( const HttpRequest& request) { - return base::MakeUnique<HungAfterHeadersHttpResponse>(); + return std::make_unique<HungAfterHeadersHttpResponse>(); +} + +// /gzip-body?<body> +// Returns a response with a gzipped body of "<body>". Attempts to allocate +// enough memory to contain the body, but DCHECKs if that fails. +std::unique_ptr<HttpResponse> HandleGzipBody(const HttpRequest& request) { + std::string uncompressed_body = request.GetURL().query(); + // Attempt to pick size that's large enough even in the worst case (deflate + // block headers should be shorter than 512 bytes, and deflating should never + // double size of data, modulo headers). + // TODO(mmenke): This is rather awkward. Worth improving CompressGzip? + std::vector<char> compressed_body(uncompressed_body.size() * 2 + 512); + size_t compressed_size = compressed_body.size(); + CompressGzip(uncompressed_body.c_str(), uncompressed_body.size(), + compressed_body.data(), &compressed_size, + true /* gzip_framing */); + // CompressGzip should DCHECK itself if this fails, anyways. + DCHECK_GE(compressed_body.size(), compressed_size); + + std::unique_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); + http_response->set_content( + std::string(compressed_body.data(), compressed_size)); + http_response->AddCustomHeader("Content-Encoding", "gzip"); + return std::move(http_response); } } // anonymous namespace @@ -687,6 +713,8 @@ void RegisterDefaultHandlers(EmbeddedTestServer* server) { PREFIXED_HANDLER("/hung", &HandleHungResponse)); server->RegisterDefaultHandler( PREFIXED_HANDLER("/hung-after-headers", &HandleHungAfterHeadersResponse)); + server->RegisterDefaultHandler( + PREFIXED_HANDLER("/gzip-body", &HandleGzipBody)); // TODO(svaldez): HandleDownload // TODO(svaldez): HandleDownloadFinish 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 83112a2baee..df705db89c3 100644 --- a/chromium/net/test/embedded_test_server/embedded_test_server.cc +++ b/chromium/net/test/embedded_test_server/embedded_test_server.cc @@ -53,12 +53,9 @@ EmbeddedTestServer::EmbeddedTestServer(Type type) weak_factory_(this) { DCHECK(thread_checker_.CalledOnValidThread()); - if (is_using_ssl_) { - base::ThreadRestrictions::ScopedAllowIO allow_io_for_importing_test_cert; - TestRootCerts* root_certs = TestRootCerts::GetInstance(); - base::FilePath certs_dir(GetTestCertsDirectory()); - root_certs->AddFromFile(certs_dir.AppendASCII("root_ca_cert.pem")); - } + if (!is_using_ssl_) + return; + RegisterTestCerts(); } EmbeddedTestServer::~EmbeddedTestServer() { @@ -76,6 +73,14 @@ EmbeddedTestServer::~EmbeddedTestServer() { } } +void EmbeddedTestServer::RegisterTestCerts() { + base::ThreadRestrictions::ScopedAllowIO allow_io_for_importing_test_cert; + TestRootCerts* root_certs = TestRootCerts::GetInstance(); + bool added_root_certs = root_certs->AddFromFile(GetRootCertPemPath()); + DCHECK(added_root_certs) + << "Failed to install root cert from EmbeddedTestServer"; +} + void EmbeddedTestServer::SetConnectionListener( EmbeddedTestServerConnectionListener* listener) { DCHECK(!io_thread_.get()); @@ -184,6 +189,11 @@ bool EmbeddedTestServer::ShutdownAndWaitUntilComplete() { &EmbeddedTestServer::ShutdownOnIOThread, base::Unretained(this))); } +// static +base::FilePath EmbeddedTestServer::GetRootCertPemPath() { + return GetTestCertsDirectory().AppendASCII("root_ca_cert.pem"); +} + void EmbeddedTestServer::ShutdownOnIOThread() { DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); weak_factory_.InvalidateWeakPtrs(); @@ -272,10 +282,6 @@ std::string EmbeddedTestServer::GetCertificateName() const { return "localhost_cert.pem"; case CERT_EXPIRED: return "expired_cert.pem"; - case CERT_CHAIN_WRONG_ROOT: - return "redundant-server-chain.pem"; - case CERT_BAD_VALIDITY: - return "bad_validity.pem"; } return "ok_cert.pem"; @@ -386,7 +392,7 @@ void EmbeddedTestServer::HandleAcceptResult( socket = DoSSLUpgrade(std::move(socket)); std::unique_ptr<HttpConnection> http_connection_ptr = - base::MakeUnique<HttpConnection>( + std::make_unique<HttpConnection>( std::move(socket), base::Bind(&EmbeddedTestServer::HandleRequest, base::Unretained(this))); HttpConnection* http_connection = http_connection_ptr.get(); 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 f2a93072720..5d26cf4ec37 100644 --- a/chromium/net/test/embedded_test_server/embedded_test_server.h +++ b/chromium/net/test/embedded_test_server/embedded_test_server.h @@ -92,22 +92,14 @@ class EmbeddedTestServer { TYPE_HTTPS, }; + // A Java counterpart will be generated for this enum. + // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net.test enum ServerCertificate { CERT_OK, CERT_MISMATCHED_NAME, CERT_EXPIRED, - // A certificate with invalid notBefore and notAfter times. Windows' - // certificate library will not parse this certificate. - CERT_BAD_VALIDITY, - - // Cross-signed certificate to test PKIX path building. Contains an - // intermediate cross-signed by an unknown root, while the client (via - // 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, @@ -121,10 +113,22 @@ class EmbeddedTestServer { // Creates a http test server. Start() must be called to start the server. // |type| indicates the protocol type of the server (HTTP/HTTPS). + // + // When a TYPE_HTTPS server is created, EmbeddedTestServer will call + // EmbeddedTestServer::RegisterTestCerts(), so that when the default + // CertVerifiers are run in-process, they will recognize the test server's + // certs. However, if the test server is running in a different process from + // the CertVerifiers, EmbeddedTestServer::RegisterTestCerts() must be called + // in any process where CertVerifiers are expected to accept the + // EmbeddedTestServer's certs. EmbeddedTestServer(); explicit EmbeddedTestServer(Type type); ~EmbeddedTestServer(); + // Registers the EmbeddedTestServer's certs for the current process. See + // constructor documentation for more information. + static void RegisterTestCerts(); + // Sets a connection listener, that would be notified when various connection // events happen. May only be called before the server is started. Caller // maintains ownership of the listener. @@ -151,6 +155,8 @@ class EmbeddedTestServer { return listen_socket_.get() != NULL; } + static base::FilePath GetRootCertPemPath(); + HostPortPair host_port_pair() const { return HostPortPair::FromURL(base_url_); } 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 8863f832cf4..f4c3c2c51b4 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 @@ -163,7 +163,7 @@ class EmbeddedTestServerTest void OnURLFetchComplete(const URLFetcher* source) override { ++num_responses_received_; if (num_responses_received_ == num_responses_expected_) - base::MessageLoop::current()->QuitWhenIdle(); + base::RunLoop::QuitCurrentWhenIdleDeprecated(); } // Waits until the specified number of responses are received. @@ -502,11 +502,6 @@ const CertificateValuesEntry kCertificateValuesEntry[] = { {EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN, false, "localhost", "Test Root CA"}, {EmbeddedTestServer::CERT_EXPIRED, true, "127.0.0.1", "Test Root CA"}, - {EmbeddedTestServer::CERT_CHAIN_WRONG_ROOT, false, "127.0.0.1", "B CA"}, -#if !defined(OS_WIN) && !defined(OS_ANDROID) - {EmbeddedTestServer::CERT_BAD_VALIDITY, true, "Leaf Certificate", - "Test Root CA"}, -#endif }; TEST_P(EmbeddedTestServerTest, GetCertificate) { @@ -609,7 +604,7 @@ class EmbeddedTestServerThreadingTestDelegate // URLFetcherDelegate override. void OnURLFetchComplete(const URLFetcher* source) override { - base::MessageLoop::current()->QuitWhenIdle(); + base::RunLoop::QuitCurrentWhenIdleDeprecated(); } private: diff --git a/chromium/net/test/embedded_test_server/request_handler_util.cc b/chromium/net/test/embedded_test_server/request_handler_util.cc index 8982efb8c0a..2d26e243eca 100644 --- a/chromium/net/test/embedded_test_server/request_handler_util.cc +++ b/chromium/net/test/embedded_test_server/request_handler_util.cc @@ -200,7 +200,7 @@ std::unique_ptr<HttpResponse> HandleFileRequest( if (!base::ReadFileToString(headers_path, &headers_contents)) return nullptr; - return base::MakeUnique<RawHttpResponse>(headers_contents, file_contents); + return std::make_unique<RawHttpResponse>(headers_contents, file_contents); } std::unique_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); diff --git a/chromium/net/test/embedded_test_server/simple_connection_listener.cc b/chromium/net/test/embedded_test_server/simple_connection_listener.cc index 7cbe4dc1862..d2ea1c9a60f 100644 --- a/chromium/net/test/embedded_test_server/simple_connection_listener.cc +++ b/chromium/net/test/embedded_test_server/simple_connection_listener.cc @@ -33,7 +33,7 @@ void SimpleConnectionListener::ReadFromSocket(const StreamSocket& socket, int rv) {} void SimpleConnectionListener::WaitForConnections() { - EXPECT_TRUE(run_loop_task_runner_->RunsTasksOnCurrentThread()); + EXPECT_TRUE(run_loop_task_runner_->RunsTasksInCurrentSequence()); run_loop_.Run(); } diff --git a/chromium/net/test/net_test_suite.cc b/chromium/net/test/net_test_suite.cc index 1a89449e65a..29e53db0f20 100644 --- a/chromium/net/test/net_test_suite.cc +++ b/chromium/net/test/net_test_suite.cc @@ -68,6 +68,6 @@ void NetTestSuite::InitializeTestThreadNoNetworkChangeNotifier() { host_resolver_proc_->AddRule("*", "127.0.0.1"); scoped_task_environment_ = - base::MakeUnique<base::test::ScopedTaskEnvironment>( + std::make_unique<base::test::ScopedTaskEnvironment>( base::test::ScopedTaskEnvironment::MainThreadType::IO); } diff --git a/chromium/net/test/run_all_unittests.cc b/chromium/net/test/run_all_unittests.cc index becfa33cdd9..7ba6b98ad76 100644 --- a/chromium/net/test/run_all_unittests.cc +++ b/chromium/net/test/run_all_unittests.cc @@ -11,13 +11,6 @@ #include "net/test/net_test_suite.h" #include "url/url_features.h" -#if defined(OS_ANDROID) -#include "base/android/jni_android.h" -#include "base/android/jni_registrar.h" -#include "net/android/dummy_spnego_authenticator.h" -#include "net/android/net_jni_registrar.h" -#endif - #if !defined(OS_IOS) #include "mojo/edk/embedder/embedder.h" // nogncheck #endif @@ -60,21 +53,6 @@ int main(int argc, char** argv) { // Record histograms, so we can get histograms data in tests. base::StatisticsRecorder::Initialize(); -#if defined(OS_ANDROID) - const base::android::RegistrationMethod kNetTestRegisteredMethods[] = { - {"DummySpnegoAuthenticator", - net::android::DummySpnegoAuthenticator::RegisterJni}, - {"NetAndroid", net::android::RegisterJni}, - }; - - // Register JNI bindings for android. Doing it early as the test suite setup - // may initiate a call to Java. - base::android::RegisterNativeMethods( - base::android::AttachCurrentThread(), - kNetTestRegisteredMethods, - arraysize(kNetTestRegisteredMethods)); -#endif - if (!VerifyBuildIsTimely()) return 1; 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 901580126d8..bf1a41dbd5c 100644 --- a/chromium/net/test/spawned_test_server/base_test_server.cc +++ b/chromium/net/test/spawned_test_server/base_test_server.cc @@ -47,8 +47,7 @@ std::string GetHostname(BaseTestServer::Type type, } } - // Use the 127.0.0.1 as default. - return BaseTestServer::kLocalhost; + return "127.0.0.1"; } std::string GetClientCertType(SSLClientCertType type) { @@ -89,14 +88,14 @@ std::unique_ptr<base::Value> GetTLSIntoleranceType( BaseTestServer::SSLOptions::TLSIntoleranceType type) { switch (type) { case BaseTestServer::SSLOptions::TLS_INTOLERANCE_ALERT: - return base::MakeUnique<base::Value>("alert"); + return std::make_unique<base::Value>("alert"); case BaseTestServer::SSLOptions::TLS_INTOLERANCE_CLOSE: - return base::MakeUnique<base::Value>("close"); + return std::make_unique<base::Value>("close"); case BaseTestServer::SSLOptions::TLS_INTOLERANCE_RESET: - return base::MakeUnique<base::Value>("reset"); + return std::make_unique<base::Value>("reset"); default: NOTREACHED(); - return base::MakeUnique<base::Value>(""); + return std::make_unique<base::Value>(""); } } @@ -166,45 +165,9 @@ std::string OCSPDateToString( } // namespace -BaseTestServer::SSLOptions::SSLOptions() - : server_certificate(CERT_OK), - ocsp_status(OCSP_OK), - ocsp_date(OCSP_DATE_VALID), - ocsp_produced(OCSP_PRODUCED_VALID), - cert_serial(0), - request_client_certificate(false), - key_exchanges(SSLOptions::KEY_EXCHANGE_ANY), - bulk_ciphers(SSLOptions::BULK_CIPHER_ANY), - record_resume(false), - tls_intolerant(TLS_INTOLERANT_NONE), - tls_intolerance_type(TLS_INTOLERANCE_ALERT), - fallback_scsv_enabled(false), - staple_ocsp_response(false), - ocsp_server_unavailable(false), - alert_after_handshake(false), - disable_channel_id(false), - disable_extended_master_secret(false) {} - -BaseTestServer::SSLOptions::SSLOptions( - BaseTestServer::SSLOptions::ServerCertificate cert) - : server_certificate(cert), - ocsp_status(OCSP_OK), - ocsp_date(OCSP_DATE_VALID), - ocsp_produced(OCSP_PRODUCED_VALID), - cert_serial(0), - request_client_certificate(false), - key_exchanges(SSLOptions::KEY_EXCHANGE_ANY), - bulk_ciphers(SSLOptions::BULK_CIPHER_ANY), - record_resume(false), - tls_intolerant(TLS_INTOLERANT_NONE), - tls_intolerance_type(TLS_INTOLERANCE_ALERT), - fallback_scsv_enabled(false), - staple_ocsp_response(false), - ocsp_server_unavailable(false), - alert_after_handshake(false), - disable_channel_id(false), - disable_extended_master_secret(false) {} - +BaseTestServer::SSLOptions::SSLOptions() {} +BaseTestServer::SSLOptions::SSLOptions(ServerCertificate cert) + : server_certificate(cert) {} BaseTestServer::SSLOptions::SSLOptions(const SSLOptions& other) = default; BaseTestServer::SSLOptions::~SSLOptions() {} @@ -285,24 +248,12 @@ std::string BaseTestServer::SSLOptions::GetOCSPProducedArgument() const { } } -const char BaseTestServer::kLocalhost[] = "127.0.0.1"; - -BaseTestServer::BaseTestServer(Type type, const std::string& host) - : type_(type), - started_(false), - log_to_console_(false), - ws_basic_auth_(false), - no_anonymous_ftp_user_(false) { - Init(host); +BaseTestServer::BaseTestServer(Type type) : type_(type) { + Init(GetHostname(type, ssl_options_)); } BaseTestServer::BaseTestServer(Type type, const SSLOptions& ssl_options) - : ssl_options_(ssl_options), - type_(type), - started_(false), - log_to_console_(false), - ws_basic_auth_(false), - no_anonymous_ftp_user_(false) { + : ssl_options_(ssl_options), type_(type) { DCHECK(UsingSSL(type)); Init(GetHostname(type, ssl_options)); } @@ -486,7 +437,8 @@ void BaseTestServer::SetResourcePath(const base::FilePath& document_root, DCHECK(!certificates_dir_.empty()); } -bool BaseTestServer::ParseServerData(const std::string& server_data) { +bool BaseTestServer::SetAndParseServerData(const std::string& server_data, + int* port) { VLOG(1) << "Server data: " << server_data; base::JSONReader json_reader; std::unique_ptr<base::Value> value(json_reader.ReadToValue(server_data)); @@ -497,16 +449,14 @@ bool BaseTestServer::ParseServerData(const std::string& server_data) { } server_data_.reset(static_cast<base::DictionaryValue*>(value.release())); - int port = 0; - if (!server_data_->GetInteger("port", &port)) { + if (!server_data_->GetInteger("port", port)) { LOG(ERROR) << "Could not find port value"; return false; } - if ((port <= 0) || (port > std::numeric_limits<uint16_t>::max())) { + if ((*port <= 0) || (*port > std::numeric_limits<uint16_t>::max())) { LOG(ERROR) << "Invalid port value: " << port; return false; } - host_port_pair_.set_port(port); return true; } @@ -543,16 +493,16 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const { arguments->SetString("data-dir", document_root_.value()); if (VLOG_IS_ON(1) || log_to_console_) - arguments->Set("log-to-console", base::MakeUnique<base::Value>()); + arguments->Set("log-to-console", std::make_unique<base::Value>()); if (ws_basic_auth_) { DCHECK(type_ == TYPE_WS || type_ == TYPE_WSS); - arguments->Set("ws-basic-auth", base::MakeUnique<base::Value>()); + arguments->Set("ws-basic-auth", std::make_unique<base::Value>()); } if (no_anonymous_ftp_user_) { DCHECK_EQ(TYPE_FTP, type_); - arguments->Set("no-anonymous-ftp-user", base::MakeUnique<base::Value>()); + arguments->Set("no-anonymous-ftp-user", std::make_unique<base::Value>()); } if (UsingSSL(type_)) { @@ -572,7 +522,7 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const { // Check the client certificate related arguments. if (ssl_options_.request_client_certificate) - arguments->Set("ssl-client-auth", base::MakeUnique<base::Value>()); + arguments->Set("ssl-client-auth", std::make_unique<base::Value>()); std::unique_ptr<base::ListValue> ssl_client_certs(new base::ListValue()); std::vector<base::FilePath>::const_iterator it; @@ -599,11 +549,11 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const { } if (type_ == TYPE_HTTPS) { - arguments->Set("https", base::MakeUnique<base::Value>()); + arguments->Set("https", std::make_unique<base::Value>()); if (ssl_options_.server_certificate == SSLOptions::CERT_AUTO_AIA_INTERMEDIATE) - arguments->Set("aia-intermediate", base::MakeUnique<base::Value>()); + arguments->Set("aia-intermediate", std::make_unique<base::Value>()); std::string ocsp_arg = ssl_options_.GetOCSPArgument(); if (!ocsp_arg.empty()) @@ -632,14 +582,14 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const { if (bulk_cipher_values->GetSize()) arguments->Set("ssl-bulk-cipher", std::move(bulk_cipher_values)); if (ssl_options_.record_resume) - arguments->Set("https-record-resume", base::MakeUnique<base::Value>()); + arguments->Set("https-record-resume", std::make_unique<base::Value>()); if (ssl_options_.tls_intolerant != SSLOptions::TLS_INTOLERANT_NONE) { arguments->SetInteger("tls-intolerant", ssl_options_.tls_intolerant); arguments->Set("tls-intolerance-type", GetTLSIntoleranceType( ssl_options_.tls_intolerance_type)); } if (ssl_options_.fallback_scsv_enabled) - arguments->Set("fallback-scsv", base::MakeUnique<base::Value>()); + arguments->Set("fallback-scsv", std::make_unique<base::Value>()); if (!ssl_options_.signed_cert_timestamps_tls_ext.empty()) { std::string b64_scts_tls_ext; base::Base64Encode(ssl_options_.signed_cert_timestamps_tls_ext, @@ -647,10 +597,10 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const { arguments->SetString("signed-cert-timestamps-tls-ext", b64_scts_tls_ext); } if (ssl_options_.staple_ocsp_response) - arguments->Set("staple-ocsp-response", base::MakeUnique<base::Value>()); + arguments->Set("staple-ocsp-response", std::make_unique<base::Value>()); if (ssl_options_.ocsp_server_unavailable) { arguments->Set("ocsp-server-unavailable", - base::MakeUnique<base::Value>()); + std::make_unique<base::Value>()); } if (!ssl_options_.alpn_protocols.empty()) { std::unique_ptr<base::ListValue> alpn_protocols(new base::ListValue()); @@ -667,13 +617,13 @@ bool BaseTestServer::GenerateArguments(base::DictionaryValue* arguments) const { arguments->Set("npn-protocols", std::move(npn_protocols)); } if (ssl_options_.alert_after_handshake) - arguments->Set("alert-after-handshake", base::MakeUnique<base::Value>()); + arguments->Set("alert-after-handshake", std::make_unique<base::Value>()); if (ssl_options_.disable_channel_id) - arguments->Set("disable-channel-id", base::MakeUnique<base::Value>()); + arguments->Set("disable-channel-id", std::make_unique<base::Value>()); if (ssl_options_.disable_extended_master_secret) { arguments->Set("disable-extended-master-secret", - base::MakeUnique<base::Value>()); + std::make_unique<base::Value>()); } if (!ssl_options_.supported_token_binding_params.empty()) { std::unique_ptr<base::ListValue> token_binding_params( 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 438bf1779c1..fd44381abc7 100644 --- a/chromium/net/test/spawned_test_server/base_test_server.h +++ b/chromium/net/test/spawned_test_server/base_test_server.h @@ -193,16 +193,16 @@ class BaseTestServer { std::string GetOCSPProducedArgument() const; // The certificate to use when serving requests. - ServerCertificate server_certificate; + ServerCertificate server_certificate = CERT_OK; // If |server_certificate==CERT_AUTO| then this determines the type of OCSP // response returned. Ignored if |ocsp_responses| is non-empty. - OCSPStatus ocsp_status; + OCSPStatus ocsp_status = OCSP_OK; // If |server_certificate==CERT_AUTO| then this determines the date range // set on the OCSP response returned. Ignore if |ocsp_responses| is // non-empty. - OCSPDate ocsp_date; + OCSPDate ocsp_date = OCSP_DATE_VALID; // If |server_certificate==CERT_AUTO|, contains the status and validity for // multiple stapled responeses. Overrides |ocsp_status| and |ocsp_date| when @@ -211,15 +211,15 @@ class BaseTestServer { // If |server_certificate==CERT_AUTO| then this determines the validity of // the producedAt field on the returned OCSP response. - OCSPProduced ocsp_produced; + OCSPProduced ocsp_produced = OCSP_PRODUCED_VALID; // If not zero, |cert_serial| will be the serial number of the // auto-generated leaf certificate when |server_certificate==CERT_AUTO|. - uint64_t cert_serial; + uint64_t cert_serial = 0; // True if a CertificateRequest should be sent to the client during // handshaking. - bool request_client_certificate; + bool request_client_certificate = false; // If |request_client_certificate| is true, an optional list of files, // each containing a single, PEM-encoded X.509 certificates. The subject @@ -235,32 +235,32 @@ class BaseTestServer { // A bitwise-OR of KeyExchnage that should be used by the // HTTPS server, or KEY_EXCHANGE_ANY to indicate that all implemented // key exchange algorithms are acceptable. - int key_exchanges; + int key_exchanges = KEY_EXCHANGE_ANY; // A bitwise-OR of BulkCipher that should be used by the // HTTPS server, or BULK_CIPHER_ANY to indicate that all implemented // ciphers are acceptable. - int bulk_ciphers; + int bulk_ciphers = BULK_CIPHER_ANY; // If true, pass the --https-record-resume argument to testserver.py which // causes it to log session cache actions and echo the log on // /ssl-session-cache. - bool record_resume; + bool record_resume = false; // If not TLS_INTOLERANT_NONE, the server will abort any handshake that // negotiates an intolerant TLS version in order to test version fallback. - TLSIntolerantLevel tls_intolerant; + TLSIntolerantLevel tls_intolerant = TLS_INTOLERANT_NONE; // If |tls_intolerant| is not TLS_INTOLERANT_NONE, how the server reacts to // an intolerant TLS version. - TLSIntoleranceType tls_intolerance_type; + TLSIntoleranceType tls_intolerance_type = TLS_INTOLERANCE_ALERT; // fallback_scsv_enabled, if true, causes the server to process the // TLS_FALLBACK_SCSV cipher suite. This cipher suite is sent by Chrome // when performing TLS version fallback in response to an SSL handshake // failure. If this option is enabled then the server will reject fallback // connections. - bool fallback_scsv_enabled; + bool fallback_scsv_enabled = false; // Temporary glue for testing: validation of SCTs is application-controlled // and can be appropriately mocked out, so sending fake data here does not @@ -271,11 +271,11 @@ class BaseTestServer { std::string signed_cert_timestamps_tls_ext; // Whether to staple the OCSP response. - bool staple_ocsp_response; + bool staple_ocsp_response = false; // Whether to make the OCSP server unavailable. This does not affect the // stapled OCSP response. - bool ocsp_server_unavailable; + bool ocsp_server_unavailable = false; // List of protocols to advertise in NPN extension. NPN is not supported if // list is empty. Note that regardless of what protocol is negotiated, the @@ -286,23 +286,20 @@ class BaseTestServer { std::vector<std::string> alpn_protocols; // Whether to send a fatal alert immediately after completing the handshake. - bool alert_after_handshake; + bool alert_after_handshake = false; // If true, disables channel ID on the server. - bool disable_channel_id; + bool disable_channel_id = false; // If true, disables extended master secret tls extension. - bool disable_extended_master_secret; + bool disable_extended_master_secret = false; // List of token binding params that the server supports and will negotiate. std::vector<int> supported_token_binding_params; }; - // Pass as the 'host' parameter during construction to server on 127.0.0.1 - static const char kLocalhost[]; - - // Initialize a TestServer listening on a specific host (IP or hostname). - BaseTestServer(Type type, const std::string& host); + // Initialize a TestServer. + explicit BaseTestServer(Type type); // Initialize a TestServer with a specific set of SSLOptions for HTTPS or WSS. BaseTestServer(Type type, const SSLOptions& ssl_options); @@ -374,9 +371,13 @@ class BaseTestServer { void SetResourcePath(const base::FilePath& document_root, const base::FilePath& certificates_dir); - // Parses the server data read from the test server. Returns true - // on success. - bool ParseServerData(const std::string& server_data) WARN_UNUSED_RESULT; + // Parses the server data read from the test server and sets |server_data_|. + // *port is set to the port number specified in server_data. The port may be + // different from the local port set in |host_port_pair_|, specifically when + // using RemoteTestServer (which proxies connections from 127.0.0.1 to a + // different IP). Returns true on success. + bool SetAndParseServerData(const std::string& server_data, + int* port) WARN_UNUSED_RESULT; // Generates a DictionaryValue with the arguments for launching the external // Python test server. @@ -397,7 +398,9 @@ class BaseTestServer { // Directory that contains the SSL certificates. base::FilePath certificates_dir_; - // Address the test server listens on. + // Address on which the tests should connect to the server. With + // RemoteTestServer it may be different from the address on which the server + // listens on. HostPortPair host_port_pair_; // Holds the data sent from the server (e.g., port number). @@ -410,16 +413,16 @@ class BaseTestServer { Type type_; // Has the server been started? - bool started_; + bool started_ = false; // Enables logging of the server to the console. - bool log_to_console_; + bool log_to_console_ = false; // Is WebSocket basic HTTP authentication enabled? - bool ws_basic_auth_; + bool ws_basic_auth_ = false; // Disable creation of anonymous FTP user? - bool no_anonymous_ftp_user_; + bool no_anonymous_ftp_user_ = false; std::unique_ptr<ScopedPortException> allowed_port_; 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 b941b62285b..e1822dd85d6 100644 --- a/chromium/net/test/spawned_test_server/local_test_server.cc +++ b/chromium/net/test/spawned_test_server/local_test_server.cc @@ -57,10 +57,8 @@ bool AppendArgumentFromJSONValue(const std::string& key, } // namespace -LocalTestServer::LocalTestServer(Type type, - const std::string& host, - const base::FilePath& document_root) - : BaseTestServer(type, host) { +LocalTestServer::LocalTestServer(Type type, const base::FilePath& document_root) + : BaseTestServer(type) { if (!Init(document_root)) NOTREACHED(); } 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 98152a162f7..6d8a3f8c82f 100644 --- a/chromium/net/test/spawned_test_server/local_test_server.h +++ b/chromium/net/test/spawned_test_server/local_test_server.h @@ -27,11 +27,9 @@ namespace net { // same machine in which the LocalTestServer runs. class LocalTestServer : public BaseTestServer { public: - // Initialize a TestServer listening on a specific host (IP or hostname). - // |document_root| must be a relative path under the root tree. - LocalTestServer(Type type, - const std::string& host, - const base::FilePath& document_root); + // Initialize a TestServer. |document_root| must be a relative path under the + // root tree. + LocalTestServer(Type type, const base::FilePath& document_root); // Initialize a TestServer with a specific set of SSLOptions. // |document_root| must be a relative path under the root tree. 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 e5db9c010dd..71fd803b785 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 @@ -13,6 +13,7 @@ #include "base/files/scoped_file.h" #include "base/logging.h" #include "base/macros.h" +#include "base/path_service.h" #include "base/process/kill.h" #include "base/process/launch.h" #include "base/process/process_iterator.h" @@ -126,8 +127,6 @@ bool LocalTestServer::LaunchPython(const base::FilePath& testserver_path) { // Save the read half. The write half is sent to the child. child_fd_.reset(pipefd[0]); base::ScopedFD write_closer(pipefd[1]); - base::FileHandleMappingVector map_write_fd; - map_write_fd.push_back(std::make_pair(pipefd[1], pipefd[1])); python_command.AppendArg("--startup-pipe=" + base::IntToString(pipefd[1])); @@ -141,7 +140,13 @@ bool LocalTestServer::LaunchPython(const base::FilePath& testserver_path) { // Launch a new testserver process. base::LaunchOptions options; - options.fds_to_remap = &map_write_fd; + // Set CWD to source root. + if (!PathService::Get(base::DIR_SOURCE_ROOT, &options.current_directory)) { + LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT"; + return false; + } + + options.fds_to_remap.push_back(std::make_pair(pipefd[1], pipefd[1])); process_ = base::LaunchProcess(python_command, options); if (!process_.IsValid()) { LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString(); @@ -171,10 +176,12 @@ bool LocalTestServer::WaitToStart() { return false; } - if (!ParseServerData(server_data)) { + int port; + if (!SetAndParseServerData(server_data, &port)) { LOG(ERROR) << "Could not parse server_data: " << server_data; return false; } + SetPort(port); return true; } 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 65d554eba25..6d5517b9ac4 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 @@ -12,6 +12,7 @@ #include "base/environment.h" #include "base/files/file_path.h" #include "base/message_loop/message_loop.h" +#include "base/path_service.h" #include "base/process/launch.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_number_conversions.h" @@ -125,7 +126,16 @@ bool LocalTestServer::LaunchPython(const base::FilePath& testserver_path) { base::IntToString(reinterpret_cast<uintptr_t>(child_write))); base::LaunchOptions launch_options; - launch_options.inherit_handles = true; + + // Set CWD to source root. + if (!PathService::Get(base::DIR_SOURCE_ROOT, + &launch_options.current_directory)) { + LOG(ERROR) << "Failed to get DIR_SOURCE_ROOT"; + return false; + } + + // TODO(brettw) bug 748258: Share only explicit handles. + launch_options.inherit_mode = base::LaunchOptions::Inherit::kAll; process_ = base::LaunchProcess(python_command, launch_options); if (!process_.IsValid()) { LOG(ERROR) << "Failed to launch " << python_command.GetCommandLineString(); @@ -155,10 +165,12 @@ bool LocalTestServer::WaitToStart() { return false; } - if (!ParseServerData(server_data)) { + int port; + if (!SetAndParseServerData(server_data, &port)) { LOG(ERROR) << "Could not parse server_data: " << server_data; return false; } + SetPort(port); 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 feae117b549..5bf7ed2a95b 100644 --- a/chromium/net/test/spawned_test_server/remote_test_server.cc +++ b/chromium/net/test/spawned_test_server/remote_test_server.cc @@ -13,15 +13,15 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/json/json_writer.h" -#include "base/lazy_instance.h" #include "base/logging.h" -#include "base/memory/ptr_util.h" #include "base/path_service.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/values.h" #include "net/base/host_port_pair.h" #include "net/base/net_errors.h" +#include "net/test/spawned_test_server/remote_test_server_config.h" +#include "net/test/spawned_test_server/remote_test_server_proxy.h" #include "net/test/spawned_test_server/spawner_communicator.h" #include "url/gurl.h" @@ -29,48 +29,6 @@ namespace net { namespace { -// Based on how the Android runner sets things up, it is only valid for one -// RemoteTestServer to be active on the device at a time. -class RemoteTestServerTracker { - public: - void StartingServer() { - base::AutoLock lock(lock_); - CHECK_EQ(count_, 0); - count_++; - } - - void StoppingServer() { - base::AutoLock lock(lock_); - CHECK_EQ(count_, 1); - count_--; - } - - private: - // |lock_| protects access to |count_|. - base::Lock lock_; - int count_ = 0; -}; - -base::LazyInstance<RemoteTestServerTracker>::Leaky tracker = - LAZY_INSTANCE_INITIALIZER; - -// To reduce the running time of tests, tests may be sharded across several -// devices. This means that it may be necessary to support multiple instances -// of the test server spawner and the Python test server simultaneously on the -// same host. Each pair of (test server spawner, Python test server) correspond -// to a single testing device. -// The mapping between the test server spawner and the individual Python test -// servers is written to a file on the device prior to executing any tests. -base::FilePath GetTestServerPortInfoFile() { -#if !defined(OS_ANDROID) - return base::FilePath("/tmp/net-test-server-ports"); -#else - base::FilePath test_data_dir; - PathService::Get(base::DIR_ANDROID_EXTERNAL_STORAGE, &test_data_dir); - return test_data_dir.Append("net-test-server-ports"); -#endif -} - // Please keep it sync with dictionary SERVER_TYPES in testserver.py std::string GetServerTypeString(BaseTestServer::Type type) { switch (type) { @@ -95,10 +53,8 @@ std::string GetServerTypeString(BaseTestServer::Type type) { } // namespace RemoteTestServer::RemoteTestServer(Type type, - const std::string& host, const base::FilePath& document_root) - : BaseTestServer(type, host), - spawner_server_port_(0) { + : BaseTestServer(type), io_thread_("RemoteTestServer IO Thread") { if (!Init(document_root)) NOTREACHED(); } @@ -107,7 +63,7 @@ RemoteTestServer::RemoteTestServer(Type type, const SSLOptions& ssl_options, const base::FilePath& document_root) : BaseTestServer(type, ssl_options), - spawner_server_port_(0) { + io_thread_("RemoteTestServer IO Thread") { if (!Init(document_root)) NOTREACHED(); } @@ -120,15 +76,15 @@ bool RemoteTestServer::Start() { if (spawner_communicator_.get()) return true; - tracker.Get().StartingServer(); + RemoteTestServerConfig config = RemoteTestServerConfig::Load(); - spawner_communicator_.reset(new SpawnerCommunicator(spawner_server_port_)); + spawner_communicator_ = std::make_unique<SpawnerCommunicator>(config); base::DictionaryValue arguments_dict; if (!GenerateArguments(&arguments_dict)) return false; - arguments_dict.Set("on-remote-server", base::MakeUnique<base::Value>()); + arguments_dict.Set("on-remote-server", std::make_unique<base::Value>()); // Append the 'server-type' argument which is used by spawner server to // pass right server type to Python test server. @@ -141,27 +97,28 @@ bool RemoteTestServer::Start() { return false; // Start the Python test server on the remote machine. - uint16_t test_server_port; - if (!spawner_communicator_->StartServer(arguments_string, - &test_server_port)) { - return false; - } - if (0 == test_server_port) + std::string server_data; + if (!spawner_communicator_->StartServer(arguments_string, &server_data)) return false; - // Construct server data to initialize BaseTestServer::server_data_. - base::DictionaryValue server_data_dict; - // At this point, the test server should be spawned on the host. Update the - // local port to real port of Python test server, which will be forwarded to - // the remote server. - server_data_dict.SetInteger("port", test_server_port); - std::string server_data; - base::JSONWriter::Write(server_data_dict, &server_data); - if (server_data.empty() || !ParseServerData(server_data)) { + // Parse server_data. + int server_port; + if (server_data.empty() || + !SetAndParseServerData(server_data, &server_port)) { LOG(ERROR) << "Could not parse server_data: " << server_data; return false; } + // If the server is not on localhost then start a proxy on localhost to + // forward connections to the server. + if (config.address() != IPAddress::IPv4Localhost()) { + test_server_proxy_ = std::make_unique<RemoteTestServerProxy>( + IPEndPoint(config.address(), server_port), io_thread_.task_runner()); + SetPort(test_server_proxy_->local_port()); + } else { + SetPort(server_port); + } + return SetupWhenServerStarted(); } @@ -176,19 +133,18 @@ bool RemoteTestServer::BlockUntilStarted() { } bool RemoteTestServer::Stop() { - if (!spawner_communicator_.get()) + if (!spawner_communicator_) return true; - tracker.Get().StoppingServer(); - + uint16_t port = GetPort(); CleanUpWhenStoppingServer(); - bool stopped = spawner_communicator_->StopServer(); + bool stopped = spawner_communicator_->StopServer(port); if (!stopped) LOG(ERROR) << "Failed stopping RemoteTestServer"; // Explicitly reset |spawner_communicator_| to avoid reusing the stopped one. - spawner_communicator_.reset(NULL); + spawner_communicator_.reset(); return stopped; } @@ -206,45 +162,20 @@ bool RemoteTestServer::Init(const base::FilePath& document_root) { if (document_root.IsAbsolute()) return false; - // Gets ports information used by test server spawner and Python test server. - int test_server_port = 0; - - // Parse file to extract the ports information. - std::string port_info; - if (!base::ReadFileToString(GetTestServerPortInfoFile(), &port_info) || - port_info.empty()) { - return false; - } - - std::vector<std::string> ports = base::SplitString( - port_info, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - if (ports.size() != 2u) - return false; - - // Verify the ports information. - base::StringToInt(ports[0], &spawner_server_port_); - if (!spawner_server_port_ || - static_cast<uint32_t>(spawner_server_port_) >= - std::numeric_limits<uint16_t>::max()) - return false; - - // Allow the test_server_port to be 0, which means the test server spawner - // will pick up a random port to run the test server. - base::StringToInt(ports[1], &test_server_port); - if (static_cast<uint32_t>(test_server_port) >= - std::numeric_limits<uint16_t>::max()) - return false; - SetPort(test_server_port); + bool thread_started = io_thread_.StartWithOptions( + base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); + CHECK(thread_started); // Unlike LocalTestServer, RemoteTestServer passes relative paths to the test // server. The test server fails on empty strings in some configurations. base::FilePath fixed_root = document_root; if (fixed_root.empty()) fixed_root = base::FilePath(base::FilePath::kCurrentDirectory); - SetResourcePath(fixed_root, base::FilePath().AppendASCII("net") - .AppendASCII("data") - .AppendASCII("ssl") - .AppendASCII("certificates")); + SetResourcePath(fixed_root, base::FilePath() + .AppendASCII("net") + .AppendASCII("data") + .AppendASCII("ssl") + .AppendASCII("certificates")); return true; } 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 224c0cd6a11..04dcdb4cf74 100644 --- a/chromium/net/test/spawned_test_server/remote_test_server.h +++ b/chromium/net/test/spawned_test_server/remote_test_server.h @@ -8,21 +8,21 @@ #include <string> #include "base/macros.h" +#include "base/threading/thread.h" #include "net/test/spawned_test_server/base_test_server.h" namespace net { class SpawnerCommunicator; +class RemoteTestServerProxy; // The RemoteTestServer runs an external Python-based test server in another // machine that is different from the machine in which RemoteTestServer runs. class RemoteTestServer : public BaseTestServer { public: - // Initialize a TestServer listening on a specific host (IP or hostname). - // |document_root| must be a relative path under the root tree. - RemoteTestServer(Type type, - const std::string& host, - const base::FilePath& document_root); + // Initialize a TestServer. |document_root| must be a relative path under the + // root tree. + RemoteTestServer(Type type, const base::FilePath& document_root); // Initialize a TestServer with a specific set of SSLOptions. // |document_root| must be a relative path under the root tree. @@ -53,16 +53,16 @@ class RemoteTestServer : public BaseTestServer { private: bool Init(const base::FilePath& document_root); - // The local port used to communicate with the TestServer spawner. This is - // used to control the startup and shutdown of the Python TestServer running - // on the remote machine. On Android, this port will be redirected to the - // same port on the host machine. - int spawner_server_port_; + // Thread used to run all IO activity in |test_server_proxy_|. + // TODO(sergeyu): Use it for |spawner_communicator_| as well. + base::Thread io_thread_; // Helper to start and stop instances of the Python test server that runs on // the host machine. std::unique_ptr<SpawnerCommunicator> spawner_communicator_; + std::unique_ptr<RemoteTestServerProxy> test_server_proxy_; + DISALLOW_COPY_AND_ASSIGN(RemoteTestServer); }; diff --git a/chromium/net/test/spawned_test_server/remote_test_server_config.cc b/chromium/net/test/spawned_test_server/remote_test_server_config.cc new file mode 100644 index 00000000000..1e561881a6b --- /dev/null +++ b/chromium/net/test/spawned_test_server/remote_test_server_config.cc @@ -0,0 +1,95 @@ +// Copyright 2017 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/spawned_test_server/remote_test_server_config.h" + +#include "base/base_paths.h" +#include "base/environment.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/json/json_reader.h" +#include "base/lazy_instance.h" +#include "base/path_service.h" +#include "base/threading/thread_restrictions.h" +#include "base/values.h" +#include "build/build_config.h" +#include "url/gurl.h" + +namespace net { + +namespace { + +base::FilePath GetTestServerConfigFilePath() { + base::FilePath dir; +#if defined(OS_ANDROID) + PathService::Get(base::DIR_ANDROID_EXTERNAL_STORAGE, &dir); +#elif defined(OS_FUCHSIA) + dir = base::FilePath("/system"); +#else + PathService::Get(base::DIR_TEMP, &dir); +#endif + return dir.AppendASCII("net-test-server-config"); +} + +} // namespace + +RemoteTestServerConfig::RemoteTestServerConfig() = default; +RemoteTestServerConfig::~RemoteTestServerConfig() {} + +RemoteTestServerConfig::RemoteTestServerConfig( + const RemoteTestServerConfig& other) = default; +RemoteTestServerConfig& RemoteTestServerConfig::operator=( + const RemoteTestServerConfig&) = default; + +RemoteTestServerConfig RemoteTestServerConfig::Load() { + base::ThreadRestrictions::ScopedAllowIO allow_io; + + RemoteTestServerConfig result; + + base::FilePath config_path = GetTestServerConfigFilePath(); + + // Use defaults if the file doesn't exists. + if (!base::PathExists(config_path)) + return result; + + std::string config_json; + if (!ReadFileToString(config_path, &config_json)) + LOG(FATAL) << "Failed to read " << config_path.value(); + + std::unique_ptr<base::DictionaryValue> config = + base::DictionaryValue::From(base::JSONReader::Read(config_json)); + if (!config) + LOG(FATAL) << "Failed to parse " << config_path.value(); + + std::string address_str; + if (config->GetString("address", &address_str)) { + if (!result.address_.AssignFromIPLiteral(address_str)) { + LOG(FATAL) << "Invalid address specified in test server config: " + << address_str; + } + } else { + LOG(WARNING) << "address isn't specified in test server config."; + } + + if (config->GetString("spawner_url_base", &result.spawner_url_base_)) { + GURL url(result.spawner_url_base_); + if (!url.is_valid()) { + LOG(FATAL) << "Invalid spawner_url_base specified in test server config: " + << result.spawner_url_base_; + } + } + + return result; +} + +GURL RemoteTestServerConfig::GetSpawnerUrl(const std::string& command) const { + CHECK(!spawner_url_base_.empty()) + << "spawner_url_base is expected, but not set in test server config."; + std::string url = spawner_url_base_ + "/" + command; + GURL result = GURL(url); + CHECK(result.is_valid()) << url; + return result; +} + +} // namespace net diff --git a/chromium/net/test/spawned_test_server/remote_test_server_config.h b/chromium/net/test/spawned_test_server/remote_test_server_config.h new file mode 100644 index 00000000000..82686e329be --- /dev/null +++ b/chromium/net/test/spawned_test_server/remote_test_server_config.h @@ -0,0 +1,63 @@ +// Copyright 2017 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_SPAWNED_TEST_SERVER_REMOTE_TEST_SERVER_CONFIG_H_ +#define NET_TEST_SPAWNED_TEST_SERVER_REMOTE_TEST_SERVER_CONFIG_H_ + +#include <string> + +#include "base/macros.h" +#include "net/base/ip_address.h" + +class GURL; + +namespace net { + +// RemoteTestServerConfig is responsible for loading test server configuration +// from a file. Expected config location depends on platform: +// - Android: DIR_ANDROID_EXTERNAL_STORAGE/net-test-server-config +// - Fuchsia: /system/net-test-server-config +// - other platforms: DIR_TEMP/net-test-server-config +// +// If the config file doesn't exist then the default configuration is used. By +// default the server is started on 127.0.0.1. +// +// If the config file exists then it must be stored in the following format: +// { +// 'address': '127.0.0.1', +// 'spawner_url_base': 'http://localhost:5000' +// } +// +// 'spawner_url_base' specifies base URL to connect to the test server spawner +// responsible for starting and stopping test server. Currently spawner is used +// only on Android and Fuchsia. 'address' specifies IP address for the test +// server. +class RemoteTestServerConfig { + public: + RemoteTestServerConfig(); + ~RemoteTestServerConfig(); + + RemoteTestServerConfig(const RemoteTestServerConfig& other); + RemoteTestServerConfig& operator=(const RemoteTestServerConfig&); + + // Returns current test server configuration, loading it from a file if the + // file exists. + static RemoteTestServerConfig Load(); + + // IP address to use used to connect to the testserver. + const IPAddress& address() const { return address_; } + + // GURL for the test server spawner. + GURL GetSpawnerUrl(const std::string& command) const; + + private: + // Defaults that can be overridden with a config file. + IPAddress address_ = {127, 0, 0, 1}; + + std::string spawner_url_base_; +}; + +} // namespace net + +#endif // NET_TEST_SPAWNED_TEST_SERVER_REMOTE_TEST_SERVER_CONFIG_H_ diff --git a/chromium/net/test/spawned_test_server/remote_test_server_proxy.cc b/chromium/net/test/spawned_test_server/remote_test_server_proxy.cc new file mode 100644 index 00000000000..70330cba600 --- /dev/null +++ b/chromium/net/test/spawned_test_server/remote_test_server_proxy.cc @@ -0,0 +1,317 @@ +// Copyright 2017 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/spawned_test_server/remote_test_server_proxy.h" + +#include <memory> +#include <vector> + +#include "base/callback.h" +#include "base/memory/weak_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread_checker.h" +#include "net/base/io_buffer.h" +#include "net/base/net_errors.h" +#include "net/socket/stream_socket.h" +#include "net/socket/tcp_client_socket.h" +#include "net/socket/tcp_server_socket.h" + +namespace net { + +namespace { + +const int kBufferSize = 1024; + +// Helper that reads data from one socket and then forwards to another socket. +class SocketDataPump { + public: + SocketDataPump(StreamSocket* from_socket, + StreamSocket* to_socket, + base::OnceClosure on_done_callback) + : from_socket_(from_socket), + to_socket_(to_socket), + on_done_callback_(std::move(on_done_callback)) { + read_buffer_ = new IOBuffer(kBufferSize); + } + + ~SocketDataPump() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); } + + void Start() { Read(); } + + private: + void Read() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!write_buffer_); + + int result = from_socket_->Read( + read_buffer_.get(), kBufferSize, + base::Bind(&SocketDataPump::HandleReadResult, base::Unretained(this))); + if (result != ERR_IO_PENDING) + HandleReadResult(result); + } + + void HandleReadResult(int result) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (result <= 0) { + std::move(on_done_callback_).Run(); + return; + } + + write_buffer_ = new DrainableIOBuffer(read_buffer_.get(), result); + Write(); + } + + void Write() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(write_buffer_); + + int result = to_socket_->Write( + write_buffer_.get(), write_buffer_->BytesRemaining(), + base::Bind(&SocketDataPump::HandleWriteResult, base::Unretained(this))); + if (result != ERR_IO_PENDING) + HandleWriteResult(result); + } + + void HandleWriteResult(int result) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (result <= 0) { + std::move(on_done_callback_).Run(); + return; + } + + write_buffer_->DidConsume(result); + if (write_buffer_->BytesRemaining()) { + Write(); + } else { + write_buffer_ = nullptr; + Read(); + } + } + + StreamSocket* from_socket_; + StreamSocket* to_socket_; + + scoped_refptr<IOBuffer> read_buffer_; + scoped_refptr<DrainableIOBuffer> write_buffer_; + + base::OnceClosure on_done_callback_; + + THREAD_CHECKER(thread_checker_); + + DISALLOW_COPY_AND_ASSIGN(SocketDataPump); +}; + +// ConnectionProxy is responsible for proxying one connection to a remote +// address. +class ConnectionProxy { + public: + explicit ConnectionProxy(std::unique_ptr<StreamSocket> local_socket); + ~ConnectionProxy(); + + void Start(const IPEndPoint& remote_address, + base::OnceClosure on_done_callback); + + private: + void Close(); + + void HandleConnectResult(const IPEndPoint& remote_address, int result); + + base::OnceClosure on_done_callback_; + + std::unique_ptr<StreamSocket> local_socket_; + std::unique_ptr<StreamSocket> remote_socket_; + + std::unique_ptr<SocketDataPump> incoming_pump_; + std::unique_ptr<SocketDataPump> outgoing_pump_; + + THREAD_CHECKER(thread_checker_); + + base::WeakPtrFactory<ConnectionProxy> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(ConnectionProxy); +}; + +ConnectionProxy::ConnectionProxy(std::unique_ptr<StreamSocket> local_socket) + : local_socket_(std::move(local_socket)), weak_factory_(this) {} + +ConnectionProxy::~ConnectionProxy() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +} + +void ConnectionProxy::Start(const IPEndPoint& remote_address, + base::OnceClosure on_done_callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + on_done_callback_ = std::move(on_done_callback); + remote_socket_ = std::make_unique<TCPClientSocket>( + AddressList(remote_address), nullptr, nullptr, NetLogSource()); + int result = remote_socket_->Connect( + base::Bind(&ConnectionProxy::HandleConnectResult, base::Unretained(this), + remote_address)); + if (result != ERR_IO_PENDING) + HandleConnectResult(remote_address, result); +} + +void ConnectionProxy::HandleConnectResult(const IPEndPoint& remote_address, + int result) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!incoming_pump_); + DCHECK(!outgoing_pump_); + + if (result < 0) { + LOG(ERROR) << "Connection to " << remote_address.ToString() + << " failed: " << ErrorToString(result); + Close(); + return; + } + + incoming_pump_ = std::make_unique<SocketDataPump>( + remote_socket_.get(), local_socket_.get(), + base::BindOnce(&ConnectionProxy::Close, base::Unretained(this))); + outgoing_pump_ = std::make_unique<SocketDataPump>( + local_socket_.get(), remote_socket_.get(), + base::BindOnce(&ConnectionProxy::Close, base::Unretained(this))); + + auto self = weak_factory_.GetWeakPtr(); + incoming_pump_->Start(); + if (!self) + return; + + outgoing_pump_->Start(); +} + +void ConnectionProxy::Close() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + local_socket_.reset(); + remote_socket_.reset(); + std::move(on_done_callback_).Run(); +} + +} // namespace + +// RemoteTestServerProxy implementation that runs on a background IO thread. +class RemoteTestServerProxy::Core { + public: + explicit Core(const IPEndPoint& remote_address); + ~Core(); + + void Start(base::WaitableEvent* started_event); + + uint16_t local_port() const { return local_port_; } + + private: + void DoAcceptLoop(); + void OnAcceptResult(int result); + void HandleAcceptResult(int result); + void OnConnectionClosed(ConnectionProxy* connection); + + IPEndPoint remote_address_; + + std::unique_ptr<TCPServerSocket> socket_; + + uint16_t local_port_; + std::vector<std::unique_ptr<ConnectionProxy>> connections_; + + std::unique_ptr<StreamSocket> accepted_socket_; + + DISALLOW_COPY_AND_ASSIGN(Core); +}; + +RemoteTestServerProxy::Core::Core(const IPEndPoint& remote_address) + : remote_address_(remote_address) {} + +void RemoteTestServerProxy::Core::Start(base::WaitableEvent* started_event) { + socket_ = std::make_unique<TCPServerSocket>(nullptr, net::NetLogSource()); + int result = socket_->Listen(IPEndPoint(IPAddress::IPv4Localhost(), 0), 5); + CHECK_EQ(result, OK); + + // Get local port number. + IPEndPoint address; + result = socket_->GetLocalAddress(&address); + CHECK_EQ(result, OK); + local_port_ = address.port(); + + DoAcceptLoop(); + + started_event->Signal(); +} + +RemoteTestServerProxy::Core::~Core() {} + +void RemoteTestServerProxy::Core::DoAcceptLoop() { + int result = OK; + while (result == OK) { + result = socket_->Accept( + &accepted_socket_, + base::Bind(&Core::OnAcceptResult, base::Unretained(this))); + if (result != ERR_IO_PENDING) + HandleAcceptResult(result); + } +} + +void RemoteTestServerProxy::Core::OnAcceptResult(int result) { + HandleAcceptResult(result); + if (result == OK) + DoAcceptLoop(); +} + +void RemoteTestServerProxy::Core::HandleAcceptResult(int result) { + DCHECK_NE(result, ERR_IO_PENDING); + + if (result < 0) { + LOG(ERROR) << "Error when accepting a connection: " + << ErrorToString(result); + return; + } + + std::unique_ptr<ConnectionProxy> connection_proxy = + std::make_unique<ConnectionProxy>(std::move(accepted_socket_)); + ConnectionProxy* connection_proxy_ptr = connection_proxy.get(); + connections_.push_back(std::move(connection_proxy)); + + // Start() may invoke the callback so it needs to be called after the + // connection is pushed to connections_. + connection_proxy_ptr->Start( + remote_address_, + base::BindOnce(&Core::OnConnectionClosed, base::Unretained(this), + connection_proxy_ptr)); +} + +void RemoteTestServerProxy::Core::OnConnectionClosed( + ConnectionProxy* connection) { + for (auto it = connections_.begin(); it != connections_.end(); ++it) { + if (it->get() == connection) { + connections_.erase(it); + return; + } + } + NOTREACHED(); +} + +RemoteTestServerProxy::RemoteTestServerProxy( + const IPEndPoint& remote_address, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) + : io_task_runner_(io_task_runner), + core_(std::make_unique<Core>(remote_address)) { + base::WaitableEvent started_event( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + io_task_runner_->PostTask( + FROM_HERE, + base::Bind(&Core::Start, base::Unretained(core_.get()), &started_event)); + started_event.Wait(); + + local_port_ = core_->local_port(); +} + +RemoteTestServerProxy::~RemoteTestServerProxy() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + io_task_runner_->DeleteSoon(FROM_HERE, core_.release()); +} + +} // namespace net diff --git a/chromium/net/test/spawned_test_server/remote_test_server_proxy.h b/chromium/net/test/spawned_test_server/remote_test_server_proxy.h new file mode 100644 index 00000000000..538fcea075e --- /dev/null +++ b/chromium/net/test/spawned_test_server/remote_test_server_proxy.h @@ -0,0 +1,51 @@ +// Copyright 2017 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_SPAWNED_TEST_SERVER_REMOTE_TEST_SERVER_PROXY_H_ +#define NET_TEST_SPAWNED_TEST_SERVER_REMOTE_TEST_SERVER_PROXY_H_ + +#include <stdint.h> + +#include <memory> + +#include "base/memory/ref_counted.h" +#include "base/threading/thread_checker.h" + +namespace base { +class SingleThreadTaskRunner; +} // namespace base + +namespace net { + +class IPEndPoint; + +// RemoteTestServerProxy proxies TCP connection from localhost to a remote IP +// address. +class RemoteTestServerProxy { + public: + RemoteTestServerProxy( + const IPEndPoint& remote_address, + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); + ~RemoteTestServerProxy(); + + uint16_t local_port() const { return local_port_; } + + private: + class Core; + + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + + // Core implements the proxy functionality. It runs on |io_task_runner_|. + std::unique_ptr<Core> core_; + + uint16_t local_port_; + + THREAD_CHECKER(thread_checker_); + + DISALLOW_COPY_AND_ASSIGN(RemoteTestServerProxy); +}; + +} // namespace net + +#endif // NET_TEST_SPAWNED_TEST_SERVER_REMOTE_TEST_SERVER_PROXY_H_ diff --git a/chromium/net/test/spawned_test_server/remote_test_server_proxy_unittests.cc b/chromium/net/test/spawned_test_server/remote_test_server_proxy_unittests.cc new file mode 100644 index 00000000000..ddb623c13e0 --- /dev/null +++ b/chromium/net/test/spawned_test_server/remote_test_server_proxy_unittests.cc @@ -0,0 +1,148 @@ +// Copyright 2017 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/spawned_test_server/remote_test_server_proxy.h" + +#include "base/message_loop/message_loop.h" +#include "base/threading/thread.h" +#include "net/base/io_buffer.h" +#include "net/base/test_completion_callback.h" +#include "net/socket/tcp_client_socket.h" +#include "net/socket/tcp_server_socket.h" +#include "net/test/gtest_util.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using net::test::IsOk; + +namespace net { + +class RemoteTestServerProxyTest : public testing::Test { + public: + RemoteTestServerProxyTest() : io_thread_("RemoteTestServer IO Thread") { + EXPECT_TRUE(io_thread_.StartWithOptions( + base::Thread::Options(base::MessageLoop::TYPE_IO, 0))); + + listen_socket_ = + std::make_unique<TCPServerSocket>(nullptr, net::NetLogSource()); + int result = + listen_socket_->Listen(IPEndPoint(IPAddress::IPv4Localhost(), 0), 5); + EXPECT_THAT(result, IsOk()); + + // Get local address. + IPEndPoint address; + result = listen_socket_->GetLocalAddress(&address); + EXPECT_THAT(result, IsOk()); + + proxy_ = std::make_unique<RemoteTestServerProxy>(address, + io_thread_.task_runner()); + proxy_address_ = + IPEndPoint(IPAddress::IPv4Localhost(), proxy_->local_port()); + } + + void MakeConnection(std::unique_ptr<StreamSocket>* client_socket, + std::unique_ptr<StreamSocket>* server_socket) { + TestCompletionCallback connect_callback; + *client_socket = std::make_unique<TCPClientSocket>( + AddressList(proxy_address_), nullptr, nullptr, NetLogSource()); + int connect_result = (*client_socket)->Connect(connect_callback.callback()); + + TestCompletionCallback accept_callback; + int result = + listen_socket_->Accept(server_socket, accept_callback.callback()); + + ASSERT_THAT(connect_callback.GetResult(connect_result), IsOk()); + ASSERT_THAT(accept_callback.GetResult(result), IsOk()); + + EXPECT_TRUE((*server_socket)->IsConnected()); + EXPECT_TRUE((*client_socket)->IsConnected()); + } + + void SendAndReceiveData(StreamSocket* socket1, StreamSocket* socket2) { + // Send just one byte to ensure we will need only one Write() and only one + // Read(). + char test_message = '0'; + + scoped_refptr<IOBuffer> write_buffer = new IOBuffer(1); + *write_buffer->data() = test_message; + TestCompletionCallback write_callback; + int write_result = + socket1->Write(write_buffer.get(), 1, write_callback.callback()); + + scoped_refptr<IOBufferWithSize> read_buffer(new IOBufferWithSize(1024)); + TestCompletionCallback read_callback; + int read_result = socket2->Read(read_buffer.get(), read_buffer->size(), + read_callback.callback()); + + ASSERT_EQ(write_callback.GetResult(write_result), 1); + ASSERT_EQ(read_callback.GetResult(read_result), 1); + + EXPECT_EQ(test_message, *read_buffer->data()); + } + + void ExpectClosed(StreamSocket* socket) { + scoped_refptr<IOBufferWithSize> read_buffer(new IOBufferWithSize(1024)); + TestCompletionCallback read_callback; + int read_result = socket->Read(read_buffer.get(), read_buffer->size(), + read_callback.callback()); + + EXPECT_EQ(read_callback.GetResult(read_result), 0); + EXPECT_FALSE(socket->IsConnected()); + } + + protected: + base::Thread io_thread_; + + // Server socket that simulates testserver that RemoteTestServerProxy normally + // would connect to. + std::unique_ptr<TCPServerSocket> listen_socket_; + + std::unique_ptr<RemoteTestServerProxy> proxy_; + IPEndPoint proxy_address_; +}; + +TEST_F(RemoteTestServerProxyTest, SendAndReceive) { + std::unique_ptr<StreamSocket> client_socket; + std::unique_ptr<StreamSocket> server_socket; + MakeConnection(&client_socket, &server_socket); + SendAndReceiveData(client_socket.get(), server_socket.get()); + SendAndReceiveData(server_socket.get(), client_socket.get()); +} + +TEST_F(RemoteTestServerProxyTest, TwoConnections) { + std::unique_ptr<StreamSocket> client_socket1; + std::unique_ptr<StreamSocket> server_socket1; + MakeConnection(&client_socket1, &server_socket1); + + std::unique_ptr<StreamSocket> client_socket2; + std::unique_ptr<StreamSocket> server_socket2; + MakeConnection(&client_socket2, &server_socket2); + + SendAndReceiveData(client_socket1.get(), server_socket1.get()); + SendAndReceiveData(client_socket2.get(), server_socket2.get()); + SendAndReceiveData(server_socket1.get(), client_socket1.get()); + SendAndReceiveData(server_socket2.get(), client_socket2.get()); +} + +// Close socket on the server side and verify that it's closed on the client +// side. +TEST_F(RemoteTestServerProxyTest, DisconnectServer) { + std::unique_ptr<StreamSocket> client_socket; + std::unique_ptr<StreamSocket> server_socket; + MakeConnection(&client_socket, &server_socket); + server_socket.reset(); + ExpectClosed(client_socket.get()); +} + +// Close socket on the client side and verify that it's closed on the server +// side. +TEST_F(RemoteTestServerProxyTest, DisconnectClient) { + std::unique_ptr<StreamSocket> client_socket; + std::unique_ptr<StreamSocket> server_socket; + MakeConnection(&client_socket, &server_socket); + client_socket.reset(); + ExpectClosed(server_socket.get()); +} + +} // namespace net diff --git a/chromium/net/test/spawned_test_server/spawned_test_server.h b/chromium/net/test/spawned_test_server/spawned_test_server.h index aa4e37a7b38..47232ba1ffc 100644 --- a/chromium/net/test/spawned_test_server/spawned_test_server.h +++ b/chromium/net/test/spawned_test_server/spawned_test_server.h @@ -7,7 +7,7 @@ #include "build/build_config.h" -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_FUCHSIA) #include "net/test/spawned_test_server/remote_test_server.h" #else #include "net/test/spawned_test_server/local_test_server.h" @@ -15,7 +15,7 @@ namespace net { -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) || defined(OS_FUCHSIA) typedef RemoteTestServer SpawnedTestServer; #else typedef LocalTestServer SpawnedTestServer; diff --git a/chromium/net/test/spawned_test_server/spawner_communicator.cc b/chromium/net/test/spawned_test_server/spawner_communicator.cc index aac8d9d82da..89680456373 100644 --- a/chromium/net/test/spawned_test_server/spawner_communicator.cc +++ b/chromium/net/test/spawned_test_server/spawner_communicator.cc @@ -4,6 +4,8 @@ #include "net/test/spawned_test_server/spawner_communicator.h" +#include <inttypes.h> + #include <limits> #include <utility> @@ -11,7 +13,6 @@ #include "base/location.h" #include "base/logging.h" #include "base/macros.h" -#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/single_thread_task_runner.h" #include "base/strings/stringprintf.h" @@ -33,23 +34,15 @@ namespace net { namespace { -GURL GenerateSpawnerCommandURL(const std::string& command, uint16_t port) { - // Always performs HTTP request for sending command to the spawner server. - return GURL(base::StringPrintf("%s:%u/%s", "http://127.0.0.1", port, - command.c_str())); -} - int kBufferSize = 2048; // A class to hold all data needed to send a command to spawner server. class SpawnerRequestData : public base::SupportsUserData::Data { public: - SpawnerRequestData(int id, int* result_code, std::string* data_received) - : request_id_(id), - buf_(new IOBuffer(kBufferSize)), + SpawnerRequestData(int* result_code, std::string* data_received) + : buf_(new IOBuffer(kBufferSize)), result_code_(result_code), - data_received_(data_received), - response_started_count_(0) { + data_received_(data_received) { DCHECK(result_code); *result_code_ = OK; DCHECK(data_received); @@ -58,14 +51,11 @@ class SpawnerRequestData : public base::SupportsUserData::Data { ~SpawnerRequestData() override {} - bool DoesRequestIdMatch(int request_id) const { - return request_id_ == request_id; - } - IOBuffer* buf() const { return buf_.get(); } bool IsResultOK() const { return *result_code_ == OK; } + const std::string& data_received() const { return *data_received_; } void ClearReceivedData() { data_received_->clear(); } void SetResultCode(int result_code) { *result_code_ = result_code; } @@ -86,9 +76,6 @@ class SpawnerRequestData : public base::SupportsUserData::Data { } private: - // Unique ID for the current request. - int request_id_; - // Buffer that URLRequest writes into. scoped_refptr<IOBuffer> buf_; @@ -100,63 +87,56 @@ class SpawnerRequestData : public base::SupportsUserData::Data { // Used to track how many times the OnResponseStarted get called after // sending a command to spawner server. - int response_started_count_; + int response_started_count_ = 0; DISALLOW_COPY_AND_ASSIGN(SpawnerRequestData); }; } // namespace -SpawnerCommunicator::SpawnerCommunicator(uint16_t port) - : io_thread_("spawner_communicator"), +SpawnerCommunicator::SpawnerCommunicator(const RemoteTestServerConfig& config) + : config_(config), + io_thread_("spawner_communicator"), event_(base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED), - port_(port), - next_id_(0), - is_running_(false), - weak_factory_(this) {} + base::WaitableEvent::InitialState::NOT_SIGNALED) {} SpawnerCommunicator::~SpawnerCommunicator() { - DCHECK(!is_running_); + DCHECK(!io_thread_.IsRunning()); } void SpawnerCommunicator::WaitForResponse() { - DCHECK_NE(base::MessageLoop::current(), io_thread_.message_loop()); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); event_.Wait(); event_.Reset(); } void SpawnerCommunicator::StartIOThread() { - DCHECK_NE(base::MessageLoop::current(), io_thread_.message_loop()); - if (is_running_) + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (io_thread_.IsRunning()) return; - allowed_port_.reset(new ScopedPortException(port_)); - base::Thread::Options options; - options.message_loop_type = base::MessageLoop::TYPE_IO; - is_running_ = io_thread_.StartWithOptions(options); - DCHECK(is_running_); + bool thread_started = io_thread_.StartWithOptions( + base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); + DCHECK(thread_started); } void SpawnerCommunicator::Shutdown() { - DCHECK_NE(base::MessageLoop::current(), io_thread_.message_loop()); - DCHECK(is_running_); + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(io_thread_.IsRunning()); // The request and its context should be created and destroyed only on the // IO thread. DCHECK(!cur_request_.get()); DCHECK(!context_.get()); - is_running_ = false; io_thread_.Stop(); allowed_port_.reset(); } -void SpawnerCommunicator::SendCommandAndWaitForResult( +int SpawnerCommunicator::SendCommandAndWaitForResult( const std::string& command, const std::string& post_data, - int* result_code, std::string* data_received) { - if (!result_code || !data_received) - return; + DCHECK(data_received); + // Start the communicator thread to talk to test server spawner. StartIOThread(); DCHECK(io_thread_.message_loop()); @@ -164,12 +144,15 @@ void SpawnerCommunicator::SendCommandAndWaitForResult( // Since the method will be blocked until SpawnerCommunicator gets result // from the spawner server or timed-out. It's safe to use base::Unretained // when using base::Bind. + int result_code; io_thread_.task_runner()->PostTask( FROM_HERE, base::Bind(&SpawnerCommunicator::SendCommandAndWaitForResultOnIOThread, - base::Unretained(this), command, post_data, result_code, + base::Unretained(this), command, post_data, &result_code, data_received)); WaitForResponse(); + + return result_code; } void SpawnerCommunicator::SendCommandAndWaitForResultOnIOThread( @@ -177,20 +160,18 @@ void SpawnerCommunicator::SendCommandAndWaitForResultOnIOThread( const std::string& post_data, int* result_code, std::string* data_received) { - base::MessageLoop* loop = io_thread_.message_loop(); - DCHECK(loop); - DCHECK(loop->task_runner()->BelongsToCurrentThread()); + DCHECK(io_thread_.task_runner()->BelongsToCurrentThread()); // Prepare the URLRequest for sending the command. DCHECK(!cur_request_.get()); context_.reset(new TestURLRequestContext); - cur_request_ = context_->CreateRequest( - GenerateSpawnerCommandURL(command, port_), DEFAULT_PRIORITY, this); + GURL url = config_.GetSpawnerUrl(command); + allowed_port_ = std::make_unique<ScopedPortException>(url.EffectiveIntPort()); + cur_request_ = context_->CreateRequest(url, DEFAULT_PRIORITY, this); + DCHECK(cur_request_); - int current_request_id = ++next_id_; cur_request_->SetUserData( - this, base::MakeUnique<SpawnerRequestData>(current_request_id, - result_code, data_received)); + this, std::make_unique<SpawnerRequestData>(result_code, data_received)); if (post_data.empty()) { cur_request_->set_method("GET"); @@ -206,27 +187,22 @@ void SpawnerCommunicator::SendCommandAndWaitForResultOnIOThread( cur_request_->SetExtraRequestHeaders(headers); } - // Post a task to timeout this request if it takes too long. - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, base::Bind(&SpawnerCommunicator::OnTimeout, - weak_factory_.GetWeakPtr(), current_request_id), - TestTimeouts::action_max_timeout()); + timeout_timer_ = std::make_unique<base::OneShotTimer>(); + timeout_timer_->Start( + FROM_HERE, TestTimeouts::action_max_timeout(), + base::Bind(&SpawnerCommunicator::OnTimeout, base::Unretained(this))); // Start the request. cur_request_->Start(); } -void SpawnerCommunicator::OnTimeout(int id) { - // Timeout tasks may outlive the URLRequest they reference. Make sure it - // is still applicable. - if (!cur_request_.get()) - return; +void SpawnerCommunicator::OnTimeout() { + DCHECK(io_thread_.task_runner()->BelongsToCurrentThread()); + SpawnerRequestData* data = static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this)); DCHECK(data); - if (!data->DoesRequestIdMatch(id)) - return; // Set the result code and cancel the timed-out task. int result = cur_request_->CancelWithError(ERR_TIMED_OUT); OnSpawnerCommandCompleted(cur_request_.get(), result); @@ -234,6 +210,7 @@ void SpawnerCommunicator::OnTimeout(int id) { void SpawnerCommunicator::OnSpawnerCommandCompleted(URLRequest* request, int net_error) { + DCHECK(io_thread_.task_runner()->BelongsToCurrentThread()); DCHECK_NE(ERR_IO_PENDING, net_error); if (!cur_request_.get()) @@ -243,30 +220,36 @@ void SpawnerCommunicator::OnSpawnerCommandCompleted(URLRequest* request, static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this)); DCHECK(data); - // If request is faild,return the error code. - if (net_error != OK) + // If request has failed, return the error code. + if (net_error != OK) { + LOG(ERROR) << "request failed, error: " << ErrorToString(net_error); data->SetResultCode(net_error); + } else if (request->GetResponseCode() != 200) { + LOG(ERROR) << "Spawner server returned bad status: " + << request->response_headers()->GetStatusLine() << ", " + << data->data_received(); + data->SetResultCode(ERR_FAILED); + } else { + DCHECK_EQ(1, data->response_started_count()); + } if (!data->IsResultOK()) { - LOG(ERROR) << "request failed, error: " << net_error; // Clear the buffer of received data if any net error happened. data->ClearReceivedData(); - } else { - DCHECK_EQ(1, data->response_started_count()); } // Clear current request to indicate the completion of sending a command // to spawner server and getting the result. cur_request_.reset(); context_.reset(); - // Invalidate the weak pointers on the IO thread. - weak_factory_.InvalidateWeakPtrs(); + timeout_timer_.reset(); // Wakeup the caller in user thread. event_.Signal(); } void SpawnerCommunicator::ReadResult(URLRequest* request) { + DCHECK(io_thread_.task_runner()->BelongsToCurrentThread()); DCHECK_EQ(request, cur_request_.get()); SpawnerRequestData* data = static_cast<SpawnerRequestData*>(cur_request_->GetUserData(this)); @@ -293,6 +276,7 @@ void SpawnerCommunicator::ReadResult(URLRequest* request) { void SpawnerCommunicator::OnResponseStarted(URLRequest* request, int net_error) { + DCHECK(io_thread_.task_runner()->BelongsToCurrentThread()); DCHECK_EQ(request, cur_request_.get()); DCHECK_NE(ERR_IO_PENDING, net_error); @@ -307,20 +291,11 @@ void SpawnerCommunicator::OnResponseStarted(URLRequest* request, return; } - // Require HTTP responses to have a success status code. - if (request->GetResponseCode() != 200) { - LOG(ERROR) << "Spawner server returned bad status: " - << request->response_headers()->GetStatusLine(); - data->SetResultCode(ERR_FAILED); - request->Cancel(); - OnSpawnerCommandCompleted(request, ERR_ABORTED); - return; - } - ReadResult(request); } void SpawnerCommunicator::OnReadCompleted(URLRequest* request, int num_bytes) { + DCHECK(io_thread_.task_runner()->BelongsToCurrentThread()); DCHECK_NE(ERR_IO_PENDING, num_bytes); if (!cur_request_.get()) @@ -341,56 +316,29 @@ void SpawnerCommunicator::OnReadCompleted(URLRequest* request, int num_bytes) { } bool SpawnerCommunicator::StartServer(const std::string& arguments, - uint16_t* port) { - *port = 0; + std::string* server_data) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // Send the start command to spawner server to start the Python test server // on remote machine. - std::string server_return_data; - int result_code; - SendCommandAndWaitForResult("start", arguments, &result_code, - &server_return_data); - if (OK != result_code || server_return_data.empty()) - return false; - - // Check whether the data returned from spawner server is JSON-formatted. - std::unique_ptr<base::Value> value = - base::JSONReader::Read(server_return_data); - if (!value.get() || !value->IsType(base::Value::Type::DICTIONARY)) { - LOG(ERROR) << "Invalid server data: " << server_return_data.c_str(); - return false; - } - - // Check whether spawner server returns valid data. - base::DictionaryValue* server_data = - static_cast<base::DictionaryValue*>(value.get()); - std::string message; - if (!server_data->GetString("message", &message) || message != "started") { - LOG(ERROR) << "Invalid message in server data: "; - return false; - } - int int_port; - if (!server_data->GetInteger("port", &int_port) || int_port <= 0 || - int_port > std::numeric_limits<uint16_t>::max()) { - LOG(ERROR) << "Invalid port value: " << int_port; - return false; - } - *port = static_cast<uint16_t>(int_port); - return true; + int result = SendCommandAndWaitForResult("start", arguments, server_data); + return result == OK; } -bool SpawnerCommunicator::StopServer() { +bool SpawnerCommunicator::StopServer(uint16_t port) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); // It's OK to stop the SpawnerCommunicator without starting it. Some tests // have test server on their test fixture but do not actually use it. - if (!is_running_) + if (!io_thread_.IsRunning()) return true; // When the test is done, ask the test server spawner to kill the test server // on the remote machine. std::string server_return_data; - int result_code; - SendCommandAndWaitForResult("kill", "", &result_code, &server_return_data); + std::string command = base::StringPrintf("kill?port=%" PRIu16, port); + int result = + SendCommandAndWaitForResult(command, std::string(), &server_return_data); Shutdown(); - if (OK != result_code || server_return_data != "killed") + if (result != OK || server_return_data != "killed") return false; return true; } diff --git a/chromium/net/test/spawned_test_server/spawner_communicator.h b/chromium/net/test/spawned_test_server/spawner_communicator.h index e70b6eadb24..958cc79433c 100644 --- a/chromium/net/test/spawned_test_server/spawner_communicator.h +++ b/chromium/net/test/spawned_test_server/spawner_communicator.h @@ -11,11 +11,16 @@ #include <string> #include "base/macros.h" -#include "base/memory/weak_ptr.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread.h" +#include "base/threading/thread_checker.h" +#include "net/test/spawned_test_server/remote_test_server_config.h" #include "net/url_request/url_request.h" +namespace base { +class OneShotTimer; +} // namespace base + namespace net { class ScopedPortException; @@ -48,7 +53,7 @@ class ScopedPortException; // (2) Kill Python test server, format is: // Path: "/kill". // Method: "GET". -// Data to server: None. +// Data to server: port=<server_port>. // Data from server: String "killed" returned if success. // // (3) Ping Python test server to see whether it is alive, format is: @@ -62,17 +67,15 @@ class ScopedPortException; // fetched from spawner server or timed-out. class SpawnerCommunicator : public URLRequest::Delegate { public: - explicit SpawnerCommunicator(uint16_t port); + explicit SpawnerCommunicator(const RemoteTestServerConfig& config); ~SpawnerCommunicator() override; - // Starts an instance of the Python test server on the host/ machine. - // If successfully started, returns true, setting |*port| to the port - // on the local machine that can be used to communicate with the remote - // test server. + // Starts an instance of the Python test server on the host/ machine.If + // successfully started, returns true, setting |*server_data| to the server + // data returned by the spawner. bool StartServer(const std::string& arguments, - uint16_t* port) WARN_UNUSED_RESULT; - - bool StopServer() WARN_UNUSED_RESULT; + std::string* server_data) WARN_UNUSED_RESULT; + bool StopServer(uint16_t port) WARN_UNUSED_RESULT; private: // Starts the IO thread. Called on the user thread. @@ -84,16 +87,13 @@ class SpawnerCommunicator : public URLRequest::Delegate { // Waits for the server response on IO thread. Called on the user thread. void WaitForResponse(); - // Sends a command to the test server over HTTP, returning the result code - // |*result_code| and response data in |*data_received|, those two arguments - // must be not NULL, otherwise the method returns immediately without sending - // the |command|. If |post_data| is empty, HTTP GET will be used to send - // |command|. If |post_data| is non-empty, performs an HTTP POST. - // This method is called on the user thread. - void SendCommandAndWaitForResult(const std::string& command, - const std::string& post_data, - int* result_code, - std::string* data_received); + // Sends a command to the test server over HTTP, returning response data in + // |*data_received|, which must not be nullptr. If |post_data| is empty, HTTP + // GET will be used to send |command|. If |post_data| is non-empty, performs + // an HTTP POST. This method is called on the user thread. + int SendCommandAndWaitForResult(const std::string& command, + const std::string& post_data, + std::string* data_received); // Performs the command sending on the IO thread. Called on the IO thread. void SendCommandAndWaitForResultOnIOThread(const std::string& command, @@ -111,8 +111,10 @@ class SpawnerCommunicator : public URLRequest::Delegate { // Called on the IO thread upon completion of the spawner command. void OnSpawnerCommandCompleted(URLRequest* request, int net_error); - // Callback on the IO thread for time-out task of request with id |id|. - void OnTimeout(int id); + // Timeout timer task. Runs on IO thread. + void OnTimeout(); + + const RemoteTestServerConfig config_; // A thread to communicate with test_spawner server. base::Thread io_thread_; @@ -120,30 +122,19 @@ class SpawnerCommunicator : public URLRequest::Delegate { // WaitableEvent to notify whether the communication is done. base::WaitableEvent event_; - // The local port used to communicate with the TestServer spawner. This is - // used to control the startup and shutdown of the Python TestServer running - // on the remote machine. On Android, this port will be redirected to the - // same port on the host machine. - const uint16_t port_; - - // Helper to add |port_| to the list of the globally explicitly allowed ports. + // Helper to add spawner port to the list of the globally explicitly allowed + // ports. std::unique_ptr<ScopedPortException> allowed_port_; - // The next ID to use for |cur_request_| (monotonically increasing). - int next_id_; - // Request context used by |cur_request_|. std::unique_ptr<URLRequestContext> context_; // The current (in progress) request, or NULL. std::unique_ptr<URLRequest> cur_request_; - // Only gets/sets |is_running_| on user's thread to avoid race-condition. - bool is_running_; + std::unique_ptr<base::OneShotTimer> timeout_timer_; - // Factory for creating the time-out task. This takes care of revoking - // outstanding tasks when |this| is deleted. - base::WeakPtrFactory<SpawnerCommunicator> weak_factory_; + THREAD_CHECKER(thread_checker_); DISALLOW_COPY_AND_ASSIGN(SpawnerCommunicator); }; diff --git a/chromium/net/test/test_data_directory.cc b/chromium/net/test/test_data_directory.cc index f751751c5db..b5c4574e6c8 100644 --- a/chromium/net/test/test_data_directory.cc +++ b/chromium/net/test/test_data_directory.cc @@ -37,11 +37,7 @@ base::FilePath GetTestCertsDirectory() { } base::FilePath GetTestClientCertsDirectory() { -#if defined(OS_ANDROID) return base::FilePath(kNetDataRelativePath).Append(kCertificateDataSubPath); -#else - return GetTestCertsDirectory(); -#endif } base::FilePath GetWebSocketTestDataDirectory() { diff --git a/chromium/net/test/test_data_directory.h b/chromium/net/test/test_data_directory.h index 790c5c4ad38..f7ab7ee9ccd 100644 --- a/chromium/net/test/test_data_directory.h +++ b/chromium/net/test/test_data_directory.h @@ -17,10 +17,10 @@ base::FilePath GetTestNetDataDirectory(); // tree that contains certificates for testing. base::FilePath GetTestCertsDirectory(); -// Returns the base::FilePath object representing the path to client -// certificate files to be used in the |client_authorities| list -// of a net::SSLConfig object. For all other uses, use -// GetTestCertsDirectory() instead. +// Returns the base::FilePath to client certificate directory, relative to the +// source tree root. It should be used to set |client_authorities| list of a +// net::SSLConfig object. For all other uses, use GetTestCertsDirectory() +// instead. base::FilePath GetTestClientCertsDirectory(); // Returns the base::FilePath object representing the relative path containing diff --git a/chromium/net/test/url_request/url_request_hanging_read_job.cc b/chromium/net/test/url_request/url_request_hanging_read_job.cc index 5e36dc11e5c..2c947c884bb 100644 --- a/chromium/net/test/url_request/url_request_hanging_read_job.cc +++ b/chromium/net/test/url_request/url_request_hanging_read_job.cc @@ -97,9 +97,9 @@ void URLRequestHangingReadJob::AddUrlHandler() { // Add |hostname| to URLRequestFilter for HTTP and HTTPS. URLRequestFilter* filter = URLRequestFilter::GetInstance(); filter->AddHostnameInterceptor("http", kMockHostname, - base::MakeUnique<MockJobInterceptor>()); + std::make_unique<MockJobInterceptor>()); filter->AddHostnameInterceptor("https", kMockHostname, - base::MakeUnique<MockJobInterceptor>()); + std::make_unique<MockJobInterceptor>()); } // static 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 index e984b070aee..f526a35a67e 100644 --- a/chromium/net/test/url_request/url_request_mock_data_job.cc +++ b/chromium/net/test/url_request/url_request_mock_data_job.cc @@ -177,9 +177,9 @@ void URLRequestMockDataJob::AddUrlHandlerForHostname( // Add |hostname| to URLRequestFilter for HTTP and HTTPS. URLRequestFilter* filter = URLRequestFilter::GetInstance(); filter->AddHostnameInterceptor("http", hostname, - base::MakeUnique<MockJobInterceptor>()); + std::make_unique<MockJobInterceptor>()); filter->AddHostnameInterceptor("https", hostname, - base::MakeUnique<MockJobInterceptor>()); + std::make_unique<MockJobInterceptor>()); } // static |