summaryrefslogtreecommitdiff
path: root/chromium/content/browser/frame_host/navigation_handle_impl.h
blob: cee19438d46ac62872ff2f6d28ec9040e836a421 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_FRAME_HOST_NAVIGATION_HANDLE_IMPL_H_
#define CONTENT_BROWSER_FRAME_HOST_NAVIGATION_HANDLE_IMPL_H_

#include "content/public/browser/navigation_handle.h"

#include <stddef.h>

#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "content/browser/frame_host/frame_tree_node.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/common/content_export.h"
#include "content/public/browser/navigation_data.h"
#include "content/public/browser/navigation_throttle.h"
#include "url/gurl.h"

struct FrameHostMsg_DidCommitProvisionalLoad_Params;

namespace content {

class NavigatorDelegate;
class ResourceRequestBodyImpl;
struct NavigationRequestInfo;

// This class keeps track of a single navigation. It is created upon receipt of
// a DidStartProvisionalLoad IPC in a RenderFrameHost. The RenderFrameHost owns
// the newly created NavigationHandleImpl as long as the navigation is ongoing.
// The NavigationHandleImpl in the RenderFrameHost will be reset when the
// navigation stops, that is if one of the following events happen:
//   - The RenderFrameHost receives a DidStartProvisionalLoad IPC for a new
//   navigation (see below for special cases where the DidStartProvisionalLoad
//   message does not indicate the start of a new navigation).
//   - The RenderFrameHost stops loading.
//   - The RenderFrameHost receives a DidDropNavigation IPC.
//
// When the navigation encounters an error, the DidStartProvisionalLoad marking
// the start of the load of the error page will not be considered as marking a
// new navigation. It will not reset the NavigationHandleImpl in the
// RenderFrameHost.
//
// If the navigation needs a cross-site transfer, then the NavigationHandleImpl
// will briefly be held by the RenderFrameHostManager, until a suitable
// RenderFrameHost for the navigation has been found. The ownership of the
// NavigationHandleImpl will then be transferred to the new RenderFrameHost.
// The DidStartProvisionalLoad received by the new RenderFrameHost for the
// transferring navigation will not reset the NavigationHandleImpl, as it does
// not mark the start of a new navigation.
//
// PlzNavigate: the NavigationHandleImpl is created just after creating a new
// NavigationRequest. It is then owned by the NavigationRequest until the
// navigation is ready to commit. The NavigationHandleImpl ownership is then
// transferred to the RenderFrameHost in which the navigation will commit.
//
// When PlzNavigate is enabled, the NavigationHandleImpl will never be reset
// following the receipt of a DidStartProvisionalLoad IPC. There are also no
// transferring navigations. The other causes of NavigationHandleImpl reset in
// the RenderFrameHost still apply.
class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
 public:
  // |navigation_start| comes from the DidStartProvisionalLoad IPC, which tracks
  // both renderer-initiated and browser-initiated navigation start.
  // PlzNavigate: This value always comes from the CommonNavigationParams
  // associated with this navigation.
  static std::unique_ptr<NavigationHandleImpl> Create(
      const GURL& url,
      FrameTreeNode* frame_tree_node,
      bool is_renderer_initiated,
      bool is_synchronous,
      bool is_srcdoc,
      const base::TimeTicks& navigation_start,
      int pending_nav_entry_id);
  ~NavigationHandleImpl() override;

  // NavigationHandle implementation:
  const GURL& GetURL() override;
  bool IsInMainFrame() override;
  bool IsParentMainFrame() override;
  bool IsRendererInitiated() override;
  bool IsSynchronousNavigation() override;
  bool IsSrcdoc() override;
  bool WasServerRedirect() override;
  int GetFrameTreeNodeId() override;
  int GetParentFrameTreeNodeId() override;
  const base::TimeTicks& NavigationStart() override;
  bool IsPost() override;
  const Referrer& GetReferrer() override;
  bool HasUserGesture() override;
  ui::PageTransition GetPageTransition() override;
  bool IsExternalProtocol() override;
  net::Error GetNetErrorCode() override;
  RenderFrameHostImpl* GetRenderFrameHost() override;
  bool IsSamePage() override;
  bool HasCommitted() override;
  bool IsErrorPage() override;
  void Resume() override;
  void CancelDeferredNavigation(
      NavigationThrottle::ThrottleCheckResult result) override;
  void RegisterThrottleForTesting(
      std::unique_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;
  NavigationData* GetNavigationData() override;

  NavigatorDelegate* GetDelegate() const;

  // Returns the response headers for the request or nullptr if there are none.
  // This should only be accessed after a redirect was encountered or after the
  // navigation is ready to commit. The headers returned should not be modified,
  // as modifications will not be reflected in the network stack.
  const net::HttpResponseHeaders* GetResponseHeaders();

  // Get the unique id from the NavigationEntry associated with this
  // NavigationHandle. Note that a synchronous, renderer-initiated navigation
  // will not have a NavigationEntry associated with it, and this will return 0.
  int pending_nav_entry_id() const { return pending_nav_entry_id_; }

  // Changes the pending NavigationEntry ID for this handle.  This is currently
  // required during transfer navigations.
  // TODO(creis): Remove this when transfer navigations do not require pending
  // entries.  See https://crbug.com/495161.
  void update_entry_id_for_transfer(int nav_entry_id) {
    pending_nav_entry_id_ = nav_entry_id;
  }

  void set_net_error_code(net::Error net_error_code) {
    net_error_code_ = net_error_code;
  }

  // Returns whether the navigation is currently being transferred from one
  // RenderFrameHost to another. In particular, a DidStartProvisionalLoad IPC
  // for the navigation URL, received in the new RenderFrameHost, should not
  // indicate the start of a new navigation in that case.
  bool is_transferring() const { return is_transferring_; }
  void set_is_transferring(bool is_transferring) {
    is_transferring_ = is_transferring;
  }

  // Updates the RenderFrameHost that is about to commit the navigation. This
  // is used during transfer navigations.
  void set_render_frame_host(RenderFrameHostImpl* render_frame_host) {
    render_frame_host_ = render_frame_host;
  }

  // Returns the POST body associated with this navigation.  This will be
  // null for GET and/or other non-POST requests (or if a response to a POST
  // request was a redirect that changed the method to GET - for example 302).
  const scoped_refptr<ResourceRequestBodyImpl>& resource_request_body() const {
    return resource_request_body_;
  }

  typedef base::Callback<void(NavigationThrottle::ThrottleCheckResult)>
      ThrottleChecksFinishedCallback;

  // Called when the URLRequest will start in the network stack.  |callback|
  // will be called when all throttle checks have completed. This will allow
  // the caller to cancel the navigation or let it proceed.
  void WillStartRequest(
      const std::string& method,
      scoped_refptr<content::ResourceRequestBodyImpl> resource_request_body,
      const Referrer& sanitized_referrer,
      bool has_user_gesture,
      ui::PageTransition transition,
      bool is_external_protocol,
      const ThrottleChecksFinishedCallback& callback);

  // Called when the URLRequest will be redirected in the network stack.
  // |callback| will be called when all throttles check have completed. This
  // will allow the caller to cancel the navigation or let it proceed.
  // This will also inform the delegate that the request was redirected.
  void WillRedirectRequest(
      const GURL& new_url,
      const std::string& new_method,
      const GURL& new_referrer_url,
      bool new_is_external_protocol,
      scoped_refptr<net::HttpResponseHeaders> response_headers,
      const ThrottleChecksFinishedCallback& callback);

  // Called when the URLRequest has delivered response headers and metadata.
  // |callback| will be called when all throttle checks have completed,
  // allowing the caller to cancel the navigation or let it proceed.
  // NavigationHandle will not call |callback| with a result of DEFER.
  // If the result is PROCEED, then 'ReadyToCommitNavigation' will be called
  // with |render_frame_host| and |response_headers| just before calling
  // |callback|.
  void WillProcessResponse(
      RenderFrameHostImpl* render_frame_host,
      scoped_refptr<net::HttpResponseHeaders> response_headers,
      const ThrottleChecksFinishedCallback& callback);

  // Returns the FrameTreeNode this navigation is happening in.
  FrameTreeNode* frame_tree_node() { return frame_tree_node_; }

  // Called when the navigation is ready to be committed in
  // |render_frame_host|. This will update the |state_| and inform the
  // delegate.
  void ReadyToCommitNavigation(RenderFrameHostImpl* render_frame_host);

  // Called when the navigation was committed in |render_frame_host|. This will
  // update the |state_|.
  void DidCommitNavigation(
      const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
      bool same_page,
      RenderFrameHostImpl* render_frame_host);

  // Called during commit. Takes ownership of the embedder's NavigationData
  // instance. This NavigationData may have been cloned prior to being added
  // here.
  void set_navigation_data(std::unique_ptr<NavigationData> navigation_data) {
    navigation_data_ = std::move(navigation_data);
  }

 private:
  friend class NavigationHandleImplTest;

  // Used to track the state the navigation is currently in.
  enum State {
    INITIAL = 0,
    WILL_SEND_REQUEST,
    DEFERRING_START,
    WILL_REDIRECT_REQUEST,
    DEFERRING_REDIRECT,
    CANCELING,
    WILL_PROCESS_RESPONSE,
    DEFERRING_RESPONSE,
    READY_TO_COMMIT,
    DID_COMMIT,
    DID_COMMIT_ERROR_PAGE,
  };

  NavigationHandleImpl(const GURL& url,
                       FrameTreeNode* frame_tree_node,
                       bool is_renderer_initiated,
                       bool is_synchronous,
                       bool is_srcdoc,
                       const base::TimeTicks& navigation_start,
                       int pending_nav_entry_id);

  NavigationThrottle::ThrottleCheckResult CheckWillStartRequest();
  NavigationThrottle::ThrottleCheckResult CheckWillRedirectRequest();
  NavigationThrottle::ThrottleCheckResult CheckWillProcessResponse();

  // Helper function to run and reset the |complete_callback_|. This marks the
  // end of a round of NavigationThrottleChecks.
  void RunCompleteCallback(NavigationThrottle::ThrottleCheckResult result);

  // Used in tests.
  State state() const { return state_; }

  // See NavigationHandle for a description of those member variables.
  GURL url_;
  Referrer sanitized_referrer_;
  bool has_user_gesture_;
  ui::PageTransition transition_;
  bool is_external_protocol_;
  net::Error net_error_code_;
  RenderFrameHostImpl* render_frame_host_;
  const bool is_renderer_initiated_;
  bool is_same_page_;
  const bool is_synchronous_;
  const bool is_srcdoc_;
  bool was_redirected_;
  scoped_refptr<net::HttpResponseHeaders> response_headers_;

  // The HTTP method used for the navigation.
  std::string method_;

  // The POST body associated with this navigation.  This will be null for GET
  // and/or other non-POST requests (or if a response to a POST request was a
  // redirect that changed the method to GET - for example 302).
  scoped_refptr<ResourceRequestBodyImpl> resource_request_body_;

  // 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_;

  // The FrameTreeNode this navigation is happening in.
  FrameTreeNode* frame_tree_node_;

  // A list of Throttles registered for this navigation.
  ScopedVector<NavigationThrottle> throttles_;

  // The index of the next throttle to check.
  size_t next_index_;

  // The time this navigation started.
  const base::TimeTicks navigation_start_;

  // The unique id of the corresponding NavigationEntry.
  int pending_nav_entry_id_;

  // This callback will be run when all throttle checks have been performed.
  ThrottleChecksFinishedCallback complete_callback_;

  // Embedder data tied to this navigation.
  std::unique_ptr<NavigationData> navigation_data_;

  DISALLOW_COPY_AND_ASSIGN(NavigationHandleImpl);
};

}  // namespace content

#endif  // CONTENT_BROWSER_FRAME_HOST_NAVIGATION_HANDLE_IMPL_H_