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"
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
;
37 case FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE
:
38 load_flags
|= net::LOAD_BYPASS_CACHE
;
40 case FrameMsg_Navigate_Type::RESTORE
:
41 load_flags
|= net::LOAD_PREFERRING_CACHE
;
43 case FrameMsg_Navigate_Type::RESTORE_WITH_POST
:
44 load_flags
|= net::LOAD_ONLY_FROM_CACHE
;
46 case FrameMsg_Navigate_Type::NORMAL
:
56 scoped_ptr
<NavigationRequest
> NavigationRequest::CreateBrowserInitiated(
57 FrameTreeNode
* frame_tree_node
,
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(
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();
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
),
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();
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()
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() {
179 DCHECK(state_
== NOT_STARTED
|| state_
== WAITING_FOR_RENDERER_RESPONSE
);
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);
197 loader_
= NavigationURLLoader::Create(
198 frame_tree_node_
->navigator()->GetController()->GetBrowserContext(),
199 frame_tree_node_
->frame_tree_node_id(), info_
.Pass(), this);
203 // There is no need to make a network request for this navigation, so commit
205 state_
= RESPONSE_STARTED
;
206 frame_tree_node_
->navigator()->CommitNavigation(
207 frame_tree_node_
, nullptr, scoped_ptr
<StreamHandle
>());
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);
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
,
261 DCHECK(state_
== STARTED
);
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
,
273 } // namespace content