| Index: chrome/browser/renderer_host/redirect_to_file_resource_handler.cc
|
| ===================================================================
|
| --- chrome/browser/renderer_host/redirect_to_file_resource_handler.cc (revision 0)
|
| +++ chrome/browser/renderer_host/redirect_to_file_resource_handler.cc (revision 0)
|
| @@ -0,0 +1,185 @@
|
| +// Copyright (c) 2010 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 "chrome/browser/renderer_host/redirect_to_file_resource_handler.h"
|
| +
|
| +#include "base/file_util.h"
|
| +#include "base/platform_file.h"
|
| +#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
|
| +#include "chrome/common/resource_response.h"
|
| +#include "net/base/io_buffer.h"
|
| +#include "net/base/mime_sniffer.h"
|
| +#include "net/base/net_errors.h"
|
| +
|
| +// TODO(darin): Use the buffer sizing algorithm from AsyncResourceHandler.
|
| +static const int kReadBufSize = 32768;
|
| +
|
| +RedirectToFileResourceHandler::RedirectToFileResourceHandler(
|
| + ResourceHandler* next_handler,
|
| + int process_id,
|
| + ResourceDispatcherHost* host)
|
| + : host_(host),
|
| + next_handler_(next_handler),
|
| + process_id_(process_id),
|
| + request_id_(-1),
|
| + buf_(new net::GrowableIOBuffer()),
|
| + buf_write_pending_(false),
|
| + write_cursor_(0),
|
| + write_callback_(ALLOW_THIS_IN_INITIALIZER_LIST(this),
|
| + &RedirectToFileResourceHandler::DidWriteToFile),
|
| + write_callback_pending_(false) {
|
| +}
|
| +
|
| +bool RedirectToFileResourceHandler::OnUploadProgress(int request_id,
|
| + uint64 position,
|
| + uint64 size) {
|
| + return next_handler_->OnUploadProgress(request_id, position, size);
|
| +}
|
| +
|
| +bool RedirectToFileResourceHandler::OnRequestRedirected(
|
| + int request_id,
|
| + const GURL& new_url,
|
| + ResourceResponse* response,
|
| + bool* defer) {
|
| + return next_handler_->OnRequestRedirected(request_id, new_url, response,
|
| + defer);
|
| +}
|
| +
|
| +bool RedirectToFileResourceHandler::OnResponseStarted(
|
| + int request_id,
|
| + ResourceResponse* response) {
|
| + if (response->response_head.status.is_success()) {
|
| + // TODO(darin): Move this file creation to a background thread.
|
| + file_util::CreateTemporaryFile(&file_path_);
|
| + response->response_head.download_file_path = file_path_;
|
| + }
|
| + return next_handler_->OnResponseStarted(request_id, response);
|
| +}
|
| +
|
| +bool RedirectToFileResourceHandler::OnWillStart(int request_id,
|
| + const GURL& url,
|
| + bool* defer) {
|
| + return next_handler_->OnWillStart(request_id, url, defer);
|
| +}
|
| +
|
| +bool RedirectToFileResourceHandler::OnWillRead(int request_id,
|
| + net::IOBuffer** buf,
|
| + int* buf_size,
|
| + int min_size) {
|
| + DCHECK(min_size == -1);
|
| +
|
| + if (!buf_->capacity())
|
| + buf_->SetCapacity(kReadBufSize);
|
| +
|
| + // We should have paused this network request already if the buffer is full.
|
| + DCHECK(!BufIsFull());
|
| +
|
| + *buf = buf_;
|
| + *buf_size = buf_->RemainingCapacity();
|
| +
|
| + buf_write_pending_ = true;
|
| + return true;
|
| +}
|
| +
|
| +bool RedirectToFileResourceHandler::OnReadCompleted(int request_id,
|
| + int* bytes_read) {
|
| + if (!buf_write_pending_) {
|
| + // Ignore spurious OnReadCompleted! PauseRequest(true) called from within
|
| + // OnReadCompleted tells the ResourceDispatcherHost that we did not consume
|
| + // the data. PauseRequest(false) then repeats the last OnReadCompleted
|
| + // call. We pause the request so that we can copy our buffer to disk, so
|
| + // we need to consume the data now. The ResourceDispatcherHost pause
|
| + // mechanism does not fit our use case very well.
|
| + // TODO(darin): Fix the ResourceDispatcherHost to avoid this hack!
|
| + return true;
|
| + }
|
| +
|
| + buf_write_pending_ = false;
|
| +
|
| + // We use the buffer's offset field to record the end of the buffer.
|
| +
|
| + int new_offset = buf_->offset() + *bytes_read;
|
| + DCHECK(new_offset <= buf_->capacity());
|
| + buf_->set_offset(new_offset);
|
| +
|
| + if (!file_stream_.IsOpen()) {
|
| + int rv = file_stream_.Open(file_path_, base::PLATFORM_FILE_OPEN |
|
| + base::PLATFORM_FILE_WRITE |
|
| + base::PLATFORM_FILE_ASYNC);
|
| + if (rv != net::OK)
|
| + return false;
|
| + }
|
| +
|
| + if (BufIsFull())
|
| + host_->PauseRequest(process_id_, request_id, true);
|
| +
|
| + request_id_ = request_id;
|
| + return WriteMore();
|
| +}
|
| +
|
| +bool RedirectToFileResourceHandler::OnResponseCompleted(
|
| + int request_id,
|
| + const URLRequestStatus& status,
|
| + const std::string& security_info) {
|
| + return next_handler_->OnResponseCompleted(request_id, status, security_info);
|
| +}
|
| +
|
| +void RedirectToFileResourceHandler::OnRequestClosed() {
|
| + next_handler_->OnRequestClosed();
|
| +}
|
| +
|
| +RedirectToFileResourceHandler::~RedirectToFileResourceHandler() {
|
| +}
|
| +
|
| +void RedirectToFileResourceHandler::DidWriteToFile(int result) {
|
| + write_callback_pending_ = false;
|
| +
|
| + bool failed = false;
|
| + if (result > 0) {
|
| + write_cursor_ += result;
|
| + failed = !WriteMore();
|
| + } else {
|
| + failed = true;
|
| + }
|
| +
|
| + if (failed)
|
| + host_->CancelRequest(process_id_, request_id_, false);
|
| +}
|
| +
|
| +bool RedirectToFileResourceHandler::WriteMore() {
|
| + for (;;) {
|
| + if (write_cursor_ == buf_->offset()) {
|
| + // We've caught up to the network load, but it may be in the process of
|
| + // appending more data to the buffer.
|
| + if (!buf_write_pending_) {
|
| + if (BufIsFull())
|
| + host_->PauseRequest(process_id_, request_id_, false);
|
| + buf_->set_offset(0);
|
| + write_cursor_ = 0;
|
| + }
|
| + return true;
|
| + }
|
| + if (write_callback_pending_)
|
| + return true;
|
| + DCHECK(write_cursor_ < buf_->offset());
|
| + int rv = file_stream_.Write(buf_->StartOfBuffer() + write_cursor_,
|
| + buf_->offset() - write_cursor_,
|
| + &write_callback_);
|
| + if (rv == net::ERR_IO_PENDING) {
|
| + write_callback_pending_ = true;
|
| + return true;
|
| + }
|
| + if (rv < 0)
|
| + return false;
|
| + write_cursor_ += rv;
|
| + }
|
| +}
|
| +
|
| +bool RedirectToFileResourceHandler::BufIsFull() const {
|
| + // This is a hack to workaround BufferedResourceHandler's inability to
|
| + // deal with a ResourceHandler that returns a buffer size of less than
|
| + // 2 * net::kMaxBytesToSniff from its OnWillRead method.
|
| + // TODO(darin): Fix this retardation!
|
| + return buf_->RemainingCapacity() <= (2 * net::kMaxBytesToSniff);
|
| +}
|
|
|
| Property changes on: chrome\browser\renderer_host\redirect_to_file_resource_handler.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|