diff --git a/include/cef.h b/include/cef.h index ef66283a4..6e1aa3eb5 100644 --- a/include/cef.h +++ b/include/cef.h @@ -1274,6 +1274,16 @@ public: CefRefPtr response, int loadFlags) { return false; } + /// + // 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. + /// + /*--cef()--*/ + virtual void OnResourceRedirect(CefRefPtr browser, + const CefString& old_url, + CefString& new_url) {} + /// // Called on the UI thread after a response to the resource request is // received. Set |filter| if response content needs to be monitored and/or diff --git a/include/cef_capi.h b/include/cef_capi.h index 6bca5d1f2..9ac4e0272 100644 --- a/include/cef_capi.h +++ b/include/cef_capi.h @@ -1100,6 +1100,15 @@ typedef struct _cef_request_handler_t struct _cef_stream_reader_t** resourceStream, struct _cef_response_t* response, int loadFlags); + /// + // 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. + /// + void (CEF_CALLBACK *on_resource_redirect)(struct _cef_request_handler_t* self, + struct _cef_browser_t* browser, const cef_string_t* old_url, + cef_string_t* new_url); + /// // Called on the UI thread after a response to the resource request is // received. Set |filter| if response content needs to be monitored and/or diff --git a/libcef/browser_resource_loader_bridge.cc b/libcef/browser_resource_loader_bridge.cc index b425b74b3..f791e9636 100644 --- a/libcef/browser_resource_loader_bridge.cc +++ b/libcef/browser_resource_loader_bridge.cc @@ -453,10 +453,11 @@ class RequestProxy : public net::URLRequest::Delegate, // redirect to the specified URL handled = true; - params->url = GURL(std::string(redirectUrl)); + GURL new_url = GURL(std::string(redirectUrl)); ResourceResponseInfo info; bool defer_redirect; - OnReceivedRedirect(params->url, info, &defer_redirect); + OnReceivedRedirect(params->url, new_url, info, &defer_redirect); + params->url = new_url; } else if (resourceStream.get()) { // load from the provided resource stream handled = true; @@ -630,12 +631,30 @@ class RequestProxy : public net::URLRequest::Delegate, // by the SyncRequestProxy subclass. virtual void OnReceivedRedirect( + const GURL& old_url, const GURL& new_url, const ResourceResponseInfo& info, bool* defer_redirect) { *defer_redirect = true; // See AsyncFollowDeferredRedirect + + GURL final_url = new_url; + + if (browser_.get()) { + CefRefPtr client = browser_->GetClient(); + CefRefPtr handler; + if (client.get()) + handler = client->GetRequestHandler(); + + if(handler.get()) { + CefString newUrlStr = new_url.spec(); + handler->OnResourceRedirect(browser_, old_url.spec(), newUrlStr); + if (newUrlStr != new_url.spec()) + final_url = GURL(std::string(newUrlStr)); + } + } + owner_loop_->PostTask(FROM_HERE, base::Bind( - &RequestProxy::NotifyReceivedRedirect, this, new_url, info)); + &RequestProxy::NotifyReceivedRedirect, this, final_url, info)); } virtual void OnReceivedResponse( @@ -691,7 +710,7 @@ class RequestProxy : public net::URLRequest::Delegate, DCHECK(request->status().is_success()); ResourceResponseInfo info; PopulateResponseInfo(request, &info); - OnReceivedRedirect(new_url, info, defer_redirect); + OnReceivedRedirect(request->url(), new_url, info, defer_redirect); } virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE { diff --git a/libcef_dll/cpptoc/request_handler_cpptoc.cc b/libcef_dll/cpptoc/request_handler_cpptoc.cc index 913602bf8..6386e6002 100644 --- a/libcef_dll/cpptoc/request_handler_cpptoc.cc +++ b/libcef_dll/cpptoc/request_handler_cpptoc.cc @@ -123,6 +123,39 @@ int CEF_CALLBACK request_handler_on_before_resource_load( } +void CEF_CALLBACK request_handler_on_resource_redirect( + struct _cef_request_handler_t* self, cef_browser_t* browser, + const cef_string_t* old_url, cef_string_t* new_url) +{ + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: browser; type: refptr_diff + DCHECK(browser); + if (!browser) + return; + // Verify param: old_url; type: string_byref_const + DCHECK(old_url); + if (!old_url) + return; + // Verify param: new_url; type: string_byref + DCHECK(new_url); + if (!new_url) + return; + + // Translate param: new_url; type: string_byref + CefString new_urlStr(new_url); + + // Execute + CefRequestHandlerCppToC::Get(self)->OnResourceRedirect( + CefBrowserCToCpp::Wrap(browser), + CefString(old_url), + new_urlStr); +} + + void CEF_CALLBACK request_handler_on_resource_response( struct _cef_request_handler_t* self, cef_browser_t* browser, const cef_string_t* url, struct _cef_response_t* response, @@ -341,6 +374,7 @@ CefRequestHandlerCppToC::CefRequestHandlerCppToC(CefRequestHandler* cls) struct_.struct_.on_before_browse = request_handler_on_before_browse; struct_.struct_.on_before_resource_load = request_handler_on_before_resource_load; + struct_.struct_.on_resource_redirect = request_handler_on_resource_redirect; struct_.struct_.on_resource_response = request_handler_on_resource_response; struct_.struct_.on_protocol_execution = request_handler_on_protocol_execution; struct_.struct_.get_download_handler = request_handler_get_download_handler; diff --git a/libcef_dll/ctocpp/request_handler_ctocpp.cc b/libcef_dll/ctocpp/request_handler_ctocpp.cc index f4eabf8a1..ce006259d 100644 --- a/libcef_dll/ctocpp/request_handler_ctocpp.cc +++ b/libcef_dll/ctocpp/request_handler_ctocpp.cc @@ -109,6 +109,31 @@ bool CefRequestHandlerCToCpp::OnBeforeResourceLoad( } +void CefRequestHandlerCToCpp::OnResourceRedirect(CefRefPtr browser, + const CefString& old_url, CefString& new_url) +{ + if (CEF_MEMBER_MISSING(struct_, on_resource_redirect)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: browser; type: refptr_diff + DCHECK(browser.get()); + if (!browser.get()) + return; + // Verify param: old_url; type: string_byref_const + DCHECK(!old_url.empty()); + if (old_url.empty()) + return; + + // Execute + struct_->on_resource_redirect(struct_, + CefBrowserCppToC::Wrap(browser), + old_url.GetStruct(), + new_url.GetWritableStruct()); +} + + void CefRequestHandlerCToCpp::OnResourceResponse(CefRefPtr browser, const CefString& url, CefRefPtr response, CefRefPtr& filter) diff --git a/libcef_dll/ctocpp/request_handler_ctocpp.h b/libcef_dll/ctocpp/request_handler_ctocpp.h index e576503fb..f96128436 100644 --- a/libcef_dll/ctocpp/request_handler_ctocpp.h +++ b/libcef_dll/ctocpp/request_handler_ctocpp.h @@ -41,6 +41,8 @@ public: CefRefPtr request, CefString& redirectUrl, CefRefPtr& resourceStream, CefRefPtr response, int loadFlags) OVERRIDE; + virtual void OnResourceRedirect(CefRefPtr browser, + const CefString& old_url, CefString& new_url) OVERRIDE; virtual void OnResourceResponse(CefRefPtr browser, const CefString& url, CefRefPtr response, CefRefPtr& filter) OVERRIDE; diff --git a/tests/unittests/navigation_unittest.cc b/tests/unittests/navigation_unittest.cc index 0fde4e026..ff90ab899 100644 --- a/tests/unittests/navigation_unittest.cc +++ b/tests/unittests/navigation_unittest.cc @@ -336,3 +336,104 @@ TEST(NavigationTest, FrameNameIdent) ASSERT_TRUE(handler->got_frame2_ident_parent_after_); ASSERT_TRUE(handler->got_frame3_ident_parent_after_); } + + +namespace { + +class RedirectTestHandler : public TestHandler +{ +public: + RedirectTestHandler() {} + + virtual void RunTest() OVERRIDE + { + // Create the browser. + CreateBrowser(kNav1); + } + + virtual bool OnBeforeBrowse(CefRefPtr browser, + CefRefPtr frame, + CefRefPtr request, + NavType navType, + bool isRedirect) OVERRIDE + { + std::string url = request->GetURL(); + + if (url == kNav1) { + got_nav1_before_browse_.yes(); + } else if (url == kNav2) { + // should not happen + got_nav2_before_browse_.yes(); + } else if (url == kNav3) { + got_nav3_before_browse_.yes(); + + // End of test. + DestroyTest(); + } + + return false; + } + + virtual bool OnBeforeResourceLoad(CefRefPtr browser, + CefRefPtr request, + CefString& redirectUrl, + CefRefPtr& resourceStream, + CefRefPtr response, + int loadFlags) OVERRIDE + { + std::string url = request->GetURL(); + + if (url == kNav1) { + got_nav1_before_resource_load_.yes(); + + // Redirect to the 2nd URL. + redirectUrl = kNav2; + } else if(url == kNav2) { + // Should not happen. + got_nav2_before_resource_load_.yes(); + } else if(url == kNav3) { + // Should not happen. + got_nav3_before_resource_load_.yes(); + } + + return false; + } + + virtual void OnResourceRedirect(CefRefPtr browser, + const CefString& old_url, + CefString& new_url) OVERRIDE + { + if (old_url == kNav1 && new_url == kNav2) { + got_nav1_redirect_.yes(); + + // Change the redirect to the 3rd URL. + new_url = kNav3; + } + } + + TrackCallback got_nav1_before_browse_; + TrackCallback got_nav2_before_browse_; + TrackCallback got_nav3_before_browse_; + TrackCallback got_nav1_before_resource_load_; + TrackCallback got_nav2_before_resource_load_; + TrackCallback got_nav3_before_resource_load_; + TrackCallback got_nav1_redirect_; +}; + +} // namespace + +// Verify frame names and identifiers. +TEST(NavigationTest, Redirect) +{ + CefRefPtr handler = + new RedirectTestHandler(); + handler->ExecuteTest(); + + ASSERT_TRUE(handler->got_nav1_before_browse_); + ASSERT_FALSE(handler->got_nav2_before_browse_); + ASSERT_TRUE(handler->got_nav3_before_browse_); + ASSERT_TRUE(handler->got_nav1_before_resource_load_); + ASSERT_FALSE(handler->got_nav2_before_resource_load_); + ASSERT_FALSE(handler->got_nav3_before_resource_load_); + ASSERT_TRUE(handler->got_nav1_redirect_); +}