OLD | NEW |
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 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 "chrome/browser/chromeos/policy/upload_job_impl.h" | 5 #include "chrome/browser/chromeos/policy/upload_job_impl.h" |
6 | 6 |
| 7 #include <stddef.h> |
7 #include <set> | 8 #include <set> |
8 #include <utility> | 9 #include <utility> |
9 | 10 |
10 #include "base/logging.h" | 11 #include "base/logging.h" |
11 #include "base/macros.h" | 12 #include "base/macros.h" |
12 #include "base/rand_util.h" | |
13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
14 #include "google_apis/gaia/gaia_constants.h" | 14 #include "google_apis/gaia/gaia_constants.h" |
15 #include "google_apis/gaia/google_service_auth_error.h" | 15 #include "google_apis/gaia/google_service_auth_error.h" |
| 16 #include "net/base/mime_util.h" |
16 #include "net/http/http_status_code.h" | 17 #include "net/http/http_status_code.h" |
17 #include "net/url_request/url_request_status.h" | 18 #include "net/url_request/url_request_status.h" |
18 | 19 |
19 namespace policy { | 20 namespace policy { |
20 | 21 |
21 namespace { | 22 namespace { |
22 | 23 |
23 // Defines the characters that might appear in strings generated by | |
24 // GenerateRandomString(). | |
25 const char kAlphaNum[] = | |
26 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | |
27 | |
28 // Format for bearer tokens in HTTP requests to access OAuth 2.0 protected | 24 // Format for bearer tokens in HTTP requests to access OAuth 2.0 protected |
29 // resources. | 25 // resources. |
30 const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s"; | 26 const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s"; |
31 | 27 |
32 // Prefix added to a randomly generated string when choosing the MIME boundary. | |
33 const char kMultipartBoundaryPrefix[] = "----**--"; | |
34 | |
35 // Postfix added to a randomly generated string when choosing the MIME boundary. | |
36 const char kMultipartBoundaryPostfix[] = "--**----"; | |
37 | |
38 // Value the "Content-Type" field will be set to in the POST request. | 28 // Value the "Content-Type" field will be set to in the POST request. |
39 const char kUploadContentType[] = "multipart/form-data"; | 29 const char kUploadContentType[] = "multipart/form-data"; |
40 | 30 |
41 // Number of retries when randomly generating a MIME boundary. | |
42 const int kMimeBoundaryRetries = 3; | |
43 | |
44 // Length of the random string for the MIME boundary. | |
45 const int kMimeBoundarySize = 32; | |
46 | |
47 // Number of upload retries. | 31 // Number of upload retries. |
48 const int kMaxRetries = 1; | 32 const int kMaxRetries = 1; |
49 | 33 |
50 // Generates a random alphanumeric string of length |length|. | 34 // Max size of MIME boundary according to RFC 1341, section 7.2.1. |
51 std::string GenerateRandomString(size_t length) { | 35 const size_t kMaxMimeBoundarySize = 70; |
52 std::string random; | |
53 random.reserve(length); | |
54 for (size_t i = 0; i < length; i++) | |
55 random.push_back(kAlphaNum[base::RandGenerator(sizeof(kAlphaNum) - 1)]); | |
56 return random; | |
57 } | |
58 | 36 |
59 } // namespace | 37 } // namespace |
60 | 38 |
61 UploadJobImpl::Delegate::~Delegate() { | 39 UploadJobImpl::Delegate::~Delegate() { |
62 } | 40 } |
63 | 41 |
64 UploadJobImpl::MimeBoundaryGenerator::~MimeBoundaryGenerator() { | 42 UploadJobImpl::MimeBoundaryGenerator::~MimeBoundaryGenerator() { |
65 } | 43 } |
66 | 44 |
67 UploadJobImpl::RandomMimeBoundaryGenerator::~RandomMimeBoundaryGenerator() { | 45 UploadJobImpl::RandomMimeBoundaryGenerator::~RandomMimeBoundaryGenerator() { |
(...skipping 20 matching lines...) Expand all Loading... |
88 // header. If the |filename| is the empty string, the header field will be | 66 // header. If the |filename| is the empty string, the header field will be |
89 // omitted. | 67 // omitted. |
90 const std::string& GetFilename() const; | 68 const std::string& GetFilename() const; |
91 | 69 |
92 // Returns the data contained in this DataSegment. Ownership is passed. | 70 // Returns the data contained in this DataSegment. Ownership is passed. |
93 scoped_ptr<std::string> GetData(); | 71 scoped_ptr<std::string> GetData(); |
94 | 72 |
95 // Returns the size in bytes of the blob in |data_|. | 73 // Returns the size in bytes of the blob in |data_|. |
96 size_t GetDataSize() const; | 74 size_t GetDataSize() const; |
97 | 75 |
98 // Helper method that performs a substring match of |chunk| in |data_|. | |
99 // Returns |true| if |chunk| matches a substring, |false| otherwise. | |
100 bool CheckIfDataContains(const std::string& chunk); | |
101 | |
102 private: | 76 private: |
103 const std::string name_; | 77 const std::string name_; |
104 const std::string filename_; | 78 const std::string filename_; |
105 scoped_ptr<std::string> data_; | 79 scoped_ptr<std::string> data_; |
106 std::map<std::string, std::string> header_entries_; | 80 std::map<std::string, std::string> header_entries_; |
107 | 81 |
108 DISALLOW_COPY_AND_ASSIGN(DataSegment); | 82 DISALLOW_COPY_AND_ASSIGN(DataSegment); |
109 }; | 83 }; |
110 | 84 |
111 DataSegment::DataSegment( | 85 DataSegment::DataSegment( |
(...skipping 18 matching lines...) Expand all Loading... |
130 } | 104 } |
131 | 105 |
132 const std::string& DataSegment::GetFilename() const { | 106 const std::string& DataSegment::GetFilename() const { |
133 return filename_; | 107 return filename_; |
134 } | 108 } |
135 | 109 |
136 scoped_ptr<std::string> DataSegment::GetData() { | 110 scoped_ptr<std::string> DataSegment::GetData() { |
137 return std::move(data_); | 111 return std::move(data_); |
138 } | 112 } |
139 | 113 |
140 bool DataSegment::CheckIfDataContains(const std::string& chunk) { | |
141 DCHECK(data_); | |
142 return data_->find(chunk) != std::string::npos; | |
143 } | |
144 | |
145 size_t DataSegment::GetDataSize() const { | 114 size_t DataSegment::GetDataSize() const { |
146 DCHECK(data_); | 115 DCHECK(data_); |
147 return data_->size(); | 116 return data_->size(); |
148 } | 117 } |
149 | 118 |
150 std::string UploadJobImpl::RandomMimeBoundaryGenerator::GenerateBoundary( | 119 std::string UploadJobImpl::RandomMimeBoundaryGenerator::GenerateBoundary() |
151 size_t length) const { | 120 const { |
152 std::string boundary; | 121 return net::GenerateMimeMultipartBoundary(); |
153 boundary.reserve(length); | |
154 DCHECK_GT(length, sizeof(kMultipartBoundaryPrefix) + | |
155 sizeof(kMultipartBoundaryPostfix)); | |
156 const size_t random_part_length = length - sizeof(kMultipartBoundaryPrefix) - | |
157 sizeof(kMultipartBoundaryPostfix); | |
158 boundary.append(kMultipartBoundaryPrefix); | |
159 boundary.append(GenerateRandomString(random_part_length)); | |
160 boundary.append(kMultipartBoundaryPostfix); | |
161 return boundary; | |
162 } | 122 } |
163 | 123 |
164 UploadJobImpl::UploadJobImpl( | 124 UploadJobImpl::UploadJobImpl( |
165 const GURL& upload_url, | 125 const GURL& upload_url, |
166 const std::string& account_id, | 126 const std::string& account_id, |
167 OAuth2TokenService* token_service, | 127 OAuth2TokenService* token_service, |
168 scoped_refptr<net::URLRequestContextGetter> url_context_getter, | 128 scoped_refptr<net::URLRequestContextGetter> url_context_getter, |
169 Delegate* delegate, | 129 Delegate* delegate, |
170 scoped_ptr<MimeBoundaryGenerator> boundary_generator) | 130 scoped_ptr<MimeBoundaryGenerator> boundary_generator) |
171 : OAuth2TokenService::Consumer("cros_upload_job"), | 131 : OAuth2TokenService::Consumer("cros_upload_job"), |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 return true; | 189 return true; |
230 | 190 |
231 std::set<std::string> used_names; | 191 std::set<std::string> used_names; |
232 | 192 |
233 // Check uniqueness of header field names. | 193 // Check uniqueness of header field names. |
234 for (const auto& data_segment : data_segments_) { | 194 for (const auto& data_segment : data_segments_) { |
235 if (!used_names.insert(data_segment->GetName()).second) | 195 if (!used_names.insert(data_segment->GetName()).second) |
236 return false; | 196 return false; |
237 } | 197 } |
238 | 198 |
239 // Generates random MIME boundaries and tests if they appear in any of the | 199 mime_boundary_.reset( |
240 // data segments. Tries up to |kMimeBoundaryRetries| times to find a MIME | 200 new std::string(boundary_generator_->GenerateBoundary())); |
241 // boundary that does not appear within any data segment. | |
242 bool found = false; | |
243 int retry = 0; | |
244 do { | |
245 found = true; | |
246 mime_boundary_.reset(new std::string( | |
247 boundary_generator_->GenerateBoundary(kMimeBoundarySize))); | |
248 for (const auto& data_segment : data_segments_) { | |
249 if (data_segment->CheckIfDataContains(*mime_boundary_)) { | |
250 found = false; | |
251 break; | |
252 } | |
253 } | |
254 ++retry; | |
255 } while (!found && retry <= kMimeBoundaryRetries); | |
256 | |
257 // Notify the delegate that content encoding failed. | |
258 if (!found) { | |
259 delegate_->OnFailure(CONTENT_ENCODING_ERROR); | |
260 mime_boundary_.reset(); | |
261 return false; | |
262 } | |
263 | 201 |
264 // Estimate an upper bound for the total message size to make memory | 202 // Estimate an upper bound for the total message size to make memory |
265 // allocation more efficient. It is not an error if this turns out to be too | 203 // allocation more efficient. It is not an error if this turns out to be too |
266 // small as std::string will take care of the realloc. | 204 // small as std::string will take care of the realloc. |
267 size_t size = 0; | 205 size_t size = 0; |
268 for (const auto& data_segment : data_segments_) { | 206 for (const auto& data_segment : data_segments_) { |
269 for (const auto& entry : data_segment->GetHeaderEntries()) | 207 for (const auto& entry : data_segment->GetHeaderEntries()) |
270 size += entry.first.size() + entry.second.size(); | 208 size += entry.first.size() + entry.second.size(); |
271 size += kMimeBoundarySize + data_segment->GetName().size() + | 209 size += kMaxMimeBoundarySize + data_segment->GetName().size() + |
272 data_segment->GetFilename().size() + data_segment->GetDataSize(); | 210 data_segment->GetFilename().size() + data_segment->GetDataSize(); |
273 // Add some extra space for all the constants and control characters. | 211 // Add some extra space for all the constants and control characters. |
274 size += 128; | 212 size += 128; |
275 } | 213 } |
276 | 214 |
277 // Allocate memory of the expected size. | 215 // Allocate memory of the expected size. |
278 post_data_.reset(new std::string); | 216 post_data_.reset(new std::string); |
279 post_data_->reserve(size); | 217 post_data_->reserve(size); |
280 | 218 |
281 for (const auto& data_segment : data_segments_) { | 219 for (const auto& data_segment : data_segments_) { |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 if (success) { | 342 if (success) { |
405 state_ = SUCCESS; | 343 state_ = SUCCESS; |
406 delegate_->OnSuccess(); | 344 delegate_->OnSuccess(); |
407 } else { | 345 } else { |
408 state_ = ERROR; | 346 state_ = ERROR; |
409 delegate_->OnFailure(SERVER_ERROR); | 347 delegate_->OnFailure(SERVER_ERROR); |
410 } | 348 } |
411 } | 349 } |
412 | 350 |
413 } // namespace policy | 351 } // namespace policy |
OLD | NEW |