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

Side by Side Diff: util/net/http_multipart_builder.cc

Issue 681303003: Add HTTPMultipartBuilder and its test. (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Created 6 years, 1 month 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
(Empty)
1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util/net/http_multipart_builder.h"
16
17 #include <vector>
18
19 #include "base/rand_util.h"
20 #include "base/strings/stringprintf.h"
21 #include "util/net/http_body.h"
22
23 namespace crashpad {
24
25 HTTPMultipartBuilder::HTTPMultipartBuilder()
26 : form_data_(), file_attachments_() {
27 }
28
29 HTTPMultipartBuilder::~HTTPMultipartBuilder() {
30 }
31
32 void HTTPMultipartBuilder::SetFormData(const std::string& key,
33 const std::string& value) {
34 form_data_[key] = value;
35 }
36
37 void HTTPMultipartBuilder::SetFileAttachment(
38 const std::string& upload_file_name,
39 const base::FilePath& path) {
40 file_attachments_[upload_file_name] = path;
41 }
42
43 scoped_ptr<HTTPBodyStream> HTTPMultipartBuilder::GetBodyStream() {
44 std::vector<HTTPBodyStream*> streams;
45 std::string boundary = GenerateBoundaryString();
46
47 for (const auto& pair : form_data_) {
48 std::string field = GetFormDataBoundary(boundary, pair.first);
49 field += pair.second;
50 field += "\r\n";
51 streams.push_back(new StringHTTPBodyStream(field));
Mark Mentovai 2014/10/28 22:34:28 It’s a little scuzzy for all of these new objects
Robert Sesek 2014/10/29 19:52:01 Done.
52 }
53
54 for (const auto& pair : file_attachments_) {
55 streams.push_back(
56 new StringHTTPBodyStream(GetFormDataBoundary(boundary, pair.first)));
57 streams.push_back(new FileHTTPBodyStream(pair.second));
58 streams.push_back(new StringHTTPBodyStream("\r\n"));
59 }
60
61 return scoped_ptr<HTTPBodyStream>(new CompositeHTTPBodyStream(streams));
Mark Mentovai 2014/10/28 22:34:28 You need a terminating boundary too, which should
Robert Sesek 2014/10/29 19:52:01 I was originally going to handle this in Transport
62 }
63
64 // static
65 std::string HTTPMultipartBuilder::GenerateBoundaryString() {
66 // RFC 2046 §5.1.1 says that the boundary string may be 1 to 70 characters
67 // long, choosing from the set of alphanumeric characters along with
68 // characters from the set “'()+_,-./:=? ”, and not ending in a space.
69 // However, some servers have been observed as dealing poorly with certain
70 // nonalphanumeric characters. See
71 // blink/Source/platform/network/FormDataBuilder.cpp
72 // blink::FormDataBuilder::generateUniqueBoundaryString().
73 //
74 // This implementation produces a 56-character string with over 190 bits of
75 // randomness (62^32 > 2^190).
76 std::string boundary_string = "---MultipartBoundary-";
77 for (int index = 0; index < 32; ++index) {
78 const char kCharacters[] =
79 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
80 int random_value = base::RandGenerator(strlen(kCharacters));
81 boundary_string += kCharacters[random_value];
82 }
83 boundary_string += "---";
84 return boundary_string;
85 }
86
87 // static
88 std::string HTTPMultipartBuilder::EncodeFieldName(const std::string& name) {
89 // RFC 2388 §3 says to encode non-ASCII field names according to RFC 2047, but
90 // no browsers implement that behavior. Instead, they send field names in the
91 // page hosting the form’s encoding. However, some form of escaping is needed.
92 // This URL-escapes the quote character and newline characters, per Blink. See
93 // blink/Source/platform/network/FormDataBuilder.cpp
94 // blink::appendQuotedString().
95 //
96 // TODO(mark): This encoding is not necessarily correct, and the same code in
97 // Blink is marked with a FIXME. Blink does not escape the '%' character,
98 // that’s a local addition, but it seems appropriate to be able to decode the
99 // string properly.
100 std::string encoded;
101 for (char character : name) {
102 switch (character) {
103 case '\r':
104 case '\n':
105 case '"':
106 case '%':
107 encoded += base::StringPrintf("%%%02x", character);
108 break;
109 default:
110 encoded += character;
111 break;
112 }
113 }
114
115 return encoded;
116 }
117
118 // static
119 std::string HTTPMultipartBuilder::GetFormDataBoundary(
120 const std::string& boundary,
121 const std::string& name) {
122 return base::StringPrintf(
123 "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n",
124 boundary.c_str(),
125 EncodeFieldName(name).c_str());
126 }
127
128 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698