Add ability to stop CefURLRequest on redirect (issue #1329)

This commit is contained in:
Mike Wiedenbauer 2018-04-10 13:04:57 -04:00 committed by Marshall Greenblatt
parent bcb7529ed3
commit 5211ca6298
14 changed files with 220 additions and 5 deletions

View File

@ -33,7 +33,7 @@
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
// $hash=561e4711432158fd3da971f3c0240dcf5e8e782a$
// $hash=fd2cbc427bccf30298e26dd6c3bcef9551433f8b$
//
#ifndef CEF_INCLUDE_CAPI_CEF_RESPONSE_CAPI_H_
@ -127,6 +127,18 @@ typedef struct _cef_response_t {
///
void(CEF_CALLBACK* set_header_map)(struct _cef_response_t* self,
cef_string_multimap_t headerMap);
///
// Get the resolved URL after redirects or changed as a result of HSTS.
///
// The resulting string must be freed by calling cef_string_userfree_free().
cef_string_userfree_t(CEF_CALLBACK* get_url)(struct _cef_response_t* self);
///
// Set the resolved URL after redirects or changed as a result of HSTS.
///
void(CEF_CALLBACK* set_url)(struct _cef_response_t* self,
const cef_string_t* url);
} cef_response_t;
///

View File

@ -128,6 +128,18 @@ class CefResponse : public virtual CefBaseRefCounted {
///
/*--cef()--*/
virtual void SetHeaderMap(const HeaderMap& headerMap) = 0;
///
// Get the resolved URL after redirects or changed as a result of HSTS.
///
/*--cef()--*/
virtual CefString GetURL() = 0;
///
// Set the resolved URL after redirects or changed as a result of HSTS.
///
/*--cef()--*/
virtual void SetURL(const CefString& url) = 0;
};
#endif // CEF_INCLUDE_CEF_RESPONSE_H_

View File

@ -1264,6 +1264,12 @@ typedef enum {
// originated in the browser process.
///
UR_FLAG_NO_RETRY_ON_5XX = 1 << 5,
///
// If set 3XX responses will cause the fetch to halt immediately rather than
// continue through the redirect.
///
UR_FLAG_STOP_ON_REDIRECT = 1 << 6,
} cef_urlrequest_flags_t;
///

View File

@ -356,6 +356,9 @@ class CefBrowserURLRequest::Context
CefResponseImpl* responseImpl =
static_cast<CefResponseImpl*>(response_.get());
responseImpl->SetURL(fetcher_->GetURL().spec());
responseImpl->SetStatus(fetcher_->GetResponseCode());
net::HttpResponseHeaders* headers = fetcher_->GetResponseHeaders();
if (headers)
responseImpl->SetResponseHeaders(*headers);

View File

@ -336,6 +336,14 @@ bool CefResourceRequestJob::GetCharset(std::string* charset) {
return false;
}
int CefResourceRequestJob::GetResponseCode() const {
CEF_REQUIRE_IOT();
if (response_.get())
return response_->GetStatus();
return -1;
}
void CefResourceRequestJob::SendHeaders() {
CEF_REQUIRE_IOT();

View File

@ -41,6 +41,7 @@ class CefResourceRequestJob : public net::URLRequestJob {
bool IsRedirectResponse(GURL* location, int* http_status_code) override;
bool GetMimeType(std::string* mime_type) const override;
bool GetCharset(std::string* charset) override;
int GetResponseCode() const override;
void SendHeaders();

View File

@ -745,6 +745,8 @@ void CefRequestImpl::Get(net::URLFetcher& fetcher,
if (flags & UR_FLAG_NO_RETRY_ON_5XX)
fetcher.SetAutomaticallyRetryOn5xx(false);
if (flags & UR_FLAG_STOP_ON_REDIRECT)
fetcher.SetStopOnRedirect(true);
int net_flags = 0;

View File

@ -13,6 +13,7 @@
#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/WebURL.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#define CHECK_READONLY_RETURN_VOID() \
@ -95,6 +96,17 @@ CefString CefResponseImpl::GetHeader(const CefString& name) {
return value;
}
CefString CefResponseImpl::GetURL() {
base::AutoLock lock_scope(lock_);
return url_;
}
void CefResponseImpl::SetURL(const CefString& url) {
base::AutoLock lock_scope(lock_);
CHECK_READONLY_RETURN_VOID();
url_ = url;
}
void CefResponseImpl::GetHeaderMap(HeaderMap& map) {
base::AutoLock lock_scope(lock_);
map = header_map_;
@ -190,6 +202,8 @@ void CefResponseImpl::Set(const blink::WebURLResponse& response) {
status_text_ = str.Utf16();
str = response.MimeType();
mime_type_ = str.Utf16();
str = response.Url().GetString();
url_ = str.Utf16();
class HeaderVisitor : public blink::WebHTTPHeaderVisitor {
public:

View File

@ -13,7 +13,7 @@
namespace net {
class HttpResponseHeaders;
class URLRequest;
}
} // namespace net
namespace blink {
class WebURLResponse;
@ -37,6 +37,8 @@ class CefResponseImpl : public CefResponse {
CefString GetHeader(const CefString& name) override;
void GetHeaderMap(HeaderMap& headerMap) override;
void SetHeaderMap(const HeaderMap& headerMap) override;
CefString GetURL() override;
void SetURL(const CefString& url) override;
net::HttpResponseHeaders* GetResponseHeaders();
void SetResponseHeaders(const net::HttpResponseHeaders& headers);
@ -51,6 +53,7 @@ class CefResponseImpl : public CefResponse {
int status_code_;
CefString status_text_;
CefString mime_type_;
CefString url_;
HeaderMap header_map_;
bool read_only_;

View File

@ -23,6 +23,7 @@
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
using blink::WebReferrerPolicy;
using blink::WebString;
using blink::WebURL;
using blink::WebURLError;
@ -52,6 +53,13 @@ class CefWebURLLoaderClient : public blink::WebURLLoaderClient {
int64_t total_encoded_data_length,
int64_t total_encoded_body_length,
int64_t total_decoded_body_length) override;
bool WillFollowRedirect(const WebURL& new_url,
const WebURL& new_site_for_cookies,
const WebString& new_referrer,
WebReferrerPolicy new_referrer_policy,
const WebString& new_method,
const WebURLResponse& passed_redirect_response,
bool& report_raw_headers) override;
protected:
// The context_ pointer will outlive this object.
@ -127,6 +135,28 @@ class CefRenderURLRequest::Context
loader_->Cancel();
}
void OnStopRedirect(const WebURL& redirect_url,
const WebURLResponse& response) {
DCHECK(CalledOnValidThread());
response_was_cached_ = webkit_glue::ResponseWasCached(response);
response_ = CefResponse::Create();
CefResponseImpl* responseImpl =
static_cast<CefResponseImpl*>(response_.get());
// In case of StopOnRedirect we only set these fields. Everything else is
// left blank. This also replicates the behaviour of the browser urlrequest
// fetcher.
responseImpl->SetStatus(response.HttpStatusCode());
responseImpl->SetURL(redirect_url.GetString().Utf16());
responseImpl->SetReadOnly(true);
status_ = UR_CANCELED;
error_code_ = ERR_ABORTED;
OnComplete();
}
void OnResponse(const WebURLResponse& response) {
DCHECK(CalledOnValidThread());
@ -277,6 +307,21 @@ void CefWebURLLoaderClient::DidFail(const WebURLError& error,
context_->OnError(error);
}
bool CefWebURLLoaderClient::WillFollowRedirect(
const WebURL& new_url,
const WebURL& new_site_for_cookies,
const WebString& new_referrer,
WebReferrerPolicy new_referrer_policy,
const WebString& new_method,
const WebURLResponse& passed_redirect_response,
bool& report_raw_headers) {
if (request_flags_ & UR_FLAG_STOP_ON_REDIRECT) {
context_->OnStopRedirect(new_url, passed_redirect_response);
return false;
}
return true;
}
} // namespace
// CefRenderURLRequest --------------------------------------------------------

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=f2872ff67c69f164f899040c77340e116bd214c0$
// $hash=9cf199db470205062b0c4d39f7daa739db2a95a2$
//
#include "libcef_dll/cpptoc/response_cpptoc.h"
@ -222,6 +222,37 @@ void CEF_CALLBACK response_set_header_map(struct _cef_response_t* self,
CefResponseCppToC::Get(self)->SetHeaderMap(headerMapMultimap);
}
cef_string_userfree_t CEF_CALLBACK
response_get_url(struct _cef_response_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return NULL;
// Execute
CefString _retval = CefResponseCppToC::Get(self)->GetURL();
// Return type: string
return _retval.DetachToUserFree();
}
void CEF_CALLBACK response_set_url(struct _cef_response_t* self,
const cef_string_t* url) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Verify param: url; type: string_byref_const
DCHECK(url);
if (!url)
return;
// Execute
CefResponseCppToC::Get(self)->SetURL(CefString(url));
}
} // namespace
// CONSTRUCTOR - Do not edit by hand.
@ -239,6 +270,8 @@ CefResponseCppToC::CefResponseCppToC() {
GetStruct()->get_header = response_get_header;
GetStruct()->get_header_map = response_get_header_map;
GetStruct()->set_header_map = response_set_header_map;
GetStruct()->get_url = response_get_url;
GetStruct()->set_url = response_set_url;
}
template <>

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=00cc7ae2c2822a50218bb1e3b9cab95ab67236a6$
// $hash=fbfca8a1320ab81bda709202462543a658ed886d$
//
#include "libcef_dll/ctocpp/response_ctocpp.h"
@ -224,6 +224,38 @@ void CefResponseCToCpp::SetHeaderMap(const HeaderMap& headerMap) {
cef_string_multimap_free(headerMapMultimap);
}
CefString CefResponseCToCpp::GetURL() {
cef_response_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, get_url))
return CefString();
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
cef_string_userfree_t _retval = _struct->get_url(_struct);
// Return type: string
CefString _retvalStr;
_retvalStr.AttachToUserFree(_retval);
return _retvalStr;
}
void CefResponseCToCpp::SetURL(const CefString& url) {
cef_response_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, set_url))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: url; type: string_byref_const
DCHECK(!url.empty());
if (url.empty())
return;
// Execute
_struct->set_url(_struct, url.GetStruct());
}
// CONSTRUCTOR - Do not edit by hand.
CefResponseCToCpp::CefResponseCToCpp() {}

View File

@ -9,7 +9,7 @@
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
// $hash=0c155aa07dd80b78f92950d0fc8ff4fec7df9a21$
// $hash=1b7de3f18de3231ea172447565684df6f0fcf265$
//
#ifndef CEF_LIBCEF_DLL_CTOCPP_RESPONSE_CTOCPP_H_
@ -45,6 +45,8 @@ class CefResponseCToCpp : public CefCToCppRefCounted<CefResponseCToCpp,
CefString GetHeader(const CefString& name) OVERRIDE;
void GetHeaderMap(HeaderMap& headerMap) OVERRIDE;
void SetHeaderMap(const HeaderMap& headerMap) OVERRIDE;
CefString GetURL() OVERRIDE;
void SetURL(const CefString& url) OVERRIDE;
};
#endif // CEF_LIBCEF_DLL_CTOCPP_RESPONSE_CTOCPP_H_

View File

@ -57,6 +57,7 @@ enum RequestTestMode {
REQTEST_GET_NODATA,
REQTEST_GET_ALLOWCOOKIES,
REQTEST_GET_REDIRECT,
REQTEST_GET_REDIRECT_STOP,
REQTEST_GET_REFERRER,
REQTEST_POST,
REQTEST_POST_FILE,
@ -1058,6 +1059,8 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
REGISTER_TEST(REQTEST_GET_ALLOWCOOKIES, SetupGetAllowCookiesTest,
SingleRunTest);
REGISTER_TEST(REQTEST_GET_REDIRECT, SetupGetRedirectTest, SingleRunTest);
REGISTER_TEST(REQTEST_GET_REDIRECT_STOP, SetupGetRedirectStopTest,
SingleRunTest);
REGISTER_TEST(REQTEST_GET_REFERRER, SetupGetReferrerTest, SingleRunTest);
REGISTER_TEST(REQTEST_POST, SetupPostTest, SingleRunTest);
REGISTER_TEST(REQTEST_POST_FILE, SetupPostFileTest, SingleRunTest);
@ -1240,6 +1243,41 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
complete_callback.Run();
}
void SetupGetRedirectStopTest(const base::Closure& complete_callback) {
settings_.request = CefRequest::Create();
settings_.request->SetURL(GetTestURL("GetTest.html"));
settings_.request->SetMethod("GET");
// With the test server only the status is expected
// on stop redirects.
settings_.response = CefResponse::Create();
settings_.response->SetStatus(302);
// Add a redirect request.
settings_.redirect_request = CefRequest::Create();
settings_.redirect_request->SetURL(GetTestURL("redirect.html"));
settings_.redirect_request->SetMethod("GET");
settings_.redirect_request->SetFlags(UR_FLAG_STOP_ON_REDIRECT);
settings_.redirect_response = CefResponse::Create();
settings_.redirect_response->SetMimeType("text/html");
settings_.redirect_response->SetStatus(302);
settings_.redirect_response->SetStatusText("Found");
CefResponse::HeaderMap headerMap;
headerMap.insert(std::make_pair("Location", settings_.request->GetURL()));
settings_.redirect_response->SetHeaderMap(headerMap);
settings_.expected_status = UR_CANCELED;
settings_.expected_error_code = ERR_ABORTED;
settings_.expect_download_data = false;
settings_.expect_download_progress = false;
settings_.expected_send_count = 1;
settings_.expected_receive_count = 1;
complete_callback.Run();
}
void SetupGetReferrerTest(const base::Closure& complete_callback) {
settings_.request = CefRequest::Create();
settings_.request->SetURL(GetTestURL("GetTest.html"));
@ -2210,6 +2248,8 @@ void RegisterURLRequestCustomSchemes(
context_mode, true, test_server_backend); \
REQ_TEST(BrowserGETRedirect##suffix, REQTEST_GET_REDIRECT, context_mode, \
true, test_server_backend); \
REQ_TEST(BrowserGETRedirectStop##suffix, REQTEST_GET_REDIRECT_STOP, \
context_mode, true, test_server_backend); \
REQ_TEST(BrowserGETReferrer##suffix, REQTEST_GET_REFERRER, context_mode, \
true, test_server_backend); \
REQ_TEST(BrowserPOST##suffix, REQTEST_POST, context_mode, true, \
@ -2228,6 +2268,8 @@ void RegisterURLRequestCustomSchemes(
context_mode, false, test_server_backend); \
REQ_TEST(RendererGETRedirect##suffix, REQTEST_GET_REDIRECT, context_mode, \
false, test_server_backend); \
REQ_TEST(RendererGETRedirectStop##suffix, REQTEST_GET_REDIRECT_STOP, \
context_mode, false, test_server_backend); \
REQ_TEST(RendererGETReferrer##suffix, REQTEST_GET_REFERRER, context_mode, \
false, test_server_backend); \
REQ_TEST(RendererPOST##suffix, REQTEST_POST, context_mode, false, \