Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(800)

Side by Side Diff: content/browser/loader/intercepting_resource_handler.cc

Issue 2743723003: Add buffering to MimeSniffingResourceHandler.
Patch Set: Remove unused 'first_call' variable. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/location.h" 8 #include "base/location.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/ptr_util.h" 10 #include "base/memory/ptr_util.h"
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 HoldController(std::move(controller)); 91 HoldController(std::move(controller));
92 state_ = State::SWAPPING_HANDLERS; 92 state_ = State::SWAPPING_HANDLERS;
93 93
94 DoLoop(); 94 DoLoop();
95 } 95 }
96 96
97 void InterceptingResourceHandler::OnWillRead( 97 void InterceptingResourceHandler::OnWillRead(
98 scoped_refptr<net::IOBuffer>* buf, 98 scoped_refptr<net::IOBuffer>* buf,
99 int* buf_size, 99 int* buf_size,
100 std::unique_ptr<ResourceController> controller) { 100 std::unique_ptr<ResourceController> controller) {
101 if (state_ == State::PASS_THROUGH) { 101 DCHECK_EQ(state_, State::PASS_THROUGH);
102 next_handler_->OnWillRead(buf, buf_size, std::move(controller)); 102 return next_handler_->OnWillRead(buf, buf_size, std::move(controller));
103 return;
104 }
105
106 DCHECK_EQ(State::STARTING, state_);
107 DCHECK(!first_read_buffer_);
108 DCHECK_EQ(0, first_read_buffer_size_);
109 DCHECK(!parent_read_buffer_);
110 DCHECK(!parent_read_buffer_size_);
111
112 parent_read_buffer_ = buf;
113 parent_read_buffer_size_ = buf_size;
114
115 state_ = State::SENDING_ON_WILL_READ_TO_OLD_HANDLER;
116 HoldController(std::move(controller));
117 DoLoop();
118 } 103 }
119 104
120 void InterceptingResourceHandler::OnReadCompleted( 105 void InterceptingResourceHandler::OnReadCompleted(
121 int bytes_read, 106 int bytes_read,
122 std::unique_ptr<ResourceController> controller) { 107 std::unique_ptr<ResourceController> controller) {
123 DCHECK(!has_controller()); 108 DCHECK(!has_controller());
109 DCHECK_EQ(state_, State::PASS_THROUGH);
110 DCHECK_GE(bytes_read, 0);
124 111
125 DCHECK_GE(bytes_read, 0); 112 next_handler_->OnReadCompleted(bytes_read, std::move(controller));
126 if (state_ == State::PASS_THROUGH) {
127 if (first_read_buffer_double_) {
128 // |first_read_buffer_double_| was allocated and the user wrote data to
129 // the buffer, but switching has not been done after all.
130 memcpy(first_read_buffer_->data(), first_read_buffer_double_->data(),
131 bytes_read);
132 first_read_buffer_ = nullptr;
133 first_read_buffer_double_ = nullptr;
134 }
135 next_handler_->OnReadCompleted(bytes_read, std::move(controller));
136 return;
137 }
138
139 DCHECK_EQ(State::WAITING_FOR_ON_READ_COMPLETED, state_);
140 first_read_buffer_bytes_read_ = bytes_read;
141 state_ = State::SENDING_BUFFER_TO_NEW_HANDLER;
142 HoldController(std::move(controller));
143 DoLoop();
144 } 113 }
145 114
146 void InterceptingResourceHandler::OnResponseCompleted( 115 void InterceptingResourceHandler::OnResponseCompleted(
147 const net::URLRequestStatus& status, 116 const net::URLRequestStatus& status,
148 std::unique_ptr<ResourceController> controller) { 117 std::unique_ptr<ResourceController> controller) {
118 if (!new_handler_)
119 state_ = State::PASS_THROUGH;
120
149 if (state_ == State::PASS_THROUGH) { 121 if (state_ == State::PASS_THROUGH) {
150 LayeredResourceHandler::OnResponseCompleted(status, std::move(controller));
151 return;
152 }
153 if (!new_handler_) {
154 // Therer is only one ResourceHandler in this InterceptingResourceHandler.
155 state_ = State::PASS_THROUGH;
156 first_read_buffer_double_ = nullptr;
157 next_handler_->OnResponseCompleted(status, std::move(controller)); 122 next_handler_->OnResponseCompleted(status, std::move(controller));
158 return; 123 return;
159 } 124 }
160 125
161 // There are two ResourceHandlers in this InterceptingResourceHandler. 126 // There are two ResourceHandlers in this InterceptingResourceHandler.
162 // |next_handler_| is the old handler and |new_handler_| is the new handler. 127 // |next_handler_| is the old handler and |new_handler_| is the new handler.
163 // As written in the class comment, this class assumes that the old handler 128 // As written in the class comment, this class assumes that the old handler
164 // will immediately call Resume() in OnResponseCompleted. 129 // will immediately call Resume() in OnResponseCompleted.
165 bool was_resumed = false; 130 bool was_resumed = false;
166 // TODO(mmenke): Get rid of NullResourceController and do something more 131 // TODO(mmenke): Get rid of NullResourceController and do something more
167 // reasonable. 132 // reasonable.
168 next_handler_->OnResponseCompleted( 133 next_handler_->OnResponseCompleted(
169 status, base::MakeUnique<NullResourceController>(&was_resumed)); 134 status, base::MakeUnique<NullResourceController>(&was_resumed));
170 DCHECK(was_resumed); 135 DCHECK(was_resumed);
171 136
172 state_ = State::PASS_THROUGH; 137 state_ = State::PASS_THROUGH;
173 first_read_buffer_double_ = nullptr;
174 next_handler_ = std::move(new_handler_); 138 next_handler_ = std::move(new_handler_);
175 next_handler_->OnResponseCompleted(status, std::move(controller)); 139 next_handler_->OnResponseCompleted(status, std::move(controller));
176 } 140 }
177 141
178 void InterceptingResourceHandler::UseNewHandler( 142 void InterceptingResourceHandler::UseNewHandler(
179 std::unique_ptr<ResourceHandler> new_handler, 143 std::unique_ptr<ResourceHandler> new_handler,
180 const std::string& payload_for_old_handler) { 144 const std::string& payload_for_old_handler) {
181 new_handler_ = std::move(new_handler); 145 new_handler_ = std::move(new_handler);
182 new_handler_->SetDelegate(delegate()); 146 new_handler_->SetDelegate(delegate());
183 payload_for_old_handler_ = payload_for_old_handler; 147 payload_for_old_handler_ = payload_for_old_handler;
184 } 148 }
185 149
186 void InterceptingResourceHandler::DoLoop() { 150 void InterceptingResourceHandler::DoLoop() {
187 DCHECK(!in_do_loop_); 151 DCHECK(!in_do_loop_);
188 DCHECK(!advance_to_next_state_); 152 DCHECK(!advance_to_next_state_);
189 153
190 base::AutoReset<bool> auto_in_do_loop(&in_do_loop_, true); 154 base::AutoReset<bool> auto_in_do_loop(&in_do_loop_, true);
191 advance_to_next_state_ = true; 155 advance_to_next_state_ = true;
192 156
193 while (advance_to_next_state_) { 157 while (advance_to_next_state_) {
194 advance_to_next_state_ = false; 158 advance_to_next_state_ = false;
195 159
196 switch (state_) { 160 switch (state_) {
197 case State::STARTING: 161 case State::STARTING:
198 case State::WAITING_FOR_ON_READ_COMPLETED:
199 case State::PASS_THROUGH: 162 case State::PASS_THROUGH:
200 NOTREACHED(); 163 NOTREACHED();
201 break; 164 break;
202 case State::SENDING_ON_WILL_READ_TO_OLD_HANDLER:
203 SendOnWillReadToOldHandler();
204 break;
205 case State::WAITING_FOR_OLD_HANDLERS_BUFFER:
206 OnBufferReceived();
207 break;
208 case State::SENDING_ON_WILL_START_TO_NEW_HANDLER: 165 case State::SENDING_ON_WILL_START_TO_NEW_HANDLER:
209 SendOnResponseStartedToNewHandler(); 166 SendOnResponseStartedToNewHandler();
210 break; 167 break;
211 case State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER:
212 if (first_read_buffer_double_) {
213 // OnWillRead has been called, so copying the data from
214 // |first_read_buffer_double_| to |first_read_buffer_| will be needed
215 // when OnReadCompleted is called.
216 state_ = State::WAITING_FOR_ON_READ_COMPLETED;
217 } else {
218 // OnWillRead has not been called, so no special handling will be
219 // needed from now on.
220 state_ = State::PASS_THROUGH;
221 }
222 ResumeInternal();
223 break;
224 case State::SWAPPING_HANDLERS: 168 case State::SWAPPING_HANDLERS:
225 SendOnResponseStartedToOldHandler(); 169 SendOnResponseStartedToOldHandler();
226 break; 170 break;
227 case State::SENDING_PAYLOAD_TO_OLD_HANDLER: 171 case State::SENDING_PAYLOAD_TO_OLD_HANDLER:
228 SendPayloadToOldHandler(); 172 SendPayloadToOldHandler();
229 break; 173 break;
230 case State::RECEIVING_BUFFER_FROM_OLD_HANDLER: 174 case State::RECEIVING_BUFFER_FROM_OLD_HANDLER:
231 ReceivedBufferFromOldHandler(); 175 ReceivedBufferFromOldHandler();
232 break; 176 break;
233 case State::SENDING_BUFFER_TO_NEW_HANDLER:
234 SendFirstReadBufferToNewHandler();
235 break;
236 case State::SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER:
237 ReceivedBufferFromNewHandler();
238 break;
239 } 177 }
240 } 178 }
241 } 179 }
242 180
243 void InterceptingResourceHandler::ResumeInternal() { 181 void InterceptingResourceHandler::ResumeInternal() {
244 DCHECK(has_controller()); 182 DCHECK(has_controller());
245 if (state_ == State::STARTING || 183 if (state_ == State::STARTING ||
246 state_ == State::WAITING_FOR_ON_READ_COMPLETED ||
247 state_ == State::PASS_THROUGH) { 184 state_ == State::PASS_THROUGH) {
248 // Uninteresting Resume: just delegate to the original resource controller. 185 // Uninteresting Resume: just delegate to the original resource controller.
249 Resume(); 186 Resume();
250 return; 187 return;
251 } 188 }
252 189
253 // If called recusively from a DoLoop, advance state when returning to the 190 // If called recusively from a DoLoop, advance state when returning to the
254 // loop. 191 // loop.
255 if (in_do_loop_) { 192 if (in_do_loop_) {
256 DCHECK(!advance_to_next_state_); 193 DCHECK(!advance_to_next_state_);
257 advance_to_next_state_ = true; 194 advance_to_next_state_ = true;
258 return; 195 return;
259 } 196 }
260 197
261 // Can't call DoLoop synchronously, as it may call into |next_handler_| 198 // Can't call DoLoop synchronously, as it may call into |next_handler_|
262 // synchronously, which is what called Resume(). 199 // synchronously, which is what called Resume().
263 base::ThreadTaskRunnerHandle::Get()->PostTask( 200 base::ThreadTaskRunnerHandle::Get()->PostTask(
264 FROM_HERE, base::Bind(&InterceptingResourceHandler::DoLoop, 201 FROM_HERE, base::Bind(&InterceptingResourceHandler::DoLoop,
265 weak_ptr_factory_.GetWeakPtr())); 202 weak_ptr_factory_.GetWeakPtr()));
266 } 203 }
267 204
268 void InterceptingResourceHandler::SendOnWillReadToOldHandler() {
269 DCHECK_EQ(State::SENDING_ON_WILL_READ_TO_OLD_HANDLER, state_);
270
271 state_ = State::WAITING_FOR_OLD_HANDLERS_BUFFER;
272 next_handler_->OnWillRead(&first_read_buffer_, &first_read_buffer_size_,
273 base::MakeUnique<Controller>(this));
274 }
275
276 void InterceptingResourceHandler::OnBufferReceived() {
277 DCHECK_EQ(State::WAITING_FOR_OLD_HANDLERS_BUFFER, state_);
278
279 // TODO(mmenke): If this method is just going to allocate a double buffer
280 // anyways, can the call to the old handler's OnWillRead be removed? That
281 // would mean handling replaying data in the case that |next_handler_|'s
282 // buffer is smaller than the double buffer, but SendPayloadToOldHandler
283 // already handles that case, anyways, so could share that code with the
284 // no-swap path as well. Or better, just have MimeSniffingResourceHandler
285 // create and manage the buffer itself.
286 first_read_buffer_double_ =
287 new net::IOBuffer(static_cast<size_t>(first_read_buffer_size_));
288 *parent_read_buffer_ = first_read_buffer_double_;
289 *parent_read_buffer_size_ = first_read_buffer_size_;
290
291 parent_read_buffer_ = nullptr;
292 parent_read_buffer_size_ = nullptr;
293
294 state_ = State::STARTING;
295 Resume();
296 }
297
298 void InterceptingResourceHandler::SendOnResponseStartedToOldHandler() { 205 void InterceptingResourceHandler::SendOnResponseStartedToOldHandler() {
299 state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER; 206 state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER;
300 next_handler_->OnResponseStarted(response_.get(), 207 next_handler_->OnResponseStarted(response_.get(),
301 base::MakeUnique<Controller>(this)); 208 base::MakeUnique<Controller>(this));
302 } 209 }
303 210
304 void InterceptingResourceHandler::SendPayloadToOldHandler() { 211 void InterceptingResourceHandler::SendPayloadToOldHandler() {
305 DCHECK_EQ(State::SENDING_PAYLOAD_TO_OLD_HANDLER, state_); 212 DCHECK_EQ(State::SENDING_PAYLOAD_TO_OLD_HANDLER, state_);
306 DCHECK(has_controller()); 213 DCHECK(has_controller());
307 214
308 if (static_cast<size_t>(payload_bytes_written_) == 215 if (static_cast<size_t>(payload_bytes_written_) ==
309 payload_for_old_handler_.size()) { 216 payload_for_old_handler_.size()) {
310 net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0); 217 net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
311 if (payload_for_old_handler_.empty()) { 218 if (payload_for_old_handler_.empty()) {
312 // If there is no payload, just finalize the request on the old handler. 219 // If there is no payload, just finalize the request on the old handler.
313 status = net::URLRequestStatus::FromError(net::ERR_ABORTED); 220 status = net::URLRequestStatus::FromError(net::ERR_ABORTED);
314 } 221 }
315 bool was_resumed = false; 222 bool was_resumed = false;
316 // TODO(mmenke): Get rid of NullResourceController and do something more 223 // TODO(mmenke): Get rid of NullResourceController and do something more
317 // reasonable. 224 // reasonable.
318 next_handler_->OnResponseCompleted( 225 next_handler_->OnResponseCompleted(
319 status, base::MakeUnique<NullResourceController>(&was_resumed)); 226 status, base::MakeUnique<NullResourceController>(&was_resumed));
320 DCHECK(was_resumed); 227 DCHECK(was_resumed);
321 228
322 next_handler_ = std::move(new_handler_); 229 next_handler_ = std::move(new_handler_);
323 state_ = State::SENDING_ON_WILL_START_TO_NEW_HANDLER; 230 state_ = State::SENDING_ON_WILL_START_TO_NEW_HANDLER;
231
232 // Note that this call may be a lie--the new handler will often have been
233 // substituted in after the request has actually started, so the new
234 // handler will not have the chance to cancel the request before it starts.
324 next_handler_->OnWillStart(request()->url(), 235 next_handler_->OnWillStart(request()->url(),
325 base::MakeUnique<Controller>(this)); 236 base::MakeUnique<Controller>(this));
326 return; 237 return;
327 } 238 }
328 239
329 state_ = State::RECEIVING_BUFFER_FROM_OLD_HANDLER; 240 state_ = State::RECEIVING_BUFFER_FROM_OLD_HANDLER;
330 241
331 scoped_refptr<net::IOBuffer> buffer; 242 DCHECK_EQ(read_buffer_size_, 0);
332 // If |first_read_buffer_| is non-NULL, it was already received from 243 next_handler_->OnWillRead(&read_buffer_, &read_buffer_size_,
333 // |next_handler_| via OnWillRead. Can just use the buffer.
334 if (first_read_buffer_) {
335 DCHECK_GT(first_read_buffer_size_, 0);
336
337 ResumeInternal();
338 return;
339 }
340
341 DCHECK(!first_read_buffer_size_);
342 next_handler_->OnWillRead(&first_read_buffer_, &first_read_buffer_size_,
343 base::MakeUnique<Controller>(this)); 244 base::MakeUnique<Controller>(this));
344 } 245 }
345 246
346 void InterceptingResourceHandler::ReceivedBufferFromOldHandler() { 247 void InterceptingResourceHandler::ReceivedBufferFromOldHandler() {
347 DCHECK_EQ(State::RECEIVING_BUFFER_FROM_OLD_HANDLER, state_); 248 DCHECK_EQ(State::RECEIVING_BUFFER_FROM_OLD_HANDLER, state_);
348 DCHECK(first_read_buffer_); 249 DCHECK(read_buffer_);
349 DCHECK_GT(first_read_buffer_size_, 0); 250 DCHECK_GT(read_buffer_size_, 0);
350 251
351 int bytes_to_copy = 252 int bytes_to_copy = std::min(
352 std::min(first_read_buffer_size_, 253 read_buffer_size_, static_cast<int>(payload_for_old_handler_.size() -
353 static_cast<int>(payload_for_old_handler_.size() - 254 payload_bytes_written_));
354 payload_bytes_written_)); 255 memcpy(read_buffer_->data(),
355 memcpy(first_read_buffer_->data(),
356 payload_for_old_handler_.data() + payload_bytes_written_, 256 payload_for_old_handler_.data() + payload_bytes_written_,
357 bytes_to_copy); 257 bytes_to_copy);
358 payload_bytes_written_ += bytes_to_copy; 258 payload_bytes_written_ += bytes_to_copy;
359 259
360 first_read_buffer_ = nullptr; 260 read_buffer_ = nullptr;
361 first_read_buffer_size_ = 0; 261 read_buffer_size_ = 0;
362 262
363 state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER; 263 state_ = State::SENDING_PAYLOAD_TO_OLD_HANDLER;
364 next_handler_->OnReadCompleted(bytes_to_copy, 264 next_handler_->OnReadCompleted(bytes_to_copy,
365 base::MakeUnique<Controller>(this)); 265 base::MakeUnique<Controller>(this));
366 } 266 }
367 267
368 void InterceptingResourceHandler::SendOnResponseStartedToNewHandler() { 268 void InterceptingResourceHandler::SendOnResponseStartedToNewHandler() {
369 state_ = State::SENDING_ON_RESPONSE_STARTED_TO_NEW_HANDLER; 269 state_ = State::PASS_THROUGH;
370 next_handler_->OnResponseStarted(response_.get(), 270 next_handler_->OnResponseStarted(response_.get(),
371 base::MakeUnique<Controller>(this)); 271 base::MakeUnique<Controller>(this));
372 } 272 }
373 273
374 void InterceptingResourceHandler::SendFirstReadBufferToNewHandler() {
375 DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER);
376 DCHECK(!new_handler_read_buffer_);
377 DCHECK(!new_handler_read_buffer_size_);
378
379 if (first_read_buffer_bytes_written_ == first_read_buffer_bytes_read_) {
380 state_ = State::PASS_THROUGH;
381 first_read_buffer_double_ = nullptr;
382 ResumeInternal();
383 return;
384 }
385
386 state_ = State::SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER;
387 next_handler_->OnWillRead(&new_handler_read_buffer_,
388 &new_handler_read_buffer_size_,
389 base::MakeUnique<Controller>(this));
390 }
391
392 void InterceptingResourceHandler::ReceivedBufferFromNewHandler() {
393 DCHECK_EQ(state_, State::SENDING_BUFFER_TO_NEW_HANDLER_WAITING_FOR_BUFFER);
394 DCHECK(new_handler_read_buffer_);
395 DCHECK(new_handler_read_buffer_size_);
396
397 int bytes_to_copy =
398 std::min(new_handler_read_buffer_size_,
399 static_cast<int>(first_read_buffer_bytes_read_ -
400 first_read_buffer_bytes_written_));
401 memcpy(new_handler_read_buffer_->data(),
402 first_read_buffer_double_->data() + first_read_buffer_bytes_written_,
403 bytes_to_copy);
404 first_read_buffer_bytes_written_ += bytes_to_copy;
405
406 new_handler_read_buffer_ = nullptr;
407 new_handler_read_buffer_size_ = 0;
408
409 state_ = State::SENDING_BUFFER_TO_NEW_HANDLER;
410 next_handler_->OnReadCompleted(bytes_to_copy,
411 base::MakeUnique<Controller>(this));
412 }
413
414 } // namespace content 274 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698