blob: a3afb3fa7b6abacd66982cc1a51b7ef1fc9cb9b8 [file] [log] [blame]
[email protected]0a0b2542012-01-03 08:25:221// Copyright (c) 2012 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
[email protected]678c0362012-12-05 08:02:445#include "content/browser/loader/buffered_resource_handler.h"
[email protected]e3c404b2008-12-23 01:07:326
[email protected]dd9b5462009-09-25 17:22:237#include <vector>
8
[email protected]d33e7cc2011-09-23 01:43:569#include "base/bind.h"
[email protected]5203e6002009-07-29 03:42:0010#include "base/logging.h"
[email protected]835d7c82010-10-14 04:38:3811#include "base/metrics/histogram.h"
[email protected]348fbaac2013-06-11 06:31:5112#include "base/strings/string_util.h"
[email protected]254ed742011-08-16 18:45:2713#include "content/browser/download/download_resource_handler.h"
[email protected]14365e32012-01-24 01:12:2214#include "content/browser/download/download_stats.h"
[email protected]3b455502012-12-11 18:22:5815#include "content/browser/loader/certificate_resource_handler.h"
[email protected]678c0362012-12-05 08:02:4416#include "content/browser/loader/resource_dispatcher_host_impl.h"
17#include "content/browser/loader/resource_request_info_impl.h"
[email protected]e67385f2011-12-21 06:00:5618#include "content/browser/plugin_service_impl.h"
[email protected]87f3c082011-10-19 18:07:4419#include "content/public/browser/content_browser_client.h"
[email protected]530047e2013-07-12 17:02:2520#include "content/public/browser/download_item.h"
[email protected]29a5ffc82012-03-13 19:35:5821#include "content/public/browser/download_save_info.h"
[email protected]530047e2013-07-12 17:02:2522#include "content/public/browser/download_url_parameters.h"
[email protected]ce967862012-02-09 22:47:0523#include "content/public/browser/resource_context.h"
[email protected]1bd0ef12011-10-20 05:24:1724#include "content/public/browser/resource_dispatcher_host_delegate.h"
[email protected]2336ffe2011-11-24 01:23:3425#include "content/public/common/resource_response.h"
[email protected]d7bd3e52013-07-21 04:29:2026#include "content/public/common/webplugininfo.h"
[email protected]dd9b5462009-09-25 17:22:2327#include "net/base/io_buffer.h"
[email protected]9dea9e1f2009-01-29 00:30:4728#include "net/base/mime_sniffer.h"
[email protected]35fa6a22009-08-15 00:04:0129#include "net/base/mime_util.h"
[email protected]dd9b5462009-09-25 17:22:2330#include "net/base/net_errors.h"
[email protected]28ca9fb2012-01-28 14:50:2431#include "net/http/http_content_disposition.h"
[email protected]319d9e6f2009-02-18 19:47:2132#include "net/http/http_response_headers.h"
[email protected]e3c404b2008-12-23 01:07:3233
[email protected]d18720a2012-01-06 09:53:5534namespace content {
35
[email protected]306291392009-01-17 19:15:3636namespace {
37
38void RecordSnifferMetrics(bool sniffing_blocked,
39 bool we_would_like_to_sniff,
40 const std::string& mime_type) {
[email protected]de415552013-01-23 04:12:1741 static base::HistogramBase* nosniff_usage(NULL);
[email protected]81ce9f3b2011-04-05 04:48:5342 if (!nosniff_usage)
43 nosniff_usage = base::BooleanHistogram::FactoryGet(
[email protected]de415552013-01-23 04:12:1744 "nosniff.usage", base::HistogramBase::kUmaTargetedHistogramFlag);
[email protected]e8829a192009-12-06 00:09:3745 nosniff_usage->AddBoolean(sniffing_blocked);
[email protected]306291392009-01-17 19:15:3646
47 if (sniffing_blocked) {
[email protected]de415552013-01-23 04:12:1748 static base::HistogramBase* nosniff_otherwise(NULL);
[email protected]81ce9f3b2011-04-05 04:48:5349 if (!nosniff_otherwise)
50 nosniff_otherwise = base::BooleanHistogram::FactoryGet(
[email protected]de415552013-01-23 04:12:1751 "nosniff.otherwise", base::HistogramBase::kUmaTargetedHistogramFlag);
[email protected]e8829a192009-12-06 00:09:3752 nosniff_otherwise->AddBoolean(we_would_like_to_sniff);
[email protected]306291392009-01-17 19:15:3653
[email protected]de415552013-01-23 04:12:1754 static base::HistogramBase* nosniff_empty_mime_type(NULL);
[email protected]81ce9f3b2011-04-05 04:48:5355 if (!nosniff_empty_mime_type)
56 nosniff_empty_mime_type = base::BooleanHistogram::FactoryGet(
57 "nosniff.empty_mime_type",
[email protected]de415552013-01-23 04:12:1758 base::HistogramBase::kUmaTargetedHistogramFlag);
[email protected]e8829a192009-12-06 00:09:3759 nosniff_empty_mime_type->AddBoolean(mime_type.empty());
[email protected]306291392009-01-17 19:15:3660 }
61}
62
[email protected]926360f2012-06-29 04:45:0263// Used to write into an existing IOBuffer at a given offset.
64class DependentIOBuffer : public net::WrappedIOBuffer {
65 public:
66 DependentIOBuffer(net::IOBuffer* buf, int offset)
67 : net::WrappedIOBuffer(buf->data() + offset),
68 buf_(buf) {
69 }
70
71 private:
[email protected]c3e35892013-02-12 02:08:0172 virtual ~DependentIOBuffer() {}
[email protected]926360f2012-06-29 04:45:0273
74 scoped_refptr<net::IOBuffer> buf_;
75};
76
[email protected]306291392009-01-17 19:15:3677} // namespace
78
[email protected]ea114722012-03-12 01:11:2579BufferedResourceHandler::BufferedResourceHandler(
[email protected]d651cbc2012-05-31 21:33:0580 scoped_ptr<ResourceHandler> next_handler,
[email protected]ea114722012-03-12 01:11:2581 ResourceDispatcherHostImpl* host,
82 net::URLRequest* request)
[email protected]d651cbc2012-05-31 21:33:0583 : LayeredResourceHandler(next_handler.Pass()),
[email protected]926360f2012-06-29 04:45:0284 state_(STATE_STARTING),
[email protected]e3c404b2008-12-23 01:07:3285 host_(host),
86 request_(request),
[email protected]dd9b5462009-09-25 17:22:2387 read_buffer_size_(0),
[email protected]e3c404b2008-12-23 01:07:3288 bytes_read_(0),
[email protected]926360f2012-06-29 04:45:0289 must_download_(false),
[email protected]5c1d3e52012-08-01 05:14:2790 must_download_is_set_(false),
91 weak_ptr_factory_(this) {
[email protected]926360f2012-06-29 04:45:0292}
93
94BufferedResourceHandler::~BufferedResourceHandler() {
95}
96
97void BufferedResourceHandler::SetController(ResourceController* controller) {
98 ResourceHandler::SetController(controller);
99
100 // Downstream handlers see us as their ResourceController, which allows us to
101 // consume part or all of the resource response, and then later replay it to
102 // downstream handler.
103 DCHECK(next_handler_.get());
104 next_handler_->SetController(this);
[email protected]e3c404b2008-12-23 01:07:32105}
106
[email protected]2336ffe2011-11-24 01:23:34107bool BufferedResourceHandler::OnResponseStarted(
108 int request_id,
[email protected]22b305442012-05-21 18:02:59109 ResourceResponse* response,
110 bool* defer) {
[email protected]e3c404b2008-12-23 01:07:32111 response_ = response;
[email protected]22b305442012-05-21 18:02:59112
[email protected]926360f2012-06-29 04:45:02113 // TODO(darin): It is very odd to special-case 304 responses at this level.
114 // We do so only because the code always has, see r24977 and r29355. The
115 // fact that 204 is no longer special-cased this way suggests that 304 need
116 // not be special-cased either.
117 //
118 // The network stack only forwards 304 responses that were not received in
119 // response to a conditional request (i.e., If-Modified-Since). Other 304
120 // responses end up being translated to 200 or whatever the cached response
121 // code happens to be. It should be very rare to see a 304 at this level.
[email protected]22b305442012-05-21 18:02:59122
[email protected]fc72bb12013-06-02 21:13:46123 if (!(response_->head.headers.get() &&
[email protected]926360f2012-06-29 04:45:02124 response_->head.headers->response_code() == 304)) {
125 if (ShouldSniffContent()) {
126 state_ = STATE_BUFFERING;
127 return true;
128 }
129
130 if (response_->head.mime_type.empty()) {
131 // Ugg. The server told us not to sniff the content but didn't give us
132 // a mime type. What's a browser to do? Turns out, we're supposed to
133 // treat the response as "text/plain". This is the most secure option.
134 response_->head.mime_type.assign("text/plain");
135 }
[email protected]3ff679262012-10-12 23:40:05136
137 // Treat feed types as text/plain.
138 if (response_->head.mime_type == "application/rss+xml" ||
139 response_->head.mime_type == "application/atom+xml") {
140 response_->head.mime_type.assign("text/plain");
141 }
[email protected]22b305442012-05-21 18:02:59142 }
[email protected]926360f2012-06-29 04:45:02143
144 state_ = STATE_PROCESSING;
145 return ProcessResponse(defer);
[email protected]e3c404b2008-12-23 01:07:32146}
147
[email protected]e3c404b2008-12-23 01:07:32148// We'll let the original event handler provide a buffer, and reuse it for
149// subsequent reads until we're done buffering.
[email protected]9dea9e1f2009-01-29 00:30:47150bool BufferedResourceHandler::OnWillRead(int request_id, net::IOBuffer** buf,
151 int* buf_size, int min_size) {
[email protected]926360f2012-06-29 04:45:02152 if (state_ == STATE_STREAMING)
153 return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
154
155 DCHECK_EQ(-1, min_size);
156
[email protected]fc72bb12013-06-02 21:13:46157 if (read_buffer_.get()) {
[email protected]926360f2012-06-29 04:45:02158 CHECK_LT(bytes_read_, read_buffer_size_);
[email protected]fc72bb12013-06-02 21:13:46159 *buf = new DependentIOBuffer(read_buffer_.get(), bytes_read_);
[email protected]926360f2012-06-29 04:45:02160 *buf_size = read_buffer_size_ - bytes_read_;
161 } else {
162 if (!next_handler_->OnWillRead(request_id, buf, buf_size, min_size))
163 return false;
164
165 read_buffer_ = *buf;
166 read_buffer_size_ = *buf_size;
167 DCHECK_GE(read_buffer_size_, net::kMaxBytesToSniff * 2);
[email protected]e3c404b2008-12-23 01:07:32168 }
[email protected]67199052009-06-12 21:15:33169 return true;
[email protected]e3c404b2008-12-23 01:07:32170}
171
[email protected]926360f2012-06-29 04:45:02172bool BufferedResourceHandler::OnReadCompleted(int request_id, int bytes_read,
[email protected]22b305442012-05-21 18:02:59173 bool* defer) {
[email protected]926360f2012-06-29 04:45:02174 if (state_ == STATE_STREAMING)
175 return next_handler_->OnReadCompleted(request_id, bytes_read, defer);
[email protected]e3c404b2008-12-23 01:07:32176
[email protected]926360f2012-06-29 04:45:02177 DCHECK_EQ(state_, STATE_BUFFERING);
178 bytes_read_ += bytes_read;
[email protected]e3c404b2008-12-23 01:07:32179
[email protected]926360f2012-06-29 04:45:02180 if (!DetermineMimeType() && (bytes_read > 0))
181 return true; // Needs more data, so keep buffering.
182
183 state_ = STATE_PROCESSING;
184 return ProcessResponse(defer);
185}
186
187bool BufferedResourceHandler::OnResponseCompleted(
188 int request_id,
189 const net::URLRequestStatus& status,
190 const std::string& security_info) {
191 // Upon completion, act like a pass-through handler in case the downstream
192 // handler defers OnResponseCompleted.
193 state_ = STATE_STREAMING;
194
195 return next_handler_->OnResponseCompleted(request_id, status, security_info);
196}
197
198void BufferedResourceHandler::Resume() {
199 switch (state_) {
200 case STATE_BUFFERING:
201 case STATE_PROCESSING:
202 NOTREACHED();
203 break;
204 case STATE_REPLAYING:
[email protected]dd32b1272013-05-04 14:17:11205 base::MessageLoop::current()->PostTask(
[email protected]926360f2012-06-29 04:45:02206 FROM_HERE,
207 base::Bind(&BufferedResourceHandler::CallReplayReadCompleted,
[email protected]5c1d3e52012-08-01 05:14:27208 weak_ptr_factory_.GetWeakPtr()));
[email protected]926360f2012-06-29 04:45:02209 break;
210 case STATE_STARTING:
211 case STATE_STREAMING:
212 controller()->Resume();
213 break;
214 }
215}
216
217void BufferedResourceHandler::Cancel() {
218 controller()->Cancel();
219}
220
[email protected]2756a8e2012-09-07 18:24:29221void BufferedResourceHandler::CancelAndIgnore() {
222 controller()->CancelAndIgnore();
223}
224
[email protected]af3d4962012-10-19 10:57:26225void BufferedResourceHandler::CancelWithError(int error_code) {
226 controller()->CancelWithError(error_code);
227}
228
[email protected]926360f2012-06-29 04:45:02229bool BufferedResourceHandler::ProcessResponse(bool* defer) {
230 DCHECK_EQ(STATE_PROCESSING, state_);
231
232 // TODO(darin): Stop special-casing 304 responses.
[email protected]fc72bb12013-06-02 21:13:46233 if (!(response_->head.headers.get() &&
[email protected]926360f2012-06-29 04:45:02234 response_->head.headers->response_code() == 304)) {
235 if (!SelectNextHandler(defer))
[email protected]e3c404b2008-12-23 01:07:32236 return false;
[email protected]22b305442012-05-21 18:02:59237 if (*defer)
[email protected]98d6f152011-09-29 19:35:51238 return true;
[email protected]926360f2012-06-29 04:45:02239 }
240
241 state_ = STATE_REPLAYING;
242
243 int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID();
[email protected]fc72bb12013-06-02 21:13:46244 if (!next_handler_->OnResponseStarted(request_id, response_.get(), defer))
[email protected]926360f2012-06-29 04:45:02245 return false;
246
[email protected]fc72bb12013-06-02 21:13:46247 if (!read_buffer_.get()) {
[email protected]926360f2012-06-29 04:45:02248 state_ = STATE_STREAMING;
[email protected]35fa6a22009-08-15 00:04:01249 return true;
[email protected]e3c404b2008-12-23 01:07:32250 }
251
[email protected]926360f2012-06-29 04:45:02252 if (!*defer)
253 return ReplayReadCompleted(defer);
[email protected]5e5e0c82012-01-25 09:12:29254
[email protected]926360f2012-06-29 04:45:02255 return true;
[email protected]e3c404b2008-12-23 01:07:32256}
257
[email protected]926360f2012-06-29 04:45:02258bool BufferedResourceHandler::ShouldSniffContent() {
259 const std::string& mime_type = response_->head.mime_type;
[email protected]e3c404b2008-12-23 01:07:32260
261 std::string content_type_options;
262 request_->GetResponseHeaderByName("x-content-type-options",
263 &content_type_options);
[email protected]306291392009-01-17 19:15:36264
[email protected]926360f2012-06-29 04:45:02265 bool sniffing_blocked =
[email protected]423bd5b842009-01-23 17:30:50266 LowerCaseEqualsASCII(content_type_options, "nosniff");
[email protected]926360f2012-06-29 04:45:02267 bool we_would_like_to_sniff =
268 net::ShouldSniffMimeType(request_->url(), mime_type);
[email protected]306291392009-01-17 19:15:36269
270 RecordSnifferMetrics(sniffing_blocked, we_would_like_to_sniff, mime_type);
271
272 if (!sniffing_blocked && we_would_like_to_sniff) {
[email protected]e3c404b2008-12-23 01:07:32273 // We're going to look at the data before deciding what the content type
274 // is. That means we need to delay sending the ResponseStarted message
275 // over the IPC channel.
[email protected]238667042010-10-23 01:40:00276 VLOG(1) << "To buffer: " << request_->url().spec();
[email protected]e3c404b2008-12-23 01:07:32277 return true;
278 }
279
[email protected]e3c404b2008-12-23 01:07:32280 return false;
281}
282
[email protected]926360f2012-06-29 04:45:02283bool BufferedResourceHandler::DetermineMimeType() {
284 DCHECK_EQ(STATE_BUFFERING, state_);
[email protected]35fa6a22009-08-15 00:04:01285
[email protected]926360f2012-06-29 04:45:02286 const std::string& type_hint = response_->head.mime_type;
287
288 std::string new_type;
289 bool made_final_decision =
290 net::SniffMimeType(read_buffer_->data(), bytes_read_, request_->url(),
291 type_hint, &new_type);
292
293 // SniffMimeType() returns false if there is not enough data to determine
294 // the mime type. However, even if it returns false, it returns a new type
295 // that is probably better than the current one.
296 response_->head.mime_type.assign(new_type);
297
298 return made_final_decision;
[email protected]35fa6a22009-08-15 00:04:01299}
300
[email protected]926360f2012-06-29 04:45:02301bool BufferedResourceHandler::SelectNextHandler(bool* defer) {
302 DCHECK(!response_->head.mime_type.empty());
[email protected]e3c404b2008-12-23 01:07:32303
[email protected]926360f2012-06-29 04:45:02304 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request_);
305 const std::string& mime_type = response_->head.mime_type;
[email protected]a755e1072009-10-23 16:58:37306
[email protected]3b455502012-12-11 18:22:58307 if (net::IsSupportedCertificateMimeType(mime_type)) {
308 // Install certificate file.
[email protected]d651cbc2012-05-31 21:33:05309 scoped_ptr<ResourceHandler> handler(
[email protected]3b455502012-12-11 18:22:58310 new CertificateResourceHandler(request_,
311 info->GetChildID(),
312 info->GetRouteID()));
[email protected]926360f2012-06-29 04:45:02313 return UseAlternateNextHandler(handler.Pass());
[email protected]5a9d58fa2012-05-29 15:15:04314 }
315
[email protected]926360f2012-06-29 04:45:02316 if (!info->allow_download())
[email protected]5e5e0c82012-01-25 09:12:29317 return true;
318
[email protected]3ca004f72012-12-18 10:35:21319 bool must_download = MustDownload();
320 if (!must_download) {
[email protected]926360f2012-06-29 04:45:02321 if (net::IsSupportedMimeType(mime_type))
[email protected]35fa6a22009-08-15 00:04:01322 return true;
[email protected]35fa6a22009-08-15 00:04:01323
[email protected]646889822013-03-20 00:26:45324 scoped_ptr<ResourceHandler> handler(
[email protected]fc72bb12013-06-02 21:13:46325 host_->MaybeInterceptAsStream(request_, response_.get()));
[email protected]646889822013-03-20 00:26:45326 if (handler)
327 return UseAlternateNextHandler(handler.Pass());
328
[email protected]ebd71962012-12-20 02:56:55329#if defined(ENABLE_PLUGINS)
[email protected]926360f2012-06-29 04:45:02330 bool stale;
331 bool has_plugin = HasSupportingPlugin(&stale);
[email protected]68598072011-07-29 08:21:28332 if (stale) {
[email protected]926360f2012-06-29 04:45:02333 // Refresh the plugins asynchronously.
334 PluginServiceImpl::GetInstance()->GetPlugins(
[email protected]5c1d3e52012-08-01 05:14:27335 base::Bind(&BufferedResourceHandler::OnPluginsLoaded,
336 weak_ptr_factory_.GetWeakPtr()));
[email protected]926360f2012-06-29 04:45:02337 *defer = true;
[email protected]35fa6a22009-08-15 00:04:01338 return true;
339 }
[email protected]926360f2012-06-29 04:45:02340 if (has_plugin)
341 return true;
[email protected]ebd71962012-12-20 02:56:55342#endif
[email protected]35fa6a22009-08-15 00:04:01343 }
344
[email protected]926360f2012-06-29 04:45:02345 // Install download handler
346 info->set_is_download(true);
347 scoped_ptr<ResourceHandler> handler(
348 host_->CreateResourceHandlerForDownload(
349 request_,
350 true, // is_content_initiated
[email protected]3ca004f72012-12-18 10:35:21351 must_download,
[email protected]530047e2013-07-12 17:02:25352 content::DownloadItem::kInvalidId,
[email protected]c873c862012-10-17 15:32:12353 scoped_ptr<DownloadSaveInfo>(new DownloadSaveInfo()),
[email protected]530047e2013-07-12 17:02:25354 DownloadUrlParameters::OnStartedCallback()));
[email protected]926360f2012-06-29 04:45:02355 return UseAlternateNextHandler(handler.Pass());
[email protected]35fa6a22009-08-15 00:04:01356}
357
[email protected]926360f2012-06-29 04:45:02358bool BufferedResourceHandler::UseAlternateNextHandler(
359 scoped_ptr<ResourceHandler> new_handler) {
[email protected]fc72bb12013-06-02 21:13:46360 if (response_->head.headers.get() && // Can be NULL if FTP.
[email protected]926360f2012-06-29 04:45:02361 response_->head.headers->response_code() / 100 != 2) {
362 // The response code indicates that this is an error page, but we don't
363 // know how to display the content. We follow Firefox here and show our
364 // own error page instead of triggering a download.
365 // TODO(abarth): We should abstract the response_code test, but this kind
366 // of check is scattered throughout our codebase.
367 request_->CancelWithError(net::ERR_FILE_NOT_FOUND);
368 return false;
369 }
370
371 int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID();
372
[email protected]0dc72bbe2010-04-08 15:29:17373 // Inform the original ResourceHandler that this will be handled entirely by
374 // the new ResourceHandler.
[email protected]5e5e0c82012-01-25 09:12:29375 // TODO(darin): We should probably check the return values of these.
[email protected]22b305442012-05-21 18:02:59376 bool defer_ignored = false;
[email protected]fc72bb12013-06-02 21:13:46377 next_handler_->OnResponseStarted(request_id, response_.get(), &defer_ignored);
[email protected]22b305442012-05-21 18:02:59378 DCHECK(!defer_ignored);
[email protected]2756a8e2012-09-07 18:24:29379 net::URLRequestStatus status(net::URLRequestStatus::CANCELED,
380 net::ERR_ABORTED);
[email protected]5e5e0c82012-01-25 09:12:29381 next_handler_->OnResponseCompleted(request_id, status, std::string());
[email protected]0dc72bbe2010-04-08 15:29:17382
383 // This is handled entirely within the new ResourceHandler, so just reset the
384 // original ResourceHandler.
[email protected]926360f2012-06-29 04:45:02385 next_handler_ = new_handler.Pass();
386 next_handler_->SetController(this);
[email protected]5e5e0c82012-01-25 09:12:29387
[email protected]926360f2012-06-29 04:45:02388 return CopyReadBufferToNextHandler(request_id);
[email protected]5e5e0c82012-01-25 09:12:29389}
390
[email protected]926360f2012-06-29 04:45:02391bool BufferedResourceHandler::ReplayReadCompleted(bool* defer) {
[email protected]fc72bb12013-06-02 21:13:46392 DCHECK(read_buffer_.get());
[email protected]5e5e0c82012-01-25 09:12:29393
[email protected]926360f2012-06-29 04:45:02394 int request_id = ResourceRequestInfo::ForRequest(request_)->GetRequestID();
395 bool result = next_handler_->OnReadCompleted(request_id, bytes_read_, defer);
396
397 read_buffer_ = NULL;
398 read_buffer_size_ = 0;
399 bytes_read_ = 0;
400
401 state_ = STATE_STREAMING;
402
403 return result;
[email protected]5e5e0c82012-01-25 09:12:29404}
405
[email protected]926360f2012-06-29 04:45:02406void BufferedResourceHandler::CallReplayReadCompleted() {
407 bool defer = false;
408 if (!ReplayReadCompleted(&defer)) {
409 controller()->Cancel();
410 } else if (!defer) {
411 state_ = STATE_STREAMING;
412 controller()->Resume();
413 }
414}
415
416bool BufferedResourceHandler::MustDownload() {
417 if (must_download_is_set_)
418 return must_download_;
419
420 must_download_is_set_ = true;
421
422 std::string disposition;
423 request_->GetResponseHeaderByName("content-disposition", &disposition);
424 if (!disposition.empty() &&
425 net::HttpContentDisposition(disposition, std::string()).is_attachment()) {
426 must_download_ = true;
427 } else if (host_->delegate() &&
428 host_->delegate()->ShouldForceDownloadResource(
429 request_->url(), response_->head.mime_type)) {
430 must_download_ = true;
431 } else {
432 must_download_ = false;
433 }
434
435 return must_download_;
436}
437
438bool BufferedResourceHandler::HasSupportingPlugin(bool* stale) {
439 ResourceRequestInfoImpl* info = ResourceRequestInfoImpl::ForRequest(request_);
440
441 bool allow_wildcard = false;
[email protected]d7bd3e52013-07-21 04:29:20442 WebPluginInfo plugin;
[email protected]926360f2012-06-29 04:45:02443 return PluginServiceImpl::GetInstance()->GetPluginInfo(
444 info->GetChildID(), info->GetRouteID(), info->GetContext(),
445 request_->url(), GURL(), response_->head.mime_type, allow_wildcard,
446 stale, &plugin, NULL);
447}
448
449bool BufferedResourceHandler::CopyReadBufferToNextHandler(int request_id) {
[email protected]5e5e0c82012-01-25 09:12:29450 if (!bytes_read_)
[email protected]926360f2012-06-29 04:45:02451 return true;
[email protected]5e5e0c82012-01-25 09:12:29452
453 net::IOBuffer* buf = NULL;
454 int buf_len = 0;
[email protected]926360f2012-06-29 04:45:02455 if (!next_handler_->OnWillRead(request_id, &buf, &buf_len, bytes_read_))
456 return false;
457
458 CHECK((buf_len >= bytes_read_) && (bytes_read_ >= 0));
459 memcpy(buf->data(), read_buffer_->data(), bytes_read_);
460 return true;
[email protected]0dc72bbe2010-04-08 15:29:17461}
462
[email protected]d33e7cc2011-09-23 01:43:56463void BufferedResourceHandler::OnPluginsLoaded(
[email protected]d7bd3e52013-07-21 04:29:20464 const std::vector<WebPluginInfo>& plugins) {
[email protected]22b305442012-05-21 18:02:59465 bool defer = false;
[email protected]926360f2012-06-29 04:45:02466 if (!ProcessResponse(&defer)) {
[email protected]56f0b082012-06-14 07:12:32467 controller()->Cancel();
[email protected]926360f2012-06-29 04:45:02468 } else if (!defer) {
[email protected]56f0b082012-06-14 07:12:32469 controller()->Resume();
[email protected]22b305442012-05-21 18:02:59470 }
[email protected]e3c404b2008-12-23 01:07:32471}
[email protected]d18720a2012-01-06 09:53:55472
473} // namespace content