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

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

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

Powered by Google App Engine
This is Rietveld 408576698