// Copyright (c) 2012 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. #include "content/browser/renderer_host/throttling_resource_handler.h" #include "content/browser/renderer_host/resource_dispatcher_host_impl.h" #include "content/public/browser/resource_throttle.h" #include "content/public/common/resource_response.h" namespace content { ThrottlingResourceHandler::ThrottlingResourceHandler( ResourceDispatcherHostImpl* host, ResourceHandler* next_handler, int child_id, int request_id, ScopedVector throttles) : LayeredResourceHandler(next_handler), deferred_stage_(DEFERRED_NONE), host_(host), child_id_(child_id), request_id_(request_id), throttles_(throttles.Pass()), index_(0) { for (size_t i = 0; i < throttles_.size(); ++i) throttles_[i]->set_controller(this); } bool ThrottlingResourceHandler::OnRequestRedirected(int request_id, const GURL& new_url, ResourceResponse* response, bool* defer) { DCHECK_EQ(request_id_, request_id); *defer = false; while (index_ < throttles_.size()) { throttles_[index_]->WillRedirectRequest(new_url, defer); index_++; if (*defer) { deferred_stage_ = DEFERRED_REDIRECT; deferred_url_ = new_url; deferred_response_ = response; return true; // Do not cancel. } } index_ = 0; // Reset for next time. return next_handler_->OnRequestRedirected(request_id, new_url, response, defer); } bool ThrottlingResourceHandler::OnWillStart(int request_id, const GURL& url, bool* defer) { DCHECK_EQ(request_id_, request_id); *defer = false; while (index_ < throttles_.size()) { throttles_[index_]->WillStartRequest(defer); index_++; if (*defer) { deferred_stage_ = DEFERRED_START; deferred_url_ = url; return true; // Do not cancel. } } index_ = 0; // Reset for next time. return next_handler_->OnWillStart(request_id, url, defer); } bool ThrottlingResourceHandler::OnResponseStarted( int request_id, content::ResourceResponse* response) { DCHECK_EQ(request_id_, request_id); while (index_ < throttles_.size()) { bool defer = false; throttles_[index_]->WillProcessResponse(&defer); index_++; if (defer) { host_->PauseRequest(child_id_, request_id_, true); deferred_stage_ = DEFERRED_RESPONSE; deferred_response_ = response; return true; // Do not cancel. } } index_ = 0; // Reset for next time. return next_handler_->OnResponseStarted(request_id, response); } void ThrottlingResourceHandler::OnRequestClosed() { throttles_.reset(); next_handler_->OnRequestClosed(); } void ThrottlingResourceHandler::Cancel() { host_->CancelRequest(child_id_, request_id_, false); } void ThrottlingResourceHandler::Resume() { switch (deferred_stage_) { case DEFERRED_NONE: NOTREACHED(); break; case DEFERRED_START: ResumeStart(); break; case DEFERRED_REDIRECT: ResumeRedirect(); break; case DEFERRED_RESPONSE: ResumeResponse(); break; } deferred_stage_ = DEFERRED_NONE; } ThrottlingResourceHandler::~ThrottlingResourceHandler() { } void ThrottlingResourceHandler::ResumeStart() { GURL url = deferred_url_; deferred_url_ = GURL(); bool defer = false; if (!OnWillStart(request_id_, url, &defer)) { Cancel(); } else if (!defer) { host_->StartDeferredRequest(child_id_, request_id_); } } void ThrottlingResourceHandler::ResumeRedirect() { GURL new_url = deferred_url_; deferred_url_ = GURL(); scoped_refptr response; deferred_response_.swap(response); bool defer = false; if (!OnRequestRedirected(request_id_, new_url, response, &defer)) { Cancel(); } else if (!defer) { host_->FollowDeferredRedirect(child_id_, request_id_, false, GURL()); } } void ThrottlingResourceHandler::ResumeResponse() { scoped_refptr response; deferred_response_.swap(response); // OnResponseStarted will pause again if necessary. host_->PauseRequest(child_id_, request_id_, false); if (!OnResponseStarted(request_id_, response)) Cancel(); } } // namespace content