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_element.h" | 5 #include "net/base/upload_element.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/threading/thread_restrictions.h" | 10 #include "base/threading/thread_restrictions.h" |
11 #include "net/base/file_stream.h" | 11 #include "net/base/file_stream.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 UploadElement::UploadElement() | 16 UploadElement::UploadElement() |
17 : type_(TYPE_BYTES), | 17 : type_(TYPE_BYTES), |
18 bytes_start_(NULL), | 18 bytes_start_(NULL), |
19 bytes_length_(0), | 19 bytes_length_(0), |
20 file_range_offset_(0), | 20 file_range_offset_(0), |
21 file_range_length_(kuint64max), | 21 file_range_length_(kuint64max) { |
22 override_content_length_(false), | |
23 content_length_computed_(false), | |
24 content_length_(-1), | |
25 offset_(0), | |
26 file_stream_(NULL) { | |
27 } | 22 } |
28 | 23 |
29 UploadElement::~UploadElement() { | 24 UploadElement::~UploadElement() { |
30 // In the common case |file__stream_| will be null. | |
31 if (file_stream_) { | |
32 // Temporarily allow until fix: http://crbug.com/72001. | |
33 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
34 file_stream_->CloseSync(); | |
35 delete file_stream_; | |
36 } | |
37 } | |
38 | |
39 uint64 UploadElement::GetContentLength() { | |
40 if (override_content_length_ || content_length_computed_) | |
41 return content_length_; | |
42 | |
43 if (type_ == TYPE_BYTES) | |
44 return bytes_length(); | |
45 | |
46 DCHECK_EQ(TYPE_FILE, type_); | |
47 DCHECK(!file_stream_); | |
48 | |
49 // TODO(darin): This size calculation could be out of sync with the state of | |
50 // the file when we get around to reading it. We should probably find a way | |
51 // to lock the file or somehow protect against this error condition. | |
52 | |
53 content_length_computed_ = true; | |
54 content_length_ = 0; | |
55 | |
56 // We need to open the file here to decide if we should report the file's | |
57 // size or zero. We cache the open file, so that we can still read it when | |
58 // it comes time to. | |
59 file_stream_ = OpenFileStream(); | |
60 if (!file_stream_) | |
61 return 0; | |
62 | |
63 int64 length = 0; | |
64 if (!file_util::GetFileSize(file_path_, &length)) | |
65 return 0; | |
66 | |
67 if (file_range_offset_ >= static_cast<uint64>(length)) | |
68 return 0; // range is beyond eof | |
69 | |
70 // compensate for the offset and clip file_range_length_ to eof | |
71 content_length_ = std::min(length - file_range_offset_, file_range_length_); | |
72 return content_length_; | |
73 } | |
74 | |
75 int UploadElement::ReadSync(char* buf, int buf_len) { | |
76 if (type_ == TYPE_BYTES) { | |
77 return ReadFromMemorySync(buf, buf_len); | |
78 } else if (type_ == TYPE_FILE) { | |
79 return ReadFromFileSync(buf, buf_len); | |
80 } | |
81 | |
82 NOTREACHED(); | |
83 return 0; | |
84 } | |
85 | |
86 uint64 UploadElement::BytesRemaining() { | |
87 return GetContentLength() - offset_; | |
88 } | |
89 | |
90 void UploadElement::ResetOffset() { | |
91 offset_ = 0; | |
92 | |
93 // Delete the file stream if already opened, so we can reread the file from | |
94 // the beginning. | |
95 if (file_stream_) { | |
96 // Temporarily allow until fix: http://crbug.com/72001. | |
97 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
98 file_stream_->CloseSync(); | |
99 delete file_stream_; | |
100 file_stream_ = NULL; | |
101 } | |
102 } | |
103 | |
104 FileStream* UploadElement::OpenFileStream() { | |
105 scoped_ptr<FileStream> file(new FileStream(NULL)); | |
106 int64 rv = file->OpenSync( | |
107 file_path_, | |
108 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ); | |
109 if (rv != OK) { | |
110 // If the file can't be opened, we'll just upload an empty file. | |
111 DLOG(WARNING) << "Failed to open \"" << file_path_.value() | |
112 << "\" for reading: " << rv; | |
113 return NULL; | |
114 } | |
115 if (file_range_offset_) { | |
116 rv = file->SeekSync(FROM_BEGIN, file_range_offset_); | |
117 if (rv < 0) { | |
118 DLOG(WARNING) << "Failed to seek \"" << file_path_.value() | |
119 << "\" to offset: " << file_range_offset_ << " (" << rv | |
120 << ")"; | |
121 return NULL; | |
122 } | |
123 } | |
124 | |
125 return file.release(); | |
126 } | |
127 | |
128 int UploadElement::ReadFromMemorySync(char* buf, int buf_len) { | |
129 DCHECK_LT(0, buf_len); | |
130 DCHECK(type_ == TYPE_BYTES); | |
131 | |
132 const size_t num_bytes_to_read = std::min(BytesRemaining(), | |
133 static_cast<uint64>(buf_len)); | |
134 | |
135 // Check if we have anything to copy first, because we are getting | |
136 // the address of an element in |bytes_| and that will throw an | |
137 // exception if |bytes_| is an empty vector. | |
138 if (num_bytes_to_read > 0) | |
139 memcpy(buf, bytes() + offset_, num_bytes_to_read); | |
140 | |
141 offset_ += num_bytes_to_read; | |
142 return num_bytes_to_read; | |
143 } | |
144 | |
145 int UploadElement::ReadFromFileSync(char* buf, int buf_len) { | |
146 DCHECK_LT(0, buf_len); | |
147 DCHECK_EQ(TYPE_FILE, type_); | |
148 | |
149 // Open the file of the current element if not yet opened. | |
150 // In common usage, GetContentLength() opened it already. | |
151 if (!file_stream_) { | |
152 // Temporarily allow until fix: http://crbug.com/72001. | |
153 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
154 file_stream_ = OpenFileStream(); | |
155 } | |
156 | |
157 const int num_bytes_to_read = | |
158 static_cast<int>(std::min(BytesRemaining(), | |
159 static_cast<uint64>(buf_len))); | |
160 if (num_bytes_to_read > 0) { | |
161 int num_bytes_consumed = 0; | |
162 // Temporarily allow until fix: http://crbug.com/72001. | |
163 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
164 // file_stream_ is NULL if the target file is | |
165 // missing or not readable. | |
166 if (file_stream_) { | |
167 num_bytes_consumed = | |
168 file_stream_->ReadSync(buf, num_bytes_to_read); | |
169 } | |
170 if (num_bytes_consumed <= 0) { | |
171 // If there's less data to read than we initially observed, then | |
172 // pad with zero. Otherwise the server will hang waiting for the | |
173 // rest of the data. | |
174 memset(buf, 0, num_bytes_to_read); | |
175 } | |
176 } | |
177 | |
178 offset_ += num_bytes_to_read; | |
179 return num_bytes_to_read; | |
180 } | 25 } |
181 | 26 |
182 } // namespace net | 27 } // namespace net |
OLD | NEW |