From 9368185ec8fa36d1f9e678802b9af597df3c2297 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Fri, 29 Jul 2022 12:34:30 -0400 Subject: [PATCH] Add CefTestServer that supports both HTTP and HTTPS (see issue #3348) --- BUILD.gn | 3 + cef_paths.gypi | 16 +- cef_paths2.gypi | 1 + include/capi/test/cef_test_server_capi.h | 194 ++++ include/cef_api_hash.h | 8 +- include/test/cef_test_server.h | 181 ++++ libcef/browser/test/test_server_impl.cc | 270 +++++ libcef/browser/test/test_server_impl.h | 39 + .../test/test_server_connection_cpptoc.cc | 152 +++ .../test/test_server_connection_cpptoc.h | 38 + libcef_dll/cpptoc/test/test_server_cpptoc.cc | 104 ++ libcef_dll/cpptoc/test/test_server_cpptoc.h | 37 + .../cpptoc/test/test_server_handler_cpptoc.cc | 88 ++ .../cpptoc/test/test_server_handler_cpptoc.h | 38 + .../test/test_server_connection_ctocpp.cc | 146 +++ .../test/test_server_connection_ctocpp.h | 50 + libcef_dll/ctocpp/test/test_server_ctocpp.cc | 98 ++ libcef_dll/ctocpp/test/test_server_ctocpp.h | 41 + .../ctocpp/test/test_server_handler_ctocpp.cc | 83 ++ .../ctocpp/test/test_server_handler_ctocpp.h | 44 + libcef_dll/wrapper/libcef_dll_dylib.cc | 14 +- libcef_dll/wrapper_types.h | 5 +- patch/patch.cfg | 5 + patch/patches/net_test_server_3798752.patch | 22 + tests/ceftests/test_server_unittest.cc | 967 ++++++++++++++++++ 25 files changed, 2637 insertions(+), 7 deletions(-) create mode 100644 include/capi/test/cef_test_server_capi.h create mode 100644 include/test/cef_test_server.h create mode 100644 libcef/browser/test/test_server_impl.cc create mode 100644 libcef/browser/test/test_server_impl.h create mode 100644 libcef_dll/cpptoc/test/test_server_connection_cpptoc.cc create mode 100644 libcef_dll/cpptoc/test/test_server_connection_cpptoc.h create mode 100644 libcef_dll/cpptoc/test/test_server_cpptoc.cc create mode 100644 libcef_dll/cpptoc/test/test_server_cpptoc.h create mode 100644 libcef_dll/cpptoc/test/test_server_handler_cpptoc.cc create mode 100644 libcef_dll/cpptoc/test/test_server_handler_cpptoc.h create mode 100644 libcef_dll/ctocpp/test/test_server_connection_ctocpp.cc create mode 100644 libcef_dll/ctocpp/test/test_server_connection_ctocpp.h create mode 100644 libcef_dll/ctocpp/test/test_server_ctocpp.cc create mode 100644 libcef_dll/ctocpp/test/test_server_ctocpp.h create mode 100644 libcef_dll/ctocpp/test/test_server_handler_ctocpp.cc create mode 100644 libcef_dll/ctocpp/test/test_server_handler_ctocpp.h create mode 100644 patch/patches/net_test_server_3798752.patch create mode 100644 tests/ceftests/test_server_unittest.cc diff --git a/BUILD.gn b/BUILD.gn index 94b3645d2..da12645a7 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -420,11 +420,14 @@ source_set("libcef_test_support") { testonly = true sources = [ + "libcef/browser/test/test_server_impl.cc", + "libcef/browser/test/test_server_impl.h", "libcef/common/test/translator_test_impl.cc", ] deps = [ ":libcef_static", + "//net:test_support", # Support for UI input events. "//ui/views:test_support", diff --git a/cef_paths.gypi b/cef_paths.gypi index c0caf6ff8..07f6e8af9 100644 --- a/cef_paths.gypi +++ b/cef_paths.gypi @@ -8,7 +8,7 @@ # by hand. See the translator.README.txt file in the tools directory for # more information. # -# $hash=3ed1afd1b5f881884e6cfd0186fe41bb7b19fd38$ +# $hash=ffc0502a0275b74228f1fd642566d3f020e538a0$ # { @@ -92,6 +92,7 @@ 'include/cef_xml_reader.h', 'include/cef_zip_reader.h', 'include/test/cef_test_helpers.h', + 'include/test/cef_test_server.h', 'include/test/cef_translator_test.h', 'include/views/cef_box_layout.h', 'include/views/cef_browser_view.h', @@ -194,6 +195,7 @@ 'include/capi/cef_xml_reader_capi.h', 'include/capi/cef_zip_reader_capi.h', 'include/capi/test/cef_test_helpers_capi.h', + 'include/capi/test/cef_test_server_capi.h', 'include/capi/test/cef_translator_test_capi.h', 'include/capi/views/cef_box_layout_capi.h', 'include/capi/views/cef_browser_view_capi.h', @@ -462,6 +464,12 @@ 'libcef_dll/ctocpp/task_ctocpp.h', 'libcef_dll/cpptoc/task_runner_cpptoc.cc', 'libcef_dll/cpptoc/task_runner_cpptoc.h', + 'libcef_dll/cpptoc/test/test_server_cpptoc.cc', + 'libcef_dll/cpptoc/test/test_server_cpptoc.h', + 'libcef_dll/cpptoc/test/test_server_connection_cpptoc.cc', + 'libcef_dll/cpptoc/test/test_server_connection_cpptoc.h', + 'libcef_dll/ctocpp/test/test_server_handler_ctocpp.cc', + 'libcef_dll/ctocpp/test/test_server_handler_ctocpp.h', 'libcef_dll/cpptoc/views/textfield_cpptoc.cc', 'libcef_dll/cpptoc/views/textfield_cpptoc.h', 'libcef_dll/ctocpp/views/textfield_delegate_ctocpp.cc', @@ -780,6 +788,12 @@ 'libcef_dll/cpptoc/task_cpptoc.h', 'libcef_dll/ctocpp/task_runner_ctocpp.cc', 'libcef_dll/ctocpp/task_runner_ctocpp.h', + 'libcef_dll/ctocpp/test/test_server_ctocpp.cc', + 'libcef_dll/ctocpp/test/test_server_ctocpp.h', + 'libcef_dll/ctocpp/test/test_server_connection_ctocpp.cc', + 'libcef_dll/ctocpp/test/test_server_connection_ctocpp.h', + 'libcef_dll/cpptoc/test/test_server_handler_cpptoc.cc', + 'libcef_dll/cpptoc/test/test_server_handler_cpptoc.h', 'libcef_dll/ctocpp/views/textfield_ctocpp.cc', 'libcef_dll/ctocpp/views/textfield_ctocpp.h', 'libcef_dll/cpptoc/views/textfield_delegate_cpptoc.cc', diff --git a/cef_paths2.gypi b/cef_paths2.gypi index 37e83ab5f..a24501279 100644 --- a/cef_paths2.gypi +++ b/cef_paths2.gypi @@ -533,6 +533,7 @@ 'tests/ceftests/test_server_runner.cc', 'tests/ceftests/test_server_runner_normal.cc', 'tests/ceftests/test_server_runner_test.cc', + 'tests/ceftests/test_server_unittest.cc', 'tests/ceftests/test_suite.cc', 'tests/ceftests/test_suite.h', 'tests/ceftests/test_util.cc', diff --git a/include/capi/test/cef_test_server_capi.h b/include/capi/test/cef_test_server_capi.h new file mode 100644 index 000000000..0b43d6583 --- /dev/null +++ b/include/capi/test/cef_test_server_capi.h @@ -0,0 +1,194 @@ +// Copyright (c) 2022 Marshall A. Greenblatt. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the name Chromium Embedded +// Framework nor the names of its contributors may be used to endorse +// or promote products derived from this software without specific prior +// written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool and should not edited +// by hand. See the translator.README.txt file in the tools directory for +// more information. +// +// $hash=e95435aed845767b3c7253547d253cabe44f88cb$ +// + +#ifndef CEF_INCLUDE_CAPI_TEST_CEF_TEST_SERVER_CAPI_H_ +#define CEF_INCLUDE_CAPI_TEST_CEF_TEST_SERVER_CAPI_H_ +#pragma once + +#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \ + !defined(UNIT_TEST) +#error This file can be included for unit tests only +#endif + +#include "include/capi/cef_base_capi.h" +#include "include/capi/cef_request_capi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct _cef_test_server_connection_t; +struct _cef_test_server_handler_t; + +/// +// Structure representing an embedded test server that supports HTTP/HTTPS +// requests. This is a basic server providing only an essential subset of the +// HTTP/1.1 protocol. Especially, it assumes that the request syntax is correct. +// It *does not* support a Chunked Transfer Encoding. Server capacity is limited +// and is intended to handle only a small number of simultaneous connections +// (e.g. for communicating between applications on localhost). The functions of +// this structure are safe to call from any thread in the brower process unless +// otherwise indicated. +/// +typedef struct _cef_test_server_t { + /// + // Base structure. + /// + cef_base_ref_counted_t base; + + /// + // Stop the server and shut down the dedicated server thread. This function + // must be called on the same thread as CreateAndStart. It will block until + // the dedicated server thread has shut down. + /// + void(CEF_CALLBACK* stop)(struct _cef_test_server_t* self); + + /// + // Returns the server origin including the port number (e.g. + // "[http|https]://127.0.0.1:". + /// + // The resulting string must be freed by calling cef_string_userfree_free(). + cef_string_userfree_t(CEF_CALLBACK* get_origin)( + struct _cef_test_server_t* self); +} cef_test_server_t; + +/// +// Create and start a new test server that binds to |port|. If |port| is 0 an +// available port number will be selected. If |https_server| is true (1) the +// server will be HTTPS, otherwise it will be HTTP. Returns the newly created +// server object on success, or nullptr if the server cannot be started. +// +// A new thread will be created for each CreateAndStart call (the "dedicated +// server thread"). It is therefore recommended to use a different +// cef_test_server_handler_t instance for each CreateAndStart call to avoid +// thread safety issues in the cef_test_server_handler_t implementation. +// +// On success, this function will block until the dedicated server thread has +// started. The server will continue running until Stop is called. +/// +CEF_EXPORT cef_test_server_t* cef_test_server_create_and_start( + uint16 port, + int https_server, + struct _cef_test_server_handler_t* handler); + +/// +// Implement this structure to handle test server requests. A new thread will be +// created for each cef_test_server_t::CreateAndStart call (the "dedicated +// server thread"), and the functions of this structure will be called on that +// thread. See related documentation on cef_test_server_t::CreateAndStart. +/// +typedef struct _cef_test_server_handler_t { + /// + // Base structure. + /// + cef_base_ref_counted_t base; + + /// + // Called when |server| receives a request. To handle the request return true + // (1) and use |connection| to send the response either synchronously or + // asynchronously. Otherwise, return false (0) if the request is unhandled. + // When returning false (0) do not call any |connection| functions. + /// + int(CEF_CALLBACK* on_test_server_request)( + struct _cef_test_server_handler_t* self, + struct _cef_test_server_t* server, + struct _cef_request_t* request, + struct _cef_test_server_connection_t* connection); +} cef_test_server_handler_t; + +/// +// Structure representing a test server connection. The functions of this +// structure are safe to call from any thread in the brower process unless +// otherwise indicated. +/// +typedef struct _cef_test_server_connection_t { + /// + // Base structure. + /// + cef_base_ref_counted_t base; + + /// + // Send an HTTP 200 "OK" response. |content_type| is the response content type + // (e.g. "text/html"). |data| is the response content and |data_size| is the + // size of |data| in bytes. The contents of |data| will be copied. The + // connection will be closed automatically after the response is sent. + /// + void(CEF_CALLBACK* send_http200response)( + struct _cef_test_server_connection_t* self, + const cef_string_t* content_type, + const void* data, + size_t data_size); + + /// + // Send an HTTP 404 "Not Found" response. The connection will be closed + // automatically after the response is sent. + /// + void(CEF_CALLBACK* send_http404response)( + struct _cef_test_server_connection_t* self); + + /// + // Send an HTTP 500 "Internal Server Error" response. |error_message| is the + // associated error message. The connection will be closed automatically after + // the response is sent. + /// + void(CEF_CALLBACK* send_http500response)( + struct _cef_test_server_connection_t* self, + const cef_string_t* error_message); + + /// + // Send a custom HTTP response. |response_code| is the HTTP response code sent + // in the status line (e.g. 200). |content_type| is the response content type + // (e.g. "text/html"). |data| is the response content and |data_size| is the + // size of |data| in bytes. The contents of |data| will be copied. + // |extra_headers| is an optional map of additional header key/value pairs. + // The connection will be closed automatically after the response is sent. + /// + void(CEF_CALLBACK* send_http_response)( + struct _cef_test_server_connection_t* self, + int response_code, + const cef_string_t* content_type, + const void* data, + size_t data_size, + cef_string_multimap_t extra_headers); +} cef_test_server_connection_t; + +#ifdef __cplusplus +} +#endif + +#endif // CEF_INCLUDE_CAPI_TEST_CEF_TEST_SERVER_CAPI_H_ diff --git a/include/cef_api_hash.h b/include/cef_api_hash.h index 1a7536200..15df38240 100644 --- a/include/cef_api_hash.h +++ b/include/cef_api_hash.h @@ -42,13 +42,13 @@ // way that may cause binary incompatibility with other builds. The universal // hash value will change if any platform is affected whereas the platform hash // values will change only if that particular platform is affected. -#define CEF_API_HASH_UNIVERSAL "0a10c7f55cfae29a42269f384be6cf146b173e41" +#define CEF_API_HASH_UNIVERSAL "75e20201c2d8df3e03f2c8e285d348ef9748ec52" #if defined(OS_WIN) -#define CEF_API_HASH_PLATFORM "e867a338bca4b75fefaf7a8f9db88b23d3491521" +#define CEF_API_HASH_PLATFORM "8ade85f2430574759f46159d4e1b58758d7e69c8" #elif defined(OS_MAC) -#define CEF_API_HASH_PLATFORM "44255a9eaf170ae120ee53a45a98fe89aadee9b6" +#define CEF_API_HASH_PLATFORM "3cd04d7d724ad382f1647b93b81e3ab59ab18db6" #elif defined(OS_LINUX) -#define CEF_API_HASH_PLATFORM "38388c135e2f855789db0e073bfb63093a0507ac" +#define CEF_API_HASH_PLATFORM "1fe0b7b127d115c74650d21a408cfa08d83418e8" #endif #ifdef __cplusplus diff --git a/include/test/cef_test_server.h b/include/test/cef_test_server.h new file mode 100644 index 000000000..03edce497 --- /dev/null +++ b/include/test/cef_test_server.h @@ -0,0 +1,181 @@ +// Copyright (c) 2022 Marshall A. Greenblatt. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the name Chromium Embedded +// Framework nor the names of its contributors may be used to endorse +// or promote products derived from this software without specific prior +// written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// --------------------------------------------------------------------------- +// +// The contents of this file must follow a specific format in order to +// support the CEF translator tool. See the translator.README.txt file in the +// tools directory for more information. +// +// THIS FILE IS FOR TESTING PURPOSES ONLY. +// +// The APIs defined in this file are for testing purposes only. They should only +// be included from unit test targets. +// + +#ifndef CEF_INCLUDE_TEST_CEF_TEST_SERVER_H_ +#define CEF_INCLUDE_TEST_CEF_TEST_SERVER_H_ +#pragma once + +#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \ + !defined(UNIT_TEST) +#error This file can be included for unit tests only +#endif + +#include +#include "include/cef_base.h" +#include "include/cef_request.h" + +class CefTestServerConnection; +class CefTestServerHandler; + +/// +// Class representing an embedded test server that supports HTTP/HTTPS requests. +// This is a basic server providing only an essential subset of the HTTP/1.1 +// protocol. Especially, it assumes that the request syntax is correct. It *does +// not* support a Chunked Transfer Encoding. Server capacity is limited and is +// intended to handle only a small number of simultaneous connections (e.g. for +// communicating between applications on localhost). The methods of this class +// are safe to call from any thread in the brower process unless otherwise +// indicated. +/// +/*--cef(source=library)--*/ +class CefTestServer : public CefBaseRefCounted { + public: + /// + // Create and start a new test server that binds to |port|. If |port| is 0 an + // available port number will be selected. If |https_server| is true the + // server will be HTTPS, otherwise it will be HTTP. Returns the newly created + // server object on success, or nullptr if the server cannot be started. + // + // A new thread will be created for each CreateAndStart call (the "dedicated + // server thread"). It is therefore recommended to use a different + // CefTestServerHandler instance for each CreateAndStart call to avoid thread + // safety issues in the CefTestServerHandler implementation. + // + // On success, this method will block until the dedicated server thread has + // started. The server will continue running until Stop is called. + /// + /*--cef()--*/ + static CefRefPtr CreateAndStart( + uint16 port, + bool https_server, + CefRefPtr handler); + + /// + // Stop the server and shut down the dedicated server thread. This method must + // be called on the same thread as CreateAndStart. It will block until the + // dedicated server thread has shut down. + /// + /*--cef()--*/ + virtual void Stop() = 0; + + /// + // Returns the server origin including the port number (e.g. + // "[http|https]://127.0.0.1:". + /// + /*--cef()--*/ + virtual CefString GetOrigin() = 0; +}; + +/// +// Implement this interface to handle test server requests. A new thread will be +// created for each CefTestServer::CreateAndStart call (the "dedicated server +// thread"), and the methods of this class will be called on that thread. See +// related documentation on CefTestServer::CreateAndStart. +/// +/*--cef(source=client)--*/ +class CefTestServerHandler : public virtual CefBaseRefCounted { + public: + /// + // Called when |server| receives a request. To handle the request return true + // and use |connection| to send the response either synchronously or + // asynchronously. Otherwise, return false if the request is unhandled. When + // returning false do not call any |connection| methods. + /// + /*--cef()--*/ + virtual bool OnTestServerRequest( + CefRefPtr server, + CefRefPtr request, + CefRefPtr connection) = 0; +}; + +/// +// Class representing a test server connection. The methods of this class are +// safe to call from any thread in the brower process unless otherwise +// indicated. +/// +/*--cef(source=library)--*/ +class CefTestServerConnection : public CefBaseRefCounted { + public: + typedef std::multimap HeaderMap; + + /// + // Send an HTTP 200 "OK" response. |content_type| is the response content type + // (e.g. "text/html"). |data| is the response content and |data_size| is the + // size of |data| in bytes. The contents of |data| will be copied. The + // connection will be closed automatically after the response is sent. + /// + /*--cef()--*/ + virtual void SendHttp200Response(const CefString& content_type, + const void* data, + size_t data_size) = 0; + + /// + // Send an HTTP 404 "Not Found" response. The connection will be closed + // automatically after the response is sent. + /// + /*--cef()--*/ + virtual void SendHttp404Response() = 0; + + /// + // Send an HTTP 500 "Internal Server Error" response. |error_message| is the + // associated error message. The connection will be closed automatically after + // the response is sent. + /// + /*--cef()--*/ + virtual void SendHttp500Response(const CefString& error_message) = 0; + + /// + // Send a custom HTTP response. |response_code| is the HTTP response code sent + // in the status line (e.g. 200). |content_type| is the response content type + // (e.g. "text/html"). |data| is the response content and |data_size| is the + // size of |data| in bytes. The contents of |data| will be copied. + // |extra_headers| is an optional map of additional header key/value pairs. + // The connection will be closed automatically after the response is sent. + /// + /*--cef(optional_param=extra_headers)--*/ + virtual void SendHttpResponse(int response_code, + const CefString& content_type, + const void* data, + size_t data_size, + const HeaderMap& extra_headers) = 0; +}; + +#endif // CEF_INCLUDE_TEST_CEF_TEST_SERVER_H_ diff --git a/libcef/browser/test/test_server_impl.cc b/libcef/browser/test/test_server_impl.cc new file mode 100644 index 000000000..582f7066e --- /dev/null +++ b/libcef/browser/test/test_server_impl.cc @@ -0,0 +1,270 @@ +// Copyright 2022 The Chromium Embedded Framework 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 "libcef/browser/test/test_server_impl.h" + +#include "libcef/common/net/http_header_utils.h" + +#include "base/logging.h" +#include "base/strings/string_util.h" +#include "base/threading/thread_checker.h" +#include "base/threading/thread_task_runner_handle.h" +#include "net/http/http_request_headers.h" +#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/test/embedded_test_server/http_response.h" + +using namespace net::test_server; + +namespace { + +class CefTestServerConnectionImpl : public CefTestServerConnection { + public: + explicit CefTestServerConnectionImpl( + base::WeakPtr delegate) + : delegate_(delegate), task_runner_(base::ThreadTaskRunnerHandle::Get()) { + DCHECK(delegate_); + DCHECK(task_runner_); + } + + void SendHttp200Response(const CefString& content_type, + const void* data, + size_t data_size) override { + auto response = std::make_unique(); + response->set_code(net::HTTP_OK); + response->set_content_type(base::StringPiece(content_type.ToString())); + response->set_content( + base::StringPiece(reinterpret_cast(data), data_size)); + SendBasicHttpResponse(std::move(response)); + } + + void SendHttp404Response() override { + auto response = std::make_unique(); + response->set_code(net::HTTP_NOT_FOUND); + SendBasicHttpResponse(std::move(response)); + } + + void SendHttp500Response(const CefString& error_message) override { + auto response = std::make_unique(); + response->set_code(net::HTTP_INTERNAL_SERVER_ERROR); + response->set_content_type(base::StringPiece("text/html")); + response->set_content(base::StringPiece(error_message.ToString())); + SendBasicHttpResponse(std::move(response)); + } + + void SendHttpResponse(int response_code, + const CefString& content_type, + const void* data, + size_t data_size, + const HeaderMap& extra_headers) override { + auto response = std::make_unique(); + response->set_code(static_cast(response_code)); + response->set_content_type(base::StringPiece(content_type.ToString())); + response->set_content( + base::StringPiece(reinterpret_cast(data), data_size)); + for (const auto& [key, value] : extra_headers) { + response->AddCustomHeader(key.ToString(), value.ToString()); + } + SendBasicHttpResponse(std::move(response)); + } + + private: + void SendBasicHttpResponse(std::unique_ptr response) { + if (!task_runner_->BelongsToCurrentThread()) { + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&CefTestServerConnectionImpl::SendBasicHttpResponse, + this, std::move(response))); + return; + } + + if (delegate_) { + response->SendResponse(delegate_); + } + } + + base::WeakPtr delegate_; + scoped_refptr task_runner_; + + IMPLEMENT_REFCOUNTING(CefTestServerConnectionImpl); +}; + +class CefHttpResponse : public HttpResponse { + public: + CefHttpResponse(CefRefPtr server, + CefRefPtr handler, + CefRefPtr request) + : server_(server), handler_(handler), request_(request) { + DCHECK(server_); + DCHECK(handler_); + DCHECK(request_); + } + + CefHttpResponse(const CefHttpResponse&) = delete; + CefHttpResponse& operator=(const CefHttpResponse&) = delete; + + void SendResponse(base::WeakPtr delegate) override { + CefRefPtr connection( + new CefTestServerConnectionImpl(delegate)); + const bool handled = + handler_->OnTestServerRequest(server_, request_, connection.get()); + if (handled) + return; + + LOG(WARNING) << "Request not handled. Returning 404: " + << request_->GetURL().ToString(); + connection->SendHttp404Response(); + } + + private: + CefRefPtr server_; + CefRefPtr handler_; + CefRefPtr request_; +}; + +CefRefPtr CreateCefRequest(const HttpRequest& request) { + CefRefPtr post_data; + if (!request.content.empty()) { + post_data = CefPostData::Create(); + auto element = CefPostDataElement::Create(); + element->SetToBytes(request.content.size(), request.content.c_str()); + post_data->AddElement(element); + } + + CefRequest::HeaderMap header_map; + CefString referer; + + HttpHeaderUtils::ParseHeaders(request.all_headers, header_map); + + // CefRequest will strip the Referer header from the map, so we don't need to + // do that here. + for (const auto& [key, value] : header_map) { + if (base::EqualsCaseInsensitiveASCII(key.ToString(), + net::HttpRequestHeaders::kReferer)) { + referer = value; + } + } + + auto cef_request = CefRequest::Create(); + cef_request->Set(request.GetURL().spec(), request.method_string, post_data, + header_map); + if (!referer.empty()) + cef_request->SetReferrer(referer, REFERRER_POLICY_DEFAULT); + return cef_request; +} + +} // namespace + +class CefTestServerImpl::Context { + public: + Context(CefRefPtr server, + CefRefPtr handler) + : server_(server), handler_(handler) { + DCHECK(server_); + DCHECK(handler_); + } + + Context(const Context&) = delete; + Context& operator=(const Context&) = delete; + + ~Context() { + // The server should not be running. + DCHECK(!test_server_); + } + + bool Start(uint16 port, bool https_server) { + DCHECK(thread_checker_.CalledOnValidThread()); + + DCHECK(!test_server_); + test_server_ = std::make_unique( + https_server ? EmbeddedTestServer::TYPE_HTTPS + : EmbeddedTestServer::TYPE_HTTP); + + // Unretained is safe because Stop is called before |this| is destroyed. + test_server_->RegisterRequestHandler( + base::BindRepeating(&Context::HandleRequest, base::Unretained(this))); + + test_server_handle_ = + test_server_->StartAndReturnHandle(static_cast(port)); + if (!test_server_handle_) { + test_server_.reset(); + return false; + } + + origin_ = test_server_->base_url(); + return true; + } + + void Stop() { + // Should be called on the creation thread. + DCHECK(thread_checker_.CalledOnValidThread()); + + DCHECK(test_server_); + + // Destruction of |test_server_handle_| will stop the server and block until + // the dedicated server thread has shut down. + test_server_handle_ = EmbeddedTestServerHandle(); + test_server_.reset(); + + server_ = nullptr; + handler_ = nullptr; + } + + const GURL& origin() const { return origin_; } + + private: + std::unique_ptr HandleRequest(const HttpRequest& request) { + // Should be on the dedicated server thread. + DCHECK(!thread_checker_.CalledOnValidThread()); + return std::make_unique(server_, handler_, + CreateCefRequest(request)); + } + + // Safe to access on any thread. + CefRefPtr server_; + CefRefPtr handler_; + GURL origin_; + + base::ThreadChecker thread_checker_; + + // Only accessed on the creation thread. + std::unique_ptr test_server_; + EmbeddedTestServerHandle test_server_handle_; +}; + +bool CefTestServerImpl::Start(uint16 port, + bool https_server, + CefRefPtr handler) { + DCHECK(!context_); + context_ = std::make_unique(this, handler); + if (context_->Start(port, https_server)) { + const auto& origin = context_->origin().spec(); + // Remove the trailing '/' + origin_ = origin.substr(0, origin.length() - 1); + return true; + } + + context_.reset(); + return false; +} + +void CefTestServerImpl::Stop() { + DCHECK(context_); + context_->Stop(); + context_.reset(); +} + +CefString CefTestServerImpl::GetOrigin() { + return origin_; +} + +// static +CefRefPtr CefTestServer::CreateAndStart( + uint16 port, + bool https_server, + CefRefPtr handler) { + CefRefPtr server(new CefTestServerImpl()); + if (server->Start(port, https_server, handler)) + return server; + return nullptr; +} diff --git a/libcef/browser/test/test_server_impl.h b/libcef/browser/test/test_server_impl.h new file mode 100644 index 000000000..9ed6da20d --- /dev/null +++ b/libcef/browser/test/test_server_impl.h @@ -0,0 +1,39 @@ +// Copyright 2022 The Chromium Embedded Framework 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 CEF_LIBCEF_BROWSER_TEST_TEST_SERVER_IMPL_H_ +#define CEF_LIBCEF_BROWSER_TEST_TEST_SERVER_IMPL_H_ +#pragma once + +#include + +#include "include/test/cef_test_server.h" + +class CefTestServerImpl : public CefTestServer { + public: + CefTestServerImpl() = default; + + CefTestServerImpl(const CefTestServerImpl&) = delete; + CefTestServerImpl& operator=(const CefTestServerImpl&) = delete; + + bool Start(uint16 port, + bool https_server, + CefRefPtr handler); + + // CefTestServer methods: + void Stop() override; + CefString GetOrigin() override; + + private: + // Only accessed on the creation thread. + class Context; + std::unique_ptr context_; + + // Safe to access on any thread. + CefString origin_; + + IMPLEMENT_REFCOUNTING(CefTestServerImpl); +}; + +#endif // CEF_LIBCEF_BROWSER_TEST_TEST_SERVER_IMPL_H_ diff --git a/libcef_dll/cpptoc/test/test_server_connection_cpptoc.cc b/libcef_dll/cpptoc/test/test_server_connection_cpptoc.cc new file mode 100644 index 000000000..64526aca8 --- /dev/null +++ b/libcef_dll/cpptoc/test/test_server_connection_cpptoc.cc @@ -0,0 +1,152 @@ +// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=4015c7179f87d58159252275559c0a11ee9958c7$ +// + +#include "libcef_dll/cpptoc/test/test_server_connection_cpptoc.h" +#include "libcef_dll/shutdown_checker.h" +#include "libcef_dll/transfer_util.h" + +namespace { + +// MEMBER FUNCTIONS - Body may be edited by hand. + +void CEF_CALLBACK test_server_connection_send_http200response( + struct _cef_test_server_connection_t* self, + const cef_string_t* content_type, + const void* data, + size_t data_size) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: content_type; type: string_byref_const + DCHECK(content_type); + if (!content_type) + return; + // Verify param: data; type: simple_byaddr + DCHECK(data); + if (!data) + return; + + // Execute + CefTestServerConnectionCppToC::Get(self)->SendHttp200Response( + CefString(content_type), data, data_size); +} + +void CEF_CALLBACK test_server_connection_send_http404response( + struct _cef_test_server_connection_t* self) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefTestServerConnectionCppToC::Get(self)->SendHttp404Response(); +} + +void CEF_CALLBACK test_server_connection_send_http500response( + struct _cef_test_server_connection_t* self, + const cef_string_t* error_message) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: error_message; type: string_byref_const + DCHECK(error_message); + if (!error_message) + return; + + // Execute + CefTestServerConnectionCppToC::Get(self)->SendHttp500Response( + CefString(error_message)); +} + +void CEF_CALLBACK test_server_connection_send_http_response( + struct _cef_test_server_connection_t* self, + int response_code, + const cef_string_t* content_type, + const void* data, + size_t data_size, + cef_string_multimap_t extra_headers) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: content_type; type: string_byref_const + DCHECK(content_type); + if (!content_type) + return; + // Verify param: data; type: simple_byaddr + DCHECK(data); + if (!data) + return; + // Unverified params: extra_headers + + // Translate param: extra_headers; type: string_map_multi_byref_const + std::multimap extra_headersMultimap; + transfer_string_multimap_contents(extra_headers, extra_headersMultimap); + + // Execute + CefTestServerConnectionCppToC::Get(self)->SendHttpResponse( + response_code, CefString(content_type), data, data_size, + extra_headersMultimap); +} + +} // namespace + +// CONSTRUCTOR - Do not edit by hand. + +CefTestServerConnectionCppToC::CefTestServerConnectionCppToC() { + GetStruct()->send_http200response = + test_server_connection_send_http200response; + GetStruct()->send_http404response = + test_server_connection_send_http404response; + GetStruct()->send_http500response = + test_server_connection_send_http500response; + GetStruct()->send_http_response = test_server_connection_send_http_response; +} + +// DESTRUCTOR - Do not edit by hand. + +CefTestServerConnectionCppToC::~CefTestServerConnectionCppToC() { + shutdown_checker::AssertNotShutdown(); +} + +template <> +CefRefPtr CefCppToCRefCounted< + CefTestServerConnectionCppToC, + CefTestServerConnection, + cef_test_server_connection_t>::UnwrapDerived(CefWrapperType type, + cef_test_server_connection_t* + s) { + NOTREACHED() << "Unexpected class type: " << type; + return nullptr; +} + +template <> +CefWrapperType CefCppToCRefCounted::kWrapperType = + WT_TEST_SERVER_CONNECTION; diff --git a/libcef_dll/cpptoc/test/test_server_connection_cpptoc.h b/libcef_dll/cpptoc/test/test_server_connection_cpptoc.h new file mode 100644 index 000000000..6c7036213 --- /dev/null +++ b/libcef_dll/cpptoc/test/test_server_connection_cpptoc.h @@ -0,0 +1,38 @@ +// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=253d69f93a8637dad0b6d90f8993617694d40732$ +// + +#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_CONNECTION_CPPTOC_H_ +#define CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_CONNECTION_CPPTOC_H_ +#pragma once + +#if !defined(BUILDING_CEF_SHARED) +#error This file can be included DLL-side only +#endif + +#include "include/capi/test/cef_test_server_capi.h" +#include "include/test/cef_test_server.h" +#include "libcef_dll/cpptoc/cpptoc_ref_counted.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed DLL-side only. +class CefTestServerConnectionCppToC + : public CefCppToCRefCounted { + public: + CefTestServerConnectionCppToC(); + virtual ~CefTestServerConnectionCppToC(); +}; + +#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_CONNECTION_CPPTOC_H_ diff --git a/libcef_dll/cpptoc/test/test_server_cpptoc.cc b/libcef_dll/cpptoc/test/test_server_cpptoc.cc new file mode 100644 index 000000000..7d0f04795 --- /dev/null +++ b/libcef_dll/cpptoc/test/test_server_cpptoc.cc @@ -0,0 +1,104 @@ +// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=ff1da376e035d2eda9050f4d68b39b9e7e7d368e$ +// + +#include "libcef_dll/cpptoc/test/test_server_cpptoc.h" +#include "libcef_dll/ctocpp/test/test_server_handler_ctocpp.h" +#include "libcef_dll/shutdown_checker.h" + +// GLOBAL FUNCTIONS - Body may be edited by hand. + +CEF_EXPORT cef_test_server_t* cef_test_server_create_and_start( + uint16 port, + int https_server, + struct _cef_test_server_handler_t* handler) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: handler; type: refptr_diff + DCHECK(handler); + if (!handler) + return NULL; + + // Execute + CefRefPtr _retval = + CefTestServer::CreateAndStart(port, https_server ? true : false, + CefTestServerHandlerCToCpp::Wrap(handler)); + + // Return type: refptr_same + return CefTestServerCppToC::Wrap(_retval); +} + +namespace { + +// MEMBER FUNCTIONS - Body may be edited by hand. + +void CEF_CALLBACK test_server_stop(struct _cef_test_server_t* self) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + + // Execute + CefTestServerCppToC::Get(self)->Stop(); +} + +cef_string_userfree_t CEF_CALLBACK +test_server_get_origin(struct _cef_test_server_t* self) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return NULL; + + // Execute + CefString _retval = CefTestServerCppToC::Get(self)->GetOrigin(); + + // Return type: string + return _retval.DetachToUserFree(); +} + +} // namespace + +// CONSTRUCTOR - Do not edit by hand. + +CefTestServerCppToC::CefTestServerCppToC() { + GetStruct()->stop = test_server_stop; + GetStruct()->get_origin = test_server_get_origin; +} + +// DESTRUCTOR - Do not edit by hand. + +CefTestServerCppToC::~CefTestServerCppToC() { + shutdown_checker::AssertNotShutdown(); +} + +template <> +CefRefPtr +CefCppToCRefCounted:: + UnwrapDerived(CefWrapperType type, cef_test_server_t* s) { + NOTREACHED() << "Unexpected class type: " << type; + return nullptr; +} + +template <> +CefWrapperType CefCppToCRefCounted::kWrapperType = + WT_TEST_SERVER; diff --git a/libcef_dll/cpptoc/test/test_server_cpptoc.h b/libcef_dll/cpptoc/test/test_server_cpptoc.h new file mode 100644 index 000000000..177a9b9d7 --- /dev/null +++ b/libcef_dll/cpptoc/test/test_server_cpptoc.h @@ -0,0 +1,37 @@ +// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=bd5e875346e2fe779bdfda2e9e3caad228689ac1$ +// + +#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_CPPTOC_H_ +#define CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_CPPTOC_H_ +#pragma once + +#if !defined(BUILDING_CEF_SHARED) +#error This file can be included DLL-side only +#endif + +#include "include/capi/test/cef_test_server_capi.h" +#include "include/test/cef_test_server.h" +#include "libcef_dll/cpptoc/cpptoc_ref_counted.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed DLL-side only. +class CefTestServerCppToC : public CefCppToCRefCounted { + public: + CefTestServerCppToC(); + virtual ~CefTestServerCppToC(); +}; + +#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_CPPTOC_H_ diff --git a/libcef_dll/cpptoc/test/test_server_handler_cpptoc.cc b/libcef_dll/cpptoc/test/test_server_handler_cpptoc.cc new file mode 100644 index 000000000..2568dbdef --- /dev/null +++ b/libcef_dll/cpptoc/test/test_server_handler_cpptoc.cc @@ -0,0 +1,88 @@ +// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=7cd3cda97645c531a682b0dfefe33c4c94802dc9$ +// + +#include "libcef_dll/cpptoc/test/test_server_handler_cpptoc.h" +#include "libcef_dll/ctocpp/request_ctocpp.h" +#include "libcef_dll/ctocpp/test/test_server_connection_ctocpp.h" +#include "libcef_dll/ctocpp/test/test_server_ctocpp.h" +#include "libcef_dll/shutdown_checker.h" + +namespace { + +// MEMBER FUNCTIONS - Body may be edited by hand. + +int CEF_CALLBACK test_server_handler_on_test_server_request( + struct _cef_test_server_handler_t* self, + cef_test_server_t* server, + cef_request_t* request, + struct _cef_test_server_connection_t* connection) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return 0; + // Verify param: server; type: refptr_diff + DCHECK(server); + if (!server) + return 0; + // Verify param: request; type: refptr_diff + DCHECK(request); + if (!request) + return 0; + // Verify param: connection; type: refptr_diff + DCHECK(connection); + if (!connection) + return 0; + + // Execute + bool _retval = CefTestServerHandlerCppToC::Get(self)->OnTestServerRequest( + CefTestServerCToCpp::Wrap(server), CefRequestCToCpp::Wrap(request), + CefTestServerConnectionCToCpp::Wrap(connection)); + + // Return type: bool + return _retval; +} + +} // namespace + +// CONSTRUCTOR - Do not edit by hand. + +CefTestServerHandlerCppToC::CefTestServerHandlerCppToC() { + GetStruct()->on_test_server_request = + test_server_handler_on_test_server_request; +} + +// DESTRUCTOR - Do not edit by hand. + +CefTestServerHandlerCppToC::~CefTestServerHandlerCppToC() { + shutdown_checker::AssertNotShutdown(); +} + +template <> +CefRefPtr CefCppToCRefCounted< + CefTestServerHandlerCppToC, + CefTestServerHandler, + cef_test_server_handler_t>::UnwrapDerived(CefWrapperType type, + cef_test_server_handler_t* s) { + NOTREACHED() << "Unexpected class type: " << type; + return nullptr; +} + +template <> +CefWrapperType CefCppToCRefCounted::kWrapperType = + WT_TEST_SERVER_HANDLER; diff --git a/libcef_dll/cpptoc/test/test_server_handler_cpptoc.h b/libcef_dll/cpptoc/test/test_server_handler_cpptoc.h new file mode 100644 index 000000000..f000cdde5 --- /dev/null +++ b/libcef_dll/cpptoc/test/test_server_handler_cpptoc.h @@ -0,0 +1,38 @@ +// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=c1e57c3ad143ac617900ced69827b02e19f9234e$ +// + +#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_HANDLER_CPPTOC_H_ +#define CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_HANDLER_CPPTOC_H_ +#pragma once + +#if !defined(WRAPPING_CEF_SHARED) +#error This file can be included wrapper-side only +#endif + +#include "include/capi/test/cef_test_server_capi.h" +#include "include/test/cef_test_server.h" +#include "libcef_dll/cpptoc/cpptoc_ref_counted.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed wrapper-side only. +class CefTestServerHandlerCppToC + : public CefCppToCRefCounted { + public: + CefTestServerHandlerCppToC(); + virtual ~CefTestServerHandlerCppToC(); +}; + +#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_HANDLER_CPPTOC_H_ diff --git a/libcef_dll/ctocpp/test/test_server_connection_ctocpp.cc b/libcef_dll/ctocpp/test/test_server_connection_ctocpp.cc new file mode 100644 index 000000000..ece305502 --- /dev/null +++ b/libcef_dll/ctocpp/test/test_server_connection_ctocpp.cc @@ -0,0 +1,146 @@ +// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=7b5fb7ede3a40321b3e077fa1aa1cd09ad2478d0$ +// + +#include "libcef_dll/ctocpp/test/test_server_connection_ctocpp.h" +#include "libcef_dll/shutdown_checker.h" +#include "libcef_dll/transfer_util.h" + +// VIRTUAL METHODS - Body may be edited by hand. + +NO_SANITIZE("cfi-icall") +void CefTestServerConnectionCToCpp::SendHttp200Response( + const CefString& content_type, + const void* data, + size_t data_size) { + shutdown_checker::AssertNotShutdown(); + + cef_test_server_connection_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, send_http200response)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: content_type; type: string_byref_const + DCHECK(!content_type.empty()); + if (content_type.empty()) + return; + // Verify param: data; type: simple_byaddr + DCHECK(data); + if (!data) + return; + + // Execute + _struct->send_http200response(_struct, content_type.GetStruct(), data, + data_size); +} + +NO_SANITIZE("cfi-icall") +void CefTestServerConnectionCToCpp::SendHttp404Response() { + shutdown_checker::AssertNotShutdown(); + + cef_test_server_connection_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, send_http404response)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + _struct->send_http404response(_struct); +} + +NO_SANITIZE("cfi-icall") +void CefTestServerConnectionCToCpp::SendHttp500Response( + const CefString& error_message) { + shutdown_checker::AssertNotShutdown(); + + cef_test_server_connection_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, send_http500response)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: error_message; type: string_byref_const + DCHECK(!error_message.empty()); + if (error_message.empty()) + return; + + // Execute + _struct->send_http500response(_struct, error_message.GetStruct()); +} + +NO_SANITIZE("cfi-icall") +void CefTestServerConnectionCToCpp::SendHttpResponse( + int response_code, + const CefString& content_type, + const void* data, + size_t data_size, + const HeaderMap& extra_headers) { + shutdown_checker::AssertNotShutdown(); + + cef_test_server_connection_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, send_http_response)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: content_type; type: string_byref_const + DCHECK(!content_type.empty()); + if (content_type.empty()) + return; + // Verify param: data; type: simple_byaddr + DCHECK(data); + if (!data) + return; + // Unverified params: extra_headers + + // Translate param: extra_headers; type: string_map_multi_byref_const + cef_string_multimap_t extra_headersMultimap = cef_string_multimap_alloc(); + DCHECK(extra_headersMultimap); + if (extra_headersMultimap) + transfer_string_multimap_contents(extra_headers, extra_headersMultimap); + + // Execute + _struct->send_http_response(_struct, response_code, content_type.GetStruct(), + data, data_size, extra_headersMultimap); + + // Restore param:extra_headers; type: string_map_multi_byref_const + if (extra_headersMultimap) + cef_string_multimap_free(extra_headersMultimap); +} + +// CONSTRUCTOR - Do not edit by hand. + +CefTestServerConnectionCToCpp::CefTestServerConnectionCToCpp() {} + +// DESTRUCTOR - Do not edit by hand. + +CefTestServerConnectionCToCpp::~CefTestServerConnectionCToCpp() { + shutdown_checker::AssertNotShutdown(); +} + +template <> +cef_test_server_connection_t* CefCToCppRefCounted< + CefTestServerConnectionCToCpp, + CefTestServerConnection, + cef_test_server_connection_t>::UnwrapDerived(CefWrapperType type, + CefTestServerConnection* c) { + NOTREACHED() << "Unexpected class type: " << type; + return nullptr; +} + +template <> +CefWrapperType CefCToCppRefCounted::kWrapperType = + WT_TEST_SERVER_CONNECTION; diff --git a/libcef_dll/ctocpp/test/test_server_connection_ctocpp.h b/libcef_dll/ctocpp/test/test_server_connection_ctocpp.h new file mode 100644 index 000000000..818843c0c --- /dev/null +++ b/libcef_dll/ctocpp/test/test_server_connection_ctocpp.h @@ -0,0 +1,50 @@ +// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=f216ade0a1b147a5ec5dce9b7196c6cbaa4cb637$ +// + +#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_CONNECTION_CTOCPP_H_ +#define CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_CONNECTION_CTOCPP_H_ +#pragma once + +#if !defined(WRAPPING_CEF_SHARED) +#error This file can be included wrapper-side only +#endif + +#include "include/capi/test/cef_test_server_capi.h" +#include "include/test/cef_test_server.h" +#include "libcef_dll/ctocpp/ctocpp_ref_counted.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed wrapper-side only. +class CefTestServerConnectionCToCpp + : public CefCToCppRefCounted { + public: + CefTestServerConnectionCToCpp(); + virtual ~CefTestServerConnectionCToCpp(); + + // CefTestServerConnection methods. + void SendHttp200Response(const CefString& content_type, + const void* data, + size_t data_size) override; + void SendHttp404Response() override; + void SendHttp500Response(const CefString& error_message) override; + void SendHttpResponse(int response_code, + const CefString& content_type, + const void* data, + size_t data_size, + const HeaderMap& extra_headers) override; +}; + +#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_CONNECTION_CTOCPP_H_ diff --git a/libcef_dll/ctocpp/test/test_server_ctocpp.cc b/libcef_dll/ctocpp/test/test_server_ctocpp.cc new file mode 100644 index 000000000..e9e8c409f --- /dev/null +++ b/libcef_dll/ctocpp/test/test_server_ctocpp.cc @@ -0,0 +1,98 @@ +// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=3cb71639ce1fb2986ca0d8ff437b0264d550d784$ +// + +#include "libcef_dll/ctocpp/test/test_server_ctocpp.h" +#include "libcef_dll/cpptoc/test/test_server_handler_cpptoc.h" +#include "libcef_dll/shutdown_checker.h" + +// STATIC METHODS - Body may be edited by hand. + +NO_SANITIZE("cfi-icall") +CefRefPtr CefTestServer::CreateAndStart( + uint16 port, + bool https_server, + CefRefPtr handler) { + shutdown_checker::AssertNotShutdown(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: handler; type: refptr_diff + DCHECK(handler.get()); + if (!handler.get()) + return nullptr; + + // Execute + cef_test_server_t* _retval = cef_test_server_create_and_start( + port, https_server, CefTestServerHandlerCppToC::Wrap(handler)); + + // Return type: refptr_same + return CefTestServerCToCpp::Wrap(_retval); +} + +// VIRTUAL METHODS - Body may be edited by hand. + +NO_SANITIZE("cfi-icall") void CefTestServerCToCpp::Stop() { + shutdown_checker::AssertNotShutdown(); + + cef_test_server_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, stop)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + _struct->stop(_struct); +} + +NO_SANITIZE("cfi-icall") CefString CefTestServerCToCpp::GetOrigin() { + shutdown_checker::AssertNotShutdown(); + + cef_test_server_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, get_origin)) + return CefString(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_string_userfree_t _retval = _struct->get_origin(_struct); + + // Return type: string + CefString _retvalStr; + _retvalStr.AttachToUserFree(_retval); + return _retvalStr; +} + +// CONSTRUCTOR - Do not edit by hand. + +CefTestServerCToCpp::CefTestServerCToCpp() {} + +// DESTRUCTOR - Do not edit by hand. + +CefTestServerCToCpp::~CefTestServerCToCpp() { + shutdown_checker::AssertNotShutdown(); +} + +template <> +cef_test_server_t* +CefCToCppRefCounted:: + UnwrapDerived(CefWrapperType type, CefTestServer* c) { + NOTREACHED() << "Unexpected class type: " << type; + return nullptr; +} + +template <> +CefWrapperType CefCToCppRefCounted::kWrapperType = + WT_TEST_SERVER; diff --git a/libcef_dll/ctocpp/test/test_server_ctocpp.h b/libcef_dll/ctocpp/test/test_server_ctocpp.h new file mode 100644 index 000000000..ddb244414 --- /dev/null +++ b/libcef_dll/ctocpp/test/test_server_ctocpp.h @@ -0,0 +1,41 @@ +// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=19937e8e0f9281513073c78b9152dd4afd3cc233$ +// + +#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_CTOCPP_H_ +#define CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_CTOCPP_H_ +#pragma once + +#if !defined(WRAPPING_CEF_SHARED) +#error This file can be included wrapper-side only +#endif + +#include "include/capi/test/cef_test_server_capi.h" +#include "include/test/cef_test_server.h" +#include "libcef_dll/ctocpp/ctocpp_ref_counted.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed wrapper-side only. +class CefTestServerCToCpp : public CefCToCppRefCounted { + public: + CefTestServerCToCpp(); + virtual ~CefTestServerCToCpp(); + + // CefTestServer methods. + void Stop() override; + CefString GetOrigin() override; +}; + +#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_CTOCPP_H_ diff --git a/libcef_dll/ctocpp/test/test_server_handler_ctocpp.cc b/libcef_dll/ctocpp/test/test_server_handler_ctocpp.cc new file mode 100644 index 000000000..6be9cf8d2 --- /dev/null +++ b/libcef_dll/ctocpp/test/test_server_handler_ctocpp.cc @@ -0,0 +1,83 @@ +// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=a57c9fca8e9dcf286cde0a82717b046e7e0a1ade$ +// + +#include "libcef_dll/ctocpp/test/test_server_handler_ctocpp.h" +#include "libcef_dll/cpptoc/request_cpptoc.h" +#include "libcef_dll/cpptoc/test/test_server_connection_cpptoc.h" +#include "libcef_dll/cpptoc/test/test_server_cpptoc.h" +#include "libcef_dll/shutdown_checker.h" + +// VIRTUAL METHODS - Body may be edited by hand. + +NO_SANITIZE("cfi-icall") +bool CefTestServerHandlerCToCpp::OnTestServerRequest( + CefRefPtr server, + CefRefPtr request, + CefRefPtr connection) { + shutdown_checker::AssertNotShutdown(); + + cef_test_server_handler_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, on_test_server_request)) + return false; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: server; type: refptr_diff + DCHECK(server.get()); + if (!server.get()) + return false; + // Verify param: request; type: refptr_diff + DCHECK(request.get()); + if (!request.get()) + return false; + // Verify param: connection; type: refptr_diff + DCHECK(connection.get()); + if (!connection.get()) + return false; + + // Execute + int _retval = _struct->on_test_server_request( + _struct, CefTestServerCppToC::Wrap(server), + CefRequestCppToC::Wrap(request), + CefTestServerConnectionCppToC::Wrap(connection)); + + // Return type: bool + return _retval ? true : false; +} + +// CONSTRUCTOR - Do not edit by hand. + +CefTestServerHandlerCToCpp::CefTestServerHandlerCToCpp() {} + +// DESTRUCTOR - Do not edit by hand. + +CefTestServerHandlerCToCpp::~CefTestServerHandlerCToCpp() { + shutdown_checker::AssertNotShutdown(); +} + +template <> +cef_test_server_handler_t* CefCToCppRefCounted< + CefTestServerHandlerCToCpp, + CefTestServerHandler, + cef_test_server_handler_t>::UnwrapDerived(CefWrapperType type, + CefTestServerHandler* c) { + NOTREACHED() << "Unexpected class type: " << type; + return nullptr; +} + +template <> +CefWrapperType CefCToCppRefCounted::kWrapperType = + WT_TEST_SERVER_HANDLER; diff --git a/libcef_dll/ctocpp/test/test_server_handler_ctocpp.h b/libcef_dll/ctocpp/test/test_server_handler_ctocpp.h new file mode 100644 index 000000000..a06ed46ed --- /dev/null +++ b/libcef_dll/ctocpp/test/test_server_handler_ctocpp.h @@ -0,0 +1,44 @@ +// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// +// $hash=5e5af6baf4b4a60e2d1569927c2142e1323ca37b$ +// + +#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_HANDLER_CTOCPP_H_ +#define CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_HANDLER_CTOCPP_H_ +#pragma once + +#if !defined(BUILDING_CEF_SHARED) +#error This file can be included DLL-side only +#endif + +#include "include/capi/test/cef_test_server_capi.h" +#include "include/test/cef_test_server.h" +#include "libcef_dll/ctocpp/ctocpp_ref_counted.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed DLL-side only. +class CefTestServerHandlerCToCpp + : public CefCToCppRefCounted { + public: + CefTestServerHandlerCToCpp(); + virtual ~CefTestServerHandlerCToCpp(); + + // CefTestServerHandler methods. + bool OnTestServerRequest( + CefRefPtr server, + CefRefPtr request, + CefRefPtr connection) override; +}; + +#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_HANDLER_CTOCPP_H_ diff --git a/libcef_dll/wrapper/libcef_dll_dylib.cc b/libcef_dll/wrapper/libcef_dll_dylib.cc index b81413cd3..937f5e359 100644 --- a/libcef_dll/wrapper/libcef_dll_dylib.cc +++ b/libcef_dll/wrapper/libcef_dll_dylib.cc @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=cd24810e169a9b119137caec3f864fdd6327c887$ +// $hash=5bba27a98f6ef56e7577c563084beb0f185cf164$ // #include @@ -52,6 +52,7 @@ #include "include/capi/cef_xml_reader_capi.h" #include "include/capi/cef_zip_reader_capi.h" #include "include/capi/test/cef_test_helpers_capi.h" +#include "include/capi/test/cef_test_server_capi.h" #include "include/capi/test/cef_translator_test_capi.h" #include "include/capi/views/cef_browser_view_capi.h" #include "include/capi/views/cef_display_capi.h" @@ -209,6 +210,7 @@ struct libcef_pointers { decltype(&cef_waitable_event_create) cef_waitable_event_create; decltype(&cef_xml_reader_create) cef_xml_reader_create; decltype(&cef_zip_reader_create) cef_zip_reader_create; + decltype(&cef_test_server_create_and_start) cef_test_server_create_and_start; decltype(&cef_translator_test_create) cef_translator_test_create; decltype(&cef_translator_test_ref_ptr_library_create) cef_translator_test_ref_ptr_library_create; @@ -422,6 +424,7 @@ int libcef_init_pointers(const char* path) { INIT_ENTRY(cef_waitable_event_create); INIT_ENTRY(cef_xml_reader_create); INIT_ENTRY(cef_zip_reader_create); + INIT_ENTRY(cef_test_server_create_and_start); INIT_ENTRY(cef_translator_test_create); INIT_ENTRY(cef_translator_test_ref_ptr_library_create); INIT_ENTRY(cef_translator_test_ref_ptr_library_child_create); @@ -1140,6 +1143,15 @@ struct _cef_zip_reader_t* cef_zip_reader_create( return g_libcef_pointers.cef_zip_reader_create(stream); } +NO_SANITIZE("cfi-icall") +struct _cef_test_server_t* cef_test_server_create_and_start( + uint16 port, + int https_server, + struct _cef_test_server_handler_t* handler) { + return g_libcef_pointers.cef_test_server_create_and_start(port, https_server, + handler); +} + NO_SANITIZE("cfi-icall") struct _cef_translator_test_t* cef_translator_test_create() { return g_libcef_pointers.cef_translator_test_create(); diff --git a/libcef_dll/wrapper_types.h b/libcef_dll/wrapper_types.h index 2e7cbb728..84028b423 100644 --- a/libcef_dll/wrapper_types.h +++ b/libcef_dll/wrapper_types.h @@ -9,7 +9,7 @@ // implementations. See the translator.README.txt file in the tools directory // for more information. // -// $hash=5e9ff0d723683c16009ad0c7c697ea461b653aaf$ +// $hash=15d99837c9ebf79df1d1ec2bab84900260410046$ // #ifndef CEF_LIBCEF_DLL_WRAPPER_TYPES_H_ @@ -141,6 +141,9 @@ enum CefWrapperType { WT_STRING_VISITOR, WT_TASK, WT_TASK_RUNNER, + WT_TEST_SERVER, + WT_TEST_SERVER_CONNECTION, + WT_TEST_SERVER_HANDLER, WT_TEXTFIELD, WT_TEXTFIELD_DELEGATE, WT_THREAD, diff --git a/patch/patch.cfg b/patch/patch.cfg index 5cdf70d90..539dcabe8 100644 --- a/patch/patch.cfg +++ b/patch/patch.cfg @@ -592,5 +592,10 @@ patches = [ # https://chromium-review.googlesource.com/c/linux-syscall-support/+/3786946/ 'name': 'linux_arm_1292951', 'path': 'third_party/lss', + }, + { + # Fix deadlock in EmbeddedTestServer::ShutdownAndWaitUntilComplete. + # https://chromium-review.googlesource.com/c/chromium/src/+/3798752 + 'name': 'net_test_server_3798752' } ] diff --git a/patch/patches/net_test_server_3798752.patch b/patch/patches/net_test_server_3798752.patch new file mode 100644 index 000000000..ce5c43e3c --- /dev/null +++ b/patch/patches/net_test_server_3798752.patch @@ -0,0 +1,22 @@ +diff --git net/test/embedded_test_server/embedded_test_server.cc net/test/embedded_test_server/embedded_test_server.cc +index 01233b6c48eb3..d5f8e53a499b1 100644 +--- net/test/embedded_test_server/embedded_test_server.cc ++++ net/test/embedded_test_server/embedded_test_server.cc +@@ -974,7 +974,7 @@ bool EmbeddedTestServer::PostTaskToIOThreadAndWait(base::OnceClosure closure) { + if (!base::CurrentThread::Get()) + temporary_loop = std::make_unique(); + +- base::RunLoop run_loop; ++ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); + if (!io_thread_->task_runner()->PostTaskAndReply( + FROM_HERE, std::move(closure), run_loop.QuitClosure())) { + return false; +@@ -1001,7 +1001,7 @@ bool EmbeddedTestServer::PostTaskToIOThreadAndWaitWithResult( + if (!base::CurrentThread::Get()) + temporary_loop = std::make_unique(); + +- base::RunLoop run_loop; ++ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); + bool task_result = false; + if (!base::PostTaskAndReplyWithResult( + io_thread_->task_runner().get(), FROM_HERE, std::move(task), diff --git a/tests/ceftests/test_server_unittest.cc b/tests/ceftests/test_server_unittest.cc new file mode 100644 index 000000000..28deb265e --- /dev/null +++ b/tests/ceftests/test_server_unittest.cc @@ -0,0 +1,967 @@ +// Copyright (c) 2022 The Chromium Embedded Framework 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 +#include +#include +#include + +#include "include/base/cef_callback.h" +#include "include/base/cef_ref_counted.h" +#include "include/cef_command_line.h" +#include "include/cef_task.h" +#include "include/cef_urlrequest.h" +#include "include/test/cef_test_server.h" +#include "include/wrapper/cef_closure_task.h" +#include "tests/ceftests/routing_test_handler.h" +#include "tests/ceftests/test_util.h" +#include "tests/gtest/include/gtest/gtest.h" + +namespace { + +const char kPlaceholderOrigin[] = "http://placeholder/"; +const int kTestTimeout = 5000; + +// Handles the test server. Used for both HTTP and HTTPS tests. +class TestServerHandler : public CefTestServerHandler { + public: + // HTTP test handler. + // The methods of this class are always executed on the server thread. + class HttpRequestHandler { + public: + virtual ~HttpRequestHandler() {} + virtual bool HandleRequest( + CefRefPtr server, + CefRefPtr request, + CefRefPtr connection) = 0; + virtual bool VerifyResults() = 0; + virtual std::string ToString() = 0; + }; + + using StartCallback = + base::OnceCallback; + + // |start_callback| will be executed on the UI thread after the server is + // started. + // |destroy_callback| will be executed on the UI thread after this handler + // object is destroyed. + TestServerHandler(StartCallback start_callback, + base::OnceClosure destroy_callback) + : initialized_(false), + start_callback_(std::move(start_callback)), + destroy_callback_(std::move(destroy_callback)), + expected_http_request_ct_(0), + actual_http_request_ct_(0) { + EXPECT_FALSE(destroy_callback_.is_null()); + } + + virtual ~TestServerHandler() { + EXPECT_UI_THREAD(); + std::move(destroy_callback_).Run(); + } + + // Must be called before CreateServer(). + void AddHttpRequestHandler( + std::unique_ptr request_handler) { + EXPECT_FALSE(initialized_); + EXPECT_TRUE(request_handler); + http_request_handler_list_.push_back(std::move(request_handler)); + } + + // Must be called before CreateServer(). + void SetExpectedHttpRequestCount(int expected) { + EXPECT_FALSE(initialized_); + expected_http_request_ct_ = expected; + } + + void CreateServer(bool https_server) { + EXPECT_FALSE(initialized_); + initialized_ = true; + https_server_ = https_server; + + // Blocks until the server is created. + server_ = CefTestServer::CreateAndStart(/*port=*/0, https_server, this); + + origin_ = server_->GetOrigin(); + EXPECT_TRUE(VerifyOrigin(origin_)); + + RunStartCallback(); + } + + // Results in a call to VerifyResults() and eventual execution of the + // |destroy_callback|. + void ShutdownServer() { + EXPECT_TRUE(server_); + server_->Stop(); + server_ = nullptr; + VerifyResults(); + } + + bool OnTestServerRequest( + CefRefPtr server, + CefRefPtr request, + CefRefPtr connection) override { + EXPECT_TRUE(server); + EXPECT_STREQ(origin_.c_str(), server->GetOrigin().ToString().c_str()); + + EXPECT_TRUE(request); + EXPECT_TRUE(VerifyRequest(request)); + + EXPECT_TRUE(connection); + + bool handled = false; + for (const auto& handler : http_request_handler_list_) { + handled = handler->HandleRequest(server, request, connection); + if (handled) + break; + } + EXPECT_TRUE(handled) << "missing HttpRequestHandler for " + << request->GetURL().ToString(); + + actual_http_request_ct_++; + + return handled; + } + + private: + bool VerifyOrigin(const std::string& origin) const { + V_DECLARE(); + V_EXPECT_TRUE(origin.find(https_server_ ? "https://" : "http://") == 0) + << "origin " << origin_; + V_RETURN(); + } + + bool VerifyRequest(CefRefPtr request) const { + V_DECLARE(); + + V_EXPECT_FALSE(request->GetMethod().empty()); + + const std::string& url = request->GetURL(); + V_EXPECT_FALSE(url.empty()); + V_EXPECT_TRUE(VerifyOrigin(url)) << "url " << url; + + CefRefPtr post_data = request->GetPostData(); + if (post_data) { + CefPostData::ElementVector elements; + post_data->GetElements(elements); + V_EXPECT_TRUE(elements.size() == 1); + V_EXPECT_TRUE(elements[0]->GetBytesCount() > 0U); + } + + V_RETURN(); + } + + void VerifyResults() const { + EXPECT_EQ(expected_http_request_ct_, actual_http_request_ct_); + + for (const auto& handler : http_request_handler_list_) { + EXPECT_TRUE(handler->VerifyResults()) + << "HttpRequestHandler for " << handler->ToString(); + } + } + + private: + void RunStartCallback() { + if (!CefCurrentlyOn(TID_UI)) { + CefPostTask(TID_UI, + base::BindOnce(&TestServerHandler::RunStartCallback, this)); + return; + } + + EXPECT_FALSE(start_callback_.is_null()); + std::move(start_callback_).Run(server_->GetOrigin()); + } + + CefRefPtr server_; + bool initialized_; + + // After initialization only accessed on the UI thread. + StartCallback start_callback_; + base::OnceClosure destroy_callback_; + + bool https_server_ = false; + std::string origin_; + + // After initialization the below members are only accessed on the server + // thread. + + std::list> http_request_handler_list_; + + int expected_http_request_ct_; + int actual_http_request_ct_; + + IMPLEMENT_REFCOUNTING(TestServerHandler); + DISALLOW_COPY_AND_ASSIGN(TestServerHandler); +}; + +// HTTP TESTS + +// Test runner for 1 or more HTTP requests/responses. +// Works similarly to TestHandler but without the CefClient dependencies. +class HttpTestRunner : public base::RefCountedThreadSafe { + public: + // The methods of this class are always executed on the UI thread. + class RequestRunner { + public: + virtual ~RequestRunner() {} + + // Create the server-side handler for the request. + virtual std::unique_ptr + CreateHttpRequestHandler() = 0; + + // Run the request and execute |complete_callback| on completion. + virtual void RunRequest(const std::string& server_origin, + base::OnceClosure complete_callback) = 0; + + virtual bool VerifyResults() = 0; + virtual std::string ToString() = 0; + }; + + // If |parallel_requests| is true all requests will be run at the same time, + // otherwise one request will be run at a time. + HttpTestRunner(bool https_server, bool parallel_requests) + : https_server_(https_server), parallel_requests_(parallel_requests) {} + + virtual ~HttpTestRunner() { + if (destroy_event_) + destroy_event_->Signal(); + } + + void AddRequestRunner(std::unique_ptr request_runner) { + EXPECT_FALSE(initialized_); + request_runner_map_.insert( + std::make_pair(++next_request_id_, request_runner.release())); + } + + // Blocks until the test has completed or timed out. + void ExecuteTest() { + EXPECT_FALSE(CefCurrentlyOn(TID_UI)); + + handler_ = new TestServerHandler( + base::BindOnce(&HttpTestRunner::OnServerStarted, this), + base::BindOnce(&HttpTestRunner::OnServerDestroyed, this)); + + run_event_ = CefWaitableEvent::CreateWaitableEvent(false, false); + + CefPostTask(TID_UI, base::BindOnce(&HttpTestRunner::RunTest, this)); + + // Block until test completion. + run_event_->Wait(); + } + + // Event that will be signaled from the HttpTestRunner destructor. + // Used by ReleaseAndWaitForDestructor. + void SetDestroyEvent(CefRefPtr event) { + destroy_event_ = event; + } + + private: + void RunTest() { + EXPECT_UI_THREAD(); + EXPECT_FALSE(initialized_); + initialized_ = true; + + EXPECT_FALSE(request_runner_map_.empty()); + RequestRunnerMap::const_iterator it = request_runner_map_.begin(); + for (; it != request_runner_map_.end(); ++it) { + handler_->AddHttpRequestHandler(it->second->CreateHttpRequestHandler()); + } + + handler_->SetExpectedHttpRequestCount( + static_cast(request_runner_map_.size())); + + handler_->CreateServer(https_server_); + + SetTestTimeout(kTestTimeout); + } + + void OnServerStarted(const std::string& server_origin) { + EXPECT_UI_THREAD(); + server_origin_ = server_origin; + if (parallel_requests_) { + RunAllRequests(); + } else { + RunNextRequest(); + } + } + + void OnServerDestroyed() { + EXPECT_UI_THREAD(); + EXPECT_FALSE(got_server_destroyed_); + got_server_destroyed_.yes(); + + // Allow the call stack to unwind. + CefPostTask(TID_UI, base::BindOnce(&HttpTestRunner::DestroyTest, this)); + } + + // Run all requests in parallel. + void RunAllRequests() { + RequestRunnerMap::const_iterator it = request_runner_map_.begin(); + for (; it != request_runner_map_.end(); ++it) { + it->second->RunRequest( + server_origin_, + base::BindOnce(&HttpTestRunner::OnRequestComplete, this, it->first)); + } + } + + // Run one request at a time. + void RunNextRequest() { + RequestRunnerMap::const_iterator it = request_runner_map_.begin(); + it->second->RunRequest( + server_origin_, + base::BindOnce(&HttpTestRunner::OnRequestComplete, this, it->first)); + } + + void OnRequestComplete(int request_id) { + EXPECT_UI_THREAD() + // Allow the call stack to unwind. + CefPostTask(TID_UI, + base::BindOnce(&HttpTestRunner::OnRequestCompleteContinue, this, + request_id)); + } + + void OnRequestCompleteContinue(int request_id) { + RequestRunnerMap::iterator it = request_runner_map_.find(request_id); + EXPECT_TRUE(it != request_runner_map_.end()); + + // Verify the request results. + EXPECT_TRUE(it->second->VerifyResults()) + << "request_id " << request_id << " RequestRunner for " + << it->second->ToString(); + delete it->second; + request_runner_map_.erase(it); + + if (request_runner_map_.empty()) { + got_all_requests_.yes(); + + // Will trigger TestServerHandler::HttpRequestHandler verification and a + // call to OnServerDestroyed(). + handler_->ShutdownServer(); + handler_ = nullptr; + } else if (!parallel_requests_) { + RunNextRequest(); + } + } + + void DestroyTest() { + EXPECT_UI_THREAD(); + + EXPECT_TRUE(got_all_requests_); + EXPECT_TRUE(got_server_destroyed_); + EXPECT_TRUE(request_runner_map_.empty()); + + // Cancel the timeout, if any. + if (ui_thread_helper_) + ui_thread_helper_.reset(); + + // Signal test completion. + run_event_->Signal(); + } + + TestHandler::UIThreadHelper* GetUIThreadHelper() { + EXPECT_UI_THREAD(); + if (!ui_thread_helper_) + ui_thread_helper_.reset(new TestHandler::UIThreadHelper()); + return ui_thread_helper_.get(); + } + + void SetTestTimeout(int timeout_ms) { + EXPECT_UI_THREAD(); + if (CefCommandLine::GetGlobalCommandLine()->HasSwitch( + "disable-test-timeout")) { + return; + } + + // Use a weak reference to |this| via UIThreadHelper so that the + // test runner can be destroyed before the timeout expires. + GetUIThreadHelper()->PostDelayedTask( + base::BindOnce(&HttpTestRunner::OnTestTimeout, base::Unretained(this), + timeout_ms), + timeout_ms); + } + + void OnTestTimeout(int timeout_ms) { + EXPECT_UI_THREAD(); + EXPECT_TRUE(false) << "Test timed out after " << timeout_ms << "ms"; + DestroyTest(); + } + + const bool https_server_; + const bool parallel_requests_; + CefRefPtr run_event_; + CefRefPtr destroy_event_; + CefRefPtr handler_; + bool initialized_ = false; + + // After initialization the below members are only accessed on the UI thread. + + std::string server_origin_; + int next_request_id_ = 0; + + // Map of request ID to RequestRunner. + typedef std::map RequestRunnerMap; + RequestRunnerMap request_runner_map_; + + TrackCallback got_all_requests_; + TrackCallback got_server_destroyed_; + + std::unique_ptr ui_thread_helper_; + + DISALLOW_COPY_AND_ASSIGN(HttpTestRunner); +}; + +// Structure representing the data that can be sent via +// CefServer::SendHttp*Response(). +struct HttpServerResponse { + enum Type { TYPE_200, TYPE_404, TYPE_500, TYPE_CUSTOM }; + + explicit HttpServerResponse(Type response_type) : type(response_type) {} + + Type type; + + // Used with 200 and CUSTOM response type. + std::string content; + std::string content_type; + + // Used with 500 response type. + std::string error_message; + + // Used with CUSTOM response type. + int response_code; + CefRequest::HeaderMap extra_headers; +}; + +void SendHttpServerResponse(CefRefPtr connection, + const HttpServerResponse& response) { + switch (response.type) { + case HttpServerResponse::TYPE_200: + EXPECT_TRUE(!response.content_type.empty()); + connection->SendHttp200Response(response.content_type, + response.content.data(), + response.content.size()); + break; + case HttpServerResponse::TYPE_404: + connection->SendHttp404Response(); + break; + case HttpServerResponse::TYPE_500: + connection->SendHttp500Response(response.error_message); + break; + case HttpServerResponse::TYPE_CUSTOM: + EXPECT_TRUE(!response.content_type.empty()); + connection->SendHttpResponse( + response.response_code, response.content_type, + response.content.data(), response.content.size(), + response.extra_headers); + break; + } +} + +std::string GetHeaderValue(const CefRequest::HeaderMap& header_map, + const std::string& header_name) { + CefRequest::HeaderMap::const_iterator it = header_map.find(header_name); + if (it != header_map.end()) + return it->second; + return std::string(); +} + +void VerifyHttpServerResponse(const HttpServerResponse& expected_response, + CefRefPtr response, + const std::string& data) { + CefRequest::HeaderMap header_map; + response->GetHeaderMap(header_map); + + switch (expected_response.type) { + case HttpServerResponse::TYPE_200: + EXPECT_EQ(200, response->GetStatus()); + EXPECT_STREQ(expected_response.content_type.c_str(), + GetHeaderValue(header_map, "Content-Type").c_str()); + EXPECT_STREQ(expected_response.content.c_str(), data.c_str()); + break; + case HttpServerResponse::TYPE_404: + EXPECT_EQ(404, response->GetStatus()); + break; + case HttpServerResponse::TYPE_500: + EXPECT_EQ(500, response->GetStatus()); + break; + case HttpServerResponse::TYPE_CUSTOM: + EXPECT_EQ(expected_response.response_code, response->GetStatus()); + EXPECT_STREQ(expected_response.content_type.c_str(), + GetHeaderValue(header_map, "Content-Type").c_str()); + EXPECT_EQ(static_cast(expected_response.content.size()), + atoi(GetHeaderValue(header_map, "Content-Length").c_str())); + EXPECT_STREQ(expected_response.content.c_str(), data.c_str()); + TestMapEqual(expected_response.extra_headers, header_map, true); + break; + } +} + +CefRefPtr CreateTestServerRequest( + const std::string& path, + const std::string& method, + const std::string& data = std::string(), + const std::string& content_type = std::string(), + const CefRequest::HeaderMap& extra_headers = CefRequest::HeaderMap()) { + CefRefPtr request = CefRequest::Create(); + + request->SetURL(kPlaceholderOrigin + path); + request->SetMethod(method); + + CefRequest::HeaderMap header_map; + + if (!data.empty()) { + CefRefPtr post_data = CefPostData::Create(); + CefRefPtr post_element = CefPostDataElement::Create(); + post_element->SetToBytes(data.size(), data.data()); + post_data->AddElement(post_element); + request->SetPostData(post_data); + + EXPECT_FALSE(content_type.empty()); + header_map.insert(std::make_pair("content-type", content_type)); + } + + if (!extra_headers.empty()) + header_map.insert(extra_headers.begin(), extra_headers.end()); + request->SetHeaderMap(header_map); + + return request; +} + +// RequestHandler that returns a static response for 1 or more requests. +class StaticHttpServerRequestHandler + : public TestServerHandler::HttpRequestHandler { + public: + StaticHttpServerRequestHandler(CefRefPtr expected_request, + int expected_request_ct, + const HttpServerResponse& response) + : expected_request_(expected_request), + expected_request_ct_(expected_request_ct), + actual_request_ct_(0), + response_(response) {} + + bool HandleRequest(CefRefPtr server, + CefRefPtr request, + CefRefPtr connection) override { + if (request->GetURL() == expected_request_->GetURL() && + request->GetMethod() == expected_request_->GetMethod()) { + TestRequestEqual(expected_request_, request, true); + actual_request_ct_++; + + SendHttpServerResponse(connection, response_); + return true; + } + + return false; + } + + bool VerifyResults() override { + EXPECT_EQ(expected_request_ct_, actual_request_ct_); + return expected_request_ct_ == actual_request_ct_; + } + + std::string ToString() override { return expected_request_->GetURL(); } + + private: + CefRefPtr expected_request_; + int expected_request_ct_; + int actual_request_ct_; + HttpServerResponse response_; + + DISALLOW_COPY_AND_ASSIGN(StaticHttpServerRequestHandler); +}; + +// URLRequestClient that runs a single request and executes a callback with the +// response. +class StaticHttpURLRequestClient : public CefURLRequestClient { + public: + using ResponseCallback = + base::OnceCallback /* response */, + const std::string& /* data */)>; + + // |response_callback| will be executed on the UI thread when the response + // is complete. + StaticHttpURLRequestClient(CefRefPtr request, + ResponseCallback response_callback) + : request_(request), response_callback_(std::move(response_callback)) { + EXPECT_TRUE(request_); + EXPECT_FALSE(response_callback_.is_null()); + } + + void RunRequest() { + EXPECT_UI_THREAD(); + CefURLRequest::Create(request_, this, nullptr); + } + + void OnRequestComplete(CefRefPtr request) override { + EXPECT_FALSE(response_callback_.is_null()); + std::move(response_callback_) + .Run(request->GetRequestError(), request->GetResponse(), data_); + } + + void OnUploadProgress(CefRefPtr request, + int64 current, + int64 total) override {} + + void OnDownloadProgress(CefRefPtr request, + int64 current, + int64 total) override {} + + void OnDownloadData(CefRefPtr request, + const void* data, + size_t data_length) override { + data_.append(static_cast(data), data_length); + } + + bool GetAuthCredentials(bool isProxy, + const CefString& host, + int port, + const CefString& realm, + const CefString& scheme, + CefRefPtr callback) override { + return false; + } + + private: + CefRefPtr request_; + ResponseCallback response_callback_; + std::string data_; + + IMPLEMENT_REFCOUNTING(StaticHttpURLRequestClient); + DISALLOW_COPY_AND_ASSIGN(StaticHttpURLRequestClient); +}; + +// RequestRunner that will manage a single static HTTP request/response. +class StaticHttpRequestRunner : public HttpTestRunner::RequestRunner { + public: + StaticHttpRequestRunner(CefRefPtr request, + const HttpServerResponse& response) + : request_(request), response_(response) {} + + static std::unique_ptr Create200( + const std::string& path, + bool with_content = true) { + CefRefPtr request = CreateTestServerRequest(path, "GET"); + HttpServerResponse response(HttpServerResponse::TYPE_200); + response.content_type = "text/html"; + if (with_content) + response.content = "200 response content"; + return std::make_unique(request, response); + } + + static std::unique_ptr Create404( + const std::string& path) { + CefRefPtr request = CreateTestServerRequest(path, "GET"); + HttpServerResponse response(HttpServerResponse::TYPE_404); + return std::make_unique(request, response); + } + + static std::unique_ptr Create500( + const std::string& path) { + CefRefPtr request = CreateTestServerRequest(path, "GET"); + // Don't retry the request. + request->SetFlags(UR_FLAG_NO_RETRY_ON_5XX); + HttpServerResponse response(HttpServerResponse::TYPE_500); + response.error_message = "Something went wrong!"; + return std::make_unique(request, response); + } + + static std::unique_ptr CreateCustom( + const std::string& path, + bool with_content = true) { + CefRequest::HeaderMap request_headers; + request_headers.insert(std::make_pair("x-request-custom1", "My Value A")); + request_headers.insert(std::make_pair("x-request-custom2", "My Value B")); + CefRefPtr request = CreateTestServerRequest( + path, "POST", "foo=bar&choo=too", "application/x-www-form-urlencoded", + request_headers); + request->SetReferrer("http://tests/referer.html", REFERRER_POLICY_DEFAULT); + + HttpServerResponse response(HttpServerResponse::TYPE_CUSTOM); + response.response_code = 202; + if (with_content) + response.content = "BlahBlahBlah"; + response.content_type = "application/x-blah-blah"; + response.extra_headers.insert( + std::make_pair("x-response-custom1", "My Value 1")); + response.extra_headers.insert( + std::make_pair("x-response-custom2", "My Value 2")); + + return std::make_unique(request, response); + } + + std::unique_ptr + CreateHttpRequestHandler() override { + EXPECT_FALSE(got_create_handler_); + got_create_handler_.yes(); + return std::make_unique(request_, 1, + response_); + } + + void RunRequest(const std::string& server_origin, + base::OnceClosure complete_callback) override { + EXPECT_UI_THREAD(); + + EXPECT_FALSE(got_run_request_); + got_run_request_.yes(); + + complete_callback_ = std::move(complete_callback); + + // Replace the placeholder with the actual server origin. + const std::string& url = request_->GetURL(); + EXPECT_TRUE(url.find(kPlaceholderOrigin) == 0); + const std::string& real_url = + server_origin + "/" + url.substr(sizeof(kPlaceholderOrigin) - 1); + request_->SetURL(real_url); + + request_client_ = new StaticHttpURLRequestClient( + request_, base::BindOnce(&StaticHttpRequestRunner::OnResponseComplete, + base::Unretained(this))); + request_client_->RunRequest(); + } + + bool VerifyResults() override { + V_DECLARE(); + V_EXPECT_TRUE(got_create_handler_); + V_EXPECT_TRUE(got_run_request_); + V_EXPECT_TRUE(got_response_complete_); + V_RETURN(); + } + + std::string ToString() override { return request_->GetURL(); } + + private: + void OnResponseComplete(cef_errorcode_t error, + CefRefPtr response, + const std::string& data) { + EXPECT_UI_THREAD(); + + EXPECT_FALSE(got_response_complete_); + got_response_complete_.yes(); + + EXPECT_EQ(error, ERR_NONE) + << "OnResponseComplete for " << request_->GetURL().ToString(); + if (error == ERR_NONE) + VerifyHttpServerResponse(response_, response, data); + + std::move(complete_callback_).Run(); + } + + CefRefPtr request_; + HttpServerResponse response_; + + CefRefPtr request_client_; + base::OnceClosure complete_callback_; + + TrackCallback got_run_request_; + TrackCallback got_create_handler_; + TrackCallback got_response_complete_; + + DISALLOW_COPY_AND_ASSIGN(StaticHttpRequestRunner); +}; + +} // namespace + +// Verify handling of a single HTTP 200 request. +TEST(TestServerTest, HttpSingle200) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of a single HTTPS 200 request. +TEST(TestServerTest, HttpsSingle200) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of a single HTTP 200 request with no content. +TEST(TestServerTest, HttpSingle200NoContent) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false); + runner->AddRequestRunner( + StaticHttpRequestRunner::Create200("200.html", false)); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of a single HTTPS 200 request with no content. +TEST(TestServerTest, HttpsSingle200NoContent) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false); + runner->AddRequestRunner( + StaticHttpRequestRunner::Create200("200.html", false)); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of a single HTTP 404 request. +TEST(TestServerTest, HttpSingle404) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of a single HTTPS 404 request. +TEST(TestServerTest, HttpsSingle404) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of a single HTTP 500 request. +TEST(TestServerTest, HttpSingle500) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of a single HTTPS 500 request. +TEST(TestServerTest, HttpsSingle500) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of a single HTTP custom request. +TEST(TestServerTest, HttpSingleCustom) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of a single HTTP custom request. +TEST(TestServerTest, HttpsSingleCustom) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of a single HTTP custom request with no content. +TEST(TestServerTest, HttpSingleCustomNoContent) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom( + "202.html", /*with_content=*/false)); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of a single HTTPS custom request with no content. +TEST(TestServerTest, HttpsSingleCustomNoContent) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom( + "202.html", /*with_content=*/false)); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of multiple HTTP requests in parallel. +TEST(TestServerTest, HttpMultipleParallel200) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/true); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200a.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200b.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200c.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of multiple HTTPS requests in parallel. +TEST(TestServerTest, HttpsMultipleParallel200) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/true); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200a.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200b.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200c.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of multiple HTTP requests in serial. +TEST(TestServerTest, HttpMultipleSerial200) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200a.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200b.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200c.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of multiple HTTPS requests in serial. +TEST(TestServerTest, HttpsMultipleSerial200) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200a.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200b.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200c.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of multiple HTTP requests in parallel. +TEST(TestServerTest, HttpMultipleParallelMixed) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/true); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of multiple HTTPS requests in parallel. +TEST(TestServerTest, HttpsMultipleParallelMixed) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/true); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of multiple HTTP requests in serial. +TEST(TestServerTest, HttpMultipleSerialMixed) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +} + +// Verify handling of multiple HTTPS requests in serial. +TEST(TestServerTest, HttpsMultipleSerialMixed) { + CefRefPtr runner = + new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false); + runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html")); + runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html")); + runner->ExecuteTest(); + ReleaseAndWaitForDestructor(runner); +}