15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/loader/redirect_to_file_resource_handler.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/browser/loader/resource_request_info_impl.h" 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/loader/temporary_file_stream.h" 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/public/browser/resource_controller.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/resource_response.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/file_stream.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/io_buffer.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/mime_sniffer.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h" 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/common/blob/shareable_file_reference.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)using storage::ShareableFileReference; 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class is similar to identically named classes in AsyncResourceHandler 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and BufferedResourceHandler, but not quite. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(ncbray) generalize and unify these cases? 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In general, it's a bad idea to point to a subbuffer (particularly with 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GrowableIOBuffer) because the backing IOBuffer may realloc its data. In this 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// particular case we know RedirectToFileResourceHandler will not realloc its 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// buffer while a write is occurring, so we should be safe. This property is 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// somewhat fragile, however, and depending on it is dangerous. A more 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// principled approach would require significant refactoring, however, so for 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the moment we're relying on fragile properties. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class DependentIOBuffer : public net::WrappedIOBuffer { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DependentIOBuffer(net::IOBuffer* backing, char* memory) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : net::WrappedIOBuffer(memory), 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) backing_(backing) { 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~DependentIOBuffer() {} 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<net::IOBuffer> backing_; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kInitialReadBufSize = 32768; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxReadBufSize = 524288; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// A separate IO thread object to manage the lifetime of the net::FileStream and 54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// the ShareableFileReference. When the handler is destroyed, it asynchronously 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// closes net::FileStream after all pending writes complete. Only after the 56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// stream is closed is the ShareableFileReference released, to ensure the 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// temporary is not deleted before it is closed. 58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class RedirectToFileResourceHandler::Writer { 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) public: 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) Writer(RedirectToFileResourceHandler* handler, 61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<net::FileStream> file_stream, 62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ShareableFileReference* deletable_file) 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) : handler_(handler), 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) file_stream_(file_stream.Pass()), 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) is_writing_(false), 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) deletable_file_(deletable_file) { 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(!deletable_file_->path().empty()); 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool is_writing() const { return is_writing_; } 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const base::FilePath& path() const { return deletable_file_->path(); } 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int Write(net::IOBuffer* buf, int buf_len) { 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(!is_writing_); 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(handler_); 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int result = file_stream_->Write( 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) buf, buf_len, 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Bind(&Writer::DidWriteToFile, base::Unretained(this))); 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (result == net::ERR_IO_PENDING) 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) is_writing_ = true; 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return result; 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) void Close() { 85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) handler_ = NULL; 86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!is_writing_) 87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CloseAndDelete(); 88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) private: 91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Only DidClose can delete this. 92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ~Writer() { 93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) void DidWriteToFile(int result) { 96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(is_writing_); 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) is_writing_ = false; 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (handler_) { 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) handler_->DidWriteToFile(result); 100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CloseAndDelete(); 102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) void CloseAndDelete() { 106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(!is_writing_); 107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int result = file_stream_->Close(base::Bind(&Writer::DidClose, 108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Unretained(this))); 109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (result != net::ERR_IO_PENDING) 110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DidClose(result); 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) void DidClose(int result) { 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) delete this; 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) RedirectToFileResourceHandler* handler_; 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<net::FileStream> file_stream_; 120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool is_writing_; 121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // We create a ShareableFileReference that's deletable for the temp file 123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // created as a result of the download. 12403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) scoped_refptr<storage::ShareableFileReference> deletable_file_; 125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(Writer); 127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}; 128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RedirectToFileResourceHandler::RedirectToFileResourceHandler( 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<ResourceHandler> next_handler, 131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) net::URLRequest* request) 1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) : LayeredResourceHandler(request, next_handler.Pass()), 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf_(new net::GrowableIOBuffer()), 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf_write_pending_(false), 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_cursor_(0), 136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) writer_(NULL), 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_buffer_size_(kInitialReadBufSize), 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) did_defer_(false), 139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) completed_during_write_(false), 140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) weak_factory_(this) { 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)RedirectToFileResourceHandler::~RedirectToFileResourceHandler() { 144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Orphan the writer to asynchronously close and release the temporary file. 145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (writer_) { 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) writer_->Close(); 147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) writer_ = NULL; 148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void RedirectToFileResourceHandler:: 152a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetCreateTemporaryFileStreamFunctionForTesting( 153a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const CreateTemporaryFileStreamFunction& create_temporary_file_stream) { 154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) create_temporary_file_stream_ = create_temporary_file_stream; 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool RedirectToFileResourceHandler::OnResponseStarted( 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResourceResponse* response, 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* defer) { 1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(writer_); 1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci response->head.download_file_path = writer_->path(); 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return next_handler_->OnResponseStarted(response, defer); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool RedirectToFileResourceHandler::OnWillStart(const GURL& url, bool* defer) { 166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(!writer_); 167a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 168a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Defer starting the request until we have created the temporary file. 169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // TODO(darin): This is sub-optimal. We should not delay starting the 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // network request like this. 171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) will_start_url_ = url; 172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) did_defer_ = *defer = true; 173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (create_temporary_file_stream_.is_null()) { 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CreateTemporaryFileStream( 175a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::Bind(&RedirectToFileResourceHandler::DidCreateTemporaryFile, 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) weak_factory_.GetWeakPtr())); 177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) create_temporary_file_stream_.Run( 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&RedirectToFileResourceHandler::DidCreateTemporaryFile, 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_factory_.GetWeakPtr())); 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return true; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)bool RedirectToFileResourceHandler::OnWillRead( 1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_refptr<net::IOBuffer>* buf, 1874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int* buf_size, 1884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int min_size) { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(-1, min_size); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buf_->capacity() < next_buffer_size_) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf_->SetCapacity(next_buffer_size_); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We should have paused this network request already if the buffer is full. 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!BufIsFull()); 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *buf = buf_.get(); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *buf_size = buf_->RemainingCapacity(); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf_write_pending_ = true; 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool RedirectToFileResourceHandler::OnReadCompleted(int bytes_read, 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool* defer) { 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(buf_write_pending_); 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf_write_pending_ = false; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use the buffer's offset field to record the end of the buffer. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int new_offset = buf_->offset() + bytes_read; 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(new_offset <= buf_->capacity()); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf_->set_offset(new_offset); 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (BufIsFull()) { 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) did_defer_ = *defer = true; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buf_->capacity() == bytes_read) { 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The network layer has saturated our buffer in one read. Next time, we 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // should give it a bigger buffer for it to fill. 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_buffer_size_ = std::min(next_buffer_size_ * 2, kMaxReadBufSize); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return WriteMore(); 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void RedirectToFileResourceHandler::OnResponseCompleted( 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const net::URLRequestStatus& status, 229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const std::string& security_info, 230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool* defer) { 231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (writer_ && writer_->is_writing()) { 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) completed_during_write_ = true; 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) completed_status_ = status; 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) completed_security_info_ = security_info; 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) did_defer_ = true; 236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) *defer = true; 237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) next_handler_->OnResponseCompleted(status, security_info, defer); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RedirectToFileResourceHandler::DidCreateTemporaryFile( 243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) base::File::Error error_code, 244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) scoped_ptr<net::FileStream> file_stream, 245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ShareableFileReference* deletable_file) { 246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(!writer_); 247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (error_code != base::File::FILE_OK) { 248a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) controller()->CancelWithError(net::FileErrorToNetError(error_code)); 249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return; 250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) writer_ = new Writer(this, file_stream.Pass(), deletable_file); 253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Resume the request. 255a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(did_defer_); 256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) bool defer = false; 257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!next_handler_->OnWillStart(will_start_url_, &defer)) { 258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) controller()->Cancel(); 259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else if (!defer) { 260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ResumeIfDeferred(); 261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) did_defer_ = false; 263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) will_start_url_ = GURL(); 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RedirectToFileResourceHandler::DidWriteToFile(int result) { 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool failed = false; 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result > 0) { 270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) next_handler_->OnDataDownloaded(result); 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_cursor_ += result; 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) failed = !WriteMore(); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) failed = true; 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (failed) { 278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(!writer_->is_writing()); 279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // TODO(davidben): Recover the error code from WriteMore or |result|, as 280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // appropriate. 281a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (completed_during_write_ && completed_status_.is_success()) { 282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // If the request successfully completed mid-write, but the write failed, 283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // convert the status to a failure for downstream. 284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) completed_status_.set_status(net::URLRequestStatus::CANCELED); 285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) completed_status_.set_error(net::ERR_FAILED); 286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!completed_during_write_) 288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) controller()->CancelWithError(net::ERR_FAILED); 289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (completed_during_write_ && !writer_->is_writing()) { 292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // Resume shutdown now that all data has been written to disk. Note that 293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // this should run even in the |failed| case above, otherwise a failed write 294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // leaves the handler stuck. 295f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool defer = false; 296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) next_handler_->OnResponseCompleted(completed_status_, 297f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) completed_security_info_, 298f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) &defer); 299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (!defer) { 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResumeIfDeferred(); 301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } else { 302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) did_defer_ = false; 303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool RedirectToFileResourceHandler::WriteMore() { 308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(writer_); 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (;;) { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (write_cursor_ == buf_->offset()) { 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We've caught up to the network load, but it may be in the process of 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // appending more data to the buffer. 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!buf_write_pending_) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (BufIsFull()) 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResumeIfDeferred(); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buf_->set_offset(0); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_cursor_ = 0; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 321a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (writer_->is_writing()) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(write_cursor_ < buf_->offset()); 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create a temporary buffer pointing to a subsection of the data buffer so 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that it can be passed to Write. This code makes some crazy scary 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // assumptions about object lifetimes, thread sharing, and that buf_ will 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not realloc durring the write due to how the state machine in this class 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // works. 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that buf_ is also shared with the code that writes data into the 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // cache, so modifying it can cause some pretty subtle race conditions: 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // https://code.google.com/p/chromium/issues/detail?id=152076 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're using DependentIOBuffer instead of DrainableIOBuffer to dodge some 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of these issues, for the moment. 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(ncbray) make this code less crazy scary. 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Also note that Write may increase the refcount of "wrapped" deep in the 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bowels of its implementation, the use of scoped_refptr here is not 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // spurious. 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<DependentIOBuffer> wrapped = new DependentIOBuffer( 340868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) buf_.get(), buf_->StartOfBuffer() + write_cursor_); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int write_len = buf_->offset() - write_cursor_; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int rv = writer_->Write(wrapped.get(), write_len); 344a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (rv == net::ERR_IO_PENDING) 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (rv <= 0) 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) next_handler_->OnDataDownloaded(rv); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_cursor_ += rv; 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool RedirectToFileResourceHandler::BufIsFull() const { 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is a hack to workaround BufferedResourceHandler's inability to 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // deal with a ResourceHandler that returns a buffer size of less than 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2 * net::kMaxBytesToSniff from its OnWillRead method. 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(darin): Fix this retardation! 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return buf_->RemainingCapacity() <= (2 * net::kMaxBytesToSniff); 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RedirectToFileResourceHandler::ResumeIfDeferred() { 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (did_defer_) { 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) did_defer_ = false; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller()->Resume(); 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace content 369