diff options
Diffstat (limited to 'content/browser/frame_host')
-rw-r--r-- | content/browser/frame_host/navigation_handle_impl.cc | 141 | ||||
-rw-r--r-- | content/browser/frame_host/navigation_handle_impl.h | 67 | ||||
-rw-r--r-- | content/browser/frame_host/navigation_request.cc | 35 | ||||
-rw-r--r-- | content/browser/frame_host/navigation_request.h | 4 | ||||
-rw-r--r-- | content/browser/frame_host/navigator_impl.cc | 2 | ||||
-rw-r--r-- | content/browser/frame_host/render_frame_host_impl.cc | 4 |
6 files changed, 226 insertions, 27 deletions
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc index 2c5e773..994a2fc 100644 --- a/content/browser/frame_host/navigation_handle_impl.cc +++ b/content/browser/frame_host/navigation_handle_impl.cc @@ -5,6 +5,8 @@ #include "content/browser/frame_host/navigation_handle_impl.h" #include "content/browser/frame_host/navigator_delegate.h" +#include "content/public/browser/content_browser_client.h" +#include "content/public/common/content_client.h" #include "net/url_request/redirect_info.h" namespace content { @@ -12,7 +14,7 @@ namespace content { // static scoped_ptr<NavigationHandleImpl> NavigationHandleImpl::Create( const GURL& url, - const bool is_main_frame, + bool is_main_frame, NavigatorDelegate* delegate) { return scoped_ptr<NavigationHandleImpl>( new NavigationHandleImpl(url, is_main_frame, delegate)); @@ -22,10 +24,14 @@ NavigationHandleImpl::NavigationHandleImpl(const GURL& url, const bool is_main_frame, NavigatorDelegate* delegate) : url_(url), - net_error_code_(net::OK), - state_(DID_START), is_main_frame_(is_main_frame), + is_post_(false), + has_user_gesture_(false), + transition_(ui::PAGE_TRANSITION_LINK), + is_external_protocol_(false), + net_error_code_(net::OK), is_same_page_(false), + state_(INITIAL), is_transferring_(false), delegate_(delegate) { delegate_->DidStartNavigation(this); @@ -35,16 +41,46 @@ NavigationHandleImpl::~NavigationHandleImpl() { delegate_->DidFinishNavigation(this); } -const GURL& NavigationHandleImpl::GetURL() const { +const GURL& NavigationHandleImpl::GetURL() { return url_; } -net::Error NavigationHandleImpl::GetNetErrorCode() const { - return net_error_code_; +bool NavigationHandleImpl::IsInMainFrame() { + return is_main_frame_; } -bool NavigationHandleImpl::IsInMainFrame() const { - return is_main_frame_; +bool NavigationHandleImpl::IsPost() { + CHECK_NE(INITIAL, state_) + << "This accessor should not be called before the request is started."; + return is_post_; +} + +const Referrer& NavigationHandleImpl::GetReferrer() { + CHECK_NE(INITIAL, state_) + << "This accessor should not be called before the request is started."; + return sanitized_referrer_; +} + +bool NavigationHandleImpl::HasUserGesture() { + CHECK_NE(INITIAL, state_) + << "This accessor should not be called before the request is started."; + return has_user_gesture_; +} + +ui::PageTransition NavigationHandleImpl::GetPageTransition() { + CHECK_NE(INITIAL, state_) + << "This accessor should not be called before the request is started."; + return transition_; +} + +bool NavigationHandleImpl::IsExternalProtocol() { + CHECK_NE(INITIAL, state_) + << "This accessor should not be called before the request is started."; + return is_external_protocol_; +} + +net::Error NavigationHandleImpl::GetNetErrorCode() { + return net_error_code_; } bool NavigationHandleImpl::IsSamePage() { @@ -54,14 +90,99 @@ bool NavigationHandleImpl::IsSamePage() { return is_same_page_; } -bool NavigationHandleImpl::HasCommittedDocument() const { +bool NavigationHandleImpl::HasCommittedDocument() { return state_ == DID_COMMIT; } -bool NavigationHandleImpl::HasCommittedErrorPage() const { +bool NavigationHandleImpl::HasCommittedErrorPage() { return state_ == DID_COMMIT_ERROR_PAGE; } +void NavigationHandleImpl::RegisterThrottleForTesting( + scoped_ptr<NavigationThrottle> navigation_throttle) { + throttles_.push_back(navigation_throttle.Pass()); +} + +NavigationThrottle::ThrottleCheckResult +NavigationHandleImpl::CallWillStartRequestForTesting( + bool is_post, + const Referrer& sanitized_referrer, + bool has_user_gesture, + ui::PageTransition transition, + bool is_external_protocol) { + return WillStartRequest(is_post, sanitized_referrer, has_user_gesture, + transition, is_external_protocol); +} + +NavigationThrottle::ThrottleCheckResult +NavigationHandleImpl::CallWillRedirectRequestForTesting( + const GURL& new_url, + bool new_method_is_post, + const GURL& new_referrer_url, + bool new_is_external_protocol) { + return WillRedirectRequest(new_url, new_method_is_post, new_referrer_url, + new_is_external_protocol); +} + +NavigationThrottle::ThrottleCheckResult NavigationHandleImpl::WillStartRequest( + bool is_post, + const Referrer& sanitized_referrer, + bool has_user_gesture, + ui::PageTransition transition, + bool is_external_protocol) { + // Update the navigation parameters. + is_post_ = is_post; + sanitized_referrer_ = sanitized_referrer; + has_user_gesture_ = has_user_gesture; + transition_ = transition; + is_external_protocol_ = is_external_protocol; + + state_ = WILL_SEND_REQUEST; + + // Register the navigation throttles. The ScopedVector returned by + // GetNavigationThrottles is not assigned to throttles_ directly because it + // would overwrite any throttle previously added with + // RegisterThrottleForTesting. + ScopedVector<NavigationThrottle> throttles_to_register = + GetContentClient()->browser()->CreateThrottlesForNavigation(this); + if (throttles_to_register.size() > 0) { + throttles_.insert(throttles_.end(), throttles_to_register.begin(), + throttles_to_register.end()); + throttles_to_register.weak_clear(); + } + + // Notify each throttle of the request. + for (NavigationThrottle* throttle : throttles_) { + NavigationThrottle::ThrottleCheckResult result = + throttle->WillStartRequest(); + if (result == NavigationThrottle::CANCEL_AND_IGNORE) + return NavigationThrottle::CANCEL_AND_IGNORE; + } + return NavigationThrottle::PROCEED; +} + +NavigationThrottle::ThrottleCheckResult +NavigationHandleImpl::WillRedirectRequest(const GURL& new_url, + bool new_method_is_post, + const GURL& new_referrer_url, + bool new_is_external_protocol) { + // Update the navigation parameters. + url_ = new_url; + is_post_ = new_method_is_post; + sanitized_referrer_.url = new_referrer_url; + sanitized_referrer_ = Referrer::SanitizeForRequest(url_, sanitized_referrer_); + is_external_protocol_ = new_is_external_protocol; + + // Have each throttle be notified of the request. + for (NavigationThrottle* throttle : throttles_) { + NavigationThrottle::ThrottleCheckResult result = + throttle->WillRedirectRequest(); + if (result == NavigationThrottle::CANCEL_AND_IGNORE) + return NavigationThrottle::CANCEL_AND_IGNORE; + } + return NavigationThrottle::PROCEED; +} + void NavigationHandleImpl::DidRedirectNavigation(const GURL& new_url) { url_ = new_url; delegate_->DidRedirectNavigation(this); diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h index 861adb0..aebb929 100644 --- a/content/browser/frame_host/navigation_handle_impl.h +++ b/content/browser/frame_host/navigation_handle_impl.h @@ -9,7 +9,9 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" #include "content/common/content_export.h" +#include "content/public/browser/navigation_throttle.h" #include "url/gurl.h" namespace content { @@ -53,18 +55,37 @@ struct NavigationRequestInfo; class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle { public: static scoped_ptr<NavigationHandleImpl> Create(const GURL& url, - const bool is_main_frame, + bool is_main_frame, NavigatorDelegate* delegate); - ~NavigationHandleImpl() override; // NavigationHandle implementation: - const GURL& GetURL() const override; - net::Error GetNetErrorCode() const override; - bool IsInMainFrame() const override; + const GURL& GetURL() override; + bool IsInMainFrame() override; + bool IsPost() override; + const Referrer& GetReferrer() override; + bool HasUserGesture() override; + ui::PageTransition GetPageTransition() override; + bool IsExternalProtocol() override; + net::Error GetNetErrorCode() override; bool IsSamePage() override; - bool HasCommittedDocument() const override; - bool HasCommittedErrorPage() const override; + bool HasCommittedDocument() override; + bool HasCommittedErrorPage() override; + void RegisterThrottleForTesting( + scoped_ptr<NavigationThrottle> navigation_throttle) override; + NavigationThrottle::ThrottleCheckResult CallWillStartRequestForTesting( + bool is_post, + const Referrer& sanitized_referrer, + bool has_user_gesture, + ui::PageTransition transition, + bool is_external_protocol) override; + NavigationThrottle::ThrottleCheckResult CallWillRedirectRequestForTesting( + const GURL& new_url, + bool new_method_is_post, + const GURL& new_referrer_url, + bool new_is_external_protocol) override; + + NavigatorDelegate* delegate() const { return delegate_; } void set_net_error_code(net::Error net_error_code) { net_error_code_ = net_error_code; @@ -79,6 +100,21 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle { is_transferring_ = is_transferring; } + // Called when the URLRequest will start in the network stack. + NavigationThrottle::ThrottleCheckResult WillStartRequest( + bool is_post, + const Referrer& sanitized_referrer, + bool has_user_gesture, + ui::PageTransition transition, + bool is_external_protocol); + + // Called when the URLRequest will be redirected in the network stack. + NavigationThrottle::ThrottleCheckResult WillRedirectRequest( + const GURL& new_url, + bool new_method_is_post, + const GURL& new_referrer_url, + bool new_is_external_protocol); + // Called when the navigation was redirected. This will update the |url_| and // inform the delegate. void DidRedirectNavigation(const GURL& new_url); @@ -90,7 +126,8 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle { private: // Used to track the state the navigation is currently in. enum State { - DID_START = 0, + INITIAL = 0, + WILL_SEND_REQUEST, DID_COMMIT, DID_COMMIT_ERROR_PAGE, }; @@ -101,11 +138,18 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle { // See NavigationHandle for a description of those member variables. GURL url_; - net::Error net_error_code_; - State state_; const bool is_main_frame_; + bool is_post_; + Referrer sanitized_referrer_; + bool has_user_gesture_; + ui::PageTransition transition_; + bool is_external_protocol_; + net::Error net_error_code_; bool is_same_page_; + // The state the navigation is in. + State state_; + // Whether the navigation is in the middle of a transfer. Set to false when // the DidStartProvisionalLoad is received from the new renderer. bool is_transferring_; @@ -114,6 +158,9 @@ class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle { // navigation. NavigatorDelegate* delegate_; + // A list of Throttles registered for this navigation. + ScopedVector<NavigationThrottle> throttles_; + DISALLOW_COPY_AND_ASSIGN(NavigationHandleImpl); }; diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index a99074f..8247f35 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc @@ -14,6 +14,7 @@ #include "content/browser/site_instance_impl.h" #include "content/common/resource_request_body.h" #include "content/public/browser/navigation_controller.h" +#include "content/public/browser/navigation_throttle.h" #include "content/public/browser/stream_handle.h" #include "content/public/common/content_client.h" #include "net/base/load_flags.h" @@ -179,6 +180,20 @@ bool NavigationRequest::BeginNavigation() { state_ = STARTED; if (ShouldMakeNetworkRequestForURL(common_params_.url)) { + // TODO(clamy): pass the real value for |is_external_protocol| if needed. + NavigationThrottle::ThrottleCheckResult result = + navigation_handle_->WillStartRequest( + begin_params_.method == "POST", + Referrer::SanitizeForRequest(common_params_.url, + common_params_.referrer), + begin_params_.has_user_gesture, common_params_.transition, false); + + // Abort the request if needed. This will destroy the NavigationRequest. + if (result == NavigationThrottle::CANCEL_AND_IGNORE) { + frame_tree_node_->ResetNavigationRequest(false); + return false; + } + loader_ = NavigationURLLoader::Create( frame_tree_node_->navigator()->GetController()->GetBrowserContext(), frame_tree_node_->frame_tree_node_id(), info_.Pass(), this); @@ -209,12 +224,24 @@ void NavigationRequest::TransferNavigationHandleOwnership( void NavigationRequest::OnRequestRedirected( const net::RedirectInfo& redirect_info, const scoped_refptr<ResourceResponse>& response) { - // TODO(davidben): Track other changes from redirects. These are important - // for, e.g., reloads. common_params_.url = redirect_info.new_url; + begin_params_.method = redirect_info.new_method; + common_params_.referrer.url = GURL(redirect_info.new_referrer); + + // TODO(clamy): Have CSP + security upgrade checks here. + // TODO(clamy): Kill the renderer if FilterURL fails? + // TODO(clamy): pass the real value for |is_external_protocol| if needed. + NavigationThrottle::ThrottleCheckResult result = + navigation_handle_->WillRedirectRequest( + common_params_.url, begin_params_.method == "POST", + common_params_.referrer.url, false); + + // Abort the request if needed. This will destroy the NavigationRequest. + if (result == NavigationThrottle::CANCEL_AND_IGNORE) { + frame_tree_node_->ResetNavigationRequest(false); + return; + } - // TODO(davidben): This where prerender and navigation_interceptor should be - // integrated. For now, just always follow all redirects. loader_->FollowRedirect(); navigation_handle_->DidRedirectNavigation(redirect_info.new_url); diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h index a1530b4..b711278 100644 --- a/content/browser/frame_host/navigation_request.h +++ b/content/browser/frame_host/navigation_request.h @@ -164,8 +164,10 @@ class CONTENT_EXPORT NavigationRequest : public NavigationURLLoaderDelegate { // Note: When the navigation is ready to commit, the url in |common_params| // will be set to the final navigation url, obtained after following all // redirects. + // Note: |common_params_| and |begin_params_| are not const as they can be + // modified during redirects. CommonNavigationParams common_params_; - const BeginNavigationParams begin_params_; + BeginNavigationParams begin_params_; const RequestNavigationParams request_params_; const bool browser_initiated_; diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc index b03e232..fa0c049 100644 --- a/content/browser/frame_host/navigator_impl.cc +++ b/content/browser/frame_host/navigator_impl.cc @@ -159,7 +159,7 @@ void NavigatorImpl::DidStartProvisionalLoad( } render_frame_host->SetNavigationHandle( - NavigationHandleImpl::Create(url, is_main_frame, delegate_)); + NavigationHandleImpl::Create(validated_url, is_main_frame, delegate_)); } void NavigatorImpl::DidFailProvisionalLoadWithError( diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 8f6c99c..aed2daa 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc @@ -1359,8 +1359,10 @@ void RenderFrameHostImpl::OnBeginNavigation( scoped_refptr<ResourceRequestBody> body) { CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableBrowserSideNavigation)); + CommonNavigationParams validated_params = common_params; + GetProcess()->FilterURL(false, &validated_params.url); frame_tree_node()->navigator()->OnBeginNavigation( - frame_tree_node(), common_params, begin_params, body); + frame_tree_node(), validated_params, begin_params, body); } void RenderFrameHostImpl::OnDispatchLoad() { |