• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Element()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 
~Element()30 UploadData::Element::~Element() {
31   // In the common case |file__stream_| will be null.
32   delete file_stream_;
33 }
34 
SetToChunk(const char * bytes,int bytes_len,bool is_last_chunk)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 
GetContentLength()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 
NewFileStreamForReading()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 
UploadData()123 UploadData::UploadData()
124     : identifier_(0),
125       chunk_callback_(NULL),
126       is_chunked_(false) {
127 }
128 
AppendBytes(const char * bytes,int bytes_len)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 
AppendFile(const FilePath & file_path)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 
AppendFileRange(const FilePath & file_path,uint64 offset,uint64 length,const base::Time & expected_modification_time)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 
AppendBlob(const GURL & blob_url)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 
AppendChunk(const char * bytes,int bytes_len,bool is_last_chunk)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 
set_chunk_callback(ChunkCallback * callback)168 void UploadData::set_chunk_callback(ChunkCallback* callback) {
169   chunk_callback_ = callback;
170 }
171 
GetContentLength()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 
SetElements(const std::vector<Element> & elements)180 void UploadData::SetElements(const std::vector<Element>& elements) {
181   elements_ = elements;
182 }
183 
~UploadData()184 UploadData::~UploadData() {
185 }
186 
187 }  // namespace net
188