| OLD | NEW | 
|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "net/base/upload_data_stream.h" | 5 #include "net/base/upload_data_stream.h" | 
| 6 | 6 | 
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" | 
| 8 #include "base/logging.h" | 8 #include "base/logging.h" | 
| 9 #include "base/threading/thread_restrictions.h" | 9 #include "base/threading/thread_restrictions.h" | 
| 10 #include "net/base/file_stream.h" | 10 #include "net/base/file_stream.h" | 
| 11 #include "net/base/io_buffer.h" | 11 #include "net/base/io_buffer.h" | 
| 12 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" | 
| 13 | 13 | 
| 14 namespace net { | 14 namespace net { | 
| 15 | 15 | 
| 16 bool UploadDataStream::merge_chunks_ = true; | 16 bool UploadDataStream::merge_chunks_ = true; | 
| 17 | 17 | 
| 18 UploadDataStream::UploadDataStream(UploadData* upload_data) | 18 UploadDataStream::UploadDataStream(UploadData* upload_data) | 
| 19     : upload_data_(upload_data), | 19     : upload_data_(upload_data), | 
| 20       element_index_(0), | 20       element_index_(0), | 
| 21       element_offset_(0), |  | 
| 22       element_file_bytes_remaining_(0), |  | 
| 23       total_size_(0), | 21       total_size_(0), | 
| 24       current_position_(0), | 22       current_position_(0), | 
| 25       initialized_successfully_(false) { | 23       initialized_successfully_(false) { | 
| 26 } | 24 } | 
| 27 | 25 | 
| 28 UploadDataStream::~UploadDataStream() { | 26 UploadDataStream::~UploadDataStream() { | 
| 29 } | 27 } | 
| 30 | 28 | 
| 31 int UploadDataStream::Init() { | 29 int UploadDataStream::Init() { | 
| 32   DCHECK(!initialized_successfully_); | 30   DCHECK(!initialized_successfully_); | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
| 50       base::ThreadRestrictions::ScopedAllowIO allow_io; | 48       base::ThreadRestrictions::ScopedAllowIO allow_io; | 
| 51       base::PlatformFileInfo info; | 49       base::PlatformFileInfo info; | 
| 52       if (file_util::GetFileInfo(element.file_path(), &info) && | 50       if (file_util::GetFileInfo(element.file_path(), &info) && | 
| 53           element.expected_file_modification_time().ToTimeT() != | 51           element.expected_file_modification_time().ToTimeT() != | 
| 54           info.last_modified.ToTimeT()) { | 52           info.last_modified.ToTimeT()) { | 
| 55         return ERR_UPLOAD_FILE_CHANGED; | 53         return ERR_UPLOAD_FILE_CHANGED; | 
| 56       } | 54       } | 
| 57     } | 55     } | 
| 58   } | 56   } | 
| 59 | 57 | 
|  | 58   // Reset the offset, as upload_data_ may already be read (i.e. UploadData | 
|  | 59   // can be reused for a new UploadDataStream). | 
|  | 60   upload_data_->ResetOffset(); | 
|  | 61 | 
| 60   initialized_successfully_ = true; | 62   initialized_successfully_ = true; | 
| 61   return OK; | 63   return OK; | 
| 62 } | 64 } | 
| 63 | 65 | 
| 64 int UploadDataStream::Read(IOBuffer* buf, int buf_len) { | 66 int UploadDataStream::Read(IOBuffer* buf, int buf_len) { | 
| 65   std::vector<UploadData::Element>& elements = *upload_data_->elements(); | 67   std::vector<UploadData::Element>& elements = *upload_data_->elements(); | 
| 66 | 68 | 
| 67   int bytes_copied = 0; | 69   int bytes_copied = 0; | 
| 68   while (bytes_copied < buf_len && element_index_ < elements.size()) { | 70   while (bytes_copied < buf_len && element_index_ < elements.size()) { | 
| 69     bool advance_to_next_element = false; |  | 
| 70 |  | 
| 71     // This is not const as GetContentLength() is not const. |  | 
| 72     UploadData::Element& element = elements[element_index_]; | 71     UploadData::Element& element = elements[element_index_]; | 
| 73 | 72 | 
| 74     const size_t free_buffer_space = buf_len - bytes_copied; | 73     bytes_copied += element.ReadSync(buf->data() + bytes_copied, | 
| 75     if (element.type() == UploadData::TYPE_BYTES || | 74                                      buf_len - bytes_copied); | 
| 76         element.type() == UploadData::TYPE_CHUNK) { |  | 
| 77       const std::vector<char>& element_data = element.bytes(); |  | 
| 78       const size_t num_bytes_left_in_element = |  | 
| 79           element_data.size() - element_offset_; |  | 
| 80 | 75 | 
| 81       const size_t num_bytes_to_copy = std::min(num_bytes_left_in_element, | 76     if (element.BytesRemaining() == 0) | 
| 82                                                 free_buffer_space); | 77         ++element_index_; | 
| 83 |  | 
| 84       // Check if we have anything to copy first, because we are getting |  | 
| 85       // the address of an element in |element_data| and that will throw an |  | 
| 86       // exception if |element_data| is an empty vector. |  | 
| 87       if (num_bytes_to_copy > 0) { |  | 
| 88         memcpy(buf->data() + bytes_copied, &element_data[element_offset_], |  | 
| 89                num_bytes_to_copy); |  | 
| 90         bytes_copied += num_bytes_to_copy; |  | 
| 91         element_offset_ += num_bytes_to_copy; |  | 
| 92       } |  | 
| 93 |  | 
| 94       // Advance to the next element if we have consumed all data in the |  | 
| 95       // current element. |  | 
| 96       if (element_offset_ == element_data.size()) |  | 
| 97         advance_to_next_element = true; |  | 
| 98     } else { |  | 
| 99       DCHECK(element.type() == UploadData::TYPE_FILE); |  | 
| 100 |  | 
| 101       // Open the file of the current element if not yet opened. |  | 
| 102       if (!element_file_stream_.get()) { |  | 
| 103         element_file_bytes_remaining_ = element.GetContentLength(); |  | 
| 104         // Temporarily allow until fix: http://crbug.com/72001. |  | 
| 105         base::ThreadRestrictions::ScopedAllowIO allow_io; |  | 
| 106         element_file_stream_.reset(element.NewFileStreamForReading()); |  | 
| 107       } |  | 
| 108 |  | 
| 109       const int num_bytes_to_read = |  | 
| 110           static_cast<int>(std::min(element_file_bytes_remaining_, |  | 
| 111                                     static_cast<uint64>(free_buffer_space))); |  | 
| 112       if (num_bytes_to_read > 0) { |  | 
| 113         int num_bytes_consumed = 0; |  | 
| 114         // Temporarily allow until fix: http://crbug.com/72001. |  | 
| 115         base::ThreadRestrictions::ScopedAllowIO allow_io; |  | 
| 116         // element_file_stream_.get() is NULL if the target file is |  | 
| 117         // missing or not readable. |  | 
| 118         if (element_file_stream_.get()) { |  | 
| 119           num_bytes_consumed = |  | 
| 120               element_file_stream_->ReadSync(buf->data() + bytes_copied, |  | 
| 121                                              num_bytes_to_read); |  | 
| 122         } |  | 
| 123         if (num_bytes_consumed <= 0) { |  | 
| 124           // If there's less data to read than we initially observed, then |  | 
| 125           // pad with zero.  Otherwise the server will hang waiting for the |  | 
| 126           // rest of the data. |  | 
| 127           memset(buf->data() + bytes_copied, 0, num_bytes_to_read); |  | 
| 128           num_bytes_consumed = num_bytes_to_read; |  | 
| 129         } |  | 
| 130         bytes_copied += num_bytes_consumed; |  | 
| 131         element_file_bytes_remaining_ -= num_bytes_consumed; |  | 
| 132       } |  | 
| 133 |  | 
| 134       // Advance to the next element if we have consumed all data in the |  | 
| 135       // current element. |  | 
| 136       if (element_file_bytes_remaining_ == 0) |  | 
| 137         advance_to_next_element = true; |  | 
| 138     } |  | 
| 139 |  | 
| 140     if (advance_to_next_element) |  | 
| 141       AdvanceToNextElement(); |  | 
| 142 | 78 | 
| 143     if (is_chunked() && !merge_chunks_) | 79     if (is_chunked() && !merge_chunks_) | 
| 144       break; | 80       break; | 
| 145   } | 81   } | 
| 146 | 82 | 
| 147   current_position_ += bytes_copied; | 83   current_position_ += bytes_copied; | 
| 148   if (is_chunked() && !IsEOF() && bytes_copied == 0) | 84   if (is_chunked() && !IsEOF() && bytes_copied == 0) | 
| 149     return ERR_IO_PENDING; | 85     return ERR_IO_PENDING; | 
| 150 | 86 | 
| 151   return bytes_copied; | 87   return bytes_copied; | 
| 152 } | 88 } | 
| 153 | 89 | 
| 154 void UploadDataStream::AdvanceToNextElement() { |  | 
| 155   ++element_index_; |  | 
| 156   element_offset_ = 0; |  | 
| 157   element_file_bytes_remaining_ = 0; |  | 
| 158   if (element_file_stream_.get()) { |  | 
| 159     // Temporarily allow until fix: http://crbug.com/72001. |  | 
| 160     base::ThreadRestrictions::ScopedAllowIO allow_io; |  | 
| 161     element_file_stream_->CloseSync(); |  | 
| 162     element_file_stream_.reset(); |  | 
| 163   } |  | 
| 164 } |  | 
| 165 |  | 
| 166 bool UploadDataStream::IsEOF() const { | 90 bool UploadDataStream::IsEOF() const { | 
| 167   const std::vector<UploadData::Element>& elements = *upload_data_->elements(); | 91   const std::vector<UploadData::Element>& elements = *upload_data_->elements(); | 
| 168 | 92 | 
| 169   // Check if all elements are consumed. | 93   // Check if all elements are consumed. | 
| 170   if (element_index_ == elements.size()) { | 94   if (element_index_ == elements.size()) { | 
| 171     // If the upload data is chunked, check if the last element is the | 95     // If the upload data is chunked, check if the last element is the | 
| 172     // last chunk. | 96     // last chunk. | 
| 173     if (!upload_data_->is_chunked() || | 97     if (!upload_data_->is_chunked() || | 
| 174         (!elements.empty() && elements.back().is_last_chunk())) { | 98         (!elements.empty() && elements.back().is_last_chunk())) { | 
| 175       return true; | 99       return true; | 
| 176     } | 100     } | 
| 177   } | 101   } | 
| 178   return false; | 102   return false; | 
| 179 } | 103 } | 
| 180 | 104 | 
| 181 bool UploadDataStream::IsInMemory() const { | 105 bool UploadDataStream::IsInMemory() const { | 
| 182   DCHECK(initialized_successfully_); | 106   DCHECK(initialized_successfully_); | 
| 183 | 107 | 
| 184   return upload_data_->IsInMemory(); | 108   return upload_data_->IsInMemory(); | 
| 185 } | 109 } | 
| 186 | 110 | 
| 187 }  // namespace net | 111 }  // namespace net | 
| OLD | NEW | 
|---|