blob: 6cba3f4759c81e69d2b22e33158dc87937a21807 [file] [log] [blame]
[email protected]f85f0702010-01-30 09:31:011// Copyright (c) 2010 The Chromium Authors. All rights reserved.
[email protected]e3c404b2008-12-23 01:07:322// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/renderer_host/async_resource_handler.h"
6
[email protected]5203e6002009-07-29 03:42:007#include "base/logging.h"
[email protected]3ba7f372008-12-31 11:58:248#include "base/process.h"
[email protected]e09ba552009-02-05 03:26:299#include "base/shared_memory.h"
[email protected]40bd6582009-12-04 23:49:5110#include "chrome/browser/net/chrome_url_request_context.h"
[email protected]92b24c12009-12-10 20:04:3511#include "chrome/browser/renderer_host/global_request_id.h"
[email protected]40bd6582009-12-04 23:49:5112#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
[email protected]e09ba552009-02-05 03:26:2913#include "chrome/common/render_messages.h"
[email protected]9dea9e1f2009-01-29 00:30:4714#include "net/base/io_buffer.h"
[email protected]3ba7f372008-12-31 11:58:2415
[email protected]db2fb782009-10-23 17:39:5316namespace {
17
[email protected]5203e6002009-07-29 03:42:0018// When reading, we don't know if we are going to get EOF (0 bytes read), so
19// we typically have a buffer that we allocated but did not use. We keep
20// this buffer around for the next read as a small optimization.
[email protected]db2fb782009-10-23 17:39:5321SharedIOBuffer* g_spare_read_buffer = NULL;
22
23// The initial size of the shared memory buffer. (32 kilobytes).
[email protected]98c45032009-10-26 17:14:2724const int kInitialReadBufSize = 32768;
[email protected]db2fb782009-10-23 17:39:5325
26// The maximum size of the shared memory buffer. (512 kilobytes).
[email protected]98c45032009-10-26 17:14:2727const int kMaxReadBufSize = 524288;
[email protected]db2fb782009-10-23 17:39:5328
29} // namespace
[email protected]9dea9e1f2009-01-29 00:30:4730
31// Our version of IOBuffer that uses shared memory.
32class SharedIOBuffer : public net::IOBuffer {
33 public:
[email protected]4a3dab22009-11-11 17:36:5034 explicit SharedIOBuffer(int buffer_size)
[email protected]db2fb782009-10-23 17:39:5335 : net::IOBuffer(),
36 ok_(false),
[email protected]ad8db612009-11-20 23:08:3837 buffer_size_(buffer_size) {}
38
39 bool Init() {
40 if (shared_memory_.Create(std::wstring(), false, false, buffer_size_) &&
41 shared_memory_.Map(buffer_size_)) {
[email protected]9dea9e1f2009-01-29 00:30:4742 data_ = reinterpret_cast<char*>(shared_memory_.memory());
[email protected]ad8db612009-11-20 23:08:3843 // TODO(hawk): Remove after debugging bug 16371.
44 CHECK(data_);
45 ok_ = true;
[email protected]9dea9e1f2009-01-29 00:30:4746 }
[email protected]ad8db612009-11-20 23:08:3847 return ok_;
[email protected]9dea9e1f2009-01-29 00:30:4748 }
[email protected]9dea9e1f2009-01-29 00:30:4749
50 base::SharedMemory* shared_memory() { return &shared_memory_; }
51 bool ok() { return ok_; }
[email protected]db2fb782009-10-23 17:39:5352 int buffer_size() { return buffer_size_; }
[email protected]9dea9e1f2009-01-29 00:30:4753
54 private:
[email protected]422c0f12009-11-05 23:37:0555 ~SharedIOBuffer() {
56 // TODO(willchan): Remove after debugging bug 16371.
57 CHECK(g_spare_read_buffer != this);
58 data_ = NULL;
59 }
60
[email protected]9dea9e1f2009-01-29 00:30:4761 base::SharedMemory shared_memory_;
62 bool ok_;
[email protected]db2fb782009-10-23 17:39:5363 int buffer_size_;
[email protected]9dea9e1f2009-01-29 00:30:4764};
[email protected]e3c404b2008-12-23 01:07:3265
66AsyncResourceHandler::AsyncResourceHandler(
67 ResourceDispatcherHost::Receiver* receiver,
[email protected]4566f132009-03-12 01:55:1368 int process_id,
[email protected]e3c404b2008-12-23 01:07:3269 int routing_id,
[email protected]4566f132009-03-12 01:55:1370 base::ProcessHandle process_handle,
[email protected]e3c404b2008-12-23 01:07:3271 const GURL& url,
72 ResourceDispatcherHost* resource_dispatcher_host)
73 : receiver_(receiver),
[email protected]4566f132009-03-12 01:55:1374 process_id_(process_id),
[email protected]e3c404b2008-12-23 01:07:3275 routing_id_(routing_id),
[email protected]4566f132009-03-12 01:55:1376 process_handle_(process_handle),
[email protected]db2fb782009-10-23 17:39:5377 rdh_(resource_dispatcher_host),
[email protected]98c45032009-10-26 17:14:2778 next_buffer_size_(kInitialReadBufSize) {
[email protected]e3c404b2008-12-23 01:07:3279}
80
[email protected]84bbb2b52009-11-07 00:23:1481AsyncResourceHandler::~AsyncResourceHandler() {
82}
83
[email protected]e3c404b2008-12-23 01:07:3284bool AsyncResourceHandler::OnUploadProgress(int request_id,
85 uint64 position,
86 uint64 size) {
87 return receiver_->Send(new ViewMsg_Resource_UploadProgress(routing_id_,
88 request_id,
89 position, size));
90}
91
92bool AsyncResourceHandler::OnRequestRedirected(int request_id,
[email protected]6568a9e32009-07-30 18:01:3993 const GURL& new_url,
94 ResourceResponse* response,
95 bool* defer) {
96 *defer = true;
97 return receiver_->Send(new ViewMsg_Resource_ReceivedRedirect(
98 routing_id_, request_id, new_url, response->response_head));
[email protected]e3c404b2008-12-23 01:07:3299}
100
101bool AsyncResourceHandler::OnResponseStarted(int request_id,
102 ResourceResponse* response) {
[email protected]f85f0702010-01-30 09:31:01103 // For changes to the main frame, inform the renderer of the new URL's
104 // per-host settings before the request actually commits. This way the
105 // renderer will be able to set these precisely at the time the
106 // request commits, avoiding the possibility of e.g. zooming the old content
107 // or of having to layout the new content twice.
[email protected]40bd6582009-12-04 23:49:51108 URLRequest* request = rdh_->GetURLRequest(
[email protected]92b24c12009-12-10 20:04:35109 GlobalRequestID(process_id_, request_id));
[email protected]40bd6582009-12-04 23:49:51110 ResourceDispatcherHostRequestInfo* info = rdh_->InfoForRequest(request);
111 if (info->resource_type() == ResourceType::MAIN_FRAME) {
112 std::string host(request->url().host());
113 ChromeURLRequestContext* context =
114 static_cast<ChromeURLRequestContext*>(request->context());
115 if (!host.empty() && context) {
[email protected]f85f0702010-01-30 09:31:01116 receiver_->Send(new ViewMsg_SetContentSettingsForLoadingHost(
117 info->route_id(), host,
118 context->host_content_settings_map()->GetContentSettings(host)));
[email protected]40bd6582009-12-04 23:49:51119 receiver_->Send(new ViewMsg_SetZoomLevelForLoadingHost(info->route_id(),
120 host, context->host_zoom_map()->GetZoomLevel(host)));
[email protected]40bd6582009-12-04 23:49:51121 }
122 }
123
[email protected]e3c404b2008-12-23 01:07:32124 receiver_->Send(new ViewMsg_Resource_ReceivedResponse(
125 routing_id_, request_id, response->response_head));
126 return true;
127}
128
[email protected]9dea9e1f2009-01-29 00:30:47129bool AsyncResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
130 int* buf_size, int min_size) {
[email protected]e3c404b2008-12-23 01:07:32131 DCHECK(min_size == -1);
[email protected]db2fb782009-10-23 17:39:53132
[email protected]5203e6002009-07-29 03:42:00133 if (g_spare_read_buffer) {
[email protected]9dea9e1f2009-01-29 00:30:47134 DCHECK(!read_buffer_);
[email protected]5203e6002009-07-29 03:42:00135 read_buffer_.swap(&g_spare_read_buffer);
136 // TODO(willchan): Remove after debugging bug 16371.
137 CHECK(read_buffer_->data());
[email protected]db2fb782009-10-23 17:39:53138
139 *buf = read_buffer_.get();
[email protected]98c45032009-10-26 17:14:27140 *buf_size = read_buffer_->buffer_size();
[email protected]e3c404b2008-12-23 01:07:32141 } else {
[email protected]db2fb782009-10-23 17:39:53142 read_buffer_ = new SharedIOBuffer(next_buffer_size_);
[email protected]ad8db612009-11-20 23:08:38143 if (!read_buffer_->Init()) {
[email protected]db2fb782009-10-23 17:39:53144 DLOG(ERROR) << "Couldn't allocate shared io buffer";
[email protected]ad8db612009-11-20 23:08:38145 read_buffer_ = NULL;
[email protected]e3c404b2008-12-23 01:07:32146 return false;
[email protected]db2fb782009-10-23 17:39:53147 }
[email protected]5203e6002009-07-29 03:42:00148 // TODO(willchan): Remove after debugging bug 16371.
149 CHECK(read_buffer_->data());
[email protected]db2fb782009-10-23 17:39:53150 *buf = read_buffer_.get();
151 *buf_size = next_buffer_size_;
[email protected]e3c404b2008-12-23 01:07:32152 }
[email protected]db2fb782009-10-23 17:39:53153
[email protected]e3c404b2008-12-23 01:07:32154 return true;
155}
156
157bool AsyncResourceHandler::OnReadCompleted(int request_id, int* bytes_read) {
158 if (!*bytes_read)
159 return true;
160 DCHECK(read_buffer_.get());
161
[email protected]98c45032009-10-26 17:14:27162 if (read_buffer_->buffer_size() == *bytes_read) {
163 // The network layer has saturated our buffer. Next time, we should give it
164 // a bigger buffer for it to fill, to minimize the number of round trips we
165 // do with the renderer process.
166 next_buffer_size_ = std::min(next_buffer_size_ * 2, kMaxReadBufSize);
167 }
168
[email protected]4566f132009-03-12 01:55:13169 if (!rdh_->WillSendData(process_id_, request_id)) {
[email protected]e3c404b2008-12-23 01:07:32170 // We should not send this data now, we have too many pending requests.
171 return true;
172 }
173
174 base::SharedMemoryHandle handle;
[email protected]4566f132009-03-12 01:55:13175 if (!read_buffer_->shared_memory()->GiveToProcess(process_handle_, &handle)) {
[email protected]e3c404b2008-12-23 01:07:32176 // We wrongfully incremented the pending data count. Fake an ACK message
177 // to fix this. We can't move this call above the WillSendData because
178 // it's killing our read_buffer_, and we don't want that when we pause
179 // the request.
[email protected]dabe6072009-03-17 00:52:35180 rdh_->DataReceivedACK(process_id_, request_id);
[email protected]ed1f53e2009-02-11 01:32:58181 // We just unmapped the memory.
182 read_buffer_ = NULL;
[email protected]e3c404b2008-12-23 01:07:32183 return false;
184 }
[email protected]9dea9e1f2009-01-29 00:30:47185 // We just unmapped the memory.
186 read_buffer_ = NULL;
[email protected]e3c404b2008-12-23 01:07:32187
188 receiver_->Send(new ViewMsg_Resource_DataReceived(
189 routing_id_, request_id, handle, *bytes_read));
190
191 return true;
192}
193
[email protected]c4891b32009-03-08 07:41:31194bool AsyncResourceHandler::OnResponseCompleted(
195 int request_id,
196 const URLRequestStatus& status,
197 const std::string& security_info) {
[email protected]e3c404b2008-12-23 01:07:32198 receiver_->Send(new ViewMsg_Resource_RequestComplete(routing_id_,
[email protected]c4891b32009-03-08 07:41:31199 request_id,
200 status,
201 security_info));
[email protected]e3c404b2008-12-23 01:07:32202
203 // If we still have a read buffer, then see about caching it for later...
[email protected]5203e6002009-07-29 03:42:00204 if (g_spare_read_buffer) {
[email protected]9dea9e1f2009-01-29 00:30:47205 read_buffer_ = NULL;
206 } else if (read_buffer_.get()) {
[email protected]31f49e52009-07-31 23:01:20207 // TODO(willchan): Remove after debugging bug 16371.
208 CHECK(read_buffer_->data());
[email protected]5203e6002009-07-29 03:42:00209 read_buffer_.swap(&g_spare_read_buffer);
[email protected]e3c404b2008-12-23 01:07:32210 }
211 return true;
212}
213
214// static
215void AsyncResourceHandler::GlobalCleanup() {
[email protected]5203e6002009-07-29 03:42:00216 if (g_spare_read_buffer) {
217 // Avoid the CHECK in SharedIOBuffer::~SharedIOBuffer().
218 SharedIOBuffer* tmp = g_spare_read_buffer;
219 g_spare_read_buffer = NULL;
220 tmp->Release();
[email protected]ed1f53e2009-02-11 01:32:58221 }
[email protected]e3c404b2008-12-23 01:07:32222}