Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2010 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 "net/base/upload_data.h"
      6 
      7 #include "base/file_util.h"
      8 #include "base/logging.h"
      9 #include "base/string_util.h"
     10 #include "net/base/file_stream.h"
     11 #include "net/base/net_errors.h"
     12 
     13 #ifdef ANDROID
     14 #include "android/jni/platform_file_jni.h"
     15 #endif
     16 
     17 namespace net {
     18 
     19 UploadData::Element::Element()
     20     : type_(TYPE_BYTES),
     21       file_range_offset_(0),
     22       file_range_length_(kuint64max),
     23       is_last_chunk_(false),
     24       override_content_length_(false),
     25       content_length_computed_(false),
     26       content_length_(-1),
     27       file_stream_(NULL) {
     28 }
     29 
     30 UploadData::Element::~Element() {
     31   // In the common case |file__stream_| will be null.
     32   delete file_stream_;
     33 }
     34 
     35 void UploadData::Element::SetToChunk(const char* bytes,
     36                                      int bytes_len,
     37                                      bool is_last_chunk) {
     38   bytes_.clear();
     39   bytes_.insert(bytes_.end(), bytes, bytes + bytes_len);
     40   type_ = TYPE_CHUNK;
     41   is_last_chunk_ = is_last_chunk;
     42 }
     43 
     44 uint64 UploadData::Element::GetContentLength() {
     45   if (override_content_length_ || content_length_computed_)
     46     return content_length_;
     47 
     48   if (type_ == TYPE_BYTES || type_ == TYPE_CHUNK)
     49     return static_cast<uint64>(bytes_.size());
     50   else if (type_ == TYPE_BLOB)
     51     // The blob reference will be resolved later.
     52     return 0;
     53 
     54   DCHECK_EQ(TYPE_FILE, type_);
     55   DCHECK(!file_stream_);
     56 
     57   // TODO(darin): This size calculation could be out of sync with the state of
     58   // the file when we get around to reading it.  We should probably find a way
     59   // to lock the file or somehow protect against this error condition.
     60 
     61   content_length_computed_ = true;
     62   content_length_ = 0;
     63 
     64 #ifdef ANDROID
     65   if (file_path_.value().find("content://") == 0) {
     66     content_length_computed_ = true;
     67     content_length_ = android::contentUrlSize(file_path_);
     68     return content_length_;
     69   }
     70 #endif
     71 
     72   // We need to open the file here to decide if we should report the file's
     73   // size or zero.  We cache the open file, so that we can still read it when
     74   // it comes time to.
     75   file_stream_ = NewFileStreamForReading();
     76   if (!file_stream_)
     77     return 0;
     78 
     79   int64 length = 0;
     80   if (!file_util::GetFileSize(file_path_, &length))
     81     return 0;
     82 
     83   if (file_range_offset_ >= static_cast<uint64>(length))
     84     return 0;  // range is beyond eof
     85 
     86   // compensate for the offset and clip file_range_length_ to eof
     87   content_length_ =  std::min(length - file_range_offset_, file_range_length_);
     88   return content_length_;
     89 }
     90 
     91 FileStream* UploadData::Element::NewFileStreamForReading() {
     92   // In common usage GetContentLength() will call this first and store the
     93   // result into |file_| and a subsequent call (from UploadDataStream) will
     94   // get the cached open FileStream.
     95   if (file_stream_) {
     96     FileStream* file = file_stream_;
     97     file_stream_ = NULL;
     98     return file;
     99   }
    100 
    101   scoped_ptr<FileStream> file(new FileStream());
    102   int64 rv = file->Open(file_path_,
    103                       base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ);
    104   if (rv != OK) {
    105     // If the file can't be opened, we'll just upload an empty file.
    106     DLOG(WARNING) << "Failed to open \"" << file_path_.value()
    107                   << "\" for reading: " << rv;
    108     return NULL;
    109   }
    110   if (file_range_offset_) {
    111     rv = file->Seek(FROM_BEGIN, file_range_offset_);
    112     if (rv < 0) {
    113       DLOG(WARNING) << "Failed to seek \"" << file_path_.value()
    114                     << "\" to offset: " << file_range_offset_ << " (" << rv
    115                     << ")";
    116       return NULL;
    117     }
    118   }
    119 
    120   return file.release();
    121 }
    122 
    123 UploadData::UploadData()
    124     : identifier_(0),
    125       chunk_callback_(NULL),
    126       is_chunked_(false) {
    127 }
    128 
    129 void UploadData::AppendBytes(const char* bytes, int bytes_len) {
    130   DCHECK(!is_chunked_);
    131   if (bytes_len > 0) {
    132     elements_.push_back(Element());
    133     elements_.back().SetToBytes(bytes, bytes_len);
    134   }
    135 }
    136 
    137 void UploadData::AppendFile(const FilePath& file_path) {
    138   DCHECK(!is_chunked_);
    139   elements_.push_back(Element());
    140   elements_.back().SetToFilePath(file_path);
    141 }
    142 
    143 void UploadData::AppendFileRange(const FilePath& file_path,
    144                                  uint64 offset, uint64 length,
    145                                  const base::Time& expected_modification_time) {
    146   DCHECK(!is_chunked_);
    147   elements_.push_back(Element());
    148   elements_.back().SetToFilePathRange(file_path, offset, length,
    149                                       expected_modification_time);
    150 }
    151 
    152 void UploadData::AppendBlob(const GURL& blob_url) {
    153   DCHECK(!is_chunked_);
    154   elements_.push_back(Element());
    155   elements_.back().SetToBlobUrl(blob_url);
    156 }
    157 
    158 void UploadData::AppendChunk(const char* bytes,
    159                              int bytes_len,
    160                              bool is_last_chunk) {
    161   DCHECK(is_chunked_);
    162   elements_.push_back(Element());
    163   elements_.back().SetToChunk(bytes, bytes_len, is_last_chunk);
    164   if (chunk_callback_)
    165     chunk_callback_->OnChunkAvailable();
    166 }
    167 
    168 void UploadData::set_chunk_callback(ChunkCallback* callback) {
    169   chunk_callback_ = callback;
    170 }
    171 
    172 uint64 UploadData::GetContentLength() {
    173   uint64 len = 0;
    174   std::vector<Element>::iterator it = elements_.begin();
    175   for (; it != elements_.end(); ++it)
    176     len += (*it).GetContentLength();
    177   return len;
    178 }
    179 
    180 void UploadData::SetElements(const std::vector<Element>& elements) {
    181   elements_ = elements;
    182 }
    183 
    184 UploadData::~UploadData() {
    185 }
    186 
    187 }  // namespace net
    188