Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / frame_host / navigation_request.cc
blobe5973ee3284556933bebee93e008f511026f5236
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"
22 namespace content {
24 namespace {
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;
34 break;
35 case FrameMsg_Navigate_Type::RELOAD_IGNORING_CACHE:
36 load_flags |= net::LOAD_BYPASS_CACHE;
37 break;
38 case FrameMsg_Navigate_Type::RESTORE:
39 load_flags |= net::LOAD_PREFERRING_CACHE;
40 break;
41 case FrameMsg_Navigate_Type::RESTORE_WITH_POST:
42 load_flags |= net::LOAD_ONLY_FROM_CACHE;
43 break;
44 case FrameMsg_Navigate_Type::NORMAL:
45 default:
46 break;
48 return load_flags;
51 } // namespace
53 // static
54 bool NavigationRequest::ShouldMakeNetworkRequest(const GURL& url) {
55 // Data urls should not make network requests.
56 // TODO(clamy): same document navigations should not make network requests.
57 return !url.SchemeIs(url::kDataScheme);
60 // static
61 scoped_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated(
62 FrameTreeNode* frame_tree_node,
63 const NavigationEntryImpl& entry,
64 FrameMsg_Navigate_Type::Value navigation_type,
65 base::TimeTicks navigation_start,
66 NavigationControllerImpl* controller) {
67 std::string method = entry.GetHasPostData() ? "POST" : "GET";
69 // Copy existing headers and add necessary headers that may not be present
70 // in the RequestNavigationParams.
71 net::HttpRequestHeaders headers;
72 headers.AddHeadersFromString(entry.extra_headers());
73 headers.SetHeaderIfMissing(net::HttpRequestHeaders::kUserAgent,
74 GetContentClient()->GetUserAgent());
75 // TODO(clamy): match what blink is doing with accept headers.
76 headers.SetHeaderIfMissing("Accept", "*/*");
78 // Fill POST data from the browser in the request body.
79 scoped_refptr<ResourceRequestBody> request_body;
80 if (entry.GetHasPostData()) {
81 request_body = new ResourceRequestBody();
82 request_body->AppendBytes(
83 reinterpret_cast<const char *>(
84 entry.GetBrowserInitiatedPostData()->front()),
85 entry.GetBrowserInitiatedPostData()->size());
88 scoped_ptr<NavigationRequest> navigation_request(new NavigationRequest(
89 frame_tree_node, entry.ConstructCommonNavigationParams(navigation_type),
90 BeginNavigationParams(method, headers.ToString(),
91 LoadFlagFromNavigationType(navigation_type), false),
92 entry.ConstructRequestNavigationParams(
93 navigation_start, controller->GetIndexOfEntry(&entry),
94 controller->GetLastCommittedEntryIndex(),
95 controller->GetEntryCount()),
96 request_body, true, &entry));
97 return navigation_request.Pass();
100 // static
101 scoped_ptr<NavigationRequest> NavigationRequest::CreateRendererInitiated(
102 FrameTreeNode* frame_tree_node,
103 const CommonNavigationParams& common_params,
104 const BeginNavigationParams& begin_params,
105 scoped_refptr<ResourceRequestBody> body,
106 int current_history_list_offset,
107 int current_history_list_length) {
108 // TODO(clamy): Check if some PageState should be provided here.
109 // TODO(clamy): See how we should handle override of the user agent when the
110 // navigation may start in a renderer and commit in another one.
111 // TODO(clamy): See if the navigation start time should be measured in the
112 // renderer and sent to the browser instead of being measured here.
113 // TODO(clamy): The pending history list offset should be properly set.
114 RequestNavigationParams request_params;
115 request_params.current_history_list_offset = current_history_list_offset;
116 request_params.current_history_list_length = current_history_list_length;
117 scoped_ptr<NavigationRequest> navigation_request(
118 new NavigationRequest(frame_tree_node, common_params, begin_params,
119 request_params, body, false, nullptr));
120 return navigation_request.Pass();
123 NavigationRequest::NavigationRequest(
124 FrameTreeNode* frame_tree_node,
125 const CommonNavigationParams& common_params,
126 const BeginNavigationParams& begin_params,
127 const RequestNavigationParams& request_params,
128 scoped_refptr<ResourceRequestBody> body,
129 bool browser_initiated,
130 const NavigationEntryImpl* entry)
131 : frame_tree_node_(frame_tree_node),
132 common_params_(common_params),
133 begin_params_(begin_params),
134 request_params_(request_params),
135 browser_initiated_(browser_initiated),
136 state_(NOT_STARTED),
137 restore_type_(NavigationEntryImpl::RESTORE_NONE),
138 is_view_source_(false),
139 bindings_(NavigationEntryImpl::kInvalidBindings) {
140 if (entry) {
141 source_site_instance_ = entry->source_site_instance();
142 dest_site_instance_ = entry->site_instance();
143 restore_type_ = entry->restore_type();
144 is_view_source_ = entry->IsViewSourceMode();
145 bindings_ = entry->bindings();
148 const GURL& first_party_for_cookies =
149 frame_tree_node->IsMainFrame()
150 ? common_params.url
151 : frame_tree_node->frame_tree()->root()->current_url();
152 bool parent_is_main_frame = !frame_tree_node->parent() ?
153 false : frame_tree_node->parent()->IsMainFrame();
154 info_.reset(new NavigationRequestInfo(
155 common_params, begin_params, first_party_for_cookies,
156 frame_tree_node->IsMainFrame(), parent_is_main_frame, body));
159 NavigationRequest::~NavigationRequest() {
162 bool NavigationRequest::BeginNavigation() {
163 DCHECK(!loader_);
164 DCHECK(state_ == NOT_STARTED || state_ == WAITING_FOR_RENDERER_RESPONSE);
165 state_ = STARTED;
167 if (ShouldMakeNetworkRequest(common_params_.url)) {
168 loader_ = NavigationURLLoader::Create(
169 frame_tree_node_->navigator()->GetController()->GetBrowserContext(),
170 frame_tree_node_->frame_tree_node_id(), info_.Pass(), this);
171 return true;
174 // There is no need to make a network request for this navigation, so commit
175 // it immediately.
176 state_ = RESPONSE_STARTED;
177 frame_tree_node_->navigator()->CommitNavigation(
178 frame_tree_node_, nullptr, scoped_ptr<StreamHandle>());
179 return false;
181 // TODO(davidben): Fire (and add as necessary) observer methods such as
182 // DidStartProvisionalLoadForFrame for the navigation.
185 void NavigationRequest::OnRequestRedirected(
186 const net::RedirectInfo& redirect_info,
187 const scoped_refptr<ResourceResponse>& response) {
188 // TODO(davidben): Track other changes from redirects. These are important
189 // for, e.g., reloads.
190 common_params_.url = redirect_info.new_url;
192 // TODO(davidben): This where prerender and navigation_interceptor should be
193 // integrated. For now, just always follow all redirects.
194 loader_->FollowRedirect();
197 void NavigationRequest::OnResponseStarted(
198 const scoped_refptr<ResourceResponse>& response,
199 scoped_ptr<StreamHandle> body) {
200 DCHECK(state_ == STARTED);
201 state_ = RESPONSE_STARTED;
202 frame_tree_node_->navigator()->CommitNavigation(frame_tree_node_,
203 response.get(), body.Pass());
206 void NavigationRequest::OnRequestFailed(int net_error) {
207 DCHECK(state_ == STARTED);
208 state_ = FAILED;
209 // TODO(davidben): Network failures should display a network error page.
210 NOTIMPLEMENTED() << " where net_error=" << net_error;
213 void NavigationRequest::OnRequestStarted(base::TimeTicks timestamp) {
214 frame_tree_node_->navigator()->LogResourceRequestTime(timestamp,
215 common_params_.url);
218 } // namespace content