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_request_info.h"
11 #include "content/browser/frame_host/navigator.h"
12 #include "content/browser/loader/navigation_url_loader.h"
13 #include "content/browser/site_instance_impl.h"
14 #include "content/common/resource_request_body.h"
15 #include "content/public/browser/navigation_controller.h"
16 #include "content/public/browser/stream_handle.h"
17 #include "content/public/common/content_client.h"
18 #include "net/base/load_flags.h"
19 #include "net/http/http_request_headers.h"
20 #include "net/url_request/redirect_info.h"
26 // Returns the net load flags to use based on the navigation type.
27 // TODO(clamy): unify the code with what is happening on the renderer side.
28 int LoadFlagFromNavigationType(FrameMsg_Navigate_Type::Value navigation_type
) {
29 int load_flags
= net::LOAD_NORMAL
;
30 switch (navigation_type
) {
31 case FrameMsg_Navigate_Type::RELOAD
:
32 case FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL
:
33 load_flags
|= net::LOAD_VALIDATE_CACHE
;
35 case FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE
:
36 load_flags
|= net::LOAD_BYPASS_CACHE
;
38 case FrameMsg_Navigate_Type::RESTORE
:
39 load_flags
|= net::LOAD_PREFERRING_CACHE
;
41 case FrameMsg_Navigate_Type::RESTORE_WITH_POST
:
42 load_flags
|= net::LOAD_ONLY_FROM_CACHE
;
44 case FrameMsg_Navigate_Type::NORMAL
:
54 scoped_ptr
<NavigationRequest
> NavigationRequest::CreateBrowserInitiated(
55 FrameTreeNode
* frame_tree_node
,
57 const Referrer
& dest_referrer
,
58 const FrameNavigationEntry
& frame_entry
,
59 const NavigationEntryImpl
& entry
,
60 FrameMsg_Navigate_Type::Value navigation_type
,
61 bool is_same_document_history_load
,
62 base::TimeTicks navigation_start
,
63 NavigationControllerImpl
* controller
) {
64 std::string method
= entry
.GetHasPostData() ? "POST" : "GET";
66 // Copy existing headers and add necessary headers that may not be present
67 // in the RequestNavigationParams.
68 net::HttpRequestHeaders headers
;
69 headers
.AddHeadersFromString(entry
.extra_headers());
70 headers
.SetHeaderIfMissing(net::HttpRequestHeaders::kUserAgent
,
71 GetContentClient()->GetUserAgent());
72 // TODO(clamy): match what blink is doing with accept headers.
73 headers
.SetHeaderIfMissing("Accept", "*/*");
75 // Fill POST data from the browser in the request body.
76 scoped_refptr
<ResourceRequestBody
> request_body
;
77 if (entry
.GetHasPostData()) {
78 request_body
= new ResourceRequestBody();
79 request_body
->AppendBytes(
80 reinterpret_cast<const char *>(
81 entry
.GetBrowserInitiatedPostData()->front()),
82 entry
.GetBrowserInitiatedPostData()->size());
85 scoped_ptr
<NavigationRequest
> navigation_request(new NavigationRequest(
87 entry
.ConstructCommonNavigationParams(dest_url
, dest_referrer
,
88 frame_entry
, navigation_type
),
89 BeginNavigationParams(method
, headers
.ToString(),
90 LoadFlagFromNavigationType(navigation_type
), false),
91 entry
.ConstructRequestNavigationParams(
92 frame_entry
, navigation_start
, is_same_document_history_load
,
93 frame_tree_node
->has_committed_real_load(),
94 controller
->GetPendingEntryIndex() == -1,
95 controller
->GetIndexOfEntry(&entry
),
96 controller
->GetLastCommittedEntryIndex(),
97 controller
->GetEntryCount()),
98 request_body
, true, &frame_entry
, &entry
));
99 return navigation_request
.Pass();
103 scoped_ptr
<NavigationRequest
> NavigationRequest::CreateRendererInitiated(
104 FrameTreeNode
* frame_tree_node
,
105 const CommonNavigationParams
& common_params
,
106 const BeginNavigationParams
& begin_params
,
107 scoped_refptr
<ResourceRequestBody
> body
,
108 int current_history_list_offset
,
109 int current_history_list_length
) {
110 // TODO(clamy): Check if some PageState should be provided here.
111 // TODO(clamy): See how we should handle override of the user agent when the
112 // navigation may start in a renderer and commit in another one.
113 // TODO(clamy): See if the navigation start time should be measured in the
114 // renderer and sent to the browser instead of being measured here.
115 // TODO(clamy): The pending history list offset should be properly set.
116 // TODO(clamy): Set has_committed_real_load.
117 RequestNavigationParams request_params
;
118 request_params
.current_history_list_offset
= current_history_list_offset
;
119 request_params
.current_history_list_length
= current_history_list_length
;
120 scoped_ptr
<NavigationRequest
> navigation_request(
121 new NavigationRequest(frame_tree_node
, common_params
, begin_params
,
122 request_params
, body
, false, nullptr, nullptr));
123 return navigation_request
.Pass();
126 NavigationRequest::NavigationRequest(
127 FrameTreeNode
* frame_tree_node
,
128 const CommonNavigationParams
& common_params
,
129 const BeginNavigationParams
& begin_params
,
130 const RequestNavigationParams
& request_params
,
131 scoped_refptr
<ResourceRequestBody
> body
,
132 bool browser_initiated
,
133 const FrameNavigationEntry
* frame_entry
,
134 const NavigationEntryImpl
* entry
)
135 : frame_tree_node_(frame_tree_node
),
136 common_params_(common_params
),
137 begin_params_(begin_params
),
138 request_params_(request_params
),
139 browser_initiated_(browser_initiated
),
141 restore_type_(NavigationEntryImpl::RESTORE_NONE
),
142 is_view_source_(false),
143 bindings_(NavigationEntryImpl::kInvalidBindings
) {
144 DCHECK_IMPLIES(browser_initiated
, entry
!= nullptr && frame_entry
!= nullptr);
145 if (browser_initiated
) {
146 // TODO(clamy): use the FrameNavigationEntry for the source SiteInstance
147 // once it has been moved from the NavigationEntry.
148 source_site_instance_
= entry
->source_site_instance();
149 dest_site_instance_
= frame_entry
->site_instance();
150 restore_type_
= entry
->restore_type();
151 is_view_source_
= entry
->IsViewSourceMode();
152 bindings_
= entry
->bindings();
154 // This is needed to have about:blank and data URLs commit in the same
155 // SiteInstance as the initiating renderer.
156 source_site_instance_
=
157 frame_tree_node
->current_frame_host()->GetSiteInstance();
160 const GURL
& first_party_for_cookies
=
161 frame_tree_node
->IsMainFrame()
163 : frame_tree_node
->frame_tree()->root()->current_url();
164 bool parent_is_main_frame
= !frame_tree_node
->parent() ?
165 false : frame_tree_node
->parent()->IsMainFrame();
166 info_
.reset(new NavigationRequestInfo(
167 common_params
, begin_params
, first_party_for_cookies
,
168 frame_tree_node
->IsMainFrame(), parent_is_main_frame
,
169 frame_tree_node
->frame_tree_node_id(), body
));
172 NavigationRequest::~NavigationRequest() {
175 bool NavigationRequest::BeginNavigation() {
177 DCHECK(state_
== NOT_STARTED
|| state_
== WAITING_FOR_RENDERER_RESPONSE
);
180 if (ShouldMakeNetworkRequestForURL(common_params_
.url
)) {
181 loader_
= NavigationURLLoader::Create(
182 frame_tree_node_
->navigator()->GetController()->GetBrowserContext(),
183 frame_tree_node_
->frame_tree_node_id(), info_
.Pass(), this);
187 // There is no need to make a network request for this navigation, so commit
189 state_
= RESPONSE_STARTED
;
190 frame_tree_node_
->navigator()->CommitNavigation(
191 frame_tree_node_
, nullptr, scoped_ptr
<StreamHandle
>());
194 // TODO(davidben): Fire (and add as necessary) observer methods such as
195 // DidStartProvisionalLoadForFrame for the navigation.
198 void NavigationRequest::OnRequestRedirected(
199 const net::RedirectInfo
& redirect_info
,
200 const scoped_refptr
<ResourceResponse
>& response
) {
201 // TODO(davidben): Track other changes from redirects. These are important
202 // for, e.g., reloads.
203 common_params_
.url
= redirect_info
.new_url
;
205 // TODO(davidben): This where prerender and navigation_interceptor should be
206 // integrated. For now, just always follow all redirects.
207 loader_
->FollowRedirect();
210 void NavigationRequest::OnResponseStarted(
211 const scoped_refptr
<ResourceResponse
>& response
,
212 scoped_ptr
<StreamHandle
> body
) {
213 DCHECK(state_
== STARTED
);
214 state_
= RESPONSE_STARTED
;
215 frame_tree_node_
->navigator()->CommitNavigation(frame_tree_node_
,
216 response
.get(), body
.Pass());
219 void NavigationRequest::OnRequestFailed(bool has_stale_copy_in_cache
,
221 DCHECK(state_
== STARTED
);
223 frame_tree_node_
->navigator()->FailedNavigation(
224 frame_tree_node_
, has_stale_copy_in_cache
, net_error
);
227 void NavigationRequest::OnRequestStarted(base::TimeTicks timestamp
) {
228 frame_tree_node_
->navigator()->LogResourceRequestTime(timestamp
,
232 } // namespace content