Add CefServer API for handling HTTP/WebSocket requests (issue #2278)

This commit is contained in:
Marshall Greenblatt 2017-11-09 14:00:47 -05:00
parent 39e689d80a
commit 4b39753c41
46 changed files with 5041 additions and 71 deletions

View File

@ -523,6 +523,8 @@ static_library("libcef_static") {
"libcef/browser/request_context_impl.cc",
"libcef/browser/request_context_impl.h",
"libcef/browser/scheme_impl.cc",
"libcef/browser/server_impl.cc",
"libcef/browser/server_impl.h",
"libcef/browser/speech_recognition_manager_delegate.cc",
"libcef/browser/speech_recognition_manager_delegate.h",
"libcef/browser/ssl_host_state_delegate.cc",

View File

@ -8,7 +8,7 @@
# by hand. See the translator.README.txt file in the tools directory for
# more information.
#
# $hash=2a6e7c37a8421d3c0d032cc907fb3058790ac71d$
# $hash=a508906eb96c55e83eda7f17639a9ddcc0632f45$
#
{
@ -67,6 +67,7 @@
'include/cef_response.h',
'include/cef_response_filter.h',
'include/cef_scheme.h',
'include/cef_server.h',
'include/cef_ssl_info.h',
'include/cef_ssl_status.h',
'include/cef_stream.h',
@ -159,6 +160,7 @@
'include/capi/cef_response_capi.h',
'include/capi/cef_response_filter_capi.h',
'include/capi/cef_scheme_capi.h',
'include/capi/cef_server_capi.h',
'include/capi/cef_ssl_info_capi.h',
'include/capi/cef_ssl_status_capi.h',
'include/capi/cef_stream_capi.h',
@ -390,6 +392,10 @@
'libcef_dll/cpptoc/views/scroll_view_cpptoc.h',
'libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.cc',
'libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h',
'libcef_dll/cpptoc/server_cpptoc.cc',
'libcef_dll/cpptoc/server_cpptoc.h',
'libcef_dll/ctocpp/server_handler_ctocpp.cc',
'libcef_dll/ctocpp/server_handler_ctocpp.h',
'libcef_dll/ctocpp/set_cookie_callback_ctocpp.cc',
'libcef_dll/ctocpp/set_cookie_callback_ctocpp.h',
'libcef_dll/cpptoc/stream_reader_cpptoc.cc',
@ -672,6 +678,10 @@
'libcef_dll/ctocpp/views/scroll_view_ctocpp.h',
'libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.cc',
'libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h',
'libcef_dll/ctocpp/server_ctocpp.cc',
'libcef_dll/ctocpp/server_ctocpp.h',
'libcef_dll/cpptoc/server_handler_cpptoc.cc',
'libcef_dll/cpptoc/server_handler_cpptoc.h',
'libcef_dll/cpptoc/set_cookie_callback_cpptoc.cc',
'libcef_dll/cpptoc/set_cookie_callback_cpptoc.h',
'libcef_dll/ctocpp/stream_reader_ctocpp.cc',

View File

@ -240,6 +240,8 @@
'tests/cefclient/browser/root_window_manager.h',
'tests/cefclient/browser/scheme_test.cc',
'tests/cefclient/browser/scheme_test.h',
'tests/cefclient/browser/server_test.cc',
'tests/cefclient/browser/server_test.h',
'tests/cefclient/browser/temp_window.h',
'tests/cefclient/browser/test_runner.cc',
'tests/cefclient/browser/test_runner.h',
@ -278,8 +280,10 @@
'tests/cefclient/resources/performance2.html',
'tests/cefclient/resources/preferences.html',
'tests/cefclient/resources/response_filter.html',
'tests/cefclient/resources/server.html',
'tests/cefclient/resources/transparency.html',
'tests/cefclient/resources/urlrequest.html',
'tests/cefclient/resources/websocket.html',
'tests/cefclient/resources/window.html',
'tests/cefclient/resources/xmlhttprequest.html',
],
@ -464,6 +468,7 @@
'tests/ceftests/run_all_unittests.cc',
'tests/ceftests/scheme_handler_unittest.cc',
'tests/ceftests/scoped_temp_dir_unittest.cc',
'tests/ceftests/server_unittest.cc',
'tests/ceftests/stream_unittest.cc',
'tests/ceftests/stream_resource_handler_unittest.cc',
'tests/ceftests/string_unittest.cc',

View File

@ -64,6 +64,16 @@ typedef int int32;
typedef unsigned int uint32;
#endif
#ifndef _INT16
#define _INT16
typedef short int16;
#endif
#ifndef _UINT16
#define _UINT16
typedef unsigned short uint16;
#endif
// UTF-16 character type.
// This should be kept synchronized with base/strings/string16.h
#ifndef char16

View File

@ -33,7 +33,7 @@
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
// $hash=81e857497b1f5e1732af7fca2250edf78c0e5415$
// $hash=35342e59ba48fc8b9783fae8e04ddc36448f72d2$
//
#ifndef CEF_INCLUDE_CAPI_CEF_REQUEST_CONTEXT_CAPI_H_
@ -244,7 +244,7 @@ typedef struct _cef_request_context_t {
///
// Clears all active and idle connections that Chromium currently has. This is
// only recommended if you have released all other CEF objects but don't yet
// want to call cef_shutdown(). If |callback| is non-NULL it will be executed
// want to call Cefshutdown(). If |callback| is non-NULL it will be executed
// on the UI thread after completion.
///
void(CEF_CALLBACK* close_all_connections)(

View File

@ -0,0 +1,327 @@
// Copyright (c) 2017 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=92c646f789ec75664bf0c9f6bc21a44ff75686cf$
//
#ifndef CEF_INCLUDE_CAPI_CEF_SERVER_CAPI_H_
#define CEF_INCLUDE_CAPI_CEF_SERVER_CAPI_H_
#pragma once
#include "include/capi/cef_base_capi.h"
#include "include/capi/cef_callback_capi.h"
#include "include/capi/cef_request_capi.h"
#include "include/capi/cef_task_capi.h"
#ifdef __cplusplus
extern "C" {
#endif
struct _cef_server_handler_t;
///
// Structure representing a server that supports HTTP and WebSocket requests.
// 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_server_t {
///
// Base structure.
///
cef_base_ref_counted_t base;
///
// Returns the task runner for the dedicated server thread.
///
struct _cef_task_runner_t*(CEF_CALLBACK* get_task_runner)(
struct _cef_server_t* self);
///
// Stop the server and shut down the dedicated server thread. See
// cef_server_handler_t::OnServerCreated documentation for a description of
// server lifespan.
///
void(CEF_CALLBACK* shutdown)(struct _cef_server_t* self);
///
// Returns true (1) if the server is currently running and accepting incoming
// connections. See cef_server_handler_t::OnServerCreated documentation for a
// description of server lifespan. This function must be called on the
// dedicated server thread.
///
int(CEF_CALLBACK* is_running)(struct _cef_server_t* self);
///
// Returns the server address including the port number.
///
// The resulting string must be freed by calling cef_string_userfree_free().
cef_string_userfree_t(CEF_CALLBACK* get_address)(struct _cef_server_t* self);
///
// Returns true (1) if the server currently has a connection. This function
// must be called on the dedicated server thread.
///
int(CEF_CALLBACK* has_connection)(struct _cef_server_t* self);
///
// Returns true (1) if |connection_id| represents a valid connection. This
// function must be called on the dedicated server thread.
///
int(CEF_CALLBACK* is_valid_connection)(struct _cef_server_t* self,
int connection_id);
///
// Send an HTTP 200 "OK" response to the connection identified by
// |connection_id|. |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_server_t* self,
int connection_id,
const cef_string_t* content_type,
const void* data,
size_t data_size);
///
// Send an HTTP 404 "Not Found" response to the connection identified by
// |connection_id|. The connection will be closed automatically after the
// response is sent.
///
void(CEF_CALLBACK* send_http404response)(struct _cef_server_t* self,
int connection_id);
///
// Send an HTTP 500 "Internal Server Error" response to the connection
// identified by |connection_id|. |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_server_t* self,
int connection_id,
const cef_string_t* error_message);
///
// Send a custom HTTP response to the connection identified by
// |connection_id|. |response_code| is the HTTP response code sent in the
// status line (e.g. 200), |content_type| is the response content type sent as
// the "Content-Type" header (e.g. "text/html"), |content_length| is the
// expected content length, and |extra_headers| is the map of extra response
// headers. If |content_length| is >= 0 then the "Content-Length" header will
// be sent. If |content_length| is 0 then no content is expected and the
// connection will be closed automatically after the response is sent. If
// |content_length| is < 0 then no "Content-Length" header will be sent and
// the client will continue reading until the connection is closed. Use the
// SendRawData function to send the content, if applicable, and call
// CloseConnection after all content has been sent.
///
void(CEF_CALLBACK* send_http_response)(struct _cef_server_t* self,
int connection_id,
int response_code,
const cef_string_t* content_type,
int64 content_length,
cef_string_multimap_t extra_headers);
///
// Send raw data directly to the connection identified by |connection_id|.
// |data| is the raw data and |data_size| is the size of |data| in bytes. The
// contents of |data| will be copied. No validation of |data| is performed
// internally so the client should be careful to send the amount indicated by
// the "Content-Length" header, if specified. See SendHttpResponse
// documentation for intended usage.
///
void(CEF_CALLBACK* send_raw_data)(struct _cef_server_t* self,
int connection_id,
const void* data,
size_t data_size);
///
// Close the connection identified by |connection_id|. See SendHttpResponse
// documentation for intended usage.
///
void(CEF_CALLBACK* close_connection)(struct _cef_server_t* self,
int connection_id);
///
// Send a WebSocket message to the connection identified by |connection_id|.
// |data| is the response content and |data_size| is the size of |data| in
// bytes. The contents of |data| will be copied. See
// cef_server_handler_t::OnWebSocketRequest documentation for intended usage.
///
void(CEF_CALLBACK* send_web_socket_message)(struct _cef_server_t* self,
int connection_id,
const void* data,
size_t data_size);
} cef_server_t;
///
// Create a new server that binds to |address| and |port|. |address| must be a
// valid IPv4 or IPv6 address (e.g. 127.0.0.1 or ::1) and |port| must be a port
// number outside of the reserved range (e.g. between 1025 and 65535 on most
// platforms). |backlog| is the maximum number of pending connections. A new
// thread will be created for each CreateServer call (the "dedicated server
// thread"). It is therefore recommended to use a different cef_server_handler_t
// instance for each CreateServer call to avoid thread safety issues in the
// cef_server_handler_t implementation. The
// cef_server_handler_t::OnServerCreated function will be called on the
// dedicated server thread to report success or failure. See
// cef_server_handler_t::OnServerCreated documentation for a description of
// server lifespan.
///
CEF_EXPORT void cef_server_create(const cef_string_t* address,
uint16 port,
int backlog,
struct _cef_server_handler_t* handler);
///
// Implement this structure to handle HTTP server requests. A new thread will be
// created for each cef_server_t::CreateServer call (the "dedicated server
// thread"), and the functions of this structure will be called on that thread.
// It is therefore recommended to use a different cef_server_handler_t instance
// for each cef_server_t::CreateServer call to avoid thread safety issues in the
// cef_server_handler_t implementation.
///
typedef struct _cef_server_handler_t {
///
// Base structure.
///
cef_base_ref_counted_t base;
///
// Called when |server| is created. If the server was started successfully
// then cef_server_t::IsRunning will return true (1). The server will continue
// running until cef_server_t::Shutdown is called, after which time
// OnServerDestroyed will be called. If the server failed to start then
// OnServerDestroyed will be called immediately after this function returns.
///
void(CEF_CALLBACK* on_server_created)(struct _cef_server_handler_t* self,
struct _cef_server_t* server);
///
// Called when |server| is destroyed. The server thread will be stopped after
// this function returns. The client should release any references to |server|
// when this function is called. See OnServerCreated documentation for a
// description of server lifespan.
///
void(CEF_CALLBACK* on_server_destroyed)(struct _cef_server_handler_t* self,
struct _cef_server_t* server);
///
// Called when a client connects to |server|. |connection_id| uniquely
// identifies the connection. Each call to this function will have a matching
// call to OnClientDisconnected.
///
void(CEF_CALLBACK* on_client_connected)(struct _cef_server_handler_t* self,
struct _cef_server_t* server,
int connection_id);
///
// Called when a client disconnects from |server|. |connection_id| uniquely
// identifies the connection. The client should release any data associated
// with |connection_id| when this function is called and |connection_id|
// should no longer be passed to cef_server_t functions. Disconnects can
// originate from either the client or the server. For example, the server
// will disconnect automatically after a cef_server_t::SendHttpXXXResponse
// function is called.
///
void(CEF_CALLBACK* on_client_disconnected)(struct _cef_server_handler_t* self,
struct _cef_server_t* server,
int connection_id);
///
// Called when |server| receives an HTTP request. |connection_id| uniquely
// identifies the connection, |client_address| is the requesting IPv4 or IPv6
// client address including port number, and |request| contains the request
// contents (URL, function, headers and optional POST data). Call cef_server_t
// functions either synchronously or asynchronusly to send a response.
///
void(CEF_CALLBACK* on_http_request)(struct _cef_server_handler_t* self,
struct _cef_server_t* server,
int connection_id,
const cef_string_t* client_address,
struct _cef_request_t* request);
///
// Called when |server| receives a WebSocket request. |connection_id| uniquely
// identifies the connection, |client_address| is the requesting IPv4 or IPv6
// client address including port number, and |request| contains the request
// contents (URL, function, headers and optional POST data). Execute
// |callback| either synchronously or asynchronously to accept or decline the
// WebSocket connection. If the request is accepted then OnWebSocketConnected
// will be called after the WebSocket has connected and incoming messages will
// be delivered to the OnWebSocketMessage callback. If the request is declined
// then the client will be disconnected and OnClientDisconnected will be
// called. Call the cef_server_t::SendWebSocketMessage function after
// receiving the OnWebSocketConnected callback to respond with WebSocket
// messages.
///
void(CEF_CALLBACK* on_web_socket_request)(struct _cef_server_handler_t* self,
struct _cef_server_t* server,
int connection_id,
const cef_string_t* client_address,
struct _cef_request_t* request,
struct _cef_callback_t* callback);
///
// Called after the client has accepted the WebSocket connection for |server|
// and |connection_id| via the OnWebSocketRequest callback. See
// OnWebSocketRequest documentation for intended usage.
///
void(CEF_CALLBACK* on_web_socket_connected)(
struct _cef_server_handler_t* self,
struct _cef_server_t* server,
int connection_id);
///
// Called when |server| receives an WebSocket message. |connection_id|
// uniquely identifies the connection, |data| is the message content and
// |data_size| is the size of |data| in bytes. Do not keep a reference to
// |data| outside of this function. See OnWebSocketRequest documentation for
// intended usage.
///
void(CEF_CALLBACK* on_web_socket_message)(struct _cef_server_handler_t* self,
struct _cef_server_t* server,
int connection_id,
const void* data,
size_t data_size);
} cef_server_handler_t;
#ifdef __cplusplus
}
#endif
#endif // CEF_INCLUDE_CAPI_CEF_SERVER_CAPI_H_

315
include/cef_server.h Normal file
View File

@ -0,0 +1,315 @@
// Copyright (c) 2017 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.
//
#ifndef CEF_INCLUDE_CEF_SERVER_H_
#define CEF_INCLUDE_CEF_SERVER_H_
#pragma once
#include <map>
#include "include/cef_base.h"
#include "include/cef_callback.h"
#include "include/cef_request.h"
#include "include/cef_task.h"
class CefServerHandler;
///
// Class representing a server that supports HTTP and WebSocket requests. 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 CefServer : public CefBaseRefCounted {
public:
typedef std::multimap<CefString, CefString> HeaderMap;
///
// Create a new server that binds to |address| and |port|. |address| must be a
// valid IPv4 or IPv6 address (e.g. 127.0.0.1 or ::1) and |port| must be a
// port number outside of the reserved range (e.g. between 1025 and 65535 on
// most platforms). |backlog| is the maximum number of pending connections.
// A new thread will be created for each CreateServer call (the "dedicated
// server thread"). It is therefore recommended to use a different
// CefServerHandler instance for each CreateServer call to avoid thread safety
// issues in the CefServerHandler implementation. The
// CefServerHandler::OnServerCreated method will be called on the dedicated
// server thread to report success or failure. See
// CefServerHandler::OnServerCreated documentation for a description of server
// lifespan.
///
/*--cef()--*/
static void CreateServer(const CefString& address,
uint16 port,
int backlog,
CefRefPtr<CefServerHandler> handler);
///
// Returns the task runner for the dedicated server thread.
///
/*--cef()--*/
virtual CefRefPtr<CefTaskRunner> GetTaskRunner() = 0;
///
// Stop the server and shut down the dedicated server thread. See
// CefServerHandler::OnServerCreated documentation for a description of
// server lifespan.
///
/*--cef()--*/
virtual void Shutdown() = 0;
///
// Returns true if the server is currently running and accepting incoming
// connections. See CefServerHandler::OnServerCreated documentation for a
// description of server lifespan. This method must be called on the dedicated
// server thread.
///
/*--cef()--*/
virtual bool IsRunning() = 0;
///
// Returns the server address including the port number.
///
/*--cef()--*/
virtual CefString GetAddress() = 0;
///
// Returns true if the server currently has a connection. This method must be
// called on the dedicated server thread.
///
/*--cef()--*/
virtual bool HasConnection() = 0;
///
// Returns true if |connection_id| represents a valid connection. This method
// must be called on the dedicated server thread.
///
/*--cef()--*/
virtual bool IsValidConnection(int connection_id) = 0;
///
// Send an HTTP 200 "OK" response to the connection identified by
// |connection_id|. |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(int connection_id,
const CefString& content_type,
const void* data,
size_t data_size) = 0;
///
// Send an HTTP 404 "Not Found" response to the connection identified by
// |connection_id|. The connection will be closed automatically after the
// response is sent.
///
/*--cef()--*/
virtual void SendHttp404Response(int connection_id) = 0;
///
// Send an HTTP 500 "Internal Server Error" response to the connection
// identified by |connection_id|. |error_message| is the associated error
// message. The connection will be closed automatically after the response is
// sent.
///
/*--cef()--*/
virtual void SendHttp500Response(int connection_id,
const CefString& error_message) = 0;
///
// Send a custom HTTP response to the connection identified by
// |connection_id|. |response_code| is the HTTP response code sent in the
// status line (e.g. 200), |content_type| is the response content type sent
// as the "Content-Type" header (e.g. "text/html"), |content_length| is the
// expected content length, and |extra_headers| is the map of extra response
// headers. If |content_length| is >= 0 then the "Content-Length" header will
// be sent. If |content_length| is 0 then no content is expected and the
// connection will be closed automatically after the response is sent. If
// |content_length| is < 0 then no "Content-Length" header will be sent and
// the client will continue reading until the connection is closed. Use the
// SendRawData method to send the content, if applicable, and call
// CloseConnection after all content has been sent.
///
/*--cef(optional_param=extra_headers)--*/
virtual void SendHttpResponse(int connection_id,
int response_code,
const CefString& content_type,
int64 content_length,
const HeaderMap& extra_headers) = 0;
///
// Send raw data directly to the connection identified by |connection_id|.
// |data| is the raw data and |data_size| is the size of |data| in bytes.
// The contents of |data| will be copied. No validation of |data| is
// performed internally so the client should be careful to send the amount
// indicated by the "Content-Length" header, if specified. See
// SendHttpResponse documentation for intended usage.
///
/*--cef()--*/
virtual void SendRawData(int connection_id,
const void* data,
size_t data_size) = 0;
///
// Close the connection identified by |connection_id|. See SendHttpResponse
// documentation for intended usage.
///
/*--cef()--*/
virtual void CloseConnection(int connection_id) = 0;
///
// Send a WebSocket message to the connection identified by |connection_id|.
// |data| is the response content and |data_size| is the size of |data| in
// bytes. The contents of |data| will be copied. See
// CefServerHandler::OnWebSocketRequest documentation for intended usage.
///
/*--cef()--*/
virtual void SendWebSocketMessage(int connection_id,
const void* data,
size_t data_size) = 0;
};
///
// Implement this interface to handle HTTP server requests. A new thread will be
// created for each CefServer::CreateServer call (the "dedicated server
// thread"), and the methods of this class will be called on that thread. It is
// therefore recommended to use a different CefServerHandler instance for each
// CefServer::CreateServer call to avoid thread safety issues in the
// CefServerHandler implementation.
///
/*--cef(source=client)--*/
class CefServerHandler : public virtual CefBaseRefCounted {
public:
///
// Called when |server| is created. If the server was started successfully
// then CefServer::IsRunning will return true. The server will continue
// running until CefServer::Shutdown is called, after which time
// OnServerDestroyed will be called. If the server failed to start then
// OnServerDestroyed will be called immediately after this method returns.
///
/*--cef()--*/
virtual void OnServerCreated(CefRefPtr<CefServer> server) = 0;
///
// Called when |server| is destroyed. The server thread will be stopped after
// this method returns. The client should release any references to |server|
// when this method is called. See OnServerCreated documentation for a
// description of server lifespan.
///
/*--cef()--*/
virtual void OnServerDestroyed(CefRefPtr<CefServer> server) = 0;
///
// Called when a client connects to |server|. |connection_id| uniquely
// identifies the connection. Each call to this method will have a matching
// call to OnClientDisconnected.
///
/*--cef()--*/
virtual void OnClientConnected(CefRefPtr<CefServer> server,
int connection_id) = 0;
///
// Called when a client disconnects from |server|. |connection_id| uniquely
// identifies the connection. The client should release any data associated
// with |connection_id| when this method is called and |connection_id| should
// no longer be passed to CefServer methods. Disconnects can originate from
// either the client or the server. For example, the server will disconnect
// automatically after a CefServer::SendHttpXXXResponse method is called.
///
/*--cef()--*/
virtual void OnClientDisconnected(CefRefPtr<CefServer> server,
int connection_id) = 0;
///
// Called when |server| receives an HTTP request. |connection_id| uniquely
// identifies the connection, |client_address| is the requesting IPv4 or IPv6
// client address including port number, and |request| contains the request
// contents (URL, method, headers and optional POST data). Call CefServer
// methods either synchronously or asynchronusly to send a response.
///
/*--cef()--*/
virtual void OnHttpRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request) = 0;
///
// Called when |server| receives a WebSocket request. |connection_id| uniquely
// identifies the connection, |client_address| is the requesting IPv4 or
// IPv6 client address including port number, and |request| contains the
// request contents (URL, method, headers and optional POST data). Execute
// |callback| either synchronously or asynchronously to accept or decline the
// WebSocket connection. If the request is accepted then OnWebSocketConnected
// will be called after the WebSocket has connected and incoming messages will
// be delivered to the OnWebSocketMessage callback. If the request is declined
// then the client will be disconnected and OnClientDisconnected will be
// called. Call the CefServer::SendWebSocketMessage method after receiving the
// OnWebSocketConnected callback to respond with WebSocket messages.
///
/*--cef()--*/
virtual void OnWebSocketRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) = 0;
///
// Called after the client has accepted the WebSocket connection for |server|
// and |connection_id| via the OnWebSocketRequest callback. See
// OnWebSocketRequest documentation for intended usage.
///
/*--cef()--*/
virtual void OnWebSocketConnected(CefRefPtr<CefServer> server,
int connection_id) = 0;
///
// Called when |server| receives an WebSocket message. |connection_id|
// uniquely identifies the connection, |data| is the message content and
// |data_size| is the size of |data| in bytes. Do not keep a reference to
// |data| outside of this method. See OnWebSocketRequest documentation for
// intended usage.
///
/*--cef()--*/
virtual void OnWebSocketMessage(CefRefPtr<CefServer> server,
int connection_id,
const void* data,
size_t data_size) = 0;
};
#endif // CEF_INCLUDE_CEF_SERVER_H_

View File

@ -0,0 +1,643 @@
// Copyright (c) 2017 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/server_impl.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/request_impl.h"
#include "libcef/common/task_runner_impl.h"
#include "base/bind.h"
#include "base/format_macros.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/task_scheduler/post_task.h"
#include "base/threading/thread.h"
#include "net/base/net_errors.h"
#include "net/http/http_request_headers.h"
#include "net/server/http_server_request_info.h"
#include "net/server/http_server_response_info.h"
#include "net/socket/server_socket.h"
#include "net/socket/tcp_server_socket.h"
#define CEF_CURRENTLY_ON_HT() CurrentlyOnHandlerThread()
#define CEF_REQUIRE_HT() DCHECK(CEF_CURRENTLY_ON_HT())
#define CEF_REQUIRE_HT_RETURN(var) \
if (!CEF_CURRENTLY_ON_HT()) { \
NOTREACHED() << "called on invalid thread"; \
return var; \
}
#define CEF_REQUIRE_HT_RETURN_VOID() \
if (!CEF_CURRENTLY_ON_HT()) { \
NOTREACHED() << "called on invalid thread"; \
return; \
}
#define CEF_POST_TASK_HT(task) task_runner_->PostTask(FROM_HERE, task);
namespace {
// Wrap a string in a unique_ptr to avoid extra copies.
std::unique_ptr<std::string> CreateUniqueString(const void* data,
size_t data_size) {
std::unique_ptr<std::string> ptr;
if (data && data_size > 0) {
ptr.reset(new std::string(static_cast<const char*>(data), data_size));
} else {
ptr.reset(new std::string());
}
return ptr;
}
CefRefPtr<CefRequest> CreateRequest(const std::string& address,
const net::HttpServerRequestInfo& info,
bool is_websocket) {
DCHECK(!address.empty());
DCHECK(!info.method.empty());
DCHECK(!info.path.empty());
CefRefPtr<CefPostData> post_data;
if (!info.data.empty()) {
post_data = CefPostData::Create();
CefRefPtr<CefPostDataElement> post_element = CefPostDataElement::Create();
post_element->SetToBytes(info.data.size(), info.data.data());
post_data->AddElement(post_element);
}
CefRequest::HeaderMap header_map;
if (!info.headers.empty()) {
net::HttpServerRequestInfo::HeadersMap::const_iterator it =
info.headers.begin();
for (; it != info.headers.end(); ++it) {
header_map.insert(std::make_pair(it->first, it->second));
}
}
CefRefPtr<CefRequestImpl> request = new CefRequestImpl();
request->Set((is_websocket ? "ws://" : "http://") + address + info.path,
info.method, post_data, header_map);
request->SetReadOnly(true);
return request;
}
// Callback implementation for WebSocket acceptance. Always executes on the UI
// thread so we can avoid multiple execution by clearing the |impl_| reference.
class AcceptWebSocketCallback : public CefCallback {
public:
AcceptWebSocketCallback(CefRefPtr<CefServerImpl> impl,
int connection_id,
net::HttpServerRequestInfo request_info)
: impl_(impl),
connection_id_(connection_id),
request_info_(request_info) {}
~AcceptWebSocketCallback() override {
if (impl_)
impl_->ContinueWebSocketRequest(connection_id_, request_info_, false);
}
void Continue() override {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::BindOnce(&AcceptWebSocketCallback::Continue, this));
return;
}
if (!impl_)
return;
impl_->ContinueWebSocketRequest(connection_id_, request_info_, true);
impl_ = nullptr;
}
void Cancel() override {
if (!CEF_CURRENTLY_ON_UIT()) {
CEF_POST_TASK(CEF_UIT,
base::BindOnce(&AcceptWebSocketCallback::Cancel, this));
return;
}
if (!impl_)
return;
impl_->ContinueWebSocketRequest(connection_id_, request_info_, false);
impl_ = nullptr;
}
private:
CefRefPtr<CefServerImpl> impl_;
int connection_id_;
net::HttpServerRequestInfo request_info_;
IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(AcceptWebSocketCallback);
DISALLOW_COPY_AND_ASSIGN(AcceptWebSocketCallback);
};
} // namespace
// CefServer
// static
void CefServer::CreateServer(const CefString& address,
uint16 port,
int backlog,
CefRefPtr<CefServerHandler> handler) {
CefRefPtr<CefServerImpl> server(new CefServerImpl(handler));
server->Start(address, port, backlog);
}
// CefServerImpl
struct CefServerImpl::ConnectionInfo {
ConnectionInfo() : is_websocket(false), is_websocket_pending(false) {}
// True if this connection is a WebSocket connection.
bool is_websocket;
bool is_websocket_pending;
};
CefServerImpl::CefServerImpl(CefRefPtr<CefServerHandler> handler)
: handler_(handler) {
DCHECK(handler_);
}
void CefServerImpl::Start(const std::string& address,
uint16 port,
int backlog) {
DCHECK(!address.empty());
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefServerImpl::StartOnUIThread, this,
address, port, backlog));
}
CefRefPtr<CefTaskRunner> CefServerImpl::GetTaskRunner() {
if (task_runner_)
return new CefTaskRunnerImpl(task_runner_);
return nullptr;
}
void CefServerImpl::Shutdown() {
CEF_POST_TASK_HT(
base::BindOnce(&CefServerImpl::ShutdownOnHandlerThread, this));
}
bool CefServerImpl::IsRunning() {
CEF_REQUIRE_HT_RETURN(false);
return !!server_.get();
}
CefString CefServerImpl::GetAddress() {
return address_;
}
bool CefServerImpl::HasConnection() {
CEF_REQUIRE_HT_RETURN(false);
return !connection_info_map_.empty();
}
bool CefServerImpl::IsValidConnection(int connection_id) {
CEF_REQUIRE_HT_RETURN(false);
return connection_info_map_.find(connection_id) != connection_info_map_.end();
}
void CefServerImpl::SendHttp200Response(int connection_id,
const CefString& content_type,
const void* data,
size_t data_size) {
SendHttp200ResponseInternal(connection_id, content_type,
CreateUniqueString(data, data_size));
}
void CefServerImpl::SendHttp404Response(int connection_id) {
if (!CEF_CURRENTLY_ON_HT()) {
CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendHttp404Response, this,
connection_id));
return;
}
if (!ValidateServer())
return;
ConnectionInfo* info = GetConnectionInfo(connection_id);
if (!info)
return;
if (info->is_websocket) {
LOG(ERROR) << "Invalid attempt to send HTTP response for connection_id "
<< connection_id;
return;
}
server_->Send404(connection_id);
server_->Close(connection_id);
}
void CefServerImpl::SendHttp500Response(int connection_id,
const CefString& error_message) {
if (!CEF_CURRENTLY_ON_HT()) {
CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendHttp500Response, this,
connection_id, error_message));
return;
}
if (!ValidateServer())
return;
ConnectionInfo* info = GetConnectionInfo(connection_id);
if (!info)
return;
if (info->is_websocket) {
LOG(ERROR) << "Invalid attempt to send HTTP response for connection_id "
<< connection_id;
return;
}
server_->Send500(connection_id, error_message);
server_->Close(connection_id);
}
void CefServerImpl::SendHttpResponse(int connection_id,
int response_code,
const CefString& content_type,
int64 content_length,
const HeaderMap& extra_headers) {
if (!CEF_CURRENTLY_ON_HT()) {
CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendHttpResponse, this,
connection_id, response_code, content_type,
content_length, extra_headers));
return;
}
if (!ValidateServer())
return;
ConnectionInfo* info = GetConnectionInfo(connection_id);
if (!info)
return;
if (info->is_websocket) {
LOG(ERROR) << "Invalid attempt to send HTTP response for connection_id "
<< connection_id;
return;
}
net::HttpServerResponseInfo response(
static_cast<net::HttpStatusCode>(response_code));
HeaderMap::const_iterator it = extra_headers.begin();
for (; it != extra_headers.end(); ++it)
response.AddHeader(it->first, it->second);
response.AddHeader(net::HttpRequestHeaders::kContentType, content_type);
if (content_length >= 0) {
response.AddHeader(
net::HttpRequestHeaders::kContentLength,
base::StringPrintf("%" PRIuS, static_cast<size_t>(content_length)));
}
server_->SendResponse(connection_id, response);
if (content_length == 0) {
server_->Close(connection_id);
}
}
void CefServerImpl::SendRawData(int connection_id,
const void* data,
size_t data_size) {
if (!data || data_size == 0)
return;
SendRawDataInternal(connection_id, CreateUniqueString(data, data_size));
}
void CefServerImpl::CloseConnection(int connection_id) {
if (!CEF_CURRENTLY_ON_HT()) {
CEF_POST_TASK_HT(
base::BindOnce(&CefServerImpl::CloseConnection, this, connection_id));
return;
}
if (ValidateServer() && GetConnectionInfo(connection_id)) {
server_->Close(connection_id);
}
}
void CefServerImpl::SendWebSocketMessage(int connection_id,
const void* data,
size_t data_size) {
if (!data || data_size == 0)
return;
SendWebSocketMessageInternal(connection_id,
CreateUniqueString(data, data_size));
}
void CefServerImpl::ContinueWebSocketRequest(
int connection_id,
const net::HttpServerRequestInfo& request_info,
bool allow) {
if (!CEF_CURRENTLY_ON_HT()) {
CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::ContinueWebSocketRequest,
this, connection_id, request_info, allow));
return;
}
if (!ValidateServer())
return;
ConnectionInfo* info = GetConnectionInfo(connection_id);
DCHECK(info);
if (!info)
return;
DCHECK(info->is_websocket);
DCHECK(info->is_websocket_pending);
if (!info->is_websocket || !info->is_websocket_pending)
return;
info->is_websocket_pending = false;
if (allow) {
server_->AcceptWebSocket(connection_id, request_info);
handler_->OnWebSocketConnected(this, connection_id);
} else {
server_->Close(connection_id);
}
}
void CefServerImpl::SendHttp200ResponseInternal(
int connection_id,
const CefString& content_type,
std::unique_ptr<std::string> data) {
if (!CEF_CURRENTLY_ON_HT()) {
CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendHttp200ResponseInternal,
this, connection_id, content_type,
base::Passed(std::move(data))));
return;
}
if (!ValidateServer())
return;
ConnectionInfo* info = GetConnectionInfo(connection_id);
if (!info)
return;
if (info->is_websocket) {
LOG(ERROR) << "Invalid attempt to send HTTP response for connection_id "
<< connection_id;
return;
}
server_->Send200(connection_id, *data, content_type);
server_->Close(connection_id);
}
void CefServerImpl::SendRawDataInternal(int connection_id,
std::unique_ptr<std::string> data) {
if (!CEF_CURRENTLY_ON_HT()) {
CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendRawDataInternal, this,
connection_id,
base::Passed(std::move(data))));
return;
}
if (!ValidateServer())
return;
if (!GetConnectionInfo(connection_id))
return;
server_->SendRaw(connection_id, *data);
}
void CefServerImpl::SendWebSocketMessageInternal(
int connection_id,
std::unique_ptr<std::string> data) {
if (!CEF_CURRENTLY_ON_HT()) {
CEF_POST_TASK_HT(
base::BindOnce(&CefServerImpl::SendWebSocketMessageInternal, this,
connection_id, base::Passed(std::move(data))));
return;
}
if (!ValidateServer())
return;
ConnectionInfo* info = GetConnectionInfo(connection_id);
if (!info)
return;
if (!info->is_websocket || info->is_websocket_pending) {
LOG(ERROR) << "Invalid attempt to send WebSocket message for connection_id "
<< connection_id;
return;
}
server_->SendOverWebSocket(connection_id, *data);
}
void CefServerImpl::OnConnect(int connection_id) {
CEF_REQUIRE_HT();
CreateConnectionInfo(connection_id);
handler_->OnClientConnected(this, connection_id);
}
void CefServerImpl::OnHttpRequest(
int connection_id,
const net::HttpServerRequestInfo& request_info) {
CEF_REQUIRE_HT();
ConnectionInfo* info = GetConnectionInfo(connection_id);
DCHECK(info);
if (!info)
return;
DCHECK(!info->is_websocket);
handler_->OnHttpRequest(this, connection_id, request_info.peer.ToString(),
CreateRequest(address_, request_info, false));
}
void CefServerImpl::OnWebSocketRequest(
int connection_id,
const net::HttpServerRequestInfo& request_info) {
CEF_REQUIRE_HT();
ConnectionInfo* info = GetConnectionInfo(connection_id);
DCHECK(info);
if (!info)
return;
DCHECK(!info->is_websocket);
info->is_websocket = true;
info->is_websocket_pending = true;
// Will eventually result in a call to ContinueWebSocketRequest.
CefRefPtr<CefCallback> callback =
new AcceptWebSocketCallback(this, connection_id, request_info);
handler_->OnWebSocketRequest(
this, connection_id, request_info.peer.ToString(),
CreateRequest(address_, request_info, true), callback);
}
void CefServerImpl::OnWebSocketMessage(int connection_id,
const std::string& data) {
CEF_REQUIRE_HT();
ConnectionInfo* info = GetConnectionInfo(connection_id);
if (!info)
return;
DCHECK(info->is_websocket);
DCHECK(!info->is_websocket_pending);
handler_->OnWebSocketMessage(this, connection_id, data.data(), data.size());
}
void CefServerImpl::OnClose(int connection_id) {
CEF_REQUIRE_HT();
RemoveConnectionInfo(connection_id);
handler_->OnClientDisconnected(this, connection_id);
}
void CefServerImpl::StartOnUIThread(const std::string& address,
uint16 port,
int backlog) {
CEF_REQUIRE_UIT();
DCHECK(!thread_);
std::unique_ptr<base::Thread> thread(
new base::Thread(base::StringPrintf("%s:%d", address.c_str(), port)));
base::Thread::Options options;
options.message_loop_type = base::MessageLoop::TYPE_IO;
if (thread->StartWithOptions(options)) {
// Add a reference that will be released in ShutdownOnUIThread().
AddRef();
thread_ = std::move(thread);
task_runner_ = thread_->task_runner();
CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::StartOnHandlerThread, this,
address, port, backlog));
}
}
void CefServerImpl::StartOnHandlerThread(const std::string& address,
uint16 port,
int backlog) {
CEF_REQUIRE_HT();
std::unique_ptr<net::ServerSocket> socket(
new net::TCPServerSocket(nullptr, net::NetLogSource()));
if (socket->ListenWithAddressAndPort(address, port, backlog) == net::OK) {
server_.reset(new net::HttpServer(std::move(socket), this));
net::IPEndPoint address;
if (server_->GetLocalAddress(&address) == net::OK)
address_ = address.ToString();
}
handler_->OnServerCreated(this);
if (!server_) {
// Server failed to start.
handler_->OnServerDestroyed(this);
CEF_POST_TASK(CEF_UIT,
base::BindOnce(&CefServerImpl::ShutdownOnUIThread, this));
}
}
void CefServerImpl::ShutdownOnHandlerThread() {
CEF_REQUIRE_HT();
if (server_) {
// Stop the server.
server_.reset();
if (!connection_info_map_.empty()) {
// Clear |connection_info_map_| first so any calls from
// OnClientDisconnected will fail as expected.
ConnectionInfoMap temp_map;
temp_map.swap(connection_info_map_);
// OnClose won't be called for clients that are connected when the server
// shuts down, so send the disconnected notification here.
ConnectionInfoMap::const_iterator it = temp_map.begin();
for (; it != temp_map.end(); ++it) {
handler_->OnClientDisconnected(this, it->first);
}
}
handler_->OnServerDestroyed(this);
}
CEF_POST_TASK(CEF_UIT,
base::BindOnce(&CefServerImpl::ShutdownOnUIThread, this));
}
void CefServerImpl::ShutdownOnUIThread() {
CEF_REQUIRE_UIT();
handler_ = nullptr;
if (thread_) {
// Stop the handler thread as a background task so the UI thread isn't
// blocked.
base::PostTaskWithTraits(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
BindOnce([](std::unique_ptr<base::Thread>) {}, std::move(thread_)));
// Release the reference that was added in StartupOnUIThread().
Release();
}
}
bool CefServerImpl::ValidateServer() const {
CEF_REQUIRE_HT();
if (!server_) {
LOG(ERROR) << "Server is not running";
return false;
}
return true;
}
CefServerImpl::ConnectionInfo* CefServerImpl::CreateConnectionInfo(
int connection_id) {
CEF_REQUIRE_HT();
#if DCHECK_IS_ON()
ConnectionInfoMap::const_iterator it =
connection_info_map_.find(connection_id);
DCHECK(it == connection_info_map_.end());
#endif
ConnectionInfo* info = new ConnectionInfo();
connection_info_map_.insert(
std::make_pair(connection_id, base::WrapUnique(info)));
return info;
}
CefServerImpl::ConnectionInfo* CefServerImpl::GetConnectionInfo(
int connection_id) const {
CEF_REQUIRE_HT();
ConnectionInfoMap::const_iterator it =
connection_info_map_.find(connection_id);
if (it != connection_info_map_.end())
return it->second.get();
LOG(ERROR) << "Invalid connection_id " << connection_id;
return nullptr;
}
void CefServerImpl::RemoveConnectionInfo(int connection_id) {
CEF_REQUIRE_HT();
ConnectionInfoMap::iterator it = connection_info_map_.find(connection_id);
DCHECK(it != connection_info_map_.end());
if (it != connection_info_map_.end())
connection_info_map_.erase(it);
}
bool CefServerImpl::CurrentlyOnHandlerThread() const {
return task_runner_ && task_runner_->BelongsToCurrentThread();
}

View File

@ -0,0 +1,113 @@
// Copyright (c) 2017 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_SERVER_IMPL_H_
#define CEF_LIBCEF_BROWSER_SERVER_IMPL_H_
#pragma once
#include <map>
#include <memory>
#include "include/cef_server.h"
#include "base/single_thread_task_runner.h"
#include "net/server/http_server.h"
namespace base {
class Thread;
};
class CefServerImpl : public CefServer, net::HttpServer::Delegate {
public:
explicit CefServerImpl(CefRefPtr<CefServerHandler> handler);
void Start(const std::string& address, uint16 port, int backlog);
// CefServer methods:
CefRefPtr<CefTaskRunner> GetTaskRunner() override;
void Shutdown() override;
bool IsRunning() override;
CefString GetAddress() override;
bool HasConnection() override;
bool IsValidConnection(int connection_id) override;
void SendHttp200Response(int connection_id,
const CefString& content_type,
const void* data,
size_t data_size) override;
void SendHttp404Response(int connection_id) override;
void SendHttp500Response(int connection_id,
const CefString& error_message) override;
void SendHttpResponse(int connection_id,
int response_code,
const CefString& content_type,
int64 content_length,
const HeaderMap& extra_headers) override;
void SendRawData(int connection_id,
const void* data,
size_t data_size) override;
void CloseConnection(int connection_id) override;
void SendWebSocketMessage(int connection_id,
const void* data,
size_t data_size) override;
void ContinueWebSocketRequest(int connection_id,
const net::HttpServerRequestInfo& request_info,
bool allow);
private:
void SendHttp200ResponseInternal(int connection_id,
const CefString& content_type,
std::unique_ptr<std::string> data);
void SendRawDataInternal(int connection_id,
std::unique_ptr<std::string> data);
void SendWebSocketMessageInternal(int connection_id,
std::unique_ptr<std::string> data);
// HttpServer::Delegate methods:
void OnConnect(int connection_id) override;
void OnHttpRequest(int connection_id,
const net::HttpServerRequestInfo& request_info) override;
void OnWebSocketRequest(
int connection_id,
const net::HttpServerRequestInfo& request_info) override;
void OnWebSocketMessage(int connection_id, const std::string& data) override;
void OnClose(int connection_id) override;
void StartOnUIThread(const std::string& address, uint16 port, int backlog);
void StartOnHandlerThread(const std::string& address,
uint16 port,
int backlog);
void ShutdownOnHandlerThread();
void ShutdownOnUIThread();
bool ValidateServer() const;
struct ConnectionInfo;
ConnectionInfo* CreateConnectionInfo(int connection_id);
ConnectionInfo* GetConnectionInfo(int connection_id) const;
void RemoveConnectionInfo(int connection_id);
bool CurrentlyOnHandlerThread() const;
// Safe to access from any thread.
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
std::string address_;
// Only accessed on the UI thread.
std::unique_ptr<base::Thread> thread_;
// Only accessed on the server thread.
CefRefPtr<CefServerHandler> handler_;
std::unique_ptr<net::HttpServer> server_;
// Map of connection_id to ConnectionInfo.
using ConnectionInfoMap = std::map<int, std::unique_ptr<ConnectionInfo>>;
ConnectionInfoMap connection_info_map_;
IMPLEMENT_REFCOUNTING(CefServerImpl);
DISALLOW_COPY_AND_ASSIGN(CefServerImpl);
};
#endif // CEF_LIBCEF_BROWSER_SERVER_IMPL_H_

View File

@ -0,0 +1,301 @@
// Copyright (c) 2017 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=aa194ad76a31d7a0497333d78595e8b349a0551e$
//
#include "libcef_dll/cpptoc/server_cpptoc.h"
#include "libcef_dll/cpptoc/task_runner_cpptoc.h"
#include "libcef_dll/ctocpp/server_handler_ctocpp.h"
#include "libcef_dll/transfer_util.h"
// GLOBAL FUNCTIONS - Body may be edited by hand.
CEF_EXPORT void cef_server_create(const cef_string_t* address,
uint16 port,
int backlog,
struct _cef_server_handler_t* handler) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: address; type: string_byref_const
DCHECK(address);
if (!address)
return;
// Verify param: handler; type: refptr_diff
DCHECK(handler);
if (!handler)
return;
// Execute
CefServer::CreateServer(CefString(address), port, backlog,
CefServerHandlerCToCpp::Wrap(handler));
}
namespace {
// MEMBER FUNCTIONS - Body may be edited by hand.
struct _cef_task_runner_t* CEF_CALLBACK
server_get_task_runner(struct _cef_server_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return NULL;
// Execute
CefRefPtr<CefTaskRunner> _retval =
CefServerCppToC::Get(self)->GetTaskRunner();
// Return type: refptr_same
return CefTaskRunnerCppToC::Wrap(_retval);
}
void CEF_CALLBACK server_shutdown(struct _cef_server_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Execute
CefServerCppToC::Get(self)->Shutdown();
}
int CEF_CALLBACK server_is_running(struct _cef_server_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Execute
bool _retval = CefServerCppToC::Get(self)->IsRunning();
// Return type: bool
return _retval;
}
cef_string_userfree_t CEF_CALLBACK
server_get_address(struct _cef_server_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return NULL;
// Execute
CefString _retval = CefServerCppToC::Get(self)->GetAddress();
// Return type: string
return _retval.DetachToUserFree();
}
int CEF_CALLBACK server_has_connection(struct _cef_server_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Execute
bool _retval = CefServerCppToC::Get(self)->HasConnection();
// Return type: bool
return _retval;
}
int CEF_CALLBACK server_is_valid_connection(struct _cef_server_t* self,
int connection_id) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Execute
bool _retval = CefServerCppToC::Get(self)->IsValidConnection(connection_id);
// Return type: bool
return _retval;
}
void CEF_CALLBACK server_send_http200response(struct _cef_server_t* self,
int connection_id,
const cef_string_t* content_type,
const void* data,
size_t data_size) {
// 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
CefServerCppToC::Get(self)->SendHttp200Response(
connection_id, CefString(content_type), data, data_size);
}
void CEF_CALLBACK server_send_http404response(struct _cef_server_t* self,
int connection_id) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Execute
CefServerCppToC::Get(self)->SendHttp404Response(connection_id);
}
void CEF_CALLBACK
server_send_http500response(struct _cef_server_t* self,
int connection_id,
const cef_string_t* error_message) {
// 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
CefServerCppToC::Get(self)->SendHttp500Response(connection_id,
CefString(error_message));
}
void CEF_CALLBACK
server_send_http_response(struct _cef_server_t* self,
int connection_id,
int response_code,
const cef_string_t* content_type,
int64 content_length,
cef_string_multimap_t extra_headers) {
// 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;
// Unverified params: extra_headers
// Translate param: extra_headers; type: string_map_multi_byref_const
std::multimap<CefString, CefString> extra_headersMultimap;
transfer_string_multimap_contents(extra_headers, extra_headersMultimap);
// Execute
CefServerCppToC::Get(self)->SendHttpResponse(
connection_id, response_code, CefString(content_type), content_length,
extra_headersMultimap);
}
void CEF_CALLBACK server_send_raw_data(struct _cef_server_t* self,
int connection_id,
const void* data,
size_t data_size) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: data; type: simple_byaddr
DCHECK(data);
if (!data)
return;
// Execute
CefServerCppToC::Get(self)->SendRawData(connection_id, data, data_size);
}
void CEF_CALLBACK server_close_connection(struct _cef_server_t* self,
int connection_id) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Execute
CefServerCppToC::Get(self)->CloseConnection(connection_id);
}
void CEF_CALLBACK server_send_web_socket_message(struct _cef_server_t* self,
int connection_id,
const void* data,
size_t data_size) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: data; type: simple_byaddr
DCHECK(data);
if (!data)
return;
// Execute
CefServerCppToC::Get(self)->SendWebSocketMessage(connection_id, data,
data_size);
}
} // namespace
// CONSTRUCTOR - Do not edit by hand.
CefServerCppToC::CefServerCppToC() {
GetStruct()->get_task_runner = server_get_task_runner;
GetStruct()->shutdown = server_shutdown;
GetStruct()->is_running = server_is_running;
GetStruct()->get_address = server_get_address;
GetStruct()->has_connection = server_has_connection;
GetStruct()->is_valid_connection = server_is_valid_connection;
GetStruct()->send_http200response = server_send_http200response;
GetStruct()->send_http404response = server_send_http404response;
GetStruct()->send_http500response = server_send_http500response;
GetStruct()->send_http_response = server_send_http_response;
GetStruct()->send_raw_data = server_send_raw_data;
GetStruct()->close_connection = server_close_connection;
GetStruct()->send_web_socket_message = server_send_web_socket_message;
}
template <>
CefRefPtr<CefServer>
CefCppToCRefCounted<CefServerCppToC, CefServer, cef_server_t>::UnwrapDerived(
CefWrapperType type,
cef_server_t* s) {
NOTREACHED() << "Unexpected class type: " << type;
return NULL;
}
#if DCHECK_IS_ON()
template <>
base::AtomicRefCount
CefCppToCRefCounted<CefServerCppToC, CefServer, cef_server_t>::DebugObjCt
ATOMIC_DECLARATION;
#endif
template <>
CefWrapperType CefCppToCRefCounted<CefServerCppToC, CefServer, cef_server_t>::
kWrapperType = WT_SERVER;

View File

@ -0,0 +1,35 @@
// Copyright (c) 2017 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=0f4a3453e43f2aa85bfdfaed15772373c43eccb8$
//
#ifndef CEF_LIBCEF_DLL_CPPTOC_SERVER_CPPTOC_H_
#define CEF_LIBCEF_DLL_CPPTOC_SERVER_CPPTOC_H_
#pragma once
#if !defined(BUILDING_CEF_SHARED)
#error This file can be included DLL-side only
#endif
#include "include/capi/cef_server_capi.h"
#include "include/cef_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 CefServerCppToC
: public CefCppToCRefCounted<CefServerCppToC, CefServer, cef_server_t> {
public:
CefServerCppToC();
};
#endif // CEF_LIBCEF_DLL_CPPTOC_SERVER_CPPTOC_H_

View File

@ -0,0 +1,244 @@
// Copyright (c) 2017 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=36e97984dadd60442c0eba6189c08b6512d05f78$
//
#include "libcef_dll/cpptoc/server_handler_cpptoc.h"
#include "libcef_dll/ctocpp/callback_ctocpp.h"
#include "libcef_dll/ctocpp/request_ctocpp.h"
#include "libcef_dll/ctocpp/server_ctocpp.h"
namespace {
// MEMBER FUNCTIONS - Body may be edited by hand.
void CEF_CALLBACK
server_handler_on_server_created(struct _cef_server_handler_t* self,
cef_server_t* server) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: server; type: refptr_diff
DCHECK(server);
if (!server)
return;
// Execute
CefServerHandlerCppToC::Get(self)->OnServerCreated(
CefServerCToCpp::Wrap(server));
}
void CEF_CALLBACK
server_handler_on_server_destroyed(struct _cef_server_handler_t* self,
cef_server_t* server) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: server; type: refptr_diff
DCHECK(server);
if (!server)
return;
// Execute
CefServerHandlerCppToC::Get(self)->OnServerDestroyed(
CefServerCToCpp::Wrap(server));
}
void CEF_CALLBACK
server_handler_on_client_connected(struct _cef_server_handler_t* self,
cef_server_t* server,
int connection_id) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: server; type: refptr_diff
DCHECK(server);
if (!server)
return;
// Execute
CefServerHandlerCppToC::Get(self)->OnClientConnected(
CefServerCToCpp::Wrap(server), connection_id);
}
void CEF_CALLBACK
server_handler_on_client_disconnected(struct _cef_server_handler_t* self,
cef_server_t* server,
int connection_id) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: server; type: refptr_diff
DCHECK(server);
if (!server)
return;
// Execute
CefServerHandlerCppToC::Get(self)->OnClientDisconnected(
CefServerCToCpp::Wrap(server), connection_id);
}
void CEF_CALLBACK
server_handler_on_http_request(struct _cef_server_handler_t* self,
cef_server_t* server,
int connection_id,
const cef_string_t* client_address,
cef_request_t* request) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: server; type: refptr_diff
DCHECK(server);
if (!server)
return;
// Verify param: client_address; type: string_byref_const
DCHECK(client_address);
if (!client_address)
return;
// Verify param: request; type: refptr_diff
DCHECK(request);
if (!request)
return;
// Execute
CefServerHandlerCppToC::Get(self)->OnHttpRequest(
CefServerCToCpp::Wrap(server), connection_id, CefString(client_address),
CefRequestCToCpp::Wrap(request));
}
void CEF_CALLBACK
server_handler_on_web_socket_request(struct _cef_server_handler_t* self,
cef_server_t* server,
int connection_id,
const cef_string_t* client_address,
cef_request_t* request,
cef_callback_t* callback) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: server; type: refptr_diff
DCHECK(server);
if (!server)
return;
// Verify param: client_address; type: string_byref_const
DCHECK(client_address);
if (!client_address)
return;
// Verify param: request; type: refptr_diff
DCHECK(request);
if (!request)
return;
// Verify param: callback; type: refptr_diff
DCHECK(callback);
if (!callback)
return;
// Execute
CefServerHandlerCppToC::Get(self)->OnWebSocketRequest(
CefServerCToCpp::Wrap(server), connection_id, CefString(client_address),
CefRequestCToCpp::Wrap(request), CefCallbackCToCpp::Wrap(callback));
}
void CEF_CALLBACK
server_handler_on_web_socket_connected(struct _cef_server_handler_t* self,
cef_server_t* server,
int connection_id) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: server; type: refptr_diff
DCHECK(server);
if (!server)
return;
// Execute
CefServerHandlerCppToC::Get(self)->OnWebSocketConnected(
CefServerCToCpp::Wrap(server), connection_id);
}
void CEF_CALLBACK
server_handler_on_web_socket_message(struct _cef_server_handler_t* self,
cef_server_t* server,
int connection_id,
const void* data,
size_t data_size) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: server; type: refptr_diff
DCHECK(server);
if (!server)
return;
// Verify param: data; type: simple_byaddr
DCHECK(data);
if (!data)
return;
// Execute
CefServerHandlerCppToC::Get(self)->OnWebSocketMessage(
CefServerCToCpp::Wrap(server), connection_id, data, data_size);
}
} // namespace
// CONSTRUCTOR - Do not edit by hand.
CefServerHandlerCppToC::CefServerHandlerCppToC() {
GetStruct()->on_server_created = server_handler_on_server_created;
GetStruct()->on_server_destroyed = server_handler_on_server_destroyed;
GetStruct()->on_client_connected = server_handler_on_client_connected;
GetStruct()->on_client_disconnected = server_handler_on_client_disconnected;
GetStruct()->on_http_request = server_handler_on_http_request;
GetStruct()->on_web_socket_request = server_handler_on_web_socket_request;
GetStruct()->on_web_socket_connected = server_handler_on_web_socket_connected;
GetStruct()->on_web_socket_message = server_handler_on_web_socket_message;
}
template <>
CefRefPtr<CefServerHandler> CefCppToCRefCounted<
CefServerHandlerCppToC,
CefServerHandler,
cef_server_handler_t>::UnwrapDerived(CefWrapperType type,
cef_server_handler_t* s) {
NOTREACHED() << "Unexpected class type: " << type;
return NULL;
}
#if DCHECK_IS_ON()
template <>
base::AtomicRefCount CefCppToCRefCounted<CefServerHandlerCppToC,
CefServerHandler,
cef_server_handler_t>::DebugObjCt
ATOMIC_DECLARATION;
#endif
template <>
CefWrapperType CefCppToCRefCounted<CefServerHandlerCppToC,
CefServerHandler,
cef_server_handler_t>::kWrapperType =
WT_SERVER_HANDLER;

View File

@ -0,0 +1,37 @@
// Copyright (c) 2017 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=01080491feb0e65e1385fcc5547ecb9c88de70c3$
//
#ifndef CEF_LIBCEF_DLL_CPPTOC_SERVER_HANDLER_CPPTOC_H_
#define CEF_LIBCEF_DLL_CPPTOC_SERVER_HANDLER_CPPTOC_H_
#pragma once
#if !defined(WRAPPING_CEF_SHARED)
#error This file can be included wrapper-side only
#endif
#include "include/capi/cef_server_capi.h"
#include "include/cef_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 CefServerHandlerCppToC
: public CefCppToCRefCounted<CefServerHandlerCppToC,
CefServerHandler,
cef_server_handler_t> {
public:
CefServerHandlerCppToC();
};
#endif // CEF_LIBCEF_DLL_CPPTOC_SERVER_HANDLER_CPPTOC_H_

View File

@ -0,0 +1,282 @@
// Copyright (c) 2017 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=ffa6d8f2bc0fd724a50856dfa867cf275345716c$
//
#include "libcef_dll/ctocpp/server_ctocpp.h"
#include "libcef_dll/cpptoc/server_handler_cpptoc.h"
#include "libcef_dll/ctocpp/task_runner_ctocpp.h"
#include "libcef_dll/transfer_util.h"
// STATIC METHODS - Body may be edited by hand.
void CefServer::CreateServer(const CefString& address,
uint16 port,
int backlog,
CefRefPtr<CefServerHandler> handler) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: address; type: string_byref_const
DCHECK(!address.empty());
if (address.empty())
return;
// Verify param: handler; type: refptr_diff
DCHECK(handler.get());
if (!handler.get())
return;
// Execute
cef_server_create(address.GetStruct(), port, backlog,
CefServerHandlerCppToC::Wrap(handler));
}
// VIRTUAL METHODS - Body may be edited by hand.
CefRefPtr<CefTaskRunner> CefServerCToCpp::GetTaskRunner() {
cef_server_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, get_task_runner))
return NULL;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
cef_task_runner_t* _retval = _struct->get_task_runner(_struct);
// Return type: refptr_same
return CefTaskRunnerCToCpp::Wrap(_retval);
}
void CefServerCToCpp::Shutdown() {
cef_server_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, shutdown))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
_struct->shutdown(_struct);
}
bool CefServerCToCpp::IsRunning() {
cef_server_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, is_running))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
int _retval = _struct->is_running(_struct);
// Return type: bool
return _retval ? true : false;
}
CefString CefServerCToCpp::GetAddress() {
cef_server_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, get_address))
return CefString();
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
cef_string_userfree_t _retval = _struct->get_address(_struct);
// Return type: string
CefString _retvalStr;
_retvalStr.AttachToUserFree(_retval);
return _retvalStr;
}
bool CefServerCToCpp::HasConnection() {
cef_server_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, has_connection))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
int _retval = _struct->has_connection(_struct);
// Return type: bool
return _retval ? true : false;
}
bool CefServerCToCpp::IsValidConnection(int connection_id) {
cef_server_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, is_valid_connection))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
int _retval = _struct->is_valid_connection(_struct, connection_id);
// Return type: bool
return _retval ? true : false;
}
void CefServerCToCpp::SendHttp200Response(int connection_id,
const CefString& content_type,
const void* data,
size_t data_size) {
cef_server_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, connection_id,
content_type.GetStruct(), data, data_size);
}
void CefServerCToCpp::SendHttp404Response(int connection_id) {
cef_server_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, send_http404response))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
_struct->send_http404response(_struct, connection_id);
}
void CefServerCToCpp::SendHttp500Response(int connection_id,
const CefString& error_message) {
cef_server_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, connection_id,
error_message.GetStruct());
}
void CefServerCToCpp::SendHttpResponse(int connection_id,
int response_code,
const CefString& content_type,
int64 content_length,
const HeaderMap& extra_headers) {
cef_server_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;
// 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, connection_id, response_code,
content_type.GetStruct(), content_length,
extra_headersMultimap);
// Restore param:extra_headers; type: string_map_multi_byref_const
if (extra_headersMultimap)
cef_string_multimap_free(extra_headersMultimap);
}
void CefServerCToCpp::SendRawData(int connection_id,
const void* data,
size_t data_size) {
cef_server_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, send_raw_data))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: data; type: simple_byaddr
DCHECK(data);
if (!data)
return;
// Execute
_struct->send_raw_data(_struct, connection_id, data, data_size);
}
void CefServerCToCpp::CloseConnection(int connection_id) {
cef_server_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, close_connection))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
_struct->close_connection(_struct, connection_id);
}
void CefServerCToCpp::SendWebSocketMessage(int connection_id,
const void* data,
size_t data_size) {
cef_server_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, send_web_socket_message))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: data; type: simple_byaddr
DCHECK(data);
if (!data)
return;
// Execute
_struct->send_web_socket_message(_struct, connection_id, data, data_size);
}
// CONSTRUCTOR - Do not edit by hand.
CefServerCToCpp::CefServerCToCpp() {}
template <>
cef_server_t*
CefCToCppRefCounted<CefServerCToCpp, CefServer, cef_server_t>::UnwrapDerived(
CefWrapperType type,
CefServer* c) {
NOTREACHED() << "Unexpected class type: " << type;
return NULL;
}
#if DCHECK_IS_ON()
template <>
base::AtomicRefCount
CefCToCppRefCounted<CefServerCToCpp, CefServer, cef_server_t>::DebugObjCt
ATOMIC_DECLARATION;
#endif
template <>
CefWrapperType CefCToCppRefCounted<CefServerCToCpp, CefServer, cef_server_t>::
kWrapperType = WT_SERVER;

View File

@ -0,0 +1,62 @@
// Copyright (c) 2017 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=7218e524c29b0837d4759117c81ffa1401759596$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_SERVER_CTOCPP_H_
#define CEF_LIBCEF_DLL_CTOCPP_SERVER_CTOCPP_H_
#pragma once
#if !defined(WRAPPING_CEF_SHARED)
#error This file can be included wrapper-side only
#endif
#include "include/capi/cef_server_capi.h"
#include "include/cef_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 CefServerCToCpp
: public CefCToCppRefCounted<CefServerCToCpp, CefServer, cef_server_t> {
public:
CefServerCToCpp();
// CefServer methods.
CefRefPtr<CefTaskRunner> GetTaskRunner() OVERRIDE;
void Shutdown() OVERRIDE;
bool IsRunning() OVERRIDE;
CefString GetAddress() OVERRIDE;
bool HasConnection() OVERRIDE;
bool IsValidConnection(int connection_id) OVERRIDE;
void SendHttp200Response(int connection_id,
const CefString& content_type,
const void* data,
size_t data_size) OVERRIDE;
void SendHttp404Response(int connection_id) OVERRIDE;
void SendHttp500Response(int connection_id,
const CefString& error_message) OVERRIDE;
void SendHttpResponse(int connection_id,
int response_code,
const CefString& content_type,
int64 content_length,
const HeaderMap& extra_headers) OVERRIDE;
void SendRawData(int connection_id,
const void* data,
size_t data_size) OVERRIDE;
void CloseConnection(int connection_id) OVERRIDE;
void SendWebSocketMessage(int connection_id,
const void* data,
size_t data_size) OVERRIDE;
};
#endif // CEF_LIBCEF_DLL_CTOCPP_SERVER_CTOCPP_H_

View File

@ -0,0 +1,223 @@
// Copyright (c) 2017 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=262176ac6f772f186c59e0bf07e07d3514fa3440$
//
#include "libcef_dll/ctocpp/server_handler_ctocpp.h"
#include "libcef_dll/cpptoc/callback_cpptoc.h"
#include "libcef_dll/cpptoc/request_cpptoc.h"
#include "libcef_dll/cpptoc/server_cpptoc.h"
// VIRTUAL METHODS - Body may be edited by hand.
void CefServerHandlerCToCpp::OnServerCreated(CefRefPtr<CefServer> server) {
cef_server_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_server_created))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: server; type: refptr_diff
DCHECK(server.get());
if (!server.get())
return;
// Execute
_struct->on_server_created(_struct, CefServerCppToC::Wrap(server));
}
void CefServerHandlerCToCpp::OnServerDestroyed(CefRefPtr<CefServer> server) {
cef_server_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_server_destroyed))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: server; type: refptr_diff
DCHECK(server.get());
if (!server.get())
return;
// Execute
_struct->on_server_destroyed(_struct, CefServerCppToC::Wrap(server));
}
void CefServerHandlerCToCpp::OnClientConnected(CefRefPtr<CefServer> server,
int connection_id) {
cef_server_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_client_connected))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: server; type: refptr_diff
DCHECK(server.get());
if (!server.get())
return;
// Execute
_struct->on_client_connected(_struct, CefServerCppToC::Wrap(server),
connection_id);
}
void CefServerHandlerCToCpp::OnClientDisconnected(CefRefPtr<CefServer> server,
int connection_id) {
cef_server_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_client_disconnected))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: server; type: refptr_diff
DCHECK(server.get());
if (!server.get())
return;
// Execute
_struct->on_client_disconnected(_struct, CefServerCppToC::Wrap(server),
connection_id);
}
void CefServerHandlerCToCpp::OnHttpRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request) {
cef_server_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_http_request))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: server; type: refptr_diff
DCHECK(server.get());
if (!server.get())
return;
// Verify param: client_address; type: string_byref_const
DCHECK(!client_address.empty());
if (client_address.empty())
return;
// Verify param: request; type: refptr_diff
DCHECK(request.get());
if (!request.get())
return;
// Execute
_struct->on_http_request(_struct, CefServerCppToC::Wrap(server),
connection_id, client_address.GetStruct(),
CefRequestCppToC::Wrap(request));
}
void CefServerHandlerCToCpp::OnWebSocketRequest(
CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) {
cef_server_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_web_socket_request))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: server; type: refptr_diff
DCHECK(server.get());
if (!server.get())
return;
// Verify param: client_address; type: string_byref_const
DCHECK(!client_address.empty());
if (client_address.empty())
return;
// Verify param: request; type: refptr_diff
DCHECK(request.get());
if (!request.get())
return;
// Verify param: callback; type: refptr_diff
DCHECK(callback.get());
if (!callback.get())
return;
// Execute
_struct->on_web_socket_request(_struct, CefServerCppToC::Wrap(server),
connection_id, client_address.GetStruct(),
CefRequestCppToC::Wrap(request),
CefCallbackCppToC::Wrap(callback));
}
void CefServerHandlerCToCpp::OnWebSocketConnected(CefRefPtr<CefServer> server,
int connection_id) {
cef_server_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_web_socket_connected))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: server; type: refptr_diff
DCHECK(server.get());
if (!server.get())
return;
// Execute
_struct->on_web_socket_connected(_struct, CefServerCppToC::Wrap(server),
connection_id);
}
void CefServerHandlerCToCpp::OnWebSocketMessage(CefRefPtr<CefServer> server,
int connection_id,
const void* data,
size_t data_size) {
cef_server_handler_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_web_socket_message))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: server; type: refptr_diff
DCHECK(server.get());
if (!server.get())
return;
// Verify param: data; type: simple_byaddr
DCHECK(data);
if (!data)
return;
// Execute
_struct->on_web_socket_message(_struct, CefServerCppToC::Wrap(server),
connection_id, data, data_size);
}
// CONSTRUCTOR - Do not edit by hand.
CefServerHandlerCToCpp::CefServerHandlerCToCpp() {}
template <>
cef_server_handler_t*
CefCToCppRefCounted<CefServerHandlerCToCpp,
CefServerHandler,
cef_server_handler_t>::UnwrapDerived(CefWrapperType type,
CefServerHandler* c) {
NOTREACHED() << "Unexpected class type: " << type;
return NULL;
}
#if DCHECK_IS_ON()
template <>
base::AtomicRefCount CefCToCppRefCounted<CefServerHandlerCToCpp,
CefServerHandler,
cef_server_handler_t>::DebugObjCt
ATOMIC_DECLARATION;
#endif
template <>
CefWrapperType CefCToCppRefCounted<CefServerHandlerCToCpp,
CefServerHandler,
cef_server_handler_t>::kWrapperType =
WT_SERVER_HANDLER;

View File

@ -0,0 +1,60 @@
// Copyright (c) 2017 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=a5012dffe69ac9161fce2e11bc2f65772bd21ff4$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_SERVER_HANDLER_CTOCPP_H_
#define CEF_LIBCEF_DLL_CTOCPP_SERVER_HANDLER_CTOCPP_H_
#pragma once
#if !defined(BUILDING_CEF_SHARED)
#error This file can be included DLL-side only
#endif
#include "include/capi/cef_server_capi.h"
#include "include/cef_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 CefServerHandlerCToCpp
: public CefCToCppRefCounted<CefServerHandlerCToCpp,
CefServerHandler,
cef_server_handler_t> {
public:
CefServerHandlerCToCpp();
// CefServerHandler methods.
void OnServerCreated(CefRefPtr<CefServer> server) override;
void OnServerDestroyed(CefRefPtr<CefServer> server) override;
void OnClientConnected(CefRefPtr<CefServer> server,
int connection_id) override;
void OnClientDisconnected(CefRefPtr<CefServer> server,
int connection_id) override;
void OnHttpRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request) override;
void OnWebSocketRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override;
void OnWebSocketConnected(CefRefPtr<CefServer> server,
int connection_id) override;
void OnWebSocketMessage(CefRefPtr<CefServer> server,
int connection_id,
const void* data,
size_t data_size) override;
};
#endif // CEF_LIBCEF_DLL_CTOCPP_SERVER_HANDLER_CTOCPP_H_

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=2df1182745ef1d14ed20428c53ed7638742c13f9$
// $hash=4ae6ce5d8ccf3b39d55d6d8a67f8daf547242271$
//
#include "include/capi/cef_app_capi.h"
@ -74,6 +74,7 @@
#include "libcef_dll/cpptoc/run_context_menu_callback_cpptoc.h"
#include "libcef_dll/cpptoc/scheme_registrar_cpptoc.h"
#include "libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h"
#include "libcef_dll/cpptoc/server_cpptoc.h"
#include "libcef_dll/cpptoc/sslinfo_cpptoc.h"
#include "libcef_dll/cpptoc/sslstatus_cpptoc.h"
#include "libcef_dll/cpptoc/stream_reader_cpptoc.h"
@ -152,6 +153,7 @@
#include "libcef_dll/ctocpp/response_filter_ctocpp.h"
#include "libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h"
#include "libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h"
#include "libcef_dll/ctocpp/server_handler_ctocpp.h"
#include "libcef_dll/ctocpp/set_cookie_callback_ctocpp.h"
#include "libcef_dll/ctocpp/string_visitor_ctocpp.h"
#include "libcef_dll/ctocpp/task_ctocpp.h"
@ -344,6 +346,8 @@ CEF_EXPORT void cef_shutdown() {
DCHECK(base::AtomicRefCountIsZero(&CefScrollViewCppToC::DebugObjCt));
DCHECK(base::AtomicRefCountIsZero(
&CefSelectClientCertificateCallbackCppToC::DebugObjCt));
DCHECK(base::AtomicRefCountIsZero(&CefServerCppToC::DebugObjCt));
DCHECK(base::AtomicRefCountIsZero(&CefServerHandlerCToCpp::DebugObjCt));
DCHECK(base::AtomicRefCountIsZero(&CefSetCookieCallbackCToCpp::DebugObjCt));
DCHECK(base::AtomicRefCountIsZero(&CefStreamReaderCppToC::DebugObjCt));
DCHECK(base::AtomicRefCountIsZero(&CefStreamWriterCppToC::DebugObjCt));

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=82e24ebf13dbb1b7430a4710fd3d296b98311d1d$
// $hash=8f5702806c240c66d2b9235cf44e58ba52fe3b63$
//
#include "include/capi/cef_app_capi.h"
@ -81,6 +81,7 @@
#include "libcef_dll/cpptoc/response_filter_cpptoc.h"
#include "libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.h"
#include "libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h"
#include "libcef_dll/cpptoc/server_handler_cpptoc.h"
#include "libcef_dll/cpptoc/set_cookie_callback_cpptoc.h"
#include "libcef_dll/cpptoc/string_visitor_cpptoc.h"
#include "libcef_dll/cpptoc/task_cpptoc.h"
@ -134,6 +135,7 @@
#include "libcef_dll/ctocpp/run_context_menu_callback_ctocpp.h"
#include "libcef_dll/ctocpp/scheme_registrar_ctocpp.h"
#include "libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h"
#include "libcef_dll/ctocpp/server_ctocpp.h"
#include "libcef_dll/ctocpp/sslinfo_ctocpp.h"
#include "libcef_dll/ctocpp/sslstatus_ctocpp.h"
#include "libcef_dll/ctocpp/stream_reader_ctocpp.h"
@ -335,6 +337,8 @@ CEF_GLOBAL void CefShutdown() {
DCHECK(base::AtomicRefCountIsZero(&CefScrollViewCToCpp::DebugObjCt));
DCHECK(base::AtomicRefCountIsZero(
&CefSelectClientCertificateCallbackCToCpp::DebugObjCt));
DCHECK(base::AtomicRefCountIsZero(&CefServerCToCpp::DebugObjCt));
DCHECK(base::AtomicRefCountIsZero(&CefServerHandlerCppToC::DebugObjCt));
DCHECK(base::AtomicRefCountIsZero(&CefSetCookieCallbackCppToC::DebugObjCt));
DCHECK(base::AtomicRefCountIsZero(&CefStreamReaderCToCpp::DebugObjCt));
DCHECK(base::AtomicRefCountIsZero(&CefStreamWriterCToCpp::DebugObjCt));

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=0e103b8e82d15405eb5fdb2efc48992dae1e9656$
// $hash=9a3b6de92214d6b132bd66d84724272c886a3758$
//
#ifndef CEF_LIBCEF_DLL_WRAPPER_TYPES_H_
@ -115,6 +115,8 @@ enum CefWrapperType {
WT_SCHEME_REGISTRAR,
WT_SCROLL_VIEW,
WT_SELECT_CLIENT_CERTIFICATE_CALLBACK,
WT_SERVER,
WT_SERVER_HANDLER,
WT_SET_COOKIE_CALLBACK,
WT_STREAM_READER,
WT_STREAM_WRITER,

View File

@ -7,12 +7,14 @@
#include <algorithm>
#include <string>
#include "tests/cefclient/browser/test_runner.h"
namespace client {
namespace binding_test {
namespace {
const char kTestUrl[] = "http://tests/binding";
const char kTestUrlPath[] = "/binding";
const char kTestMessageName[] = "BindingTest";
// Handle messages in the browser process.
@ -29,7 +31,7 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
CefRefPtr<Callback> callback) OVERRIDE {
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (url.find(kTestUrl) != 0)
if (!test_runner::IsTestURL(url, kTestUrlPath))
return false;
const std::string& message_name = request;

View File

@ -8,13 +8,14 @@
#include "include/cef_browser.h"
#include "include/wrapper/cef_helpers.h"
#include "tests/cefclient/browser/test_runner.h"
namespace client {
namespace dialog_test {
namespace {
const char kTestUrl[] = "http://tests/dialogs";
const char kTestUrlPath[] = "/dialogs";
const char kFileOpenMessageName[] = "DialogTest.FileOpen";
const char kFileOpenMultipleMessageName[] = "DialogTest.FileOpenMultiple";
const char kFileOpenFolderMessageName[] = "DialogTest.FileOpenFolder";
@ -109,7 +110,7 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (url.find(kTestUrl) != 0)
if (!test_runner::IsTestURL(url, kTestUrlPath))
return false;
if (!dialog_state_.get())

View File

@ -9,6 +9,7 @@
#include "include/cef_parser.h"
#include "include/cef_web_plugin.h"
#include "tests/cefclient/browser/test_runner.h"
namespace client {
namespace drm_test {
@ -19,7 +20,7 @@ namespace {
const int kMessageFormatError = 1;
const int kCdmLoadError = 2;
const char kTestUrl[] = "http://tests/drm";
const char kTestUrlPath[] = "/drm";
const char kWidevineCdmPathKey[] = "widevine_cdm_path";
// Callback executed once CDM registration is complete.
@ -49,7 +50,7 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
public:
Handler() {}
// Called due to cefQuery execution in binding.html.
// Called due to cefQuery execution in drm.html.
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
@ -58,7 +59,7 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
CefRefPtr<Callback> callback) OVERRIDE {
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (url.find(kTestUrl) != 0)
if (!test_runner::IsTestURL(url, kTestUrlPath))
return false;
// Parse |request| as a JSON dictionary.

View File

@ -11,13 +11,14 @@
#include "include/base/cef_logging.h"
#include "include/cef_command_line.h"
#include "include/cef_parser.h"
#include "tests/cefclient/browser/test_runner.h"
namespace client {
namespace preferences_test {
namespace {
const char kTestUrl[] = "http://tests/preferences";
const char kTestUrlPath[] = "/preferences";
// Application-specific error codes.
const int kMessageFormatError = 1;
@ -52,8 +53,8 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
CEF_REQUIRE_UI_THREAD();
// Only handle messages from the test URL.
std::string url = frame->GetURL();
if (url.find(kTestUrl) != 0)
const std::string& url = frame->GetURL();
if (!test_runner::IsTestURL(url, kTestUrlPath))
return false;
// Parse |request| as a JSON dictionary.

View File

@ -58,12 +58,14 @@
#define IDS_PERFORMANCE2_HTML 1013
#define IDS_PREFERENCES_HTML 1014
#define IDS_RESPONSE_FILTER_HTML 1015
#define IDS_TRANSPARENCY_HTML 1016
#define IDS_URLREQUEST_HTML 1017
#define IDS_WINDOW_HTML 1018
#define IDS_WINDOW_ICON_1X_PNG 1019
#define IDS_WINDOW_ICON_2X_PNG 1020
#define IDS_XMLHTTPREQUEST_HTML 1021
#define IDS_SERVER_HTML 1016
#define IDS_TRANSPARENCY_HTML 1017
#define IDS_URLREQUEST_HTML 1018
#define IDS_WEBSOCKET_HTML 1019
#define IDS_WINDOW_HTML 1020
#define IDS_WINDOW_ICON_1X_PNG 1021
#define IDS_WINDOW_ICON_2X_PNG 1022
#define IDS_XMLHTTPREQUEST_HTML 1023
#define IDS_EXTENSIONS_SET_PAGE_COLOR_ICON_PNG 1030
#define IDS_EXTENSIONS_SET_PAGE_COLOR_MANIFEST_JSON 1031

View File

@ -38,8 +38,10 @@ int GetResourceId(const char* resource_name) {
{"performance2.html", IDS_PERFORMANCE2_HTML},
{"preferences.html", IDS_PREFERENCES_HTML},
{"response_filter.html", IDS_RESPONSE_FILTER_HTML},
{"server.html", IDS_SERVER_HTML},
{"transparency.html", IDS_TRANSPARENCY_HTML},
{"urlrequest.html", IDS_URLREQUEST_HTML},
{"websocket.html", IDS_WEBSOCKET_HTML},
{"window.html", IDS_WINDOW_HTML},
{"window_icon.1x.png", IDS_WINDOW_ICON_1X_PNG},
{"window_icon.2x.png", IDS_WINDOW_ICON_2X_PNG},

View File

@ -10,6 +10,7 @@
#include "include/base/cef_logging.h"
#include "include/cef_command_line.h"
#include "tests/cefclient/browser/test_runner.h"
#include "tests/shared/common/client_switches.h"
namespace client {
@ -17,7 +18,7 @@ namespace response_filter_test {
namespace {
const char kTestUrl[] = "http://tests/response_filter";
const char kTestUrlPath[] = "/response_filter";
const char kFindString[] = "REPLACE_THIS_STRING";
const char kReplaceString[] = "This is the replaced string!";
@ -226,7 +227,8 @@ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
CefRefPtr<CefResponse> response) {
// Use the find/replace filter on the test URL.
const std::string& url = request->GetURL();
if (url.find(kTestUrl) == 0)
if (test_runner::IsTestURL(url, kTestUrlPath))
return new FindReplaceResponseFilter();
if (MatchesFilterURL(url))

View File

@ -0,0 +1,387 @@
// Copyright (c) 2017 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 "tests/cefclient/browser/server_test.h"
#include <algorithm>
#include <string>
#include "include/base/cef_bind.h"
#include "include/base/cef_weak_ptr.h"
#include "include/cef_parser.h"
#include "include/cef_server.h"
#include "include/wrapper/cef_closure_task.h"
#include "tests/shared/browser/resource_util.h"
namespace client {
namespace server_test {
namespace {
// Application-specific error codes.
const int kMessageFormatError = 1;
const int kActionStateError = 1;
// JSON dictionary keys.
const char kActionKey[] = "action";
const char kResultKey[] = "result";
const char kPortKey[] = "port";
const char kStatusKey[] = "status";
const char kMessageKey[] = "message";
// Required URL for cefQuery execution.
const char kTestUrl[] = "http://tests/server";
// Server default values.
const char kServerAddress[] = "127.0.0.1";
const int kServerPortDefault = 8099;
const int kServerBacklog = 10;
const char kDefaultPath[] = "websocket.html";
// Handles the HTTP/WebSocket server.
class ServerHandler : public CefServerHandler {
public:
typedef base::Callback<void(bool /* success */)> CompleteCallback;
ServerHandler() {}
// |complete_callback| will be executed on the UI thread after completion.
void StartServer(int port, const CompleteCallback& complete_callback) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!server_);
DCHECK(port >= 1025 && port <= 65535);
port_ = port;
complete_callback_ = complete_callback;
CefServer::CreateServer(kServerAddress, port, kServerBacklog, this);
}
// |complete_callback| will be executed on the UI thread after completion.
void StopServer(const CompleteCallback& complete_callback) {
CEF_REQUIRE_UI_THREAD();
DCHECK(server_);
complete_callback_ = complete_callback;
server_->Shutdown();
}
// CefServerHandler methods are called on the server thread.
void OnServerCreated(CefRefPtr<CefServer> server) override {
DCHECK(!server_);
server_ = server;
RunCompleteCallback(server->IsRunning());
}
void OnServerDestroyed(CefRefPtr<CefServer> server) override {
DCHECK(server_);
server_ = nullptr;
RunCompleteCallback(true);
}
void OnClientConnected(CefRefPtr<CefServer> server,
int connection_id) override {}
void OnClientDisconnected(CefRefPtr<CefServer> server,
int connection_id) override {}
void OnHttpRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request) override {
// Parse the request URL and retrieve the path without leading slash.
CefURLParts url_parts;
CefParseURL(request->GetURL(), url_parts);
std::string path = CefString(&url_parts.path);
if (!path.empty() && path[0] == '/')
path = path.substr(1);
if (path.empty())
path = kDefaultPath;
std::string mime_type;
const size_t sep = path.find_last_of(".");
if (sep != std::string::npos) {
// Determine the mime type based on the extension.
mime_type = CefGetMimeType(path.substr(sep + 1));
} else {
// No extension. Assume html.
path += ".html";
}
if (mime_type.empty())
mime_type = "text/html";
CefRefPtr<CefStreamReader> stream;
CefResponse::HeaderMap extra_headers;
if (path == "request.html") {
// Return the request contents.
stream = test_runner::GetDumpResponse(request, extra_headers);
}
if (!stream) {
// Load any resource supported by cefclient.
stream = GetBinaryResourceReader(path.c_str());
}
if (stream) {
SendHttpResponseStream(server, connection_id, mime_type, stream,
extra_headers);
} else {
server->SendHttp404Response(connection_id);
}
}
void OnWebSocketRequest(CefRefPtr<CefServer> server,
int connection_id,
const CefString& client_address,
CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
// Always accept WebSocket connections.
callback->Continue();
}
void OnWebSocketConnected(CefRefPtr<CefServer> server,
int connection_id) override {}
void OnWebSocketMessage(CefRefPtr<CefServer> server,
int connection_id,
const void* data,
size_t data_size) override {
// Echo the reverse of the message.
std::string message(static_cast<const char*>(data), data_size);
std::reverse(message.begin(), message.end());
server->SendWebSocketMessage(connection_id, message.data(), message.size());
}
int port() const { return port_; }
private:
void RunCompleteCallback(bool success) {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::Bind(&ServerHandler::RunCompleteCallback, this,
success));
return;
}
if (!complete_callback_.is_null()) {
complete_callback_.Run(success);
complete_callback_.Reset();
}
}
static void SendHttpResponseStream(CefRefPtr<CefServer> server,
int connection_id,
const std::string& mime_type,
CefRefPtr<CefStreamReader> stream,
CefResponse::HeaderMap extra_headers) {
// Determine the stream size.
stream->Seek(0, SEEK_END);
int64 content_length = stream->Tell();
stream->Seek(0, SEEK_SET);
// Send response headers.
server->SendHttpResponse(connection_id, 200, mime_type, content_length,
extra_headers);
// Send stream contents.
char buffer[8192];
size_t read;
do {
read = stream->Read(buffer, 1, sizeof(buffer));
if (read > 0)
server->SendRawData(connection_id, buffer, read);
} while (!stream->Eof() && read != 0);
// Close the connection.
server->CloseConnection(connection_id);
}
CefRefPtr<CefServer> server_;
// The below members are only accessed on the UI thread.
int port_;
CompleteCallback complete_callback_;
IMPLEMENT_REFCOUNTING(ServerHandler);
DISALLOW_COPY_AND_ASSIGN(ServerHandler);
};
// Handle messages in the browser process.
class Handler : public CefMessageRouterBrowserSide::Handler {
public:
Handler() : weak_ptr_factory_(this) {}
virtual ~Handler() {
if (handler_) {
handler_->StopServer(ServerHandler::CompleteCallback());
handler_ = nullptr;
}
}
// Called due to cefQuery execution in server.html.
virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) OVERRIDE {
CEF_REQUIRE_UI_THREAD();
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (url.find(kTestUrl) != 0)
return false;
// Parse |request| as a JSON dictionary.
CefRefPtr<CefDictionaryValue> request_dict = ParseJSON(request);
if (!request_dict) {
callback->Failure(kMessageFormatError, "Incorrect message format");
return true;
}
if (!VerifyKey(request_dict, kActionKey, VTYPE_STRING, callback))
return true;
const std::string& action = request_dict->GetString(kActionKey);
if (action == "query") {
HandleQueryAction(request_dict, callback);
} else if (action == "start") {
HandleStartAction(request_dict, callback);
} else if (action == "stop") {
HandleStopAction(request_dict, callback);
} else {
callback->Failure(kMessageFormatError, "Unrecognized action: " + action);
}
return true;
}
private:
// Return current server status.
void HandleQueryAction(CefRefPtr<CefDictionaryValue> request_dict,
CefRefPtr<Callback> callback) {
CefRefPtr<CefDictionaryValue> result_dict = CefDictionaryValue::Create();
if (handler_) {
result_dict->SetInt(kPortKey, handler_->port());
result_dict->SetString(kStatusKey, "running");
} else {
result_dict->SetInt(kPortKey, kServerPortDefault);
result_dict->SetString(kStatusKey, "stopped");
}
SendResponse(callback, true, result_dict);
}
// Start the server.
void HandleStartAction(CefRefPtr<CefDictionaryValue> request_dict,
CefRefPtr<Callback> callback) {
if (handler_) {
callback->Failure(kActionStateError, "Server is currently running");
return;
}
if (!VerifyKey(request_dict, kPortKey, VTYPE_INT, callback))
return;
const int port = request_dict->GetInt(kPortKey);
if (port < 8000 || port > 65535) {
callback->Failure(kMessageFormatError, "Invalid port number specified");
return;
}
handler_ = new ServerHandler();
// Start the server. OnComplete will be executed upon completion.
handler_->StartServer(port,
base::Bind(&Handler::OnStartComplete,
weak_ptr_factory_.GetWeakPtr(), callback));
}
// Stop the server.
void HandleStopAction(CefRefPtr<CefDictionaryValue> request_dict,
CefRefPtr<Callback> callback) {
if (!handler_) {
callback->Failure(kActionStateError, "Server is not currently running");
return;
}
// Stop the server. OnComplete will be executed upon completion.
handler_->StopServer(base::Bind(&Handler::OnStopComplete,
weak_ptr_factory_.GetWeakPtr(), callback));
handler_ = nullptr;
}
// Server start completed.
void OnStartComplete(CefRefPtr<Callback> callback, bool success) {
CEF_REQUIRE_UI_THREAD();
CefRefPtr<CefDictionaryValue> result_dict = CefDictionaryValue::Create();
if (!success) {
handler_ = nullptr;
result_dict->SetString(kMessageKey, "Server failed to start.");
}
SendResponse(callback, success, result_dict);
}
// Server stop completed.
void OnStopComplete(CefRefPtr<Callback> callback, bool success) {
CEF_REQUIRE_UI_THREAD();
CefRefPtr<CefDictionaryValue> result_dict = CefDictionaryValue::Create();
if (!success) {
result_dict->SetString(kMessageKey, "Server failed to stop.");
}
SendResponse(callback, success, result_dict);
}
// Send a response in the format expected by server.html.
static void SendResponse(CefRefPtr<Callback> callback,
bool success,
CefRefPtr<CefDictionaryValue> result_dict) {
if (!result_dict) {
result_dict = CefDictionaryValue::Create();
}
result_dict->SetString(kResultKey, success ? "success" : "failure");
CefRefPtr<CefValue> value = CefValue::Create();
value->SetDictionary(result_dict);
const std::string& response = CefWriteJSON(value, JSON_WRITER_DEFAULT);
callback->Success(response);
}
// Convert a JSON string to a dictionary value.
static CefRefPtr<CefDictionaryValue> ParseJSON(const CefString& string) {
CefRefPtr<CefValue> value = CefParseJSON(string, JSON_PARSER_RFC);
if (value.get() && value->GetType() == VTYPE_DICTIONARY)
return value->GetDictionary();
return NULL;
}
// Verify that |key| exists in |dictionary| and has type |value_type|. Fails
// |callback| and returns false on failure.
static bool VerifyKey(CefRefPtr<CefDictionaryValue> dictionary,
const char* key,
cef_value_type_t value_type,
CefRefPtr<Callback> callback) {
if (!dictionary->HasKey(key) || dictionary->GetType(key) != value_type) {
callback->Failure(
kMessageFormatError,
"Missing or incorrectly formatted message key: " + std::string(key));
return false;
}
return true;
}
// Non-nullptr while the server is running.
CefRefPtr<ServerHandler> handler_;
// Must be the last member.
base::WeakPtrFactory<Handler> weak_ptr_factory_;
};
} // namespace
void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
handlers.insert(new Handler());
}
} // namespace server_test
} // namespace client

View File

@ -0,0 +1,20 @@
// Copyright (c) 2017 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_TESTS_CEFCLIENT_BROWSER_SERVER_TEST_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_SERVER_TEST_H_
#pragma once
#include "tests/cefclient/browser/test_runner.h"
namespace client {
namespace server_test {
// Create message handlers. Called from test_runner.cc.
void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers);
} // namespace server_test
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_SERVER_TEST_H_

View File

@ -22,6 +22,7 @@
#include "tests/cefclient/browser/response_filter_test.h"
#include "tests/cefclient/browser/root_window_manager.h"
#include "tests/cefclient/browser/scheme_test.h"
#include "tests/cefclient/browser/server_test.h"
#include "tests/cefclient/browser/urlrequest_test.h"
#include "tests/cefclient/browser/window_test.h"
#include "tests/shared/browser/resource_util.h"
@ -31,6 +32,8 @@ namespace test_runner {
namespace {
const char kTestHost[] = "tests";
const char kLocalHost[] = "localhost";
const char kTestOrigin[] = "http://tests/";
// Replace all instances of |from| with |to| in |str|.
@ -432,13 +435,12 @@ class RequestDumpResourceProvider : public CefResourceManager::Provider {
return false;
}
const std::string& dump = DumpRequestContents(request->request());
std::string str =
"<html><body bgcolor=\"white\"><pre>" + dump + "</pre></body></html>";
CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
static_cast<void*>(const_cast<char*>(str.c_str())), str.size());
DCHECK(stream.get());
request->Continue(new CefStreamResourceHandler("text/html", stream));
CefResponse::HeaderMap response_headers;
CefRefPtr<CefStreamReader> response =
GetDumpResponse(request->request(), response_headers);
request->Continue(new CefStreamResourceHandler(200, "OK", "text/html",
response_headers, response));
return true;
}
@ -592,6 +594,49 @@ std::string DumpRequestContents(CefRefPtr<CefRequest> request) {
return ss.str();
}
CefRefPtr<CefStreamReader> GetDumpResponse(
CefRefPtr<CefRequest> request,
CefResponse::HeaderMap& response_headers) {
std::string origin;
// Extract the origin request header, if any. It will be specified for
// cross-origin requests.
{
CefRequest::HeaderMap requestMap;
request->GetHeaderMap(requestMap);
CefRequest::HeaderMap::const_iterator it = requestMap.begin();
for (; it != requestMap.end(); ++it) {
std::string key = it->first;
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
if (key == "origin") {
origin = it->second;
break;
}
}
}
if (!origin.empty() &&
(origin.find("http://" + std::string(kTestHost)) == 0 ||
origin.find("http://" + std::string(kLocalHost)) == 0)) {
// Allow cross-origin XMLHttpRequests from test origins.
response_headers.insert(
std::make_pair("Access-Control-Allow-Origin", origin));
// Allow the custom header from the xmlhttprequest.html example.
response_headers.insert(
std::make_pair("Access-Control-Allow-Headers", "My-Custom-Header"));
}
const std::string& dump = DumpRequestContents(request);
std::string str =
"<html><body bgcolor=\"white\"><pre>" + dump + "</pre></body></html>";
CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
static_cast<void*>(const_cast<char*>(str.c_str())), str.size());
DCHECK(stream);
return stream;
}
std::string GetDataURI(const std::string& data, const std::string& mime_type) {
return "data:" + mime_type + ";base64," +
CefURIEncode(CefBase64Encode(data.data(), data.size()), false)
@ -710,6 +755,18 @@ void Alert(CefRefPtr<CefBrowser> browser, const std::string& message) {
frame->ExecuteJavaScript("alert('" + msg + "');", frame->GetURL(), 0);
}
bool IsTestURL(const std::string& url, const std::string& path) {
CefURLParts parts;
CefParseURL(url, parts);
const std::string& url_host = CefString(&parts.host);
if (url_host != kTestHost && url_host != kLocalHost)
return false;
const std::string& url_path = CefString(&parts.path);
return url_path.find(path) == 0;
}
void CreateMessageHandlers(MessageHandlerSet& handlers) {
handlers.insert(new PromptHandler);
@ -725,6 +782,9 @@ void CreateMessageHandlers(MessageHandlerSet& handlers) {
// Create the preferences test handlers.
preferences_test::CreateMessageHandlers(handlers);
// Create the server test handlers.
server_test::CreateMessageHandlers(handlers);
// Create the urlrequest test handlers.
urlrequest_test::CreateMessageHandlers(handlers);

View File

@ -23,6 +23,12 @@ void RunTest(CefRefPtr<CefBrowser> browser, int id);
// Returns the contents of the CefRequest as a string.
std::string DumpRequestContents(CefRefPtr<CefRequest> request);
// Returns the dump response as a stream. |request| is the request.
// |response_headers| will be populated with extra response headers, if any.
CefRefPtr<CefStreamReader> GetDumpResponse(
CefRefPtr<CefRequest> request,
CefResponse::HeaderMap& response_headers);
// Returns a data: URI with the specified contents.
std::string GetDataURI(const std::string& data, const std::string& mime_type);
@ -35,6 +41,10 @@ void SetupResourceManager(CefRefPtr<CefResourceManager> resource_manager);
// Show a JS alert message.
void Alert(CefRefPtr<CefBrowser> browser, const std::string& message);
// Returns true if |url| is a test URL with the specified |path|. This matches
// both http://tests/<path> and http://localhost:xxxx/<path>.
bool IsTestURL(const std::string& url, const std::string& path);
// Create all CefMessageRouterBrowserSide::Handler objects. They will be
// deleted when the ClientHandler is destroyed.
typedef std::set<CefMessageRouterBrowserSide::Handler*> MessageHandlerSet;

View File

@ -11,13 +11,14 @@
#include "include/base/cef_logging.h"
#include "include/cef_urlrequest.h"
#include "include/wrapper/cef_helpers.h"
#include "tests/cefclient/browser/test_runner.h"
namespace client {
namespace urlrequest_test {
namespace {
const char kTestUrl[] = "http://tests/urlrequest";
const char kTestUrlPath[] = "/urlrequest";
const char kTestMessageName[] = "URLRequestTest";
// Implementation of CefURLRequestClient that stores response information. Only
@ -97,13 +98,14 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
CEF_REQUIRE_UI_THREAD();
// Only handle messages from the test URL.
std::string url = frame->GetURL();
if (url.find(kTestUrl) != 0)
const std::string& url = frame->GetURL();
if (!test_runner::IsTestURL(url, kTestUrlPath))
return false;
const std::string& message_name = request;
if (message_name.find(kTestMessageName) == 0) {
url = message_name.substr(sizeof(kTestMessageName));
const std::string& load_url =
message_name.substr(sizeof(kTestMessageName));
CancelPendingRequest();
@ -114,7 +116,7 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
// Create a CefRequest for the specified URL.
CefRefPtr<CefRequest> cef_request = CefRequest::Create();
cef_request->SetURL(url);
cef_request->SetURL(load_url);
cef_request->SetMethod("GET");
// Callback to be executed on request completion.

View File

@ -12,6 +12,7 @@
#include "include/base/cef_bind.h"
#include "include/wrapper/cef_stream_resource_handler.h"
#include "tests/cefclient/browser/main_context.h"
#include "tests/cefclient/browser/test_runner.h"
#include "tests/cefclient/browser/window_test_runner.h"
#if defined(OS_WIN) || defined(OS_LINUX)
@ -31,7 +32,7 @@ namespace window_test {
namespace {
const char kTestUrl[] = "http://tests/window";
const char kTestUrlPath[] = "/window";
const char kMessagePositionName[] = "WindowTest.Position";
const char kMessageMinimizeName[] = "WindowTest.Minimize";
const char kMessageMaximizeName[] = "WindowTest.Maximize";
@ -69,7 +70,7 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
CefRefPtr<Callback> callback) OVERRIDE {
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (url.find(kTestUrl) != 0)
if (!test_runner::IsTestURL(url, kTestUrlPath))
return false;
const std::string& message_name = request;

View File

@ -3,9 +3,22 @@
<title>Binding Test</title>
<script language="JavaScript">
function setup() {
if (location.hostname == 'tests' || location.hostname == 'localhost')
return;
alert('This page can only be run from tests or localhost.');
// Disable all elements.
var elements = document.getElementById("form").elements;
for (var i = 0, element; element = elements[i++]; ) {
element.disabled = true;
}
}
// Send a query to the browser process.
function sendMessage() {
// Results in a call to the OnQuery method in binding_test.cpp
// Results in a call to the OnQuery method in binding_test.cc
window.cefQuery({
request: 'BindingTest:' + document.getElementById("message").value,
onSuccess: function(response) {
@ -17,8 +30,8 @@ function sendMessage() {
</script>
</head>
<body bgcolor="white">
<form>
<body bgcolor="white" onload="setup()">
<form id="form">
Message: <input type="text" id="message" value="My Message">
<br/><input type="button" onclick="sendMessage();" value="Send Message">
<br/>You should see the reverse of your message below:

View File

@ -29,6 +29,17 @@ function update_time() {
function setup() {
update_time();
setInterval(update_time, 1000);
if (location.hostname != 'tests' && location.hostname != 'localhost') {
alert('Parts of this page can only be run from tests or localhost.');
return;
}
// Enable all elements.
var elements = document.getElementById("form").elements;
for (var i = 0, element; element = elements[i++]; ) {
element.disabled = false;
}
}
function show_file_dialog(element, test) {
@ -49,16 +60,16 @@ window.addEventListener('load', setup, false);
</script>
</head>
<body bgcolor="white">
<form>
<form id="form">
Click a button to show the associated dialog type.
<br/><input type="button" onclick="show_alert();" value="Show Alert">
<br/><input type="button" onclick="show_confirm();" value="Show Confirm"> <span id="cm"></span>
<br/><input type="button" onclick="show_prompt();" value="Show Prompt"> <span id="pm"></span>
<br/>input type="file": <input type="file" name="pic" accept="text/*,.js,.css,image/*">
<br/><input type="button" onclick="show_file_dialog('fo', 'FileOpen');" value="Show File Open"> <span id="fo"></span>
<br/><input type="button" onclick="show_file_dialog('fom', 'FileOpenMultiple');" value="Show File Open Multiple"> <span id="fom"></span>
<br/><input type="button" onclick="show_file_dialog('fof', 'FileOpenFolder');" value="Show File Open Folder"> <span id="fof"></span>
<br/><input type="button" onclick="show_file_dialog('fs', 'FileSave');" value="Show File Save"> <span id="fs"></span>
<br/><input type="button" onclick="show_file_dialog('fo', 'FileOpen');" value="Show File Open" disabled="true"> <span id="fo"></span>
<br/><input type="button" onclick="show_file_dialog('fom', 'FileOpenMultiple');" value="Show File Open Multiple" disabled="true"> <span id="fom"></span>
<br/><input type="button" onclick="show_file_dialog('fof', 'FileOpenFolder');" value="Show File Open Folder" disabled="true"> <span id="fof"></span>
<br/><input type="button" onclick="show_file_dialog('fs', 'FileSave');" value="Show File Save" disabled="true"> <span id="fs"></span>
<p id="time"></p>
</form>
</body>

View File

@ -3,6 +3,21 @@
<title>DRM Test</title>
<script language="JavaScript">
function setup() {
if (location.hostname == 'tests' || location.hostname == 'localhost')
return;
alert('This page can only be run from tests or localhost.');
// Disable all elements.
var elements = document.getElementById("form").elements;
for (var i = 0, element; element = elements[i++]; ) {
element.disabled = true;
}
doTest();
}
// Based on DRM detection code from https://github.com/google/shaka-player
function probeSupport() {
var tests = [];
@ -87,7 +102,7 @@ function sendMessage() {
request.widevine_cdm_path =
document.getElementById("widevine_cdm_path").value;
// Results in a call to the OnQuery method in drm_test.cpp
// Results in a call to the OnQuery method in drm_test.cc
window.cefQuery({
request: JSON.stringify(request),
onSuccess: function(response) {
@ -104,7 +119,7 @@ function sendMessage() {
</script>
</head>
<body bgcolor="white" onload="doTest()">
<body bgcolor="white" onload="setup()">
Important notes:
<ul>
<li>Clearkey support is built in and should always be enabled.</li>
@ -117,7 +132,7 @@ Important notes:
<li>Test DRM video playback <a href="https://shaka-player-demo.appspot.com/demo/">here</a>. Select an "asset" that includes Clearkey or Widevine in the name.</li>
</ul>
<form>
<form id="form">
Widevine CDM Path: <input type="text" id="widevine_cdm_path" value="" size="40">
<input type="button" onclick="sendMessage();" value="Load CDM">
</form>

View File

@ -8,32 +8,34 @@
<li><a href="http://mudcu.be/labs/JS1k/BreathingGalaxies.html">Accelerated 2D Canvas</a></li>
<li><a href="http://webkit.org/blog-files/3d-transforms/poster-circle.html">Accelerated Layers</a></li>
<li><a href="http://html5advent2011.digitpaint.nl/3/index.html">Cursors</a></li>
<li><a href="http://tests/dialogs">Dialogs</a></li>
<li><a href="dialogs">Dialogs</a></li>
<li><a href="http://html5demos.com/drag">Drag & Drop</a></li>
<li><a href="http://tests/draggable">Draggable Regions</a></li>
<li><a href="http://tests/drm">DRM (Clearkey, Widevine)</a></li>
<li><a href="draggable">Draggable Regions</a></li>
<li><a href="drm">DRM (Clearkey, Widevine)</a></li>
<li><a href="http://www.adobe.com/software/flash/about/">Flash Plugin</a> - requires "enable-system-flash" flag on Win/Mac and "ppapi-flash-path", "ppapi-flash-version" flags on Linux</li>
<li><a href="http://html5demos.com/geo">Geolocation</a></li>
<li><a href="http://www.html5test.com">HTML5 Feature Test</a></li>
<li><a href="http://html5-demos.appspot.com/static/filesystem/filer.js/demos/index.html">HTML5 Filesystem</a> - requires "cache-path" flag</li>
<li><a href="http://www.youtube.com/watch?v=siOHh0uzcuY&html5=True">HTML5 Video</a></li>
<li><a href="http://tests/binding">JavaScript Binding</a></li>
<li><a href="http://tests/performance">JavaScript Performance Tests</a></li>
<li><a href="http://tests/performance2">JavaScript Performance (2) Tests</a></li>
<li><a href="http://tests/window">JavaScript Window Manipulation</a></li>
<li><a href="http://tests/localstorage">Local Storage</a></li>
<li><a href="http://tests/pdf.pdf">PDF Viewer direct</a></li>
<li><a href="http://tests/pdf">PDF Viewer iframe</a></li>
<li><a href="http://tests/preferences">Preferences</a></li>
<li><a href="binding">JavaScript Binding</a></li>
<li><a href="performance">JavaScript Performance Tests</a></li>
<li><a href="performance2">JavaScript Performance (2) Tests</a></li>
<li><a href="window">JavaScript Window Manipulation</a></li>
<li><a href="localstorage">Local Storage</a></li>
<li><a href="pdf.pdf">PDF Viewer direct</a></li>
<li><a href="pdf">PDF Viewer iframe</a></li>
<li><a href="preferences">Preferences</a></li>
<li><a href="http://mrdoob.com/lab/javascript/requestanimationframe/">requestAnimationFrame</a></li>
<li><a href="http://tests/response_filter">Response Filtering</a></li>
<li><a href="response_filter">Response Filtering</a></li>
<li><a href="client://tests/handler.html">Scheme Handler</a></li>
<li><a href="server">HTTP/WebSocket Server</a></li>
<li><a href="websocket">WebSocket Client</a></li>
<li><a href="https://www.google.com/intl/en/chrome/demos/speech.html">Speech Input</a> - requires "enable-speech-input" flag</li>
<li><a href="http://tests/transparency">Transparency</a></li>
<li><a href="transparency">Transparency</a></li>
<li><a href="http://webglsamples.org/field/field.html">WebGL</a></li>
<li><a href="http://apprtc.appspot.com/">WebRTC</a> - requires "enable-media-stream" flag</li>
<li><a href="http://tests/urlrequest">CefURLRequest</a></li>
<li><a href="http://tests/xmlhttprequest">XMLHttpRequest</a></li>
<li><a href="urlrequest">CefURLRequest</a></li>
<li><a href="xmlhttprequest">XMLHttpRequest</a></li>
<li><a href="javascript:window.print();">Print this page with &quot;javascript:window.print();&quot;</a></li>
</ul>
</body>

View File

@ -10,8 +10,23 @@
script hosting from http://cdnjs.com/libraries/jsoneditor -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/4.2.1/jsoneditor.min.css" rel="stylesheet" type="text/css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/4.2.1/jsoneditor.min.js"></script>
<script>
function setup() {
if (location.hostname == 'tests' || location.hostname == 'localhost')
return;
alert('This page can only be run from tests or localhost.');
// Disable all elements.
var elements = document.getElementById("form").elements;
for (var i = 0, element; element = elements[i++]; ) {
element.disabled = true;
}
}
</script>
</head>
<body bgcolor="white">
<body bgcolor="white" onload="setup()">
<!-- Header -->
<div id="simple_links">
[ <b>Simple</b> ]
@ -22,6 +37,8 @@
[ <b>Advanced</b> ]
</div>
<form id="form">
<!-- Simple view -->
<div id="simple">
<p>
@ -88,6 +105,8 @@
</table>
</div>
</form>
<script>
// Reference to the JSONEditor.
var editor = null;

View File

@ -0,0 +1,104 @@
<html>
<head>
<title>Server Test</title>
<script language="JavaScript">
// Send a query to the browser process.
function sendMessage(request, success_callback) {
// Results in a call to the OnQuery method in server_test.cc
window.cefQuery({
request: JSON.stringify(request),
onSuccess: function(response) {
success_callback(response.length == 0 ? {} : JSON.parse(response));
},
onFailure: function(error_code, error_message) {
alert("Request failed with error " + error_message + "(" + error_code + ")");
}
});
}
function setButtonState(start_enabled, stop_enabled) {
document.getElementById('start').disabled = !start_enabled;
document.getElementById('stop').disabled = !stop_enabled;
document.getElementById('open').disabled = !stop_enabled;
}
function setup() {
if (location.origin != 'http://tests') {
document.getElementById('warning').style.display = 'block';
return;
}
// Query the current server state.
sendMessage({'action':'query'}, function(response) {
if (response['result'] == 'success') {
var running = (response['status'] == 'running')
setButtonState(!running, running);
var port_element = document.getElementById('port');
port_element.value = response['port'];
port_element.disabled = false;
}
});
}
function startServer() {
var port = parseInt(document.getElementById('port').value);
if (port < 1025 || port > 65535) {
alert('Specify a port number between 1025 and 65535');
return;
}
setButtonState(false, false);
sendMessage({'action':'start', 'port':port}, function(response) {
if (response['result'] == 'success') {
setButtonState(false, true);
} else {
setButtonState(true, false);
alert(response['message']);
}
});
}
function stopServer() {
setButtonState(false, false);
sendMessage({'action':'stop'}, function(response) {
if (response['result'] == 'success') {
setButtonState(true, false);
} else {
setButtonState(false, true);
alert(response['message']);
}
});
}
function openServer() {
var port = document.getElementById('port').value;
window.open('http://localhost:' + port);
}
</script>
</head>
<body bgcolor="white" onload="setup()">
<div id="warning" style="display:none;color:red;font-weight:bold;">
This page can only be run from the http://tests origin.
</div>
<p>
This page starts an HTTP/WebSocket server on localhost with the specified port number.
After starting the server click the "Open Example" button to open the WebSocket Client test in a popup window.
</p>
<p>
With this example each browser window can create/manage a separate server instance.
The server will be stopped automatically when the managing browser window is closed.
</p>
<form>
Server port: <input type="text" id="port" value="" disabled="true">
<br/><input type="button" id="start" onclick="startServer()" value="Start Server" disabled="true">
<input type="button" id="stop" onclick="stopServer()" value="Stop Server" disabled="true">
<input type="button" id="open" onclick="openServer()" value="Open Example" disabled="true">
</form>
</body>
</html>

View File

@ -1,7 +1,20 @@
<html>
<body bgcolor="white">
<head>
<script language="JavaScript">
function setup() {
if (location.hostname == 'tests' || location.hostname == 'localhost')
return;
alert('This page can only be run from tests or localhost');
// Disable all elements.
var elements = document.getElementById("form").elements;
for (var i = 0, element; element = elements[i++]; ) {
element.disabled = true;
}
}
// Send a query to the browser process.
function execURLRequest() {
document.getElementById('ta').value = 'Request pending...';
@ -18,7 +31,9 @@ function execURLRequest() {
});
}
</script>
<form>
</head>
<body bgcolor="white" onload="setup()">
<form id="form">
URL: <input type="text" id="url" value="http://www.google.com">
<br/><input type="button" onclick="execURLRequest();" value="Execute CefURLRequest">
<br/><textarea rows="10" cols="40" id="ta"></textarea>

View File

@ -0,0 +1,107 @@
<html>
<head>
<title>WebSocket Test</title>
<script language="JavaScript">
var ws = null;
function setup() {
// Match the secure state of the current origin.
var origin = location.origin;
if (origin.indexOf('http://') == 0) {
origin = origin.replace('http://', 'ws://');
} else if (origin.indexOf('https://') == 0) {
origin = origin.replace('https://', 'wss://');
} else {
origin = '';
}
if (origin.length > 0)
document.getElementById('server').value = origin;
document.getElementById('server').disabled = false;
if (location.hostname != 'localhost')
document.getElementById('warning').style.display = 'block';
setConnected(false);
}
function setConnected(connected) {
document.getElementById('connect').disabled = connected;
document.getElementById('disconnect').disabled = !connected;
document.getElementById('message').disabled = !connected;
document.getElementById('response').disabled = !connected;
document.getElementById('send').disabled = !connected;
}
function doConnect() {
var url = document.getElementById('server').value;
if (url.indexOf('ws://') < 0 && url.indexOf('wss://') < 0) {
alert('Specify a valid WebSocket server URL.');
return;
}
if (ws) {
alert('WebSocket is already connected.');
return;
}
ws = new WebSocket(url);
ws.onopen = function() { setConnected(true); };
ws.onmessage = function(event) {
document.getElementById('response').value = event.data;
};
ws.onclose = function(event) {
setConnected(false);
ws = null;
};
ws.onerror = function(event) {
if (ws.readyState == 3)
alert('WebSocket connection failed.');
}
}
function doDisconnect() {
if (!ws) {
alert('WebSocket is not currently connected.');
return;
}
ws.close();
}
function doSend() {
if (!ws) {
alert('WebSocket is not currently connected.');
return;
}
var value = document.getElementById('message').value;
if (value.length > 0)
ws.send(value);
}
</script>
</head>
<body bgcolor="white" onload="setup()">
<div id="warning" style="display:none;color:red;font-weight:bold;">
This page is most useful when loaded from localhost.
You should first create a server using the <a href="http://tests/server">HTTP/WebSocket Server test</a>.
</div>
<p>
This page tests a WebSocket connection.
The example implementation in server_test.cc will then echo the message contents in reverse.
</p>
<form>
Server URL: <input type="text" id="server" value="" disabled="true">
<br/><input type="button" id="connect" onclick="doConnect()" value="Connect" disabled="true">
<input type="button" id="disconnect" onclick="doDisconnect()" value="Disconnect" disabled="true">
<br/>Message: <input type="text" id="message" value="Test Message" disabled="true">
<input type="button" id="send" onclick="doSend()" value="Send" disabled="true">
<br/>Response: <input type="text" id="response" value="" disabled="true">
<br/><br/>
The example implementation in server_test.cc can also serve the HTTP-based <a href="other_tests">Other Tests</a>.
</form>
</body>
</html>

View File

@ -45,8 +45,10 @@ IDS_PERFORMANCE_HTML BINARY "..\\performance.html"
IDS_PERFORMANCE2_HTML BINARY "..\\performance2.html"
IDS_PREFERENCES_HTML BINARY "..\\preferences.html"
IDS_RESPONSE_FILTER_HTML BINARY "..\\response_filter.html"
IDS_SERVER_HTML BINARY "..\\server.html"
IDS_TRANSPARENCY_HTML BINARY "..\\transparency.html"
IDS_URLREQUEST_HTML BINARY "..\\urlrequest.html"
IDS_WEBSOCKET_HTML BINARY "..\\websocket.html"
IDS_WINDOW_HTML BINARY "..\\window.html"
IDS_WINDOW_ICON_1X_PNG BINARY "..\\..\\..\\shared\\resources\\window_icon.1x.png"
IDS_WINDOW_ICON_2X_PNG BINARY "..\\..\\..\\shared\\resources\\window_icon.2x.png"

View File

@ -2,6 +2,19 @@
<head>
<title>Window Test</title>
<script>
function setup() {
if (location.hostname == 'tests' || location.hostname == 'localhost')
return;
alert('This page can only be run from tests or localhost.');
// Disable all elements.
var elements = document.getElementById("form").elements;
for (var i = 0, element; element = elements[i++]; ) {
element.disabled = true;
}
}
function send_message(test, params) {
var message = 'WindowTest.' + test;
if (typeof params != 'undefined')
@ -36,13 +49,17 @@ function position() {
}
</script>
</head>
<body bgcolor="white">
<form>
<body bgcolor="white" onload="setup()">
<form id="form">
Click a button to perform the associated window action.
<br/><input type="button" onclick="minimize();" value="Minimize">
<br/><input type="button" onclick="maximize();" value="Maximize">
<br/><input type="button" onclick="restore();" value="Restore"> (minimizes and then restores the window as topmost)
<br/><input type="button" onclick="position();" value="Set Position"> X: <input type="text" size="4" id="x" value="200"> Y: <input type="text" size="4" id="y" value="100"> Width: <input type="text" size="4" id="width" value="800"> Height: <input type="text" size="4" id="height" value="600">
<br/><input type="button" onclick="position();" value="Set Position">
X: <input type="text" size="4" id="x" value="200">
Y: <input type="text" size="4" id="y" value="100">
Width: <input type="text" size="4" id="width" value="800">
Height: <input type="text" size="4" id="height" value="600">
</form>
</body>
</html>

View File

@ -3,8 +3,20 @@
<script language="JavaScript">
function execXMLHttpRequest()
{
var url = document.getElementById("url").value;
var warningElement = document.getElementById("warning");
if (url.indexOf(location.origin) != 0) {
warningElement.innerHTML =
'For cross-origin requests to succeed the server must return CORS headers:' +
'<pre>Access-Control-Allow-Origin: ' + location.origin +
'<br/>Access-Control-Allow-Header: My-Custom-Header</pre>';
warningElement.style.display = 'block';
} else {
warningElement.style.display = 'none';
}
xhr = new XMLHttpRequest();
xhr.open("GET", document.getElementById("url").value, true);
xhr.open("GET", url, true);
xhr.setRequestHeader('My-Custom-Header', 'Some Value');
xhr.onload = function(e) {
if (xhr.readyState === 4) {
@ -22,5 +34,6 @@ URL: <input type="text" id="url" value="http://tests/request">
<br/><input type="button" onclick="execXMLHttpRequest();" value="Execute XMLHttpRequest">
<br/><textarea rows="10" cols="40" id="ta"></textarea>
</form>
<div id="warning" style="display:none;font-weight:bold;"></div>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -352,6 +352,8 @@ _simpletypes = {
'void': ['void', ''],
'void*': ['void*', 'NULL'],
'int': ['int', '0'],
'int16': ['int16', '0'],
'uint16': ['uint16', '0'],
'int32': ['int32', '0'],
'uint32': ['uint32', '0'],
'int64': ['int64', '0'],