Implement improvements for request handling (issue #1327).

- Add a new CefRequestHandler::OnResourceResponse() method for inspecting the request/response headers and potentially restarting or redirecting the request.
- Add a new CefRequest::GetIdentifier() method for tracking a request across multiple CefRequestHandler callbacks.
- Pass a CefRequest object instead of just the old URL to CefRequestHandler::OnResourceRedirect().

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@2073 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2015-03-11 18:44:11 +00:00
parent 0b36550786
commit 558a8a3658
21 changed files with 745 additions and 48 deletions

View File

@ -28,3 +28,4 @@ Czarek Tomczak <czarek.tomczak@gmail.com>
Felix Bruns <felixbruns@spotify.com>
YuTeh Shen <shenyute@gmail.com>
Andrei Kurushin <ajax16384@gmail.com>
Gonzo Berman <gberman@factset.com>

View File

@ -159,6 +159,13 @@ typedef struct _cef_request_t {
///
cef_transition_type_t (CEF_CALLBACK *get_transition_type)(
struct _cef_request_t* self);
///
// Returns the globally unique identifier for this request or 0 if not
// specified. Can be used by cef_request_tHandler implementations in the
// browser process to track a single request across multiple callbacks.
///
uint64 (CEF_CALLBACK *get_identifier)(struct _cef_request_t* self);
} cef_request_t;

View File

@ -159,13 +159,24 @@ typedef struct _cef_request_handler_t {
struct _cef_frame_t* frame, struct _cef_request_t* request);
///
// Called on the IO thread when a resource load is redirected. The |old_url|
// parameter will contain the old URL. The |new_url| parameter will contain
// the new URL and can be changed if desired.
// Called on the IO thread when a resource load is redirected. The |request|
// parameter will contain the old URL and other request-related information.
// The |new_url| parameter will contain the new URL and can be changed if
// desired. The |request| object cannot be modified in this callback.
///
void (CEF_CALLBACK *on_resource_redirect)(struct _cef_request_handler_t* self,
struct _cef_browser_t* browser, struct _cef_frame_t* frame,
const cef_string_t* old_url, cef_string_t* new_url);
struct _cef_request_t* request, cef_string_t* new_url);
///
// Called on the IO thread when a resource response is received. To allow the
// resource to load normally return false (0). To redirect or retry the
// resource modify |request| (url, headers or post body) and return true (1).
// The |response| object cannot be modified in this callback.
///
int (CEF_CALLBACK *on_resource_response)(struct _cef_request_handler_t* self,
struct _cef_browser_t* browser, struct _cef_frame_t* frame,
struct _cef_request_t* request, struct _cef_response_t* response);
///
// Called on the IO thread when the browser needs credentials from the user.

View File

@ -168,6 +168,14 @@ class CefRequest : public virtual CefBase {
///
/*--cef(default_retval=TT_EXPLICIT)--*/
virtual TransitionType GetTransitionType() =0;
///
// Returns the globally unique identifier for this request or 0 if not
// specified. Can be used by CefRequestHandler implementations in the browser
// process to track a single request across multiple callbacks.
///
/*--cef()--*/
virtual uint64 GetIdentifier() =0;
};

View File

@ -165,16 +165,31 @@ class CefRequestHandler : public virtual CefBase {
}
///
// Called on the IO thread when a resource load is redirected. The |old_url|
// parameter will contain the old URL. The |new_url| parameter will contain
// the new URL and can be changed if desired.
// Called on the IO thread when a resource load is redirected. The |request|
// parameter will contain the old URL and other request-related information.
// The |new_url| parameter will contain the new URL and can be changed if
// desired. The |request| object cannot be modified in this callback.
///
/*--cef()--*/
virtual void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& old_url,
CefRefPtr<CefRequest> request,
CefString& new_url) {}
///
// Called on the IO thread when a resource response is received. To allow the
// resource to load normally return false. To redirect or retry the resource
// modify |request| (url, headers or post body) and return true. The
// |response| object cannot be modified in this callback.
///
/*--cef()--*/
virtual bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) {
return false;
}
///
// Called on the IO thread when the browser needs credentials from the user.
// |isProxy| indicates whether the host is a proxy server. |host| contains the

View File

@ -9,8 +9,13 @@
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/resource_request_job.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/http_header_utils.h"
#include "libcef/common/request_impl.h"
#include "libcef/common/response_impl.h"
#include "net/base/upload_data_stream.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request_job_manager.h"
#include "net/url_request/url_request_redirect_job.h"
CefRequestInterceptor::CefRequestInterceptor() {
@ -40,9 +45,10 @@ net::URLRequestJob* CefRequestInterceptor::MaybeInterceptRequest(
// Give the client an opportunity to replace the request.
CefRefPtr<CefResourceHandler> resourceHandler =
handler->GetResourceHandler(browser.get(), frame, req);
if (resourceHandler.get())
if (resourceHandler.get()) {
return new CefResourceRequestJob(request, network_delegate,
resourceHandler);
}
}
}
}
@ -63,12 +69,16 @@ net::URLRequestJob* CefRequestInterceptor::MaybeInterceptRedirect(
if (handler.get()) {
CefRefPtr<CefFrame> frame = browser->GetFrameForRequest(request);
CefRefPtr<CefRequest> cefRequest = new CefRequestImpl();
static_cast<CefRequestImpl*>(cefRequest.get())->Set(request);
static_cast<CefRequestImpl*>(cefRequest.get())->SetReadOnly(true);
// Give the client an opportunity to redirect the request.
CefString newUrlStr = location.spec();
handler->OnResourceRedirect(browser.get(), frame, request->url().spec(),
newUrlStr);
handler->OnResourceRedirect(browser.get(), frame, cefRequest,
newUrlStr);
if (newUrlStr != location.spec()) {
GURL new_url = GURL(std::string(newUrlStr));
const GURL new_url = GURL(newUrlStr.ToString());
if (!new_url.is_empty() && new_url.is_valid()) {
return new net::URLRequestRedirectJob(
request, network_delegate, new_url,
@ -86,5 +96,74 @@ net::URLRequestJob* CefRequestInterceptor::MaybeInterceptRedirect(
net::URLRequestJob* CefRequestInterceptor::MaybeInterceptResponse(
net::URLRequest* request,
net::NetworkDelegate* network_delegate) const {
return NULL;
CefRefPtr<CefBrowserHostImpl> browser =
CefBrowserHostImpl::GetBrowserForRequest(request);
if (!browser.get())
return NULL;
CefRefPtr<CefClient> client = browser->GetClient();
if (!client.get())
return NULL;
CefRefPtr<CefRequestHandler> handler = client->GetRequestHandler();
if (!handler.get())
return NULL;
CefRefPtr<CefFrame> frame = browser->GetFrameForRequest(request);
CefRefPtr<CefRequest> cefRequest = new CefRequestImpl();
static_cast<CefRequestImpl*>(cefRequest.get())->Set(request);
CefRefPtr<CefResponse> cefResponse = new CefResponseImpl();
static_cast<CefResponseImpl*>(cefResponse.get())->Set(request);
static_cast<CefResponseImpl*>(cefResponse.get())->SetReadOnly(true);
// Give the client an opportunity to retry or redirect the request.
if (!handler->OnResourceResponse(browser.get(), frame, cefRequest,
cefResponse)) {
return NULL;
}
// This flag will be reset by URLRequest::RestartWithJob() calling
// URLRequest::PrepareToRestart() after this method returns but we need it
// reset sooner so that we can modify the request headers without asserting.
request->set_is_pending(false);
// Update the request headers to match the CefRequest.
CefRequest::HeaderMap cefHeaders;
cefRequest->GetHeaderMap(cefHeaders);
CefString referrerStr;
referrerStr.FromASCII(net::HttpRequestHeaders::kReferer);
CefRequest::HeaderMap::iterator it = cefHeaders.find(referrerStr);
if (it != cefHeaders.end()) {
request->SetReferrer(it->second);
cefHeaders.erase(it);
}
net::HttpRequestHeaders netHeaders;
netHeaders.AddHeadersFromString(HttpHeaderUtils::GenerateHeaders(cefHeaders));
request->SetExtraRequestHeaders(netHeaders);
// Update the request body to match the CefRequest.
CefRefPtr<CefPostData> post_data = cefRequest->GetPostData();
if (post_data.get()) {
request->set_upload(
make_scoped_ptr(static_cast<CefPostDataImpl*>(post_data.get())->Get()));
} else if (request->get_upload()) {
request->set_upload(scoped_ptr<net::UploadDataStream>());
}
// If the URL was modified redirect the request.
const GURL url(cefRequest->GetURL().ToString());
if (url != request->url()) {
return new net::URLRequestRedirectJob(
request, network_delegate, url,
net::URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT,
"Resource Redirect");
}
// Otherwise queue a new job.
return net::URLRequestJobManager::GetInstance()->CreateJob(
request, network_delegate);
}

View File

@ -104,6 +104,7 @@ CefRequestImpl::CefRequestImpl()
: method_("GET"),
resource_type_(RT_SUB_RESOURCE),
transition_type_(TT_EXPLICIT),
identifier_(0U),
flags_(UR_FLAG_NONE),
read_only_(false) {
}
@ -199,6 +200,11 @@ CefRequestImpl::TransitionType CefRequestImpl::GetTransitionType() {
return transition_type_;
}
uint64 CefRequestImpl::GetIdentifier() {
base::AutoLock lock_scope(lock_);
return identifier_;
}
void CefRequestImpl::Set(net::URLRequest* request) {
base::AutoLock lock_scope(lock_);
CHECK_READONLY_RETURN_VOID();
@ -206,6 +212,7 @@ void CefRequestImpl::Set(net::URLRequest* request) {
url_ = request->url().spec();
method_ = request->method();
first_party_for_cookies_ = request->first_party_for_cookies().spec();
identifier_ = request->identifier();
net::HttpRequestHeaders headers = request->extra_request_headers();

View File

@ -48,6 +48,7 @@ class CefRequestImpl : public CefRequest {
void SetFirstPartyForCookies(const CefString& url) override;
ResourceType GetResourceType() override;
TransitionType GetTransitionType() override;
uint64 GetIdentifier() override;
// Populate this object from the URLRequest object.
void Set(net::URLRequest* request);
@ -77,6 +78,7 @@ class CefRequestImpl : public CefRequest {
HeaderMap headermap_;
ResourceType resource_type_;
TransitionType transition_type_;
uint64 identifier_;
// The below members are used by CefURLRequest.
int flags_;

View File

@ -10,6 +10,7 @@
#include "base/strings/stringprintf.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
#include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
@ -152,6 +153,7 @@ net::HttpResponseHeaders* CefResponseImpl::GetResponseHeaders() {
void CefResponseImpl::SetResponseHeaders(
const net::HttpResponseHeaders& headers) {
base::AutoLock lock_scope(lock_);
CHECK_READONLY_RETURN_VOID();
header_map_.empty();
@ -166,6 +168,8 @@ void CefResponseImpl::SetResponseHeaders(
std::string mime_type;
if (headers.GetMimeType(&mime_type))
mime_type_ = mime_type;
else
mime_type_.clear();
}
void CefResponseImpl::Set(const blink::WebURLResponse& response) {
@ -199,6 +203,14 @@ void CefResponseImpl::Set(const blink::WebURLResponse& response) {
response.visitHTTPHeaderFields(&visitor);
}
void CefResponseImpl::Set(const net::URLRequest* request) {
DCHECK(request);
const net::HttpResponseHeaders* headers = request->response_headers();
if (headers)
SetResponseHeaders(*headers);
}
void CefResponseImpl::SetReadOnly(bool read_only) {
base::AutoLock lock_scope(lock_);
read_only_ = read_only;

View File

@ -12,6 +12,7 @@
namespace net {
class HttpResponseHeaders;
class URLRequest;
}
namespace blink {
@ -39,6 +40,7 @@ class CefResponseImpl : public CefResponse {
void SetResponseHeaders(const net::HttpResponseHeaders& headers);
void Set(const blink::WebURLResponse& response);
void Set(const net::URLRequest* request);
void SetReadOnly(bool read_only);

View File

@ -309,6 +309,20 @@ cef_transition_type_t CEF_CALLBACK request_get_transition_type(
return _retval;
}
uint64 CEF_CALLBACK request_get_identifier(struct _cef_request_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Execute
uint64 _retval = CefRequestCppToC::Get(self)->GetIdentifier();
// Return type: simple
return _retval;
}
// CONSTRUCTOR - Do not edit by hand.
@ -332,6 +346,7 @@ CefRequestCppToC::CefRequestCppToC(CefRequest* cls)
request_set_first_party_for_cookies;
struct_.struct_.get_resource_type = request_get_resource_type;
struct_.struct_.get_transition_type = request_get_transition_type;
struct_.struct_.get_identifier = request_get_identifier;
}
#ifndef NDEBUG

View File

@ -18,6 +18,7 @@
#include "libcef_dll/ctocpp/frame_ctocpp.h"
#include "libcef_dll/ctocpp/quota_callback_ctocpp.h"
#include "libcef_dll/ctocpp/request_ctocpp.h"
#include "libcef_dll/ctocpp/response_ctocpp.h"
#include "libcef_dll/ctocpp/sslinfo_ctocpp.h"
#include "libcef_dll/ctocpp/web_plugin_info_ctocpp.h"
@ -155,7 +156,7 @@ struct _cef_resource_handler_t* CEF_CALLBACK request_handler_get_resource_handle
void CEF_CALLBACK request_handler_on_resource_redirect(
struct _cef_request_handler_t* self, cef_browser_t* browser,
cef_frame_t* frame, const cef_string_t* old_url, cef_string_t* new_url) {
cef_frame_t* frame, cef_request_t* request, cef_string_t* new_url) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
@ -169,9 +170,9 @@ void CEF_CALLBACK request_handler_on_resource_redirect(
DCHECK(frame);
if (!frame)
return;
// Verify param: old_url; type: string_byref_const
DCHECK(old_url);
if (!old_url)
// Verify param: request; type: refptr_diff
DCHECK(request);
if (!request)
return;
// Verify param: new_url; type: string_byref
DCHECK(new_url);
@ -185,10 +186,47 @@ void CEF_CALLBACK request_handler_on_resource_redirect(
CefRequestHandlerCppToC::Get(self)->OnResourceRedirect(
CefBrowserCToCpp::Wrap(browser),
CefFrameCToCpp::Wrap(frame),
CefString(old_url),
CefRequestCToCpp::Wrap(request),
new_urlStr);
}
int CEF_CALLBACK request_handler_on_resource_response(
struct _cef_request_handler_t* self, cef_browser_t* browser,
cef_frame_t* frame, cef_request_t* request,
struct _cef_response_t* response) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Verify param: browser; type: refptr_diff
DCHECK(browser);
if (!browser)
return 0;
// Verify param: frame; type: refptr_diff
DCHECK(frame);
if (!frame)
return 0;
// Verify param: request; type: refptr_diff
DCHECK(request);
if (!request)
return 0;
// Verify param: response; type: refptr_diff
DCHECK(response);
if (!response)
return 0;
// Execute
bool _retval = CefRequestHandlerCppToC::Get(self)->OnResourceResponse(
CefBrowserCToCpp::Wrap(browser),
CefFrameCToCpp::Wrap(frame),
CefRequestCToCpp::Wrap(request),
CefResponseCToCpp::Wrap(response));
// Return type: bool
return _retval;
}
int CEF_CALLBACK request_handler_get_auth_credentials(
struct _cef_request_handler_t* self, cef_browser_t* browser,
cef_frame_t* frame, int isProxy, const cef_string_t* host, int port,
@ -445,6 +483,7 @@ CefRequestHandlerCppToC::CefRequestHandlerCppToC(CefRequestHandler* cls)
request_handler_on_before_resource_load;
struct_.struct_.get_resource_handler = request_handler_get_resource_handler;
struct_.struct_.on_resource_redirect = request_handler_on_resource_redirect;
struct_.struct_.on_resource_response = request_handler_on_resource_response;
struct_.struct_.get_auth_credentials = request_handler_get_auth_credentials;
struct_.struct_.on_quota_request = request_handler_on_quota_request;
struct_.struct_.on_protocol_execution = request_handler_on_protocol_execution;

View File

@ -295,6 +295,19 @@ CefRequest::TransitionType CefRequestCToCpp::GetTransitionType() {
return _retval;
}
uint64 CefRequestCToCpp::GetIdentifier() {
if (CEF_MEMBER_MISSING(struct_, get_identifier))
return 0;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
uint64 _retval = struct_->get_identifier(struct_);
// Return type: simple
return _retval;
}
#ifndef NDEBUG
template<> base::AtomicRefCount CefCToCpp<CefRequestCToCpp, CefRequest,

View File

@ -48,6 +48,7 @@ class CefRequestCToCpp
virtual void SetFirstPartyForCookies(const CefString& url) OVERRIDE;
virtual ResourceType GetResourceType() OVERRIDE;
virtual TransitionType GetTransitionType() OVERRIDE;
virtual uint64 GetIdentifier() OVERRIDE;
};
#endif // USING_CEF_SHARED

View File

@ -16,6 +16,7 @@
#include "libcef_dll/cpptoc/frame_cpptoc.h"
#include "libcef_dll/cpptoc/quota_callback_cpptoc.h"
#include "libcef_dll/cpptoc/request_cpptoc.h"
#include "libcef_dll/cpptoc/response_cpptoc.h"
#include "libcef_dll/cpptoc/sslinfo_cpptoc.h"
#include "libcef_dll/cpptoc/web_plugin_info_cpptoc.h"
#include "libcef_dll/ctocpp/request_handler_ctocpp.h"
@ -152,7 +153,8 @@ CefRefPtr<CefResourceHandler> CefRequestHandlerCToCpp::GetResourceHandler(
}
void CefRequestHandlerCToCpp::OnResourceRedirect(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, const CefString& old_url, CefString& new_url) {
CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request,
CefString& new_url) {
if (CEF_MEMBER_MISSING(struct_, on_resource_redirect))
return;
@ -166,19 +168,55 @@ void CefRequestHandlerCToCpp::OnResourceRedirect(CefRefPtr<CefBrowser> browser,
DCHECK(frame.get());
if (!frame.get())
return;
// Verify param: old_url; type: string_byref_const
DCHECK(!old_url.empty());
if (old_url.empty())
// Verify param: request; type: refptr_diff
DCHECK(request.get());
if (!request.get())
return;
// Execute
struct_->on_resource_redirect(struct_,
CefBrowserCppToC::Wrap(browser),
CefFrameCppToC::Wrap(frame),
old_url.GetStruct(),
CefRequestCppToC::Wrap(request),
new_url.GetWritableStruct());
}
bool CefRequestHandlerCToCpp::OnResourceResponse(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) {
if (CEF_MEMBER_MISSING(struct_, on_resource_response))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: browser; type: refptr_diff
DCHECK(browser.get());
if (!browser.get())
return false;
// Verify param: frame; type: refptr_diff
DCHECK(frame.get());
if (!frame.get())
return false;
// Verify param: request; type: refptr_diff
DCHECK(request.get());
if (!request.get())
return false;
// Verify param: response; type: refptr_diff
DCHECK(response.get());
if (!response.get())
return false;
// Execute
int _retval = struct_->on_resource_response(struct_,
CefBrowserCppToC::Wrap(browser),
CefFrameCppToC::Wrap(frame),
CefRequestCppToC::Wrap(request),
CefResponseCppToC::Wrap(response));
// Return type: bool
return _retval?true:false;
}
bool CefRequestHandlerCToCpp::GetAuthCredentials(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, bool isProxy, const CefString& host, int port,
const CefString& realm, const CefString& scheme,

View File

@ -44,8 +44,11 @@ class CefRequestHandlerCToCpp
CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) override;
void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, const CefString& old_url,
CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request,
CefString& new_url) override;
bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) override;
bool GetAuthCredentials(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame, bool isProxy, const CefString& host, int port,
const CefString& realm, const CefString& scheme,

View File

@ -136,6 +136,13 @@ patches = [
'name': 'net_proxy_462624',
'path': '../net/proxy/',
},
{
# Make URLRequest::set_is_pending() public so that it can be called from
# CefRequestInterceptor::MaybeInterceptResponse().
# https://code.google.com/p/chromiumembedded/issues/detail?id=1327
'name': 'net_urlrequest_1327',
'path': '../net/url_request/',
},
{
# Disable scollbar bounce and overlay on OS X.
# http://code.google.com/p/chromiumembedded/issues/detail?id=364

View File

@ -0,0 +1,16 @@
diff --git url_request.h url_request.h
index 1623368..16d292d 100644
--- url_request.h
+++ url_request.h
@@ -609,10 +609,10 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe),
return proxy_server_;
}
- protected:
// Allow the URLRequestJob class to control the is_pending() flag.
void set_is_pending(bool value) { is_pending_ = value; }
+ protected:
// Allow the URLRequestJob class to set our status too
void set_status(const URLRequestStatus& value) { status_ = value; }

View File

@ -762,10 +762,11 @@ class RedirectTestHandler : public TestHandler {
void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& old_url,
CefRefPtr<CefRequest> request,
CefString& new_url) override {
// Should be called for each redirected URL.
const std::string& old_url = request->GetURL();
if (old_url == kRNav1 && new_url == kRNav2) {
// Called due to the nav1 redirect response.
got_nav1_redirect_.yes();
@ -1670,8 +1671,14 @@ class LoadNavTestHandler : public TestHandler {
CefMouseEvent mouse_event;
mouse_event.x = 20;
mouse_event.y = 20;
#if defined(OS_MACOSX)
// Use cmd instead of ctrl on OS X.
mouse_event.modifiers =
(mode_ == CTRL_LEFT_CLICK ? EVENTFLAG_COMMAND_DOWN : 0);
#else
mouse_event.modifiers =
(mode_ == CTRL_LEFT_CLICK ? EVENTFLAG_CONTROL_DOWN : 0);
#endif
cef_mouse_button_type_t button_type =
(mode_ == MIDDLE_CLICK ? MBT_MIDDLE : MBT_LEFT);

View File

@ -10,10 +10,12 @@
#include "include/base/cef_bind.h"
#include "include/cef_cookie.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_stream_resource_handler.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "tests/cefclient/browser/client_app_browser.h"
#include "tests/cefclient/renderer/client_app_renderer.h"
#include "tests/unittests/test_handler.h"
#include "tests/unittests/test_util.h"
using client::ClientAppBrowser;
using client::ClientAppRenderer;
@ -509,6 +511,413 @@ TEST(RequestHandlerTest, NotificationsCrossOriginDelayedBrowser) {
}
namespace {
const char kResourceTestHtml[] = "http://test.com/resource.html";
class ResourceResponseTest : public TestHandler {
public:
enum TestMode {
URL,
HEADER,
POST,
};
explicit ResourceResponseTest(TestMode mode)
: browser_id_(0),
main_request_id_(0U),
sub_request_id_(0U) {
if (mode == URL)
resource_test_.reset(new UrlResourceTest);
else if (mode == HEADER)
resource_test_.reset(new HeaderResourceTest);
else
resource_test_.reset(new PostResourceTest);
}
void RunTest() override {
AddResource(kResourceTestHtml, GetHtml(), "text/html");
CreateBrowser(kResourceTestHtml);
SetTestTimeout();
}
bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
bool is_redirect) override {
EXPECT_UI_THREAD();
EXPECT_EQ(0, browser_id_);
browser_id_ = browser->GetIdentifier();
EXPECT_GT(browser_id_, 0);
// This method is only called for the main resource.
EXPECT_STREQ(kResourceTestHtml, request->GetURL().ToString().c_str());
// All loads of the main resource should keep the same request id.
EXPECT_EQ(0U, main_request_id_);
main_request_id_ = request->GetIdentifier();
EXPECT_GT(main_request_id_, 0U);
return false;
}
bool OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) override {
EXPECT_IO_THREAD();
EXPECT_EQ(browser_id_, browser->GetIdentifier());
if (request->GetURL() == kResourceTestHtml) {
EXPECT_EQ(main_request_id_, request->GetIdentifier());
return false;
}
// All redirects of the sub-resource should keep the same request id.
if (sub_request_id_ == 0U) {
sub_request_id_ = request->GetIdentifier();
EXPECT_GT(sub_request_id_, 0U);
} else {
EXPECT_EQ(sub_request_id_, request->GetIdentifier());
}
return resource_test_->OnBeforeResourceLoad(browser, frame, request);
}
CefRefPtr<CefResourceHandler> GetResourceHandler(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) override {
EXPECT_IO_THREAD();
EXPECT_EQ(browser_id_, browser->GetIdentifier());
if (request->GetURL() == kResourceTestHtml) {
EXPECT_EQ(main_request_id_, request->GetIdentifier());
return TestHandler::GetResourceHandler(browser, frame, request);
}
EXPECT_EQ(sub_request_id_, request->GetIdentifier());
return resource_test_->GetResourceHandler(browser, frame, request);
}
void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefString& new_url) override {
EXPECT_IO_THREAD();
EXPECT_EQ(browser_id_, browser->GetIdentifier());
EXPECT_EQ(sub_request_id_, request->GetIdentifier());
resource_test_->OnResourceRedirect(browser, frame, request, new_url);
}
bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) override {
EXPECT_IO_THREAD();
EXPECT_TRUE(browser.get());
EXPECT_EQ(browser_id_, browser->GetIdentifier());
EXPECT_TRUE(frame.get());
EXPECT_TRUE(frame->IsMain());
if (request->GetURL() == kResourceTestHtml) {
EXPECT_EQ(main_request_id_, request->GetIdentifier());
return false;
}
EXPECT_EQ(sub_request_id_, request->GetIdentifier());
return resource_test_->OnResourceResponse(browser, frame, request,
response);
}
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) override {
EXPECT_UI_THREAD();
EXPECT_EQ(browser_id_, browser->GetIdentifier());
TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
DestroyTest();
}
void DestroyTest() override {
resource_test_->CheckExpected();
resource_test_.reset(NULL);
TestHandler::DestroyTest();
}
private:
std::string GetHtml() const {
std::stringstream html;
html << "<html><head>";
const std::string& url = resource_test_->start_url();
html << "<script type=\"text/javascript\" src=\""
<< url
<< "\"></script>";
html << "</head><body><p>Main</p></body></html>";
return html.str();
}
class ResourceTest {
public:
ResourceTest(const std::string& start_url,
size_t expected_resource_response_ct = 2U,
size_t expected_before_resource_load_ct = 1U,
size_t expected_resource_redirect_ct = 0U)
: start_url_(start_url),
resource_response_ct_(0U),
expected_resource_response_ct_(expected_resource_response_ct),
before_resource_load_ct_(0),
expected_before_resource_load_ct_(expected_before_resource_load_ct),
get_resource_handler_ct_(0U),
resource_redirect_ct_(0U),
expected_resource_redirect_ct_(expected_resource_redirect_ct) {
}
virtual ~ResourceTest() {
}
const std::string& start_url() const {
return start_url_;
}
virtual bool OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) {
before_resource_load_ct_++;
return false;
}
virtual CefRefPtr<CefResourceHandler> GetResourceHandler(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) {
get_resource_handler_ct_++;
const std::string& js_content = "<!-- -->";
CefRefPtr<CefStreamReader> stream =
CefStreamReader::CreateForData(const_cast<char*>(js_content.c_str()),
js_content.size());
return new CefStreamResourceHandler(200, "OK", "text/javascript",
CefResponse::HeaderMap(), stream);
}
virtual void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefString& new_url) {
resource_redirect_ct_++;
}
bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) {
EXPECT_TRUE(CheckUrl(request->GetURL()));
// Verify the response returned by GetResourceHandler.
EXPECT_EQ(200, response->GetStatus());
EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str());
EXPECT_STREQ("text/javascript",
response->GetMimeType().ToString().c_str());
if (resource_response_ct_++ == 0U) {
// Always redirect at least one time.
OnResourceReceived(browser, frame, request, response);
return true;
}
OnRetryReceived(browser, frame, request, response);
return (resource_response_ct_ < expected_resource_response_ct_);
}
virtual bool CheckUrl(const std::string& url) const {
return (url == start_url_);
}
virtual void CheckExpected() {
EXPECT_TRUE(got_resource_);
EXPECT_TRUE(got_resource_retry_);
EXPECT_EQ(expected_resource_response_ct_, resource_response_ct_);
EXPECT_EQ(expected_resource_response_ct_, get_resource_handler_ct_);
EXPECT_EQ(expected_before_resource_load_ct_, before_resource_load_ct_);
EXPECT_EQ(expected_resource_redirect_ct_, resource_redirect_ct_);
}
protected:
virtual void OnResourceReceived(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) {
got_resource_.yes();
}
virtual void OnRetryReceived(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) {
got_resource_retry_.yes();
}
private:
std::string start_url_;
size_t resource_response_ct_;
size_t expected_resource_response_ct_;
size_t before_resource_load_ct_;
size_t expected_before_resource_load_ct_;
size_t get_resource_handler_ct_;
size_t resource_redirect_ct_;
size_t expected_resource_redirect_ct_;
TrackCallback got_resource_;
TrackCallback got_resource_retry_;
};
class UrlResourceTest : public ResourceTest {
public:
UrlResourceTest()
: ResourceTest("http://test.com/start_url.js", 3U, 2U, 1U) {
redirect_url_ = "http://test.com/redirect_url.js";
}
bool CheckUrl(const std::string& url) const override {
if (url == redirect_url_)
return true;
return ResourceTest::CheckUrl(url);
}
void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefString& new_url) override {
ResourceTest::OnResourceRedirect(browser, frame, request, new_url);
const std::string& old_url = request->GetURL();
EXPECT_STREQ(start_url().c_str(), old_url.c_str());
EXPECT_STREQ(redirect_url_.c_str(), new_url.ToString().c_str());
}
private:
void OnResourceReceived(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) override {
ResourceTest::OnResourceReceived(browser, frame, request, response);
request->SetURL(redirect_url_);
}
void OnRetryReceived(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) override {
ResourceTest::OnRetryReceived(browser, frame, request, response);
const std::string& new_url = request->GetURL();
EXPECT_STREQ(redirect_url_.c_str(), new_url.c_str());
}
std::string redirect_url_;
};
class HeaderResourceTest : public ResourceTest {
public:
HeaderResourceTest()
: ResourceTest("http://test.com/start_header.js") {
expected_headers_.insert(std::make_pair("Test-Key1", "Value1"));
expected_headers_.insert(std::make_pair("Test-Key2", "Value2"));
}
private:
void OnResourceReceived(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) override {
ResourceTest::OnResourceReceived(browser, frame, request, response);
request->SetHeaderMap(expected_headers_);
}
void OnRetryReceived(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) override {
ResourceTest::OnRetryReceived(browser, frame, request, response);
CefRequest::HeaderMap actual_headers;
request->GetHeaderMap(actual_headers);
TestMapEqual(expected_headers_, actual_headers, true);
}
CefRequest::HeaderMap expected_headers_;
};
class PostResourceTest : public ResourceTest {
public:
PostResourceTest()
: ResourceTest("http://test.com/start_post.js") {
CefRefPtr<CefPostDataElement> elem = CefPostDataElement::Create();
const std::string data("Test Post Data");
elem->SetToBytes(data.size(), data.c_str());
expected_post_ = CefPostData::Create();
expected_post_->AddElement(elem);
}
private:
void OnResourceReceived(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) override {
ResourceTest::OnResourceReceived(browser, frame, request, response);
request->SetPostData(expected_post_);
}
void OnRetryReceived(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> response) override {
ResourceTest::OnRetryReceived(browser, frame, request, response);
CefRefPtr<CefPostData> actual_post = request->GetPostData();
TestPostDataEqual(expected_post_, actual_post);
}
CefRefPtr<CefPostData> expected_post_;
};
int browser_id_;
uint64 main_request_id_;
uint64 sub_request_id_;
scoped_ptr<ResourceTest> resource_test_;
};
} // namespace
TEST(RequestHandlerTest, ResourceResponseURL) {
CefRefPtr<ResourceResponseTest> handler =
new ResourceResponseTest(ResourceResponseTest::URL);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
TEST(RequestHandlerTest, ResourceResponseHeader) {
CefRefPtr<ResourceResponseTest> handler =
new ResourceResponseTest(ResourceResponseTest::HEADER);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
TEST(RequestHandlerTest, ResourceResponsePost) {
CefRefPtr<ResourceResponseTest> handler =
new ResourceResponseTest(ResourceResponseTest::POST);
handler->ExecuteTest();
ReleaseAndWaitForDestructor(handler);
}
// Entry point for creating request handler browser test objects.
// Called from client_app_delegates.cc.
void CreateRequestHandlerBrowserTests(

View File

@ -21,7 +21,8 @@ using client::ClientAppRenderer;
TEST(RequestTest, SetGet) {
// CefRequest CreateRequest
CefRefPtr<CefRequest> request(CefRequest::Create());
ASSERT_TRUE(request.get() != NULL);
EXPECT_TRUE(request.get() != NULL);
EXPECT_EQ(0U, request->GetIdentifier());
CefString url = "http://tests/run.html";
CefString method = "POST";
@ -31,45 +32,45 @@ TEST(RequestTest, SetGet) {
// CefPostData CreatePostData
CefRefPtr<CefPostData> postData(CefPostData::Create());
ASSERT_TRUE(postData.get() != NULL);
EXPECT_TRUE(postData.get() != NULL);
// CefPostDataElement CreatePostDataElement
CefRefPtr<CefPostDataElement> element1(CefPostDataElement::Create());
ASSERT_TRUE(element1.get() != NULL);
EXPECT_TRUE(element1.get() != NULL);
CefRefPtr<CefPostDataElement> element2(CefPostDataElement::Create());
ASSERT_TRUE(element2.get() != NULL);
EXPECT_TRUE(element2.get() != NULL);
// CefPostDataElement SetToFile
CefString file = "c:\\path\\to\\file.ext";
element1->SetToFile(file);
ASSERT_EQ(PDE_TYPE_FILE, element1->GetType());
ASSERT_EQ(file, element1->GetFile());
EXPECT_EQ(PDE_TYPE_FILE, element1->GetType());
EXPECT_EQ(file, element1->GetFile());
// CefPostDataElement SetToBytes
char bytes[] = "Test Bytes";
element2->SetToBytes(sizeof(bytes), bytes);
ASSERT_EQ(PDE_TYPE_BYTES, element2->GetType());
ASSERT_EQ(sizeof(bytes), element2->GetBytesCount());
EXPECT_EQ(PDE_TYPE_BYTES, element2->GetType());
EXPECT_EQ(sizeof(bytes), element2->GetBytesCount());
char bytesOut[sizeof(bytes)];
element2->GetBytes(sizeof(bytes), bytesOut);
ASSERT_TRUE(!memcmp(bytes, bytesOut, sizeof(bytes)));
EXPECT_TRUE(!memcmp(bytes, bytesOut, sizeof(bytes)));
// CefPostData AddElement
postData->AddElement(element1);
postData->AddElement(element2);
ASSERT_EQ((size_t)2, postData->GetElementCount());
EXPECT_EQ((size_t)2, postData->GetElementCount());
// CefPostData RemoveElement
postData->RemoveElement(element1);
ASSERT_EQ((size_t)1, postData->GetElementCount());
EXPECT_EQ((size_t)1, postData->GetElementCount());
// CefPostData RemoveElements
postData->RemoveElements();
ASSERT_EQ((size_t)0, postData->GetElementCount());
EXPECT_EQ((size_t)0, postData->GetElementCount());
postData->AddElement(element1);
postData->AddElement(element2);
ASSERT_EQ((size_t)2, postData->GetElementCount());
EXPECT_EQ((size_t)2, postData->GetElementCount());
CefPostData::ElementVector elements;
postData->GetElements(elements);
CefPostData::ElementVector::const_iterator it = elements.begin();
@ -82,11 +83,11 @@ TEST(RequestTest, SetGet) {
// CefRequest SetURL
request->SetURL(url);
ASSERT_EQ(url, request->GetURL());
EXPECT_EQ(url, request->GetURL());
// CefRequest SetMethod
request->SetMethod(method);
ASSERT_EQ(method, request->GetMethod());
EXPECT_EQ(method, request->GetMethod());
// CefRequest SetHeaderMap
request->SetHeaderMap(setHeaders);
@ -98,13 +99,17 @@ TEST(RequestTest, SetGet) {
request->SetPostData(postData);
TestPostDataEqual(postData, request->GetPostData());
EXPECT_EQ(0U, request->GetIdentifier());
request = CefRequest::Create();
ASSERT_TRUE(request.get() != NULL);
EXPECT_TRUE(request.get() != NULL);
EXPECT_EQ(0U, request->GetIdentifier());
// CefRequest Set
request->Set(url, method, postData, setHeaders);
ASSERT_EQ(url, request->GetURL());
ASSERT_EQ(method, request->GetMethod());
EXPECT_EQ(0U, request->GetIdentifier());
EXPECT_EQ(url, request->GetURL());
EXPECT_EQ(method, request->GetMethod());
request->GetHeaderMap(getHeaders);
TestMapEqual(setHeaders, getHeaders, false);
getHeaders.clear();
@ -115,7 +120,7 @@ namespace {
void CreateRequest(CefRefPtr<CefRequest>& request) {
request = CefRequest::Create();
ASSERT_TRUE(request.get() != NULL);
EXPECT_TRUE(request.get() != NULL);
request->SetURL("http://tests/run.html");
request->SetMethod("POST");
@ -126,11 +131,11 @@ void CreateRequest(CefRefPtr<CefRequest>& request) {
request->SetHeaderMap(headers);
CefRefPtr<CefPostData> postData(CefPostData::Create());
ASSERT_TRUE(postData.get() != NULL);
EXPECT_TRUE(postData.get() != NULL);
CefRefPtr<CefPostDataElement> element1(
CefPostDataElement::Create());
ASSERT_TRUE(element1.get() != NULL);
EXPECT_TRUE(element1.get() != NULL);
char bytes[] = "Test Bytes";
element1->SetToBytes(sizeof(bytes), bytes);
postData->AddElement(element1);
@ -204,8 +209,8 @@ TEST(RequestTest, SendRecv) {
new RequestSendRecvTestHandler();
handler->ExecuteTest();
ASSERT_TRUE(handler->got_before_resource_load_);
ASSERT_TRUE(handler->got_resource_handler_);
EXPECT_TRUE(handler->got_before_resource_load_);
EXPECT_TRUE(handler->got_resource_handler_);
ReleaseAndWaitForDestructor(handler);
}