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/platform_file.h"
     12 #include "base/task_runner.h"
     13 #include "net/base/file_stream.h"
     14 #include "net/base/io_buffer.h"
     15 #include "net/base/net_errors.h"
     16 
     17 namespace webkit_blob {
     18 
     19 namespace {
     20 
     21 const int kOpenFlagsForRead = base::PLATFORM_FILE_OPEN |
     22                               base::PLATFORM_FILE_READ |
     23                               base::PLATFORM_FILE_ASYNC;
     24 
     25 // Verify if the underlying file has not been modified.
     26 bool VerifySnapshotTime(const base::Time& expected_modification_time,
     27                         const base::PlatformFileInfo& file_info) {
     28   return expected_modification_time.is_null() ||
     29          expected_modification_time.ToTimeT() ==
     30              file_info.last_modified.ToTimeT();
     31 }
     32 
     33 }  // namespace
     34 
     35 LocalFileStreamReader::LocalFileStreamReader(
     36     base::TaskRunner* task_runner,
     37     const base::FilePath& file_path,
     38     int64 initial_offset,
     39     const base::Time& expected_modification_time)
     40     : task_runner_(task_runner),
     41       file_path_(file_path),
     42       initial_offset_(initial_offset),
     43       expected_modification_time_(expected_modification_time),
     44       has_pending_open_(false),
     45       weak_factory_(this) {}
     46 
     47 LocalFileStreamReader::~LocalFileStreamReader() {
     48 }
     49 
     50 int LocalFileStreamReader::Read(net::IOBuffer* buf, int buf_len,
     51                           const net::CompletionCallback& callback) {
     52   DCHECK(!has_pending_open_);
     53   if (stream_impl_)
     54     return stream_impl_->Read(buf, buf_len, callback);
     55   return Open(base::Bind(&LocalFileStreamReader::DidOpenForRead,
     56                          weak_factory_.GetWeakPtr(),
     57                          make_scoped_refptr(buf), buf_len, callback));
     58 }
     59 
     60 int64 LocalFileStreamReader::GetLength(
     61     const net::Int64CompletionCallback& callback) {
     62   const bool posted = base::FileUtilProxy::GetFileInfo(
     63       task_runner_.get(),
     64       file_path_,
     65       base::Bind(&LocalFileStreamReader::DidGetFileInfoForGetLength,
     66                  weak_factory_.GetWeakPtr(),
     67                  callback));
     68   DCHECK(posted);
     69   return net::ERR_IO_PENDING;
     70 }
     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(NULL, 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::PlatformFileError error,
    153     const base::PlatformFileInfo& file_info) {
    154   if (file_info.is_directory) {
    155     callback.Run(net::ERR_FILE_NOT_FOUND);
    156     return;
    157   }
    158   if (error != base::PLATFORM_FILE_OK) {
    159     callback.Run(net::PlatformFileErrorToNetError(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