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