Add a NavigationThrottle to the public content/ interface
[chromium-blink-merge.git] / content / browser / frame_host / navigation_request.cc
blob8247f3553bf4e565da455c8230695b3d93d091de
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/frame_host/navigation_request.h"
7 #include "content/browser/frame_host/frame_tree.h"
8 #include "content/browser/frame_host/frame_tree_node.h"
9 #include "content/browser/frame_host/navigation_controller_impl.h"
10 #include "content/browser/frame_host/navigation_handle_impl.h"
11 #include "content/browser/frame_host/navigation_request_info.h"
12 #include "content/browser/frame_host/navigator.h"
13 #include "content/browser/loader/navigation_url_loader.h"
14 #include "content/browser/site_instance_impl.h"
15 #include "content/common/resource_request_body.h"
16 #include "content/public/browser/navigation_controller.h"
17 #include "content/public/browser/navigation_throttle.h"
18 #include "content/public/browser/stream_handle.h"
19 #include "content/public/common/content_client.h"
20 #include "net/base/load_flags.h"
21 #include "net/http/http_request_headers.h"
22 #include "net/url_request/redirect_info.h"
24 namespace content {
26 namespace {
28 // Returns the net load flags to use based on the navigation type.
29 // TODO(clamy): unify the code with what is happening on the renderer side.
30 int LoadFlagFromNavigationType(FrameMsg_Navigate_Type::Value navigation_type) {
31 int load_flags = net::LOAD_NORMAL;
32 switch (navigation_type) {
33 case FrameMsg_Navigate_Type::RELOAD:
34 case FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL:
35 load_flags |= net::LOAD_VALIDATE_CACHE;
36 break;
37 case FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE:
38 load_flags |= net::LOAD_BYPASS_CACHE;
39 break;
40 case FrameMsg_Navigate_Type::RESTORE:
41 load_flags |= net::LOAD_PREFERRING_CACHE;
42 break;
43 case FrameMsg_Navigate_Type::RESTORE_WITH_POST:
44 load_flags |= net::LOAD_ONLY_FROM_CACHE;
45 break;
46 case FrameMsg_Navigate_Type::NORMAL:
47 default:
48 break;
50 return load_flags;
53 } // namespace
55 // static
56 scoped_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated(
57 FrameTreeNode* frame_tree_node,
58 const GURL& dest_url,
59 const Referrer& dest_referrer,
60 const FrameNavigationEntry& frame_entry,
61 const NavigationEntryImpl& entry,
62 FrameMsg_Navigate_Type::Value navigation_type,
63 bool is_same_document_history_load,
64 base::TimeTicks navigation_start,
65 NavigationControllerImpl* controller) {
66 std::string method = entry.GetHasPostData() ? "POST" : "GET";
68 // Copy existing headers and add necessary headers that may not be present
69 // in the RequestNavigationParams.
70 net::HttpRequestHeaders headers;
71 headers.AddHeadersFromString(entry.extra_headers());
72 headers.SetHeaderIfMissing(net::HttpRequestHeaders::kUserAgent,
73 GetContentClient()->GetUserAgent());
74 // TODO(clamy): match what blink is doing with accept headers.
75 headers.SetHeaderIfMissing("Accept", "*/*");
77 // Fill POST data from the browser in the request body.
78 scoped_refptr<ResourceRequestBody> request_body;
79 if (entry.GetHasPostData()) {
80 request_body = new ResourceRequestBody();
81 request_body->AppendBytes(
82 reinterpret_cast<const char *>(
83 entry.GetBrowserInitiatedPostData()->front()),
84 entry.GetBrowserInitiatedPostData()->size());
87 scoped_ptr<NavigationRequest> navigation_request(new NavigationRequest(
88 frame_tree_node,
89 entry.ConstructCommonNavigationParams(dest_url, dest_referrer,
90 frame_entry, navigation_type),
91 BeginNavigationParams(method, headers.ToString(),
92 LoadFlagFromNavigationType(navigation_type), false),
93 entry.ConstructRequestNavigationParams(
94 frame_entry, navigation_start, is_same_document_history_load,
95 frame_tree_node->has_committed_real_load(),
96 controller->GetPendingEntryIndex() == -1,
97 controller->GetIndexOfEntry(&entry),
98 controller->GetLastCommittedEntryIndex(),
99 controller->GetEntryCount()),
100 request_body, true, &frame_entry, &entry));
101 return navigation_request.Pass();
104 // static
105 scoped_ptr<NavigationRequest> NavigationRequest::CreateRendererInitiated(
106 FrameTreeNode* frame_tree_node,
107 const CommonNavigationParams& common_params,
108 const BeginNavigationParams& begin_params,
109 scoped_refptr<ResourceRequestBody> body,
110 int current_history_list_offset,
111 int current_history_list_length) {
112 // TODO(clamy): Check if some PageState should be provided here.
113 // TODO(clamy): See how we should handle override of the user agent when the
114 // navigation may start in a renderer and commit in another one.
115 // TODO(clamy): See if the navigation start time should be measured in the
116 // renderer and sent to the browser instead of being measured here.
117 // TODO(clamy): The pending history list offset should be properly set.
118 // TODO(clamy): Set has_committed_real_load.
119 RequestNavigationParams request_params;
120 request_params.current_history_list_offset = current_history_list_offset;
121 request_params.current_history_list_length = current_history_list_length;
122 scoped_ptr<NavigationRequest> navigation_request(
123 new NavigationRequest(frame_tree_node, common_params, begin_params,
124 request_params, body, false, nullptr, nullptr));
125 return navigation_request.Pass();
128 NavigationRequest::NavigationRequest(
129 FrameTreeNode* frame_tree_node,
130 const CommonNavigationParams& common_params,
131 const BeginNavigationParams& begin_params,
132 const RequestNavigationParams& request_params,
133 scoped_refptr<ResourceRequestBody> body,
134 bool browser_initiated,
135 const FrameNavigationEntry* frame_entry,
136 const NavigationEntryImpl* entry)
137 : frame_tree_node_(frame_tree_node),
138 common_params_(common_params),
139 begin_params_(begin_params),
140 request_params_(request_params),
141 browser_initiated_(browser_initiated),
142 state_(NOT_STARTED),
143 restore_type_(NavigationEntryImpl::RESTORE_NONE),
144 is_view_source_(false),
145 bindings_(NavigationEntryImpl::kInvalidBindings) {
146 DCHECK_IMPLIES(browser_initiated, entry != nullptr && frame_entry != nullptr);
147 if (browser_initiated) {
148 // TODO(clamy): use the FrameNavigationEntry for the source SiteInstance
149 // once it has been moved from the NavigationEntry.
150 source_site_instance_ = entry->source_site_instance();
151 dest_site_instance_ = frame_entry->site_instance();
152 restore_type_ = entry->restore_type();
153 is_view_source_ = entry->IsViewSourceMode();
154 bindings_ = entry->bindings();
155 } else {
156 // This is needed to have about:blank and data URLs commit in the same
157 // SiteInstance as the initiating renderer.
158 source_site_instance_ =
159 frame_tree_node->current_frame_host()->GetSiteInstance();
162 const GURL& first_party_for_cookies =
163 frame_tree_node->IsMainFrame()
164 ? common_params.url
165 : frame_tree_node->frame_tree()->root()->current_url();
166 bool parent_is_main_frame = !frame_tree_node->parent() ?
167 false : frame_tree_node->parent()->IsMainFrame();
168 info_.reset(new NavigationRequestInfo(
169 common_params, begin_params, first_party_for_cookies,
170 frame_tree_node->IsMainFrame(), parent_is_main_frame,
171 frame_tree_node->frame_tree_node_id(), body));
174 NavigationRequest::~NavigationRequest() {
177 bool NavigationRequest::BeginNavigation() {
178 DCHECK(!loader_);
179 DCHECK(state_ == NOT_STARTED || state_ == WAITING_FOR_RENDERER_RESPONSE);
180 state_ = STARTED;
182 if (ShouldMakeNetworkRequestForURL(common_params_.url)) {
183 // TODO(clamy): pass the real value for |is_external_protocol| if needed.
184 NavigationThrottle::ThrottleCheckResult result =
185 navigation_handle_->WillStartRequest(
186 begin_params_.method == "POST",
187 Referrer::SanitizeForRequest(common_params_.url,
188 common_params_.referrer),
189 begin_params_.has_user_gesture, common_params_.transition, false);
191 // Abort the request if needed. This will destroy the NavigationRequest.
192 if (result == NavigationThrottle::CANCEL_AND_IGNORE) {
193 frame_tree_node_->ResetNavigationRequest(false);
194 return false;
197 loader_ = NavigationURLLoader::Create(
198 frame_tree_node_->navigator()->GetController()->GetBrowserContext(),
199 frame_tree_node_->frame_tree_node_id(), info_.Pass(), this);
200 return true;
203 // There is no need to make a network request for this navigation, so commit
204 // it immediately.
205 state_ = RESPONSE_STARTED;
206 frame_tree_node_->navigator()->CommitNavigation(
207 frame_tree_node_, nullptr, scoped_ptr<StreamHandle>());
208 return false;
210 // TODO(davidben): Fire (and add as necessary) observer methods such as
211 // DidStartProvisionalLoadForFrame for the navigation.
214 void NavigationRequest::CreateNavigationHandle(NavigatorDelegate* delegate) {
215 navigation_handle_ = NavigationHandleImpl::Create(
216 common_params_.url, frame_tree_node_->IsMainFrame(), delegate);
219 void NavigationRequest::TransferNavigationHandleOwnership(
220 RenderFrameHostImpl* render_frame_host) {
221 render_frame_host->SetNavigationHandle(navigation_handle_.Pass());
224 void NavigationRequest::OnRequestRedirected(
225 const net::RedirectInfo& redirect_info,
226 const scoped_refptr<ResourceResponse>& response) {
227 common_params_.url = redirect_info.new_url;
228 begin_params_.method = redirect_info.new_method;
229 common_params_.referrer.url = GURL(redirect_info.new_referrer);
231 // TODO(clamy): Have CSP + security upgrade checks here.
232 // TODO(clamy): Kill the renderer if FilterURL fails?
233 // TODO(clamy): pass the real value for |is_external_protocol| if needed.
234 NavigationThrottle::ThrottleCheckResult result =
235 navigation_handle_->WillRedirectRequest(
236 common_params_.url, begin_params_.method == "POST",
237 common_params_.referrer.url, false);
239 // Abort the request if needed. This will destroy the NavigationRequest.
240 if (result == NavigationThrottle::CANCEL_AND_IGNORE) {
241 frame_tree_node_->ResetNavigationRequest(false);
242 return;
245 loader_->FollowRedirect();
247 navigation_handle_->DidRedirectNavigation(redirect_info.new_url);
250 void NavigationRequest::OnResponseStarted(
251 const scoped_refptr<ResourceResponse>& response,
252 scoped_ptr<StreamHandle> body) {
253 DCHECK(state_ == STARTED);
254 state_ = RESPONSE_STARTED;
255 frame_tree_node_->navigator()->CommitNavigation(frame_tree_node_,
256 response.get(), body.Pass());
259 void NavigationRequest::OnRequestFailed(bool has_stale_copy_in_cache,
260 int net_error) {
261 DCHECK(state_ == STARTED);
262 state_ = FAILED;
263 navigation_handle_->set_net_error_code(static_cast<net::Error>(net_error));
264 frame_tree_node_->navigator()->FailedNavigation(
265 frame_tree_node_, has_stale_copy_in_cache, net_error);
268 void NavigationRequest::OnRequestStarted(base::TimeTicks timestamp) {
269 frame_tree_node_->navigator()->LogResourceRequestTime(timestamp,
270 common_params_.url);
273 } // namespace content