Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(27)

Side by Side Diff: chrome/browser/chromeos/policy/upload_job_impl.cc

Issue 1547593002: Introducing a net::GenerateMimeMultipartBoundary helper. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebasing... Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698