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 <set> | 7 #include <set> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/macros.h" | 11 #include "base/macros.h" |
12 #include "base/rand_util.h" | 12 #include "base/rand_util.h" |
bartfab (slow)
2016/01/05 14:20:45
Nit: No longer used.
Łukasz Anforowicz
2016/01/05 19:16:48
Done.
| |
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; |
bartfab (slow)
2016/01/05 14:20:45
Nit: #include <stddef.h>
Łukasz Anforowicz
2016/01/05 19:16:48
Done.
| |
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 22 matching lines...) Expand all Loading... | |
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_|. | 76 // Helper method that performs a substring match of |chunk| in |data_|. |
99 // Returns |true| if |chunk| matches a substring, |false| otherwise. | 77 // Returns |true| if |chunk| matches a substring, |false| otherwise. |
100 bool CheckIfDataContains(const std::string& chunk); | 78 bool CheckIfDataContains(const std::string& chunk); |
bartfab (slow)
2016/01/05 14:20:45
Nit: This method is no longer used.
Łukasz Anforowicz
2016/01/05 19:16:48
Done. Thanks for catching this and other places w
| |
101 | 79 |
102 private: | 80 private: |
103 const std::string name_; | 81 const std::string name_; |
104 const std::string filename_; | 82 const std::string filename_; |
105 scoped_ptr<std::string> data_; | 83 scoped_ptr<std::string> data_; |
106 std::map<std::string, std::string> header_entries_; | 84 std::map<std::string, std::string> header_entries_; |
107 | 85 |
108 DISALLOW_COPY_AND_ASSIGN(DataSegment); | 86 DISALLOW_COPY_AND_ASSIGN(DataSegment); |
109 }; | 87 }; |
110 | 88 |
(...skipping 29 matching lines...) Expand all Loading... | |
140 bool DataSegment::CheckIfDataContains(const std::string& chunk) { | 118 bool DataSegment::CheckIfDataContains(const std::string& chunk) { |
141 DCHECK(data_); | 119 DCHECK(data_); |
142 return data_->find(chunk) != std::string::npos; | 120 return data_->find(chunk) != std::string::npos; |
143 } | 121 } |
144 | 122 |
145 size_t DataSegment::GetDataSize() const { | 123 size_t DataSegment::GetDataSize() const { |
146 DCHECK(data_); | 124 DCHECK(data_); |
147 return data_->size(); | 125 return data_->size(); |
148 } | 126 } |
149 | 127 |
150 std::string UploadJobImpl::RandomMimeBoundaryGenerator::GenerateBoundary( | 128 std::string UploadJobImpl::RandomMimeBoundaryGenerator::GenerateBoundary() |
151 size_t length) const { | 129 const { |
152 std::string boundary; | 130 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 } | 131 } |
163 | 132 |
164 UploadJobImpl::UploadJobImpl( | 133 UploadJobImpl::UploadJobImpl( |
165 const GURL& upload_url, | 134 const GURL& upload_url, |
166 const std::string& account_id, | 135 const std::string& account_id, |
167 OAuth2TokenService* token_service, | 136 OAuth2TokenService* token_service, |
168 scoped_refptr<net::URLRequestContextGetter> url_context_getter, | 137 scoped_refptr<net::URLRequestContextGetter> url_context_getter, |
169 Delegate* delegate, | 138 Delegate* delegate, |
170 scoped_ptr<MimeBoundaryGenerator> boundary_generator) | 139 scoped_ptr<MimeBoundaryGenerator> boundary_generator) |
171 : OAuth2TokenService::Consumer("cros_upload_job"), | 140 : OAuth2TokenService::Consumer("cros_upload_job"), |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
229 return true; | 198 return true; |
230 | 199 |
231 std::set<std::string> used_names; | 200 std::set<std::string> used_names; |
232 | 201 |
233 // Check uniqueness of header field names. | 202 // Check uniqueness of header field names. |
234 for (const auto& data_segment : data_segments_) { | 203 for (const auto& data_segment : data_segments_) { |
235 if (!used_names.insert(data_segment->GetName()).second) | 204 if (!used_names.insert(data_segment->GetName()).second) |
236 return false; | 205 return false; |
237 } | 206 } |
238 | 207 |
239 // Generates random MIME boundaries and tests if they appear in any of the | 208 mime_boundary_.reset( |
240 // data segments. Tries up to |kMimeBoundaryRetries| times to find a MIME | 209 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); | |
bartfab (slow)
2016/01/05 14:20:45
Nit: Remove CONTENT_ENCODING_ERROR from upload_job
Łukasz Anforowicz
2016/01/05 19:16:48
Done.
| |
260 mime_boundary_.reset(); | |
261 return false; | |
262 } | |
263 | 210 |
264 // Estimate an upper bound for the total message size to make memory | 211 // 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 | 212 // 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. | 213 // small as std::string will take care of the realloc. |
267 size_t size = 0; | 214 size_t size = 0; |
268 for (const auto& data_segment : data_segments_) { | 215 for (const auto& data_segment : data_segments_) { |
269 for (const auto& entry : data_segment->GetHeaderEntries()) | 216 for (const auto& entry : data_segment->GetHeaderEntries()) |
270 size += entry.first.size() + entry.second.size(); | 217 size += entry.first.size() + entry.second.size(); |
271 size += kMimeBoundarySize + data_segment->GetName().size() + | 218 size += kMaxMimeBoundarySize + data_segment->GetName().size() + |
272 data_segment->GetFilename().size() + data_segment->GetDataSize(); | 219 data_segment->GetFilename().size() + data_segment->GetDataSize(); |
273 // Add some extra space for all the constants and control characters. | 220 // Add some extra space for all the constants and control characters. |
274 size += 128; | 221 size += 128; |
275 } | 222 } |
276 | 223 |
277 // Allocate memory of the expected size. | 224 // Allocate memory of the expected size. |
278 post_data_.reset(new std::string); | 225 post_data_.reset(new std::string); |
279 post_data_->reserve(size); | 226 post_data_->reserve(size); |
280 | 227 |
281 for (const auto& data_segment : data_segments_) { | 228 for (const auto& data_segment : data_segments_) { |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
404 if (success) { | 351 if (success) { |
405 state_ = SUCCESS; | 352 state_ = SUCCESS; |
406 delegate_->OnSuccess(); | 353 delegate_->OnSuccess(); |
407 } else { | 354 } else { |
408 state_ = ERROR; | 355 state_ = ERROR; |
409 delegate_->OnFailure(SERVER_ERROR); | 356 delegate_->OnFailure(SERVER_ERROR); |
410 } | 357 } |
411 } | 358 } |
412 | 359 |
413 } // namespace policy | 360 } // namespace policy |
OLD | NEW |