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

Side by Side Diff: third_party/WebKit/Source/modules/fetch/MultipartParserTest.cpp

Issue 2292763002: [Fetch API] Implement Request.formData and Response.formData. (Closed)
Patch Set: Created 3 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
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "modules/fetch/MultipartParser.h"
6
7 #include "platform/HTTPNames.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9
10 #include <algorithm>
11 #include <string.h>
12
13 namespace blink {
14
15 namespace {
16
17 String toString(const Vector<char>& data) {
18 if (data.isEmpty())
19 return String("");
20 return String(data.data(), data.size());
21 }
22
23 class MockClient final : public GarbageCollectedFinalized<MockClient>,
24 public MultipartParser::Client {
25 USING_GARBAGE_COLLECTED_MIXIN(MockClient);
26
27 public:
28 struct Part {
29 Part() = default;
30 explicit Part(const HTTPHeaderMap& headerFields)
31 : headerFields(headerFields), dataFullyReceived(false) {}
32 HTTPHeaderMap headerFields;
33 Vector<char> data;
34 bool dataFullyReceived;
35 };
36 void partHeaderFieldsInMultipartReceived(
37 const HTTPHeaderMap& headerFields) override {
38 m_parts.append(headerFields);
39 }
40 void partDataInMultipartReceived(const char* bytes, size_t size) override {
41 m_parts.back().data.append(bytes, size);
42 }
43 void partDataInMultipartFullyReceived() override {
44 m_parts.back().dataFullyReceived = true;
45 }
46 size_t numberOfParts() const { return m_parts.size(); }
47 const Part& part(size_t partIndex) const {
48 EXPECT_LT(partIndex, numberOfParts());
49 return partIndex < numberOfParts() ? m_parts[partIndex] : m_emptyPart;
50 }
51
52 private:
53 Part m_emptyPart;
54 Vector<Part> m_parts;
55 };
56
57 constexpr char kBytes[] =
58 "preamble"
59 "\r\n--boundary\r\n\r\n"
60 "\r\n--boundary\r\ncontent-type: application/xhtml+xml\r\n\r\n1"
61 "\r\n--boundary\t\r\ncontent-type: "
62 "text/html\r\n\r\n2\r\n--\r\n--bound--\r\n--\r\n2\r\n"
63 "\r\n--boundary \r\ncontent-type: text/plain; charset=iso-8859-1\r\n\r\n333"
64 "\r\n--boundary--\t \r\n"
65 "epilogue";
66
67 TEST(MultipartParserTest, AppendDataInChunks) {
68 const size_t sizes[] = {1u, 2u, strlen(kBytes)};
69
70 Vector<char> boundary;
71 boundary.append("boundary", 8u);
72 for (const size_t size : sizes) {
73 MockClient* client = new MockClient;
74 MultipartParser* parser = new MultipartParser(boundary, client);
75
76 for (size_t i = 0u, length = strlen(kBytes); i < length; i += size)
77 EXPECT_TRUE(parser->appendData(kBytes + i, std::min(size, length - i)));
78 EXPECT_TRUE(parser->finish()) << " size=" << size;
79 EXPECT_EQ(4u, client->numberOfParts()) << " size=" << size;
80 EXPECT_EQ(0u, client->part(0).headerFields.size());
81 EXPECT_EQ(0u, client->part(0).data.size());
82 EXPECT_TRUE(client->part(0).dataFullyReceived);
83 EXPECT_EQ(1u, client->part(1).headerFields.size());
84 EXPECT_EQ("application/xhtml+xml",
85 client->part(1).headerFields.get(HTTPNames::Content_Type));
86 EXPECT_EQ("1", toString(client->part(1).data));
87 EXPECT_TRUE(client->part(1).dataFullyReceived);
88 EXPECT_EQ(1u, client->part(2).headerFields.size());
89 EXPECT_EQ("text/html",
90 client->part(2).headerFields.get(HTTPNames::Content_Type));
91 EXPECT_EQ("2\r\n--\r\n--bound--\r\n--\r\n2\r\n",
92 toString(client->part(2).data));
93 EXPECT_TRUE(client->part(2).dataFullyReceived);
94 EXPECT_EQ(1u, client->part(3).headerFields.size());
95 EXPECT_EQ("text/plain; charset=iso-8859-1",
96 client->part(3).headerFields.get(HTTPNames::Content_Type));
97 EXPECT_EQ("333", toString(client->part(3).data));
98 EXPECT_TRUE(client->part(3).dataFullyReceived);
99 }
100 }
101
102 TEST(MultipartParserTest, ContentTransferEncoding) {
103 constexpr const char* kBase64 = "base64";
104
105 constexpr char bytes1[] = "--boundary\r\ncontent-transfer-encoding: ";
106 constexpr char bytes2[] =
107 "\r\ncontent-type: application/xhtml+xml\r\n\r\nMQ==\r\n--boundary--\r\n";
108 constexpr const char* transferEncodings[] = {"binary", kBase64, "7bit",
109 "8bit"};
110
111 Vector<char> boundary;
112 boundary.append("boundary", 8u);
113 for (const char* const transferEncoding : transferEncodings) {
114 MockClient* client = new MockClient;
115 MultipartParser* parser = new MultipartParser(boundary, client);
116
117 EXPECT_TRUE(parser->appendData(bytes1, strlen(bytes1)));
118 EXPECT_TRUE(parser->appendData(transferEncoding, strlen(transferEncoding)));
119 if (transferEncoding == kBase64) {
120 EXPECT_FALSE(parser->appendData(
121 bytes2, strlen(bytes2))); // Unsupported transfer encoding.
122 EXPECT_EQ(0u, client->numberOfParts());
123 } else {
124 EXPECT_TRUE(parser->appendData(
125 bytes2, strlen(bytes2))); // No-op transfer encoding.
126 EXPECT_EQ(1u, client->numberOfParts());
127 EXPECT_EQ(2u, client->part(0).headerFields.size());
128 EXPECT_EQ(transferEncoding, client->part(0).headerFields.get(
129 HTTPNames::Content_Transfer_Encoding));
130 EXPECT_EQ("application/xhtml+xml",
131 client->part(0).headerFields.get(HTTPNames::Content_Type));
132 EXPECT_EQ("MQ==", toString(client->part(0).data));
133 EXPECT_TRUE(client->part(0).dataFullyReceived);
134 }
135 }
136 }
137
138 TEST(MultipartParserTest, Epilogue) {
139 constexpr size_t ends[] = {
140 0u, // Non-empty epilogue in the end.
141 8u, // Empty epilogue in the end.
142 9u, // Partial CRLF after close delimiter in the end.
143 10u, // No CRLF after close delimiter in the end.
144 12u, // No transport padding nor CRLF after close delimiter in the end.
145 13u, // Partial close delimiter in the end.
146 14u, // No close delimiter but a delimiter in the end.
147 15u // Partial delimiter in the end.
148 };
149
150 Vector<char> boundary;
151 boundary.append("boundary", 8u);
152 for (size_t end : ends) {
153 MockClient* client = new MockClient;
154 MultipartParser* parser = new MultipartParser(boundary, client);
155
156 EXPECT_TRUE(parser->appendData(kBytes, strlen(kBytes) - end));
157 EXPECT_EQ(end <= 12u, parser->finish()) << " end=" << end;
158 EXPECT_EQ(4u, client->numberOfParts()) << " end=" << end;
159 EXPECT_EQ(0u, client->part(0).headerFields.size());
160 EXPECT_EQ(0u, client->part(0).data.size());
161 EXPECT_TRUE(client->part(0).dataFullyReceived);
162 EXPECT_EQ(1u, client->part(1).headerFields.size());
163 EXPECT_EQ("application/xhtml+xml",
164 client->part(1).headerFields.get(HTTPNames::Content_Type));
165 EXPECT_EQ("1", toString(client->part(1).data));
166 EXPECT_TRUE(client->part(1).dataFullyReceived);
167 EXPECT_EQ(1u, client->part(2).headerFields.size());
168 EXPECT_EQ("text/html",
169 client->part(2).headerFields.get(HTTPNames::Content_Type));
170 EXPECT_EQ("2\r\n--\r\n--bound--\r\n--\r\n2\r\n",
171 toString(client->part(2).data));
172 EXPECT_TRUE(client->part(2).dataFullyReceived);
173 EXPECT_EQ(1u, client->part(3).headerFields.size());
174 EXPECT_EQ("text/plain; charset=iso-8859-1",
175 client->part(3).headerFields.get(HTTPNames::Content_Type));
176 switch (end) {
177 case 15u:
178 EXPECT_EQ("333\r\n--boundar", toString(client->part(3).data));
179 EXPECT_FALSE(client->part(3).dataFullyReceived);
180 break;
181 default:
182 EXPECT_EQ("333", toString(client->part(3).data));
183 EXPECT_TRUE(client->part(3).dataFullyReceived);
184 break;
185 }
186 }
187 }
188
189 TEST(MultipartParserTest, NoEndBoundary) {
190 constexpr char bytes[] =
191 "--boundary\r\ncontent-type: application/xhtml+xml\r\n\r\n1";
192
193 Vector<char> boundary;
194 boundary.append("boundary", 8u);
195 MockClient* client = new MockClient;
196 MultipartParser* parser = new MultipartParser(boundary, client);
197
198 EXPECT_TRUE(parser->appendData(bytes, strlen(bytes)));
199 EXPECT_FALSE(parser->finish()); // No close delimiter.
200 EXPECT_EQ(1u, client->numberOfParts());
201 EXPECT_EQ(1u, client->part(0).headerFields.size());
202 EXPECT_EQ("application/xhtml+xml",
203 client->part(0).headerFields.get(HTTPNames::Content_Type));
204 EXPECT_EQ("1", toString(client->part(0).data));
205 EXPECT_FALSE(client->part(0).dataFullyReceived);
206 }
207
208 TEST(MultipartParserTest, NoStartBoundary) {
209 constexpr char bytes[] =
210 "content-type: application/xhtml+xml\r\n\r\n1\r\n--boundary--\r\n";
211
212 Vector<char> boundary;
213 boundary.append("boundary", 8u);
214 MockClient* client = new MockClient;
215 MultipartParser* parser = new MultipartParser(boundary, client);
216
217 EXPECT_FALSE(parser->appendData(
218 bytes, strlen(bytes))); // Close delimiter before delimiter.
219 EXPECT_EQ(0u, client->numberOfParts());
220 }
221
222 TEST(MultipartParserTest, NoStartNorEndBoundary) {
223 constexpr char bytes[] = "content-type: application/xhtml+xml\r\n\r\n1";
224
225 Vector<char> boundary;
226 boundary.append("boundary", 8u);
227 MockClient* client = new MockClient;
228 MultipartParser* parser = new MultipartParser(boundary, client);
229
230 EXPECT_TRUE(parser->appendData(bytes, strlen(bytes))); // Valid preamble.
231 EXPECT_FALSE(parser->finish()); // No parts.
232 EXPECT_EQ(0u, client->numberOfParts());
233 }
234
235 constexpr size_t kStarts[] = {
236 0u, // Non-empty preamble in the beginning.
237 8u, // Empty preamble in the beginning.
238 9u, // Truncated delimiter in the beginning.
239 10u, // No preamble in the beginning.
240 11u // Truncated dash boundary in the beginning.
241 };
242
243 TEST(MultipartParserTest, Preamble) {
244 Vector<char> boundary;
245 boundary.append("boundary", 8u);
246 for (const size_t start : kStarts) {
247 MockClient* client = new MockClient;
248 MultipartParser* parser = new MultipartParser(boundary, client);
249
250 EXPECT_TRUE(parser->appendData(kBytes + start, strlen(kBytes + start)));
251 EXPECT_TRUE(parser->finish());
252 switch (start) {
253 case 9u:
254 case 11u:
255 EXPECT_EQ(3u, client->numberOfParts()) << " start=" << start;
256 EXPECT_EQ(1u, client->part(0).headerFields.size());
257 EXPECT_EQ("application/xhtml+xml",
258 client->part(0).headerFields.get(HTTPNames::Content_Type));
259 EXPECT_EQ("1", toString(client->part(0).data));
260 EXPECT_TRUE(client->part(0).dataFullyReceived);
261 EXPECT_EQ(1u, client->part(1).headerFields.size());
262 EXPECT_EQ("text/html",
263 client->part(1).headerFields.get(HTTPNames::Content_Type));
264 EXPECT_EQ("2\r\n--\r\n--bound--\r\n--\r\n2\r\n",
265 toString(client->part(1).data));
266 EXPECT_TRUE(client->part(1).dataFullyReceived);
267 EXPECT_EQ(1u, client->part(2).headerFields.size());
268 EXPECT_EQ("text/plain; charset=iso-8859-1",
269 client->part(2).headerFields.get(HTTPNames::Content_Type));
270 EXPECT_EQ("333", toString(client->part(2).data));
271 EXPECT_TRUE(client->part(2).dataFullyReceived);
272 break;
273 default:
274 EXPECT_EQ(4u, client->numberOfParts()) << " start=" << start;
275 EXPECT_EQ(0u, client->part(0).headerFields.size());
276 EXPECT_EQ(0u, client->part(0).data.size());
277 EXPECT_TRUE(client->part(0).dataFullyReceived);
278 EXPECT_EQ(1u, client->part(1).headerFields.size());
279 EXPECT_EQ("application/xhtml+xml",
280 client->part(1).headerFields.get(HTTPNames::Content_Type));
281 EXPECT_EQ("1", toString(client->part(1).data));
282 EXPECT_TRUE(client->part(1).dataFullyReceived);
283 EXPECT_EQ(1u, client->part(2).headerFields.size());
284 EXPECT_EQ("text/html",
285 client->part(2).headerFields.get(HTTPNames::Content_Type));
286 EXPECT_EQ("2\r\n--\r\n--bound--\r\n--\r\n2\r\n",
287 toString(client->part(2).data));
288 EXPECT_TRUE(client->part(2).dataFullyReceived);
289 EXPECT_EQ(1u, client->part(3).headerFields.size());
290 EXPECT_EQ("text/plain; charset=iso-8859-1",
291 client->part(3).headerFields.get(HTTPNames::Content_Type));
292 EXPECT_EQ("333", toString(client->part(3).data));
293 EXPECT_TRUE(client->part(3).dataFullyReceived);
294 break;
295 }
296 }
297 }
298
299 TEST(MultipartParserTest, PreambleWithMalformedBoundary) {
300 Vector<char> boundary;
301 boundary.append("--boundary", 10u);
302 for (const size_t start : kStarts) {
303 MockClient* client = new MockClient;
304 MultipartParser* parser = new MultipartParser(boundary, client);
305
306 EXPECT_TRUE(parser->appendData(kBytes + start,
307 strlen(kBytes + start))); // Valid preamble.
308 EXPECT_FALSE(parser->finish()); // No parts.
309 EXPECT_EQ(0u, client->numberOfParts());
310 }
311 }
312
313 } // namespace
314
315 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698