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

Side by Side Diff: third_party/WebKit/Source/core/fetch/MultipartImageResourceParserTest.cpp

Issue 1693183002: Move multipart resource handling to core/fetch (1/2) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@multipart-cleanup-preliminary
Patch Set: Created 4 years, 9 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 "core/fetch/MultipartImageResourceParser.h"
6
7 #include "platform/network/ResourceResponse.h"
8 #include "public/platform/WebURL.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <string.h>
14
15 namespace blink {
16
17 namespace {
18
19 String toString(const Vector<char>& data)
20 {
21 if (data.isEmpty())
22 return String("");
23 return String(data.data(), data.size());
24 }
25
26 class MultipartResponseTest : public testing::Test {
27 };
28
29 class MockClient final : public NoBaseWillBeGarbageCollectedFinalized<MockClient >, public MultipartImageResourceParser::Client {
30 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(MockClient);
31
32 public:
33 void didReceiveResponse(const ResourceResponse& response) override
34 {
35 m_responses.append(response);
36 m_data.append(Vector<char>());
37 }
38 void didReceiveData(const char* bytes, size_t size) override
39 {
40 m_data.last().append(bytes, size);
41 }
42
43 Vector<ResourceResponse> m_responses;
44 Vector<Vector<char>> m_data;
hiroshige 2016/02/25 21:36:27 nit: These tests do not test how many times didRec
yhirano 2016/02/26 22:21:51 I think it's OK because ImageResource doesn't upda
hiroshige 2016/02/29 16:57:07 Acknowledged.
45 };
46
47 // We can't put this in an anonymous function because it's a friend class for
48 // access to private members.
hiroshige 2016/02/25 21:36:27 nit: We can remove this comment as we no longer ha
yhirano 2016/02/26 22:21:51 Done.
49 TEST(MultipartResponseTest, PushOverLine)
50 {
51 struct {
52 const char* input;
53 const int position;
54 const int expected;
55 } lineTests[] = {
56 { "Line", 0, 0 },
57 { "Line", 2, 0 },
58 { "Line", 10, 0 },
59 { "\r\nLine", 0, 2 },
60 { "\nLine", 0, 1 },
61 { "\n\nLine", 0, 2 },
62 { "\rLine", 0, 1 },
63 { "Line\r\nLine", 4, 2 },
64 { "Line\nLine", 4, 1 },
65 { "Line\n\nLine", 4, 2 },
66 { "Line\rLine", 4, 1 },
67 { "Line\r\rLine", 4, 1 },
68 };
69 for (size_t i = 0; i < WTF_ARRAY_LENGTH(lineTests); ++i) {
70 Vector<char> input;
71 input.append(lineTests[i].input, strlen(lineTests[i].input));
72 EXPECT_EQ(lineTests[i].expected,
73 MultipartImageResourceParser::pushOverLineForTest(input, lineTests[i ].position));
74 }
75 }
76
77 TEST(MultipartResponseTest, FindBoundary)
78 {
79 struct {
80 const char* boundary;
81 const char* data;
82 const size_t position;
83 } boundaryTests[] = {
84 { "bound", "bound", 0 },
85 { "bound", "--bound", 0 },
86 { "bound", "junkbound", 4 },
87 { "bound", "junk--bound", 4 },
88 { "foo", "bound", kNotFound },
89 { "bound", "--boundbound", 0 },
90 };
91
92 for (size_t i = 0; i < WTF_ARRAY_LENGTH(boundaryTests); ++i) {
93 Vector<char> boundary, data;
94 boundary.append(boundaryTests[i].boundary, strlen(boundaryTests[i].bound ary));
95 data.append(boundaryTests[i].data, strlen(boundaryTests[i].data));
96 EXPECT_EQ(boundaryTests[i].position, MultipartImageResourceParser::findB oundaryForTest(data, &boundary));
97 }
98 }
99
100 TEST(MultipartResponseTest, NoStartBoundary)
101 {
102 ResourceResponse response;
103 response.setMimeType("multipart/x-mixed-replace");
104 response.setHTTPHeaderField("Foo", "Bar");
105 response.setHTTPHeaderField("Content-type", "text/plain");
106 MockClient* client = new MockClient;
107 Vector<char> boundary;
108 boundary.append("bound", 5);
109
110 MultipartImageResourceParser* parser = new MultipartImageResourceParser(resp onse, boundary, client);
111 const char data[] =
112 "Content-type: text/plain\n\n"
113 "This is a sample response\n"
114 "--bound--"
115 "ignore junk after end token --bound\n\nTest2\n";
116 parser->addData(data, strlen(data));
117 ASSERT_EQ(1u, client->m_responses.size());
118 ASSERT_EQ(1u, client->m_data.size());
119 EXPECT_EQ("This is a sample response", toString(client->m_data[0]));
120
121 parser->finish();
122 ASSERT_EQ(1u, client->m_responses.size());
123 ASSERT_EQ(1u, client->m_data.size());
124 EXPECT_EQ("This is a sample response", toString(client->m_data[0]));
125 }
126
127 TEST(MultipartResponseTest, NoEndBoundary)
128 {
129 ResourceResponse response;
130 response.setMimeType("multipart/x-mixed-replace");
131 response.setHTTPHeaderField("Foo", "Bar");
132 response.setHTTPHeaderField("Content-type", "text/plain");
133 MockClient* client = new MockClient;
134 Vector<char> boundary;
135 boundary.append("bound", 5);
136
137 MultipartImageResourceParser* parser = new MultipartImageResourceParser(resp onse, boundary, client);
138 const char data[] =
139 "bound\nContent-type: text/plain\n\n"
140 "This is a sample response\n";
141 parser->addData(data, strlen(data));
142 ASSERT_EQ(1u, client->m_responses.size());
143 ASSERT_EQ(1u, client->m_data.size());
144 EXPECT_EQ("This is a sample response\n", toString(client->m_data[0]));
145
146 parser->finish();
147 ASSERT_EQ(1u, client->m_responses.size());
148 ASSERT_EQ(1u, client->m_data.size());
149 EXPECT_EQ("This is a sample response\n", toString(client->m_data[0]));
150 }
151
152 TEST(MultipartResponseTest, NoStartAndEndBoundary)
153 {
154 ResourceResponse response;
155 response.setMimeType("multipart/x-mixed-replace");
156 response.setHTTPHeaderField("Foo", "Bar");
157 response.setHTTPHeaderField("Content-type", "text/plain");
158 MockClient* client = new MockClient;
159 Vector<char> boundary;
160 boundary.append("bound", 5);
161
162 MultipartImageResourceParser* parser = new MultipartImageResourceParser(resp onse, boundary, client);
163 const char data[] =
164 "Content-type: text/plain\n\n"
165 "This is a sample response\n";
166 parser->addData(data, strlen(data));
167 ASSERT_EQ(1u, client->m_responses.size());
168 ASSERT_EQ(1u, client->m_data.size());
169 EXPECT_EQ("This is a sample response\n", toString(client->m_data[0]));
170
171 parser->finish();
172 ASSERT_EQ(1u, client->m_responses.size());
173 ASSERT_EQ(1u, client->m_data.size());
174 EXPECT_EQ("This is a sample response\n", toString(client->m_data[0]));
175 }
176
177 TEST(MultipartResponseTest, MalformedBoundary)
178 {
179 // Some servers send a boundary that is prefixed by "--". See bug 5786.
180 ResourceResponse response;
181 response.setMimeType("multipart/x-mixed-replace");
182 response.setHTTPHeaderField("Foo", "Bar");
183 response.setHTTPHeaderField("Content-type", "text/plain");
184 MockClient* client = new MockClient;
185 Vector<char> boundary;
186 boundary.append("bound", 5);
hiroshige 2016/02/25 21:36:27 Perhaps this should be "--bound"? (Line 289 of con
yhirano 2016/02/26 22:21:51 Done.
187
188 MultipartImageResourceParser* parser = new MultipartImageResourceParser(resp onse, boundary, client);
189 const char data[] =
190 "--bound\n"
191 "Content-type: text/plain\n\n"
192 "This is a sample response\n"
193 "--bound--"
194 "ignore junk after end token --bound\n\nTest2\n";
195 parser->addData(data, strlen(data));
196 ASSERT_EQ(1u, client->m_responses.size());
197 ASSERT_EQ(1u, client->m_data.size());
198 EXPECT_EQ("This is a sample response", toString(client->m_data[0]));
199
200 parser->finish();
201 ASSERT_EQ(1u, client->m_responses.size());
202 ASSERT_EQ(1u, client->m_data.size());
203 EXPECT_EQ("This is a sample response", toString(client->m_data[0]));
204 }
205
206 // Used in for tests that break the data in various places.
207 struct TestChunk {
208 const int startPosition; // offset in data
209 const int endPosition; // end offset in data
210 const size_t expectedResponses;
211 const char* expectedData;
212 };
213
214 void VariousChunkSizesTest(const TestChunk chunks[], int chunks_size,
hiroshige 2016/02/25 21:36:27 nit: |variousChunkSizesTest()|, |chunksSize|, |rec
yhirano 2016/02/26 22:21:51 Done.
215 size_t responses, int received_data,
216 const char* completedData)
217 {
218 const char data[] =
219 "--bound\n" // 0-7
220 "Content-type: image/png\n\n" // 8-32
221 "datadatadatadatadata" // 33-52
222 "--bound\n" // 53-60
223 "Content-type: image/jpg\n\n" // 61-85
224 "foofoofoofoofoo" // 86-100
225 "--bound--"; // 101-109
226
227 ResourceResponse response;
228 response.setMimeType("multipart/x-mixed-replace");
229 MockClient* client = new MockClient;
230 Vector<char> boundary;
231 boundary.append("bound", 5);
232
233 MultipartImageResourceParser* parser = new MultipartImageResourceParser(resp onse, boundary, client);
234
235 for (int i = 0; i < chunks_size; ++i) {
236 ASSERT_TRUE(chunks[i].startPosition < chunks[i].endPosition);
hiroshige 2016/02/25 21:36:27 nit: ASSERT_LE() can be used.
yhirano 2016/02/26 22:21:51 Done.
237 parser->addData(data + chunks[i].startPosition, chunks[i].endPosition - chunks[i].startPosition);
238 EXPECT_EQ(chunks[i].expectedResponses, client->m_responses.size());
239 EXPECT_EQ(String(chunks[i].expectedData), client->m_data.size() > 0 ? to String(client->m_data.last()) : String(""));
240 }
241 // Check final state
242 parser->finish();
243 EXPECT_EQ(responses, client->m_responses.size());
244 EXPECT_EQ(completedData, toString(client->m_data.last()));
245 }
246
247 template <size_t N>
248 void VariousChunkSizesTest(const TestChunk (&chunks)[N], size_t responses, int r eceived_data, const char* completedData)
hiroshige 2016/02/25 21:36:27 ditto > Line 214.
yhirano 2016/02/26 22:21:51 Done.
249 {
250 VariousChunkSizesTest(chunks, N, responses, received_data, completedData);
251 }
252
253 TEST(MultipartResponseTest, BreakInBoundary)
254 {
255 // Break in the first boundary
256 const TestChunk bound1[] = {
257 { 0, 4, 0, "" },
258 { 4, 110, 2, "foofoofoofoofoo" },
259 };
260 VariousChunkSizesTest(bound1, 2, 2, "foofoofoofoofoo");
261
262 // Break in first and second
263 const TestChunk bound2[] = {
264 { 0, 4, 0, "" },
265 { 4, 55, 1, "datadatadatadat" },
266 { 55, 65, 1, "datadatadatadatadata" },
267 { 65, 110, 2, "foofoofoofoofoo" },
268 };
269 VariousChunkSizesTest(bound2, 2, 3, "foofoofoofoofoo");
270
271 // Break in second only
272 const TestChunk bound3[] = {
273 { 0, 55, 1, "datadatadatadat" },
274 { 55, 110, 2, "foofoofoofoofoo" },
275 };
276 VariousChunkSizesTest(bound3, 2, 3, "foofoofoofoofoo");
277 }
278
279 TEST(MultipartResponseTest, BreakInHeaders)
280 {
281 // Break in first header
282 const TestChunk header1[] = {
283 { 0, 10, 0, "" },
284 { 10, 35, 1, "" },
285 { 35, 110, 2, "foofoofoofoofoo" },
286 };
287 VariousChunkSizesTest(header1, 2, 2, "foofoofoofoofoo");
288
289 // Break in both headers
290 const TestChunk header2[] = {
291 { 0, 10, 0, "" },
292 { 10, 65, 1, "datadatadatadatadata" },
293 { 65, 110, 2, "foofoofoofoofoo" },
294 };
295 VariousChunkSizesTest(header2, 2, 2, "foofoofoofoofoo");
296
297 // Break at end of a header
298 const TestChunk header3[] = {
299 { 0, 33, 1, "" },
300 { 33, 65, 1, "datadatadatadatadata" },
301 { 65, 110, 2, "foofoofoofoofoo" },
302 };
303 VariousChunkSizesTest(header3, 2, 2, "foofoofoofoofoo");
304 }
305
306 TEST(MultipartResponseTest, BreakInData)
307 {
308 // All data as one chunk
309 const TestChunk data1[] = {
310 { 0, 110, 2, "foofoofoofoofoo" },
311 };
312 VariousChunkSizesTest(data1, 2, 2, "foofoofoofoofoo");
313
314 // breaks in data segment
315 const TestChunk data2[] = {
316 { 0, 35, 1, "" },
317 { 35, 65, 1, "datadatadatadatadata" },
318 { 65, 90, 2, "" },
319 { 90, 110, 2, "foofoofoofoofoo" },
320 };
321 VariousChunkSizesTest(data2, 2, 2, "foofoofoofoofoo");
322
323 // Incomplete send
324 const TestChunk data3[] = {
325 { 0, 35, 1, "" },
326 { 35, 90, 2, "" },
327 };
328 VariousChunkSizesTest(data3, 2, 2, "foof");
329 }
330
331 TEST(MultipartResponseTest, SmallChunk)
332 {
333 ResourceResponse response;
334 response.setMimeType("multipart/x-mixed-replace");
335 response.setHTTPHeaderField("Content-type", "text/plain");
336 MockClient* client = new MockClient;
337 Vector<char> boundary;
338 boundary.append("bound", 5);
339
340 MultipartImageResourceParser* parser = new MultipartImageResourceParser(resp onse, boundary, client);
341
342 // Test chunks of size 1, 2, and 0.
343 const char data[] =
344 "--boundContent-type: text/plain\n\n"
345 "\n--boundContent-type: text/plain\n\n"
346 "\n\n--boundContent-type: text/plain\n\n"
347 "--boundContent-type: text/plain\n\n"
348 "end--bound--";
349 parser->addData(data, strlen(data));
350 ASSERT_EQ(4u, client->m_responses.size());
351 ASSERT_EQ(4u, client->m_data.size());
352 EXPECT_EQ("", toString(client->m_data[0]));
353 EXPECT_EQ("\n", toString(client->m_data[1]));
354 EXPECT_EQ("", toString(client->m_data[2]));
355 EXPECT_EQ("end", toString(client->m_data[3]));
356
357 parser->finish();
358 ASSERT_EQ(4u, client->m_responses.size());
359 ASSERT_EQ(4u, client->m_data.size());
360 EXPECT_EQ("", toString(client->m_data[0]));
361 EXPECT_EQ("\n", toString(client->m_data[1]));
362 EXPECT_EQ("", toString(client->m_data[2]));
363 EXPECT_EQ("end", toString(client->m_data[3]));
364 }
365
366 TEST(MultipartResponseTest, MultipleBoundaries)
367 {
368 // Test multiple boundaries back to back
369 ResourceResponse response;
370 response.setMimeType("multipart/x-mixed-replace");
371 MockClient* client = new MockClient;
372 Vector<char> boundary;
373 boundary.append("bound", 5);
374
375 MultipartImageResourceParser* parser = new MultipartImageResourceParser(resp onse, boundary, client);
376
377 const char data[] = "--bound\r\n\r\n--bound\r\n\r\nfoofoo--bound--";
378 parser->addData(data, strlen(data));
379 ASSERT_EQ(2u, client->m_responses.size());
380 ASSERT_EQ(2u, client->m_data.size());
381 EXPECT_EQ("", toString(client->m_data[0]));
382 EXPECT_EQ("foofoo", toString(client->m_data[1]));
383 }
384
385 TEST(MultipartResponseTest, MultipartPayloadSet)
386 {
387 ResourceResponse response;
388 response.setMimeType("multipart/x-mixed-replace");
389 MockClient* client = new MockClient;
390 Vector<char> boundary;
391 boundary.append("bound", 5);
392
393 MultipartImageResourceParser* parser = new MultipartImageResourceParser(resp onse, boundary, client);
394
395 const char data[] =
396 "--bound\n"
397 "Content-type: text/plain\n\n"
398 "response data\n"
399 "--bound\n";
400 parser->addData(data, strlen(data));
401 ASSERT_EQ(1u, client->m_responses.size());
402 ASSERT_EQ(1u, client->m_data.size());
403 EXPECT_EQ("response data", toString(client->m_data[0]));
404 EXPECT_FALSE(client->m_responses[0].isMultipartPayload());
405
406 const char data2[] =
407 "Content-type: text/plain\n\n"
408 "response data2\n"
409 "--bound\n";
410 parser->addData(data2, strlen(data2));
411 ASSERT_EQ(2u, client->m_responses.size());
412 ASSERT_EQ(2u, client->m_data.size());
413 EXPECT_EQ("response data2", toString(client->m_data[1]));
414 EXPECT_TRUE(client->m_responses[1].isMultipartPayload());
415 }
416
417 } // namespace
418
419 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698