Home | History | Annotate | Download | only in blob
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "webkit/browser/blob/local_file_stream_reader.h"
      6 
      7 #include "base/file_util.h"
      8 #include "base/files/file_util_proxy.h"
      9 #include "base/location.h"
     10 #include "base/logging.h"
     11 #include "base/task_runner.h"
     12 #include "net/base/file_stream.h"
     13 #include "net/base/io_buffer.h"
     14 #include "net/base/net_errors.h"
     15 
     16 namespace webkit_blob {
     17 
     18 namespace {
     19 
     20 const int kOpenFlagsForRead = base::File::FLAG_OPEN |
     21                               base::File::FLAG_READ |
     22                               base::File::FLAG_ASYNC;
     23 
     24 }  // namespace
     25 
     26 FileStreamReader* FileStreamReader::CreateForLocalFile(
     27     base::TaskRunner* task_runner,
     28     const base::FilePath& file_path,
     29     int64 initial_offset,
     30     const base::Time& expected_modification_time) {
     31   return new LocalFileStreamReader(task_runner, file_path, initial_offset,
     32                                    expected_modification_time);
     33 }
     34 
     35 LocalFileStreamReader::~LocalFileStreamReader() {
     36 }
     37 
     38 int LocalFileStreamReader::Read(net::IOBuffer* buf, int buf_len,
     39                           const net::CompletionCallback& callback) {
     40   DCHECK(!has_pending_open_);
     41   if (stream_impl_)
     42     return stream_impl_->Read(buf, buf_len, callback);
     43   return Open(base::Bind(&LocalFileStreamReader::DidOpenForRead,
     44                          weak_factory_.GetWeakPtr(),
     45                          make_scoped_refptr(buf), buf_len, callback));
     46 }
     47 
     48 int64 LocalFileStreamReader::GetLength(
     49     const net::Int64CompletionCallback& callback) {
     50   const bool posted = base::FileUtilProxy::GetFileInfo(
     51       task_runner_.get(),
     52       file_path_,
     53       base::Bind(&LocalFileStreamReader::DidGetFileInfoForGetLength,
     54                  weak_factory_.GetWeakPtr(),
     55                  callback));
     56   DCHECK(posted);
     57   return net::ERR_IO_PENDING;
     58 }
     59 
     60 LocalFileStreamReader::LocalFileStreamReader(
     61     base::TaskRunner* task_runner,
     62     const base::FilePath& file_path,
     63     int64 initial_offset,
     64     const base::Time& expected_modification_time)
     65     : task_runner_(task_runner),
     66       file_path_(file_path),
     67       initial_offset_(initial_offset),
     68       expected_modification_time_(expected_modification_time),
     69       has_pending_open_(false),
     70       weak_factory_(this) {}
     71 
     72 int LocalFileStreamReader::Open(const net::CompletionCallback& callback) {
     73   DCHECK(!has_pending_open_);
     74   DCHECK(!stream_impl_.get());
     75   has_pending_open_ = true;
     76 
     77   // Call GetLength first to make it perform last-modified-time verification,
     78   // and then call DidVerifyForOpen for do the rest.
     79   return GetLength(base::Bind(&LocalFileStreamReader::DidVerifyForOpen,
     80                               weak_factory_.GetWeakPtr(), callback));
     81 }
     82 
     83 void LocalFileStreamReader::DidVerifyForOpen(
     84     const net::CompletionCallback& callback,
     85     int64 get_length_result) {
     86   if (get_length_result < 0) {
     87     callback.Run(static_cast<int>(get_length_result));
     88     return;
     89   }
     90 
     91   stream_impl_.reset(new net::FileStream(task_runner_));
     92   const int result = stream_impl_->Open(
     93       file_path_, kOpenFlagsForRead,
     94       base::Bind(&LocalFileStreamReader::DidOpenFileStream,
     95                  weak_factory_.GetWeakPtr(),
     96                  callback));
     97   if (result != net::ERR_IO_PENDING)
     98     callback.Run(result);
     99 }
    100 
    101 void LocalFileStreamReader::DidOpenFileStream(
    102     const net::CompletionCallback& callback,
    103     int result) {
    104   if (result != net::OK) {
    105     callback.Run(result);
    106     return;
    107   }
    108   result = stream_impl_->Seek(
    109       net::FROM_BEGIN, initial_offset_,
    110       base::Bind(&LocalFileStreamReader::DidSeekFileStream,
    111                  weak_factory_.GetWeakPtr(),
    112                  callback));
    113   if (result != net::ERR_IO_PENDING) {
    114     callback.Run(result);
    115   }
    116 }
    117 
    118 void LocalFileStreamReader::DidSeekFileStream(
    119     const net::CompletionCallback& callback,
    120     int64 seek_result) {
    121   if (seek_result < 0) {
    122     callback.Run(static_cast<int>(seek_result));
    123     return;
    124   }
    125   if (seek_result != initial_offset_) {
    126     callback.Run(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
    127     return;
    128   }
    129   callback.Run(net::OK);
    130 }
    131 
    132 void LocalFileStreamReader::DidOpenForRead(
    133     net::IOBuffer* buf,
    134     int buf_len,
    135     const net::CompletionCallback& callback,
    136     int open_result) {
    137   DCHECK(has_pending_open_);
    138   has_pending_open_ = false;
    139   if (open_result != net::OK) {
    140     stream_impl_.reset();
    141     callback.Run(open_result);
    142     return;
    143   }
    144   DCHECK(stream_impl_.get());
    145   const int read_result = stream_impl_->Read(buf, buf_len, callback);
    146   if (read_result != net::ERR_IO_PENDING)
    147     callback.Run(read_result);
    148 }
    149 
    150 void LocalFileStreamReader::DidGetFileInfoForGetLength(
    151     const net::Int64CompletionCallback& callback,
    152     base::File::Error error,
    153     const base::File::Info& file_info) {
    154   if (file_info.is_directory) {
    155     callback.Run(net::ERR_FILE_NOT_FOUND);
    156     return;
    157   }
    158   if (error != base::File::FILE_OK) {
    159     callback.Run(net::FileErrorToNetError(error));
    160     return;
    161   }
    162   if (!VerifySnapshotTime(expected_modification_time_, file_info)) {
    163     callback.Run(net::ERR_UPLOAD_FILE_CHANGED);
    164     return;
    165   }
    166   callback.Run(file_info.size);
    167 }
    168 
    169 }  // namespace webkit_blob
    170