diff --git a/include/capi/cef_response_capi.h b/include/capi/cef_response_capi.h index 5902a5dca..0ba24525d 100644 --- a/include/capi/cef_response_capi.h +++ b/include/capi/cef_response_capi.h @@ -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; /// diff --git a/include/cef_response.h b/include/cef_response.h index 551464d76..1862034aa 100644 --- a/include/cef_response.h +++ b/include/cef_response.h @@ -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_ diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h index c066abadf..8efe76406 100644 --- a/include/internal/cef_types.h +++ b/include/internal/cef_types.h @@ -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; /// diff --git a/libcef/browser/browser_urlrequest_impl.cc b/libcef/browser/browser_urlrequest_impl.cc index 5124993ff..9e8934326 100644 --- a/libcef/browser/browser_urlrequest_impl.cc +++ b/libcef/browser/browser_urlrequest_impl.cc @@ -356,6 +356,9 @@ class CefBrowserURLRequest::Context CefResponseImpl* responseImpl = static_cast(response_.get()); + responseImpl->SetURL(fetcher_->GetURL().spec()); + responseImpl->SetStatus(fetcher_->GetResponseCode()); + net::HttpResponseHeaders* headers = fetcher_->GetResponseHeaders(); if (headers) responseImpl->SetResponseHeaders(*headers); diff --git a/libcef/browser/net/resource_request_job.cc b/libcef/browser/net/resource_request_job.cc index 30512eb57..e3d056adb 100644 --- a/libcef/browser/net/resource_request_job.cc +++ b/libcef/browser/net/resource_request_job.cc @@ -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(); diff --git a/libcef/browser/net/resource_request_job.h b/libcef/browser/net/resource_request_job.h index 362dd6847..2b8060357 100644 --- a/libcef/browser/net/resource_request_job.h +++ b/libcef/browser/net/resource_request_job.h @@ -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(); diff --git a/libcef/common/request_impl.cc b/libcef/common/request_impl.cc index 866a1da16..79893f5ab 100644 --- a/libcef/common/request_impl.cc +++ b/libcef/common/request_impl.cc @@ -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; diff --git a/libcef/common/response_impl.cc b/libcef/common/response_impl.cc index 202ceaca5..57d5c3a66 100644 --- a/libcef/common/response_impl.cc +++ b/libcef/common/response_impl.cc @@ -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: diff --git a/libcef/common/response_impl.h b/libcef/common/response_impl.h index d211be8fd..87203089d 100644 --- a/libcef/common/response_impl.h +++ b/libcef/common/response_impl.h @@ -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_; diff --git a/libcef/renderer/render_urlrequest_impl.cc b/libcef/renderer/render_urlrequest_impl.cc index 3dfd52bc7..d5a451518 100644 --- a/libcef/renderer/render_urlrequest_impl.cc +++ b/libcef/renderer/render_urlrequest_impl.cc @@ -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(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 -------------------------------------------------------- diff --git a/libcef_dll/cpptoc/response_cpptoc.cc b/libcef_dll/cpptoc/response_cpptoc.cc index 32b39e744..933c7576f 100644 --- a/libcef_dll/cpptoc/response_cpptoc.cc +++ b/libcef_dll/cpptoc/response_cpptoc.cc @@ -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 <> diff --git a/libcef_dll/ctocpp/response_ctocpp.cc b/libcef_dll/ctocpp/response_ctocpp.cc index 9e2a19b37..279c7769c 100644 --- a/libcef_dll/ctocpp/response_ctocpp.cc +++ b/libcef_dll/ctocpp/response_ctocpp.cc @@ -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() {} diff --git a/libcef_dll/ctocpp/response_ctocpp.h b/libcef_dll/ctocpp/response_ctocpp.h index 3a12fb93f..1261e0a62 100644 --- a/libcef_dll/ctocpp/response_ctocpp.h +++ b/libcef_dll/ctocpp/response_ctocpp.h @@ -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 { 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 { 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, \