OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/loader/intercepting_resource_handler.h" | 5 #include "content/browser/loader/intercepting_resource_handler.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/memory/ptr_util.h" | |
8 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
10 #include "content/browser/loader/null_resource_controller.h" | |
11 #include "content/public/browser/resource_controller.h" | |
9 #include "content/public/common/resource_response.h" | 12 #include "content/public/common/resource_response.h" |
10 #include "net/base/io_buffer.h" | 13 #include "net/base/io_buffer.h" |
11 #include "net/url_request/url_request.h" | 14 #include "net/url_request/url_request.h" |
12 | 15 |
13 namespace content { | 16 namespace content { |
14 | 17 |
18 class InterceptingResourceHandler::Controller : public ResourceController { | |
19 public: | |
20 explicit Controller(InterceptingResourceHandler* mime_handler) | |
21 : intercepting_handler_(mime_handler) {} | |
22 | |
23 void Resume() override { | |
24 DCHECK(!used_); | |
25 used_ = true; | |
26 intercepting_handler_->ResumeInternal(); | |
27 } | |
28 | |
29 void Cancel() override { | |
30 DCHECK(!used_); | |
31 used_ = true; | |
32 intercepting_handler_->Cancel(); | |
33 } | |
34 | |
35 void CancelAndIgnore() override { | |
36 DCHECK(!used_); | |
37 used_ = true; | |
38 intercepting_handler_->CancelAndIgnore(); | |
39 } | |
40 | |
41 void CancelWithError(int error_code) override { | |
42 DCHECK(!used_); | |
43 used_ = true; | |
44 intercepting_handler_->CancelWithError(error_code); | |
45 } | |
46 | |
47 private: | |
48 InterceptingResourceHandler* intercepting_handler_; | |
49 bool used_ = false; | |
50 | |
51 DISALLOW_COPY_AND_ASSIGN(Controller); | |
52 }; | |
53 | |
15 InterceptingResourceHandler::InterceptingResourceHandler( | 54 InterceptingResourceHandler::InterceptingResourceHandler( |
16 std::unique_ptr<ResourceHandler> next_handler, | 55 std::unique_ptr<ResourceHandler> next_handler, |
17 net::URLRequest* request) | 56 net::URLRequest* request) |
18 : LayeredResourceHandler(request, std::move(next_handler)) { | 57 : LayeredResourceHandler(request, std::move(next_handler)) { |
19 next_handler_->SetController(this); | |
20 } | 58 } |
21 | 59 |
22 InterceptingResourceHandler::~InterceptingResourceHandler() {} | 60 InterceptingResourceHandler::~InterceptingResourceHandler() {} |
23 | 61 |
24 void InterceptingResourceHandler::SetController( | 62 void InterceptingResourceHandler::OnResponseStarted( |
25 ResourceController* controller) { | 63 ResourceResponse* response, |
26 if (state_ == State::PASS_THROUGH) | 64 std::unique_ptr<ResourceController> controller) { |
27 return LayeredResourceHandler::SetController(controller); | |
28 ResourceHandler::SetController(controller); | |
29 } | |
30 | |
31 bool InterceptingResourceHandler::OnResponseStarted(ResourceResponse* response, | |
32 bool* defer) { | |
33 // If there's no need to switch handlers, just start acting as a blind | 65 // If there's no need to switch handlers, just start acting as a blind |
34 // pass-through ResourceHandler. | 66 // pass-through ResourceHandler. |
35 if (!new_handler_) { | 67 if (!new_handler_) { |
36 state_ = State::PASS_THROUGH; | 68 state_ = State::PASS_THROUGH; |
37 next_handler_->SetController(controller()); | 69 next_handler_->OnResponseStarted(response, std::move(controller)); |
38 return next_handler_->OnResponseStarted(response, defer); | 70 return; |
39 } | 71 } |
40 | 72 |
41 DCHECK_EQ(state_, State::STARTING); | 73 DCHECK_EQ(state_, State::STARTING); |
42 // Otherwise, switch handlers. First, inform the original ResourceHandler | |
43 // that this will be handled entirely by the new ResourceHandler. | |
44 bool defer_ignored = false; | |
45 if (!next_handler_->OnResponseStarted(response, &defer_ignored)) | |
46 return false; | |
47 | |
48 // Although deferring OnResponseStarted is legal, the only downstream handler | |
49 // which does so is CrossSiteResourceHandler. Cross-site transitions should | |
50 // not trigger when switching handlers. | |
51 DCHECK(!defer_ignored); | |
52 | 74 |
53 // TODO(yhirano): Retaining ownership from a raw pointer is bad. | 75 // TODO(yhirano): Retaining ownership from a raw pointer is bad. |
Randy Smith (Not in Mondays)
2016/12/16 21:37:26
A sense a disturbance in the force ... as if sever
mmenke
2016/12/22 16:29:35
We were already doing it in the MimeBlahResourceHa
| |
54 response_ = response; | 76 response_ = response; |
77 | |
78 // Otherwise, switch handlers. First, inform the original ResourceHandler | |
79 // that this will be handled entirely by the new ResourceHandler. | |
80 set_controller(std::move(controller)); | |
55 state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER; | 81 state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER; |
56 return DoLoop(defer); | 82 next_handler_->OnResponseStarted(response, |
83 base::MakeUnique<Controller>(this)); | |
84 return; | |
57 } | 85 } |
58 | 86 |
59 bool InterceptingResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, | 87 bool InterceptingResourceHandler::OnWillRead(scoped_refptr<net::IOBuffer>* buf, |
60 int* buf_size, | 88 int* buf_size, |
61 int min_size) { | 89 int min_size) { |
62 if (state_ == State::PASS_THROUGH) | 90 if (state_ == State::PASS_THROUGH) |
63 return next_handler_->OnWillRead(buf, buf_size, min_size); | 91 return next_handler_->OnWillRead(buf, buf_size, min_size); |
64 | 92 |
65 DCHECK_EQ(State::STARTING, state_); | 93 DCHECK_EQ(State::STARTING, state_); |
66 DCHECK_EQ(-1, min_size); | 94 DCHECK_EQ(-1, min_size); |
67 | 95 |
68 if (!next_handler_->OnWillRead(buf, buf_size, min_size)) | 96 if (!next_handler_->OnWillRead(buf, buf_size, min_size)) |
69 return false; | 97 return false; |
70 | 98 |
71 first_read_buffer_ = *buf; | 99 first_read_buffer_ = *buf; |
72 first_read_buffer_size_ = *buf_size; | 100 first_read_buffer_size_ = *buf_size; |
73 first_read_buffer_double_ = new net::IOBuffer(static_cast<size_t>(*buf_size)); | 101 first_read_buffer_double_ = new net::IOBuffer(static_cast<size_t>(*buf_size)); |
74 *buf = first_read_buffer_double_; | 102 *buf = first_read_buffer_double_; |
75 return true; | 103 return true; |
76 } | 104 } |
77 | 105 |
78 bool InterceptingResourceHandler::OnReadCompleted(int bytes_read, bool* defer) { | 106 void InterceptingResourceHandler::OnReadCompleted( |
107 int bytes_read, | |
108 std::unique_ptr<ResourceController> controller) { | |
109 DCHECK(!has_controller()); | |
110 | |
79 DCHECK_GE(bytes_read, 0); | 111 DCHECK_GE(bytes_read, 0); |
80 if (state_ == State::PASS_THROUGH) { | 112 if (state_ == State::PASS_THROUGH) { |
81 if (first_read_buffer_double_) { | 113 if (first_read_buffer_double_) { |
82 // |first_read_buffer_double_| was allocated and the user wrote data to | 114 // |first_read_buffer_double_| was allocated and the user wrote data to |
83 // the buffer, but switching has not been done after all. | 115 // the buffer, but switching has not been done after all. |
84 memcpy(first_read_buffer_->data(), first_read_buffer_double_->data(), | 116 memcpy(first_read_buffer_->data(), first_read_buffer_double_->data(), |
85 bytes_read); | 117 bytes_read); |
86 first_read_buffer_ = nullptr; | 118 first_read_buffer_ = nullptr; |
87 first_read_buffer_double_ = nullptr; | 119 first_read_buffer_double_ = nullptr; |
88 } | 120 } |
89 return next_handler_->OnReadCompleted(bytes_read, defer); | 121 next_handler_->OnReadCompleted(bytes_read, std::move(controller)); |
122 return; | |
90 } | 123 } |
91 | 124 |
92 DCHECK_EQ(State::WAITING_FOR_ON_READ_COMPLETED, state_); | 125 DCHECK_EQ(State::WAITING_FOR_ON_READ_COMPLETED, state_); |
93 first_read_buffer_bytes_read_ = bytes_read; | 126 first_read_buffer_bytes_read_ = bytes_read; |
94 state_ = State::SENDING_BUFFER_TO_NEW_HANDLER; | 127 state_ = State::SENDING_BUFFER_TO_NEW_HANDLER; |
95 return DoLoop(defer); | 128 set_controller(std::move(controller)); |
129 DoLoop(); | |
96 } | 130 } |
97 | 131 |
98 void InterceptingResourceHandler::OnResponseCompleted( | 132 void InterceptingResourceHandler::OnResponseCompleted( |
99 const net::URLRequestStatus& status, | 133 const net::URLRequestStatus& status, |
100 bool* defer) { | 134 std::unique_ptr<ResourceController> controller) { |
101 if (state_ == State::PASS_THROUGH) { | 135 if (state_ == State::PASS_THROUGH) { |
102 LayeredResourceHandler::OnResponseCompleted(status, defer); | 136 LayeredResourceHandler::OnResponseCompleted(status, std::move(controller)); |
103 return; | 137 return; |
104 } | 138 } |
105 if (!new_handler_) { | 139 if (!new_handler_) { |
106 // Therer is only one ResourceHandler in this InterceptingResourceHandler. | 140 // Therer is only one ResourceHandler in this InterceptingResourceHandler. |
107 state_ = State::PASS_THROUGH; | 141 state_ = State::PASS_THROUGH; |
108 first_read_buffer_double_ = nullptr; | 142 first_read_buffer_double_ = nullptr; |
109 next_handler_->SetController(controller()); | 143 next_handler_->OnResponseCompleted(status, std::move(controller)); |
110 next_handler_->OnResponseCompleted(status, defer); | |
111 return; | 144 return; |
112 } | 145 } |
113 | 146 |
114 // There are two ResourceHandlers in this InterceptingResourceHandler. | 147 // There are two ResourceHandlers in this InterceptingResourceHandler. |
115 // |next_handler_| is the old handler and |new_handler_| is the new handler. | 148 // |next_handler_| is the old handler and |new_handler_| is the new handler. |
116 // As written in the class comment, this class assumes that the old handler | 149 // As written in the class comment, this class assumes that the old handler |
117 // will not set |*defer| in OnResponseCompleted. | 150 // will immediately call Resume() in OnResponseCompleted. |
118 next_handler_->SetController(controller()); | 151 bool was_resumed = false; |
119 next_handler_->OnResponseCompleted(status, defer); | 152 next_handler_->OnResponseCompleted( |
120 DCHECK(!*defer); | 153 status, base::MakeUnique<NullResourceController>(&was_resumed)); |
154 DCHECK(was_resumed); | |
121 | 155 |
122 state_ = State::PASS_THROUGH; | 156 state_ = State::PASS_THROUGH; |
123 first_read_buffer_double_ = nullptr; | 157 first_read_buffer_double_ = nullptr; |
124 new_handler_->SetController(controller()); | |
125 next_handler_ = std::move(new_handler_); | 158 next_handler_ = std::move(new_handler_); |
126 next_handler_->OnResponseCompleted(status, defer); | 159 next_handler_->OnResponseCompleted(status, std::move(controller)); |
127 } | 160 } |
128 | 161 |
129 void InterceptingResourceHandler::Cancel() { | 162 void InterceptingResourceHandler::ResumeInternal() { |
130 DCHECK_NE(State::PASS_THROUGH, state_); | 163 DCHECK(has_controller()); |
131 controller()->Cancel(); | |
132 } | |
133 | |
134 void InterceptingResourceHandler::CancelAndIgnore() { | |
135 DCHECK_NE(State::PASS_THROUGH, state_); | |
136 controller()->CancelAndIgnore(); | |
137 } | |
138 | |
139 void InterceptingResourceHandler::CancelWithError(int error_code) { | |
140 DCHECK_NE(State::PASS_THROUGH, state_); | |
141 controller()->CancelWithError(error_code); | |
142 } | |
143 | |
144 void InterceptingResourceHandler::Resume() { | |
145 DCHECK_NE(State::PASS_THROUGH, state_); | |
146 if (state_ == State::STARTING || | 164 if (state_ == State::STARTING || |
147 state_ == State::WAITING_FOR_ON_READ_COMPLETED) { | 165 state_ == State::WAITING_FOR_ON_READ_COMPLETED || |
166 state_ == State::PASS_THROUGH) { | |
148 // Uninteresting Resume: just delegate to the original resource controller. | 167 // Uninteresting Resume: just delegate to the original resource controller. |
149 controller()->Resume(); | 168 Resume(); |
150 return; | |
151 } | |
152 bool defer = false; | |
153 if (!DoLoop(&defer)) { | |
154 controller()->Cancel(); | |
155 return; | 169 return; |
156 } | 170 } |
157 | 171 |
158 if (!defer) | 172 DoLoop(); |
159 controller()->Resume(); | |
160 } | 173 } |
161 | 174 |
162 void InterceptingResourceHandler::UseNewHandler( | 175 void InterceptingResourceHandler::UseNewHandler( |
163 std::unique_ptr<ResourceHandler> new_handler, | 176 std::unique_ptr<ResourceHandler> new_handler, |
164 const std::string& payload_for_old_handler) { | 177 const std::string& payload_for_old_handler) { |
165 new_handler_ = std::move(new_handler); | 178 new_handler_ = std::move(new_handler); |
166 new_handler_->SetController(this); | |
167 payload_for_old_handler_ = payload_for_old_handler; | 179 payload_for_old_handler_ = payload_for_old_handler; |
168 } | 180 } |
169 | 181 |
170 bool InterceptingResourceHandler::DoLoop(bool* defer) { | 182 void InterceptingResourceHandler::DoLoop() { |
171 bool result = true; | 183 switch (state_) { |
172 do { | 184 case State::STARTING: |
173 switch (state_) { | 185 case State::WAITING_FOR_ON_READ_COMPLETED: |
174 case State::STARTING: | 186 case State::PASS_THROUGH: |
175 case State::WAITING_FOR_ON_READ_COMPLETED: | 187 NOTREACHED(); |
176 case State::PASS_THROUGH: | 188 break; |
177 NOTREACHED(); | 189 case State::SENDING_ON_WILL_START_TO_NEW_HANDLER: |
178 break; | 190 SendOnResponseStartedToNewHandler(); |
179 case State::SENDING_ON_WILL_START_TO_NEW_HANDLER: | 191 break; |
180 result = SendOnResponseStartedToNewHandler(defer); | 192 case State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER: |
181 break; | 193 if (first_read_buffer_double_) { |
182 case State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER: | 194 // OnWillRead has been called, so copying the data from |
183 if (first_read_buffer_double_) { | 195 // |first_read_buffer_double_| to |first_read_buffer_| will be needed |
184 // OnWillRead has been called, so copying the data from | 196 // when OnReadCompleted is called. |
185 // |first_read_buffer_double_| to |first_read_buffer_| will be needed | 197 state_ = State::WAITING_FOR_ON_READ_COMPLETED; |
186 // when OnReadCompleted is called. | 198 ResumeInternal(); |
187 state_ = State::WAITING_FOR_ON_READ_COMPLETED; | 199 } else { |
188 } else { | 200 // OnWillRead has not been called, so no special handling will be |
189 // OnWillRead has not been called, so no special handling will be | 201 // needed from now on. |
190 // needed from now on. | 202 state_ = State::PASS_THROUGH; |
191 state_ = State::PASS_THROUGH; | 203 ResumeInternal(); |
192 next_handler_->SetController(controller()); | 204 } |
193 } | 205 break; |
194 break; | 206 case State::SENDING_PAYLOAD_TO_OLD_HANDLER: |
195 case State::SENDING_PAYLOAD_TO_OLD_HANDLER: | 207 SendPayloadToOldHandler(); |
196 result = SendPayloadToOldHandler(defer); | 208 break; |
197 break; | 209 case State::SENDING_BUFFER_TO_NEW_HANDLER: |
198 case State::SENDING_BUFFER_TO_NEW_HANDLER: | 210 SendFirstReadBufferToNewHandler(); |
199 result = SendFirstReadBufferToNewHandler(defer); | 211 break; |
200 break; | 212 } |
201 } | |
202 } while (result && !*defer && | |
203 state_ != State::WAITING_FOR_ON_READ_COMPLETED && | |
204 state_ != State::PASS_THROUGH); | |
205 return result; | |
206 } | 213 } |
207 | 214 |
208 bool InterceptingResourceHandler::SendPayloadToOldHandler(bool* defer) { | 215 void InterceptingResourceHandler::SendPayloadToOldHandler() { |
209 DCHECK_EQ(State::SENDING_PAYLOAD_TO_OLD_HANDLER, state_); | 216 DCHECK_EQ(State::SENDING_PAYLOAD_TO_OLD_HANDLER, state_); |
210 while (payload_bytes_written_ < payload_for_old_handler_.size()) { | 217 if (payload_bytes_written_ == payload_for_old_handler_.size()) { |
211 scoped_refptr<net::IOBuffer> buffer; | 218 net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0); |
212 int size = 0; | 219 if (payload_for_old_handler_.empty()) { |
213 if (first_read_buffer_) { | 220 // If there is no payload, just finalize the request on the old handler. |
214 // |first_read_buffer_| is a buffer gotten from |next_handler_| via | 221 status = net::URLRequestStatus::FromError(net::ERR_ABORTED); |
215 // OnWillRead. Use the buffer. | 222 } |
216 buffer = first_read_buffer_; | 223 bool was_resumed = false; |
217 size = first_read_buffer_size_; | 224 next_handler_->OnResponseCompleted( |
225 status, base::MakeUnique<NullResourceController>(&was_resumed)); | |
226 DCHECK(was_resumed); | |
218 | 227 |
219 first_read_buffer_ = nullptr; | 228 next_handler_ = std::move(new_handler_); |
220 first_read_buffer_size_ = 0; | 229 state_ = State::SENDING_ON_WILL_START_TO_NEW_HANDLER; |
221 } else { | 230 next_handler_->OnWillStart(request()->url(), |
222 if (!next_handler_->OnWillRead(&buffer, &size, -1)) | 231 base::MakeUnique<Controller>(this)); |
223 return false; | 232 return; |
224 } | |
225 | |
226 size = std::min(size, static_cast<int>(payload_for_old_handler_.size() - | |
227 payload_bytes_written_)); | |
228 memcpy(buffer->data(), | |
229 payload_for_old_handler_.data() + payload_bytes_written_, size); | |
230 if (!next_handler_->OnReadCompleted(size, defer)) | |
231 return false; | |
232 payload_bytes_written_ += size; | |
233 if (*defer) | |
234 return true; | |
235 } | 233 } |
236 | 234 |
237 net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0); | 235 scoped_refptr<net::IOBuffer> buffer; |
238 if (payload_for_old_handler_.empty()) { | 236 int size = 0; |
239 // If there is no payload, just finalize the request on the old handler. | 237 if (first_read_buffer_) { |
240 status = net::URLRequestStatus::FromError(net::ERR_ABORTED); | 238 // |first_read_buffer_| is a buffer gotten from |next_handler_| via |
239 // OnWillRead. Use the buffer. | |
240 buffer = first_read_buffer_; | |
241 size = first_read_buffer_size_; | |
242 | |
243 first_read_buffer_ = nullptr; | |
244 first_read_buffer_size_ = 0; | |
245 } else { | |
246 if (!next_handler_->OnWillRead(&buffer, &size, -1)) { | |
247 Cancel(); | |
248 return; | |
249 } | |
241 } | 250 } |
242 next_handler_->OnResponseCompleted(status, defer); | |
243 DCHECK(!*defer); | |
244 | 251 |
245 next_handler_ = std::move(new_handler_); | 252 size = std::min(size, static_cast<int>(payload_for_old_handler_.size() - |
246 state_ = State::SENDING_ON_WILL_START_TO_NEW_HANDLER; | 253 payload_bytes_written_)); |
247 return next_handler_->OnWillStart(request()->url(), defer); | 254 memcpy(buffer->data(), |
255 payload_for_old_handler_.data() + payload_bytes_written_, size); | |
256 payload_bytes_written_ += size; | |
257 next_handler_->OnReadCompleted(size, base::MakeUnique<Controller>(this)); | |
248 } | 258 } |
249 | 259 |
250 bool InterceptingResourceHandler::SendOnResponseStartedToNewHandler( | 260 void InterceptingResourceHandler::SendOnResponseStartedToNewHandler() { |
251 bool* defer) { | |
252 state_ = State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER; | 261 state_ = State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER; |
253 return next_handler_->OnResponseStarted(response_.get(), defer); | 262 next_handler_->OnResponseStarted(response_.get(), |
263 base::MakeUnique<Controller>(this)); | |
254 } | 264 } |
255 | 265 |
256 bool InterceptingResourceHandler::SendFirstReadBufferToNewHandler(bool* defer) { | 266 void InterceptingResourceHandler::SendFirstReadBufferToNewHandler() { |
257 DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER); | 267 DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER); |
258 | 268 |
259 while (first_read_buffer_bytes_written_ < first_read_buffer_bytes_read_) { | 269 if (first_read_buffer_bytes_written_ == first_read_buffer_bytes_read_) { |
260 scoped_refptr<net::IOBuffer> buf; | 270 state_ = State::PASS_THROUGH; |
261 int size = 0; | 271 first_read_buffer_double_ = nullptr; |
262 if (!next_handler_->OnWillRead(&buf, &size, -1)) | 272 ResumeInternal(); |
263 return false; | 273 return; |
264 size = std::min(size, static_cast<int>(first_read_buffer_bytes_read_ - | |
265 first_read_buffer_bytes_written_)); | |
266 memcpy(buf->data(), | |
267 first_read_buffer_double_->data() + first_read_buffer_bytes_written_, | |
268 size); | |
269 if (!next_handler_->OnReadCompleted(size, defer)) | |
270 return false; | |
271 first_read_buffer_bytes_written_ += size; | |
272 if (*defer) | |
273 return true; | |
274 } | 274 } |
275 | 275 |
276 state_ = State::PASS_THROUGH; | 276 scoped_refptr<net::IOBuffer> buf; |
277 first_read_buffer_double_ = nullptr; | 277 int size = 0; |
278 next_handler_->SetController(controller()); | 278 if (!next_handler_->OnWillRead(&buf, &size, -1)) { |
279 return true; | 279 Cancel(); |
280 return; | |
281 } | |
282 size = std::min(size, static_cast<int>(first_read_buffer_bytes_read_ - | |
283 first_read_buffer_bytes_written_)); | |
284 memcpy(buf->data(), | |
285 first_read_buffer_double_->data() + first_read_buffer_bytes_written_, | |
286 size); | |
287 first_read_buffer_bytes_written_ += size; | |
288 next_handler_->OnReadCompleted(size, base::MakeUnique<Controller>(this)); | |
280 } | 289 } |
281 | 290 |
282 } // namespace content | 291 } // namespace content |
OLD | NEW |