blob: cbfbba4f99cf55a3b77020416ae06499baa6bb1c [file] [log] [blame]
clamy0e342262016-09-06 13:34:491// Copyright 2016 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.
4
5#ifndef CONTENT_BROWSER_LOADER_INTERCEPTING_RESOURCE_HANDLER_H_
6#define CONTENT_BROWSER_LOADER_INTERCEPTING_RESOURCE_HANDLER_H_
7
8#include <memory>
9#include <string>
10
11#include "base/macros.h"
12#include "base/memory/ref_counted.h"
13#include "base/memory/weak_ptr.h"
14#include "content/browser/loader/layered_resource_handler.h"
tyoshino3b3ee8e92016-12-07 16:04:0715#include "content/browser/loader/resource_controller.h"
clamy0e342262016-09-06 13:34:4916#include "content/browser/loader/resource_handler.h"
17#include "content/common/content_export.h"
18#include "net/base/io_buffer.h"
yhirano22b69a9b2016-10-19 04:39:5119#include "net/url_request/url_request_status.h"
clamy0e342262016-09-06 13:34:4920
21namespace net {
22class URLRequest;
23}
24
25namespace content {
26
mmenke87f5c77a2017-01-31 16:11:2627class ResourceController;
28
clamy0e342262016-09-06 13:34:4929// ResourceHandler that initiates special handling of the response if needed,
30// based on the response's MIME type (starts downloads, sends data to some
31// plugin types via a special channel).
yhirano22b69a9b2016-10-19 04:39:5132//
33// An InterceptingResourceHandler holds two handlers (|next_handler| and
34// |new_handler|). It assumes the following:
35// - OnResponseStarted on |next_handler| never sets |*defer|.
36// - OnResponseCompleted on |next_handler| never sets |*defer|.
clamy0e342262016-09-06 13:34:4937class CONTENT_EXPORT InterceptingResourceHandler
mmenke87f5c77a2017-01-31 16:11:2638 : public LayeredResourceHandler {
clamy0e342262016-09-06 13:34:4939 public:
40 InterceptingResourceHandler(std::unique_ptr<ResourceHandler> next_handler,
41 net::URLRequest* request);
42 ~InterceptingResourceHandler() override;
43
44 // ResourceHandler implementation:
mmenke87f5c77a2017-01-31 16:11:2645 void OnResponseStarted(
46 ResourceResponse* response,
47 std::unique_ptr<ResourceController> controller) override;
mmenke3c1d10c2017-03-09 16:25:4548 void OnWillRead(scoped_refptr<net::IOBuffer>* buf,
49 int* buf_size,
50 std::unique_ptr<ResourceController> controller) override;
mmenke87f5c77a2017-01-31 16:11:2651 void OnReadCompleted(int bytes_read,
52 std::unique_ptr<ResourceController> controller) override;
53 void OnResponseCompleted(
54 const net::URLRequestStatus& status,
55 std::unique_ptr<ResourceController> controller) override;
clamy0e342262016-09-06 13:34:4956
57 // Replaces the next handler with |new_handler|, sending
58 // |payload_for_old_handler| to the old handler. Must be called after
59 // OnWillStart and OnRequestRedirected and before OnResponseStarted. One
60 // OnWillRead call is permitted beforehand. |new_handler|'s OnWillStart and
61 // OnRequestRedirected methods will not be called.
62 void UseNewHandler(std::unique_ptr<ResourceHandler> new_handler,
63 const std::string& payload_for_old_handler);
64
65 // Used in tests.
66 ResourceHandler* new_handler_for_testing() const {
67 return new_handler_.get();
68 }
69
70 private:
mmenke87f5c77a2017-01-31 16:11:2671 // ResourceController subclass that calls into the InterceptingResourceHandler
72 // on cancel/resume.
73 class Controller;
74
clamy0e342262016-09-06 13:34:4975 enum class State {
yhirano22b69a9b2016-10-19 04:39:5176 // The InterceptingResourceHandler is waiting for the mime type of the
77 // response to be identified, to check if the next handler should be
78 // replaced with an appropriate one.
clamy0e342262016-09-06 13:34:4979 STARTING,
80
mmenke87f5c77a2017-01-31 16:11:2681 // The InterceptingResourceHandler is starting the process of swapping
82 // handlers.
83 SWAPPING_HANDLERS,
84
mmenke3c1d10c2017-03-09 16:25:4585 // States where the InterceptingResourceHandler passes the initial
86 // OnWillRead call to the old handler, and then waits for the resulting
87 // buffer read buffer.
88 SENDING_ON_WILL_READ_TO_OLD_HANDLER,
89 WAITING_FOR_OLD_HANDLERS_BUFFER,
90
yhirano22b69a9b2016-10-19 04:39:5191 // The InterceptingResourceHandler is sending the payload given via
mmenke3c1d10c2017-03-09 16:25:4592 // UseNewHandler to the old handler. The first state starts retrieving a
93 // buffer from the old handler, the second state copies as much of the data
94 // as possible to the received buffer and passes it to the old handler.
yhirano22b69a9b2016-10-19 04:39:5195 SENDING_PAYLOAD_TO_OLD_HANDLER,
mmenke3c1d10c2017-03-09 16:25:4596 RECEIVING_BUFFER_FROM_OLD_HANDLER,
clamy0e342262016-09-06 13:34:4997
mmenke90cf7fc22016-10-24 23:59:2798 // The InterceptingResourcHandler is calling the new handler's
99 // OnResponseStarted method and waiting for its completion via Resume().
100 // After completion, the InterceptingResourceHandler will transition to
101 // SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER on success.
102 SENDING_ON_WILL_START_TO_NEW_HANDLER,
103
104 // The InterceptingResourcHandler is calling the new handler's
105 // OnResponseStarted method and waiting for its completion via Resume().
106 // After completion, the InterceptingResourceHandler will transition to
yhirano22b69a9b2016-10-19 04:39:51107 // WAITING_FOR_ON_READ_COMPLETED on success.
mmenke90cf7fc22016-10-24 23:59:27108 SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER,
yhirano22b69a9b2016-10-19 04:39:51109
110 // The InterceptingResourcHandler is waiting for OnReadCompleted to be
111 // called.
112 WAITING_FOR_ON_READ_COMPLETED,
113
mmenke3c1d10c2017-03-09 16:25:45114 // The two phases of uploading previously received data stored in
115 // |first_read_buffer_double_| to the new handler, which is now stored in
116 // |next_handler_|. The first state gets a buffer to write to, and the next
117 // copies all the data it can to that buffer.
yhirano22b69a9b2016-10-19 04:39:51118 SENDING_BUFFER_TO_NEW_HANDLER,
mmenke3c1d10c2017-03-09 16:25:45119 SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER,
yhirano22b69a9b2016-10-19 04:39:51120
121 // The InterceptingResourceHandler has replaced its next ResourceHandler if
122 // needed, and has ensured the buffered read data was properly transmitted
123 // to the new ResourceHandler. The InterceptingResourceHandler now acts as
124 // a pass-through ResourceHandler.
125 PASS_THROUGH,
clamy0e342262016-09-06 13:34:49126 };
127
mmenke87f5c77a2017-01-31 16:11:26128 // Runs necessary operations depending on |state_|.
129 void DoLoop();
clamy0e342262016-09-06 13:34:49130
mmenke87f5c77a2017-01-31 16:11:26131 void ResumeInternal();
yhirano22b69a9b2016-10-19 04:39:51132
mmenke3c1d10c2017-03-09 16:25:45133 void SendOnWillReadToOldHandler();
134 void OnBufferReceived();
mmenke87f5c77a2017-01-31 16:11:26135 void SendOnResponseStartedToOldHandler();
136 void SendPayloadToOldHandler();
mmenke3c1d10c2017-03-09 16:25:45137 void ReceivedBufferFromOldHandler();
mmenke87f5c77a2017-01-31 16:11:26138 void SendFirstReadBufferToNewHandler();
139 void SendOnResponseStartedToNewHandler();
mmenke3c1d10c2017-03-09 16:25:45140 void ReceivedBufferFromNewHandler();
mmenkeb38c6a552017-01-18 18:56:18141
yhirano22b69a9b2016-10-19 04:39:51142 State state_ = State::STARTING;
clamy0e342262016-09-06 13:34:49143
144 std::unique_ptr<ResourceHandler> new_handler_;
145 std::string payload_for_old_handler_;
yhirano22b69a9b2016-10-19 04:39:51146 size_t payload_bytes_written_ = 0;
clamy0e342262016-09-06 13:34:49147
148 // Result of the first read, that may have to be passed to an alternate
149 // ResourceHandler instead of the original ResourceHandler.
150 scoped_refptr<net::IOBuffer> first_read_buffer_;
yhirano22b69a9b2016-10-19 04:39:51151 // Instead of |first_read_buffer_|, this handler creates a new IOBuffer with
152 // the same size and return it to the client.
153 scoped_refptr<net::IOBuffer> first_read_buffer_double_;
mmenke3c1d10c2017-03-09 16:25:45154 int first_read_buffer_size_ = 0;
155 int first_read_buffer_bytes_read_ = 0;
156 int first_read_buffer_bytes_written_ = 0;
157
158 // Information about the new handler's buffer while copying data from
159 // |first_read_buffer_double_| to the new handler's buffer.
160 // Note that when these are used, the old handler has been destroyed, and
161 // |next_handler_| is now the new one.
162 scoped_refptr<net::IOBuffer> new_handler_read_buffer_;
163 int new_handler_read_buffer_size_ = 0;
164
165 // Pointers to parent-owned read buffer and its size. Only used for first
166 // OnWillRead call.
167 scoped_refptr<net::IOBuffer>* parent_read_buffer_ = nullptr;
168 int* parent_read_buffer_size_ = nullptr;
yhirano22b69a9b2016-10-19 04:39:51169
170 scoped_refptr<ResourceResponse> response_;
clamy0e342262016-09-06 13:34:49171
mmenke87f5c77a2017-01-31 16:11:26172 // Next two values are used to handle synchronous Resume calls without a
173 // PostTask.
174
175 // True if the code is currently within a DoLoop.
176 bool in_do_loop_ = false;
177 // True if the request was resumed while |in_do_loop_| was true;
178 bool advance_to_next_state_ = false;
179
mmenkeb38c6a552017-01-18 18:56:18180 base::WeakPtrFactory<InterceptingResourceHandler> weak_ptr_factory_;
181
clamy0e342262016-09-06 13:34:49182 DISALLOW_COPY_AND_ASSIGN(InterceptingResourceHandler);
183};
184
185} // namespace content
186
187#endif // CONTENT_BROWSER_LOADER_INTERCEPTING_RESOURCE_HANDLER_H_