1 // Copyright (c) 2006-2008 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 <vector>
6
7 #include "base/basictypes.h"
8 #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
9 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
10 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLLoaderClient.h"
11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLResponse.h"
12 #include "webkit/glue/multipart_response_delegate.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 using std::string;
16 using WebKit::WebString;
17 using WebKit::WebURL;
18 using WebKit::WebURLError;
19 using WebKit::WebURLLoader;
20 using WebKit::WebURLLoaderClient;
21 using WebKit::WebURLRequest;
22 using WebKit::WebURLResponse;
23 using webkit_glue::MultipartResponseDelegate;
24 using webkit_glue::MultipartResponseDelegateTester;
25
26 namespace webkit_glue {
27
28 class MultipartResponseDelegateTester {
29 public:
MultipartResponseDelegateTester(MultipartResponseDelegate * delegate)30 MultipartResponseDelegateTester(MultipartResponseDelegate* delegate)
31 : delegate_(delegate) {
32 }
33
PushOverLine(const std::string & data,size_t pos)34 int PushOverLine(const std::string& data, size_t pos) {
35 return delegate_->PushOverLine(data, pos);
36 }
37
ParseHeaders()38 bool ParseHeaders() { return delegate_->ParseHeaders(); }
FindBoundary()39 size_t FindBoundary() { return delegate_->FindBoundary(); }
boundary()40 std::string& boundary() { return delegate_->boundary_; }
data()41 std::string& data() { return delegate_->data_; }
42
43 private:
44 MultipartResponseDelegate* delegate_;
45 };
46
47 } // namespace webkit_glue
48
49 namespace {
50
51 class MultipartResponseTest : public testing::Test {
52 };
53
54 class MockWebURLLoaderClient : public WebURLLoaderClient {
55 public:
MockWebURLLoaderClient()56 MockWebURLLoaderClient() { Reset(); }
57
willSendRequest(WebURLLoader *,WebURLRequest &,const WebURLResponse &)58 virtual void willSendRequest(
59 WebURLLoader*, WebURLRequest&, const WebURLResponse&) {}
didSendData(WebURLLoader *,unsigned long long,unsigned long long)60 virtual void didSendData(
61 WebURLLoader*, unsigned long long, unsigned long long) {}
62
didReceiveResponse(WebURLLoader * loader,const WebURLResponse & response)63 virtual void didReceiveResponse(WebURLLoader* loader,
64 const WebURLResponse& response) {
65 ++received_response_;
66 response_ = response;
67 data_.clear();
68 }
didReceiveData(WebKit::WebURLLoader * loader,const char * data,int data_length,int encoded_data_length)69 virtual void didReceiveData(
70 WebKit::WebURLLoader* loader,
71 const char* data,
72 int data_length,
73 int encoded_data_length) {
74 ++received_data_;
75 data_.append(data, data_length);
76 total_encoded_data_length_ += encoded_data_length;
77 }
didFinishLoading(WebURLLoader *,double finishTime)78 virtual void didFinishLoading(WebURLLoader*, double finishTime) {}
didFail(WebURLLoader *,const WebURLError &)79 virtual void didFail(WebURLLoader*, const WebURLError&) {}
80
Reset()81 void Reset() {
82 received_response_ = received_data_ = total_encoded_data_length_ = 0;
83 data_.clear();
84 response_.reset();
85 }
86
GetResponseHeader(const char * name) const87 string GetResponseHeader(const char* name) const {
88 return string(response_.httpHeaderField(WebString::fromUTF8(name)).utf8());
89 }
90
91 int received_response_, received_data_, total_encoded_data_length_;
92 string data_;
93 WebURLResponse response_;
94 };
95
96 // We can't put this in an anonymous function because it's a friend class for
97 // access to private members.
TEST(MultipartResponseTest,Functions)98 TEST(MultipartResponseTest, Functions) {
99 // PushOverLine tests
100
101 WebURLResponse response;
102 response.initialize();
103 response.setMIMEType("multipart/x-mixed-replace");
104 response.setHTTPHeaderField("Foo", "Bar");
105 response.setHTTPHeaderField("Content-type", "text/plain");
106 MockWebURLLoaderClient client;
107 MultipartResponseDelegate delegate(&client, NULL, response, "bound");
108 MultipartResponseDelegateTester delegate_tester(&delegate);
109
110 struct {
111 const char* input;
112 const int position;
113 const int expected;
114 } line_tests[] = {
115 { "Line", 0, 0 },
116 { "Line", 2, 0 },
117 { "Line", 10, 0 },
118 { "\r\nLine", 0, 2 },
119 { "\nLine", 0, 1 },
120 { "\n\nLine", 0, 2 },
121 { "\rLine", 0, 1 },
122 { "Line\r\nLine", 4, 2 },
123 { "Line\nLine", 4, 1 },
124 { "Line\n\nLine", 4, 2 },
125 { "Line\rLine", 4, 1 },
126 { "Line\r\rLine", 4, 1 },
127 };
128 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(line_tests); ++i) {
129 EXPECT_EQ(line_tests[i].expected,
130 delegate_tester.PushOverLine(line_tests[i].input,
131 line_tests[i].position));
132 }
133
134 // ParseHeaders tests
135 struct {
136 const char* data;
137 const bool rv;
138 const int received_response_calls;
139 const char* newdata;
140 } header_tests[] = {
141 { "This is junk", false, 0, "This is junk" },
142 { "Foo: bar\nBaz:\n\nAfter:\n", true, 1, "After:\n" },
143 { "Foo: bar\nBaz:\n", false, 0, "Foo: bar\nBaz:\n" },
144 { "Foo: bar\r\nBaz:\r\n\r\nAfter:\r\n", true, 1, "After:\r\n" },
145 { "Foo: bar\r\nBaz:\r\n", false, 0, "Foo: bar\r\nBaz:\r\n" },
146 { "Foo: bar\nBaz:\r\n\r\nAfter:\n\n", true, 1, "After:\n\n" },
147 { "Foo: bar\r\nBaz:\n", false, 0, "Foo: bar\r\nBaz:\n" },
148 { "\r\n", true, 1, "" },
149 };
150 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(header_tests); ++i) {
151 client.Reset();
152 delegate_tester.data().assign(header_tests[i].data);
153 EXPECT_EQ(header_tests[i].rv,
154 delegate_tester.ParseHeaders());
155 EXPECT_EQ(header_tests[i].received_response_calls,
156 client.received_response_);
157 EXPECT_EQ(string(header_tests[i].newdata),
158 delegate_tester.data());
159 }
160 // Test that the resource response is filled in correctly when parsing
161 // headers.
162 client.Reset();
163 string test_header("content-type: image/png\ncontent-length: 10\n\n");
164 delegate_tester.data().assign(test_header);
165 EXPECT_TRUE(delegate_tester.ParseHeaders());
166 EXPECT_TRUE(delegate_tester.data().length() == 0);
167 EXPECT_EQ(string("image/png"), client.GetResponseHeader("Content-Type"));
168 EXPECT_EQ(string("10"), client.GetResponseHeader("content-length"));
169 // This header is passed from the original request.
170 EXPECT_EQ(string("Bar"), client.GetResponseHeader("foo"));
171
172 // Make sure we parse the right mime-type if a charset is provided.
173 client.Reset();
174 string test_header2("content-type: text/html; charset=utf-8\n\n");
175 delegate_tester.data().assign(test_header2);
176 EXPECT_TRUE(delegate_tester.ParseHeaders());
177 EXPECT_TRUE(delegate_tester.data().length() == 0);
178 EXPECT_EQ(string("text/html; charset=utf-8"),
179 client.GetResponseHeader("Content-Type"));
180 EXPECT_EQ(string("utf-8"),
181 string(client.response_.textEncodingName().utf8()));
182
183 // FindBoundary tests
184 struct {
185 const char* boundary;
186 const char* data;
187 const size_t position;
188 } boundary_tests[] = {
189 { "bound", "bound", 0 },
190 { "bound", "--bound", 0 },
191 { "bound", "junkbound", 4 },
192 { "bound", "junk--bound", 4 },
193 { "foo", "bound", string::npos },
194 { "bound", "--boundbound", 0 },
195 };
196 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(boundary_tests); ++i) {
197 delegate_tester.boundary().assign(boundary_tests[i].boundary);
198 delegate_tester.data().assign(boundary_tests[i].data);
199 EXPECT_EQ(boundary_tests[i].position,
200 delegate_tester.FindBoundary());
201 }
202 }
203
TEST(MultipartResponseTest,MissingBoundaries)204 TEST(MultipartResponseTest, MissingBoundaries) {
205 WebURLResponse response;
206 response.initialize();
207 response.setMIMEType("multipart/x-mixed-replace");
208 response.setHTTPHeaderField("Foo", "Bar");
209 response.setHTTPHeaderField("Content-type", "text/plain");
210 MockWebURLLoaderClient client;
211 MultipartResponseDelegate delegate(&client, NULL, response, "bound");
212
213 // No start boundary
214 string no_start_boundary(
215 "Content-type: text/plain\n\n"
216 "This is a sample response\n"
217 "--bound--"
218 "ignore junk after end token --bound\n\nTest2\n");
219 delegate.OnReceivedData(no_start_boundary.c_str(),
220 static_cast<int>(no_start_boundary.length()),
221 static_cast<int>(no_start_boundary.length()));
222 EXPECT_EQ(1, client.received_response_);
223 EXPECT_EQ(1, client.received_data_);
224 EXPECT_EQ(string("This is a sample response"), client.data_);
225 EXPECT_EQ(static_cast<int>(no_start_boundary.length()),
226 client.total_encoded_data_length_);
227
228 delegate.OnCompletedRequest();
229 EXPECT_EQ(1, client.received_response_);
230 EXPECT_EQ(1, client.received_data_);
231
232 // No end boundary
233 client.Reset();
234 MultipartResponseDelegate delegate2(&client, NULL, response, "bound");
235 string no_end_boundary(
236 "bound\nContent-type: text/plain\n\n"
237 "This is a sample response\n");
238 delegate2.OnReceivedData(no_end_boundary.c_str(),
239 static_cast<int>(no_end_boundary.length()),
240 static_cast<int>(no_end_boundary.length()));
241 EXPECT_EQ(1, client.received_response_);
242 EXPECT_EQ(1, client.received_data_);
243 EXPECT_EQ("This is a sample response\n", client.data_);
244 EXPECT_EQ(static_cast<int>(no_end_boundary.length()),
245 client.total_encoded_data_length_);
246
247 delegate2.OnCompletedRequest();
248 EXPECT_EQ(1, client.received_response_);
249 EXPECT_EQ(1, client.received_data_);
250 EXPECT_EQ(string("This is a sample response\n"), client.data_);
251 EXPECT_EQ(static_cast<int>(no_end_boundary.length()),
252 client.total_encoded_data_length_);
253
254 // Neither boundary
255 client.Reset();
256 MultipartResponseDelegate delegate3(&client, NULL, response, "bound");
257 string no_boundaries(
258 "Content-type: text/plain\n\n"
259 "This is a sample response\n");
260 delegate3.OnReceivedData(no_boundaries.c_str(),
261 static_cast<int>(no_boundaries.length()),
262 static_cast<int>(no_boundaries.length()));
263 EXPECT_EQ(1, client.received_response_);
264 EXPECT_EQ(1, client.received_data_);
265 EXPECT_EQ("This is a sample response\n", client.data_);
266 EXPECT_EQ(static_cast<int>(no_boundaries.length()),
267 client.total_encoded_data_length_);
268
269 delegate3.OnCompletedRequest();
270 EXPECT_EQ(1, client.received_response_);
271 EXPECT_EQ(1, client.received_data_);
272 EXPECT_EQ(string("This is a sample response\n"), client.data_);
273 EXPECT_EQ(static_cast<int>(no_boundaries.length()),
274 client.total_encoded_data_length_);
275 }
276
TEST(MultipartResponseTest,MalformedBoundary)277 TEST(MultipartResponseTest, MalformedBoundary) {
278 // Some servers send a boundary that is prefixed by "--". See bug 5786.
279
280 WebURLResponse response;
281 response.initialize();
282 response.setMIMEType("multipart/x-mixed-replace");
283 response.setHTTPHeaderField("Foo", "Bar");
284 response.setHTTPHeaderField("Content-type", "text/plain");
285 MockWebURLLoaderClient client;
286 MultipartResponseDelegate delegate(&client, NULL, response, "--bound");
287
288 string data(
289 "--bound\n"
290 "Content-type: text/plain\n\n"
291 "This is a sample response\n"
292 "--bound--"
293 "ignore junk after end token --bound\n\nTest2\n");
294 delegate.OnReceivedData(data.c_str(),
295 static_cast<int>(data.length()),
296 static_cast<int>(data.length()));
297 EXPECT_EQ(1, client.received_response_);
298 EXPECT_EQ(1, client.received_data_);
299 EXPECT_EQ(string("This is a sample response"), client.data_);
300 EXPECT_EQ(static_cast<int>(data.length()), client.total_encoded_data_length_);
301
302 delegate.OnCompletedRequest();
303 EXPECT_EQ(1, client.received_response_);
304 EXPECT_EQ(1, client.received_data_);
305 }
306
307
308 // Used in for tests that break the data in various places.
309 struct TestChunk {
310 const int start_pos; // offset in data
311 const int end_pos; // end offset in data
312 const int expected_responses;
313 const int expected_received_data;
314 const char* expected_data;
315 const int expected_encoded_data_length;
316 };
317
VariousChunkSizesTest(const TestChunk chunks[],int chunks_size,int responses,int received_data,const char * completed_data,int completed_encoded_data_length)318 void VariousChunkSizesTest(const TestChunk chunks[], int chunks_size,
319 int responses, int received_data,
320 const char* completed_data,
321 int completed_encoded_data_length) {
322 const string data(
323 "--bound\n" // 0-7
324 "Content-type: image/png\n\n" // 8-32
325 "datadatadatadatadata" // 33-52
326 "--bound\n" // 53-60
327 "Content-type: image/jpg\n\n" // 61-85
328 "foofoofoofoofoo" // 86-100
329 "--bound--"); // 101-109
330
331 WebURLResponse response;
332 response.initialize();
333 response.setMIMEType("multipart/x-mixed-replace");
334 MockWebURLLoaderClient client;
335 MultipartResponseDelegate delegate(&client, NULL, response, "bound");
336
337 for (int i = 0; i < chunks_size; ++i) {
338 ASSERT_TRUE(chunks[i].start_pos < chunks[i].end_pos);
339 string chunk = data.substr(chunks[i].start_pos,
340 chunks[i].end_pos - chunks[i].start_pos);
341 delegate.OnReceivedData(
342 chunk.c_str(),
343 static_cast<int>(chunk.length()),
344 static_cast<int>(chunk.length()));
345 EXPECT_EQ(chunks[i].expected_responses, client.received_response_);
346 EXPECT_EQ(chunks[i].expected_received_data, client.received_data_);
347 EXPECT_EQ(string(chunks[i].expected_data), client.data_);
348 EXPECT_EQ(chunks[i].expected_encoded_data_length,
349 client.total_encoded_data_length_);
350 }
351 // Check final state
352 delegate.OnCompletedRequest();
353 EXPECT_EQ(responses, client.received_response_);
354 EXPECT_EQ(received_data, client.received_data_);
355 string completed_data_string(completed_data);
356 EXPECT_EQ(completed_data_string, client.data_);
357 EXPECT_EQ(completed_encoded_data_length, client.total_encoded_data_length_);
358 }
359
TEST(MultipartResponseTest,BreakInBoundary)360 TEST(MultipartResponseTest, BreakInBoundary) {
361 // Break in the first boundary
362 const TestChunk bound1[] = {
363 { 0, 4, 0, 0, "", 0 },
364 { 4, 110, 2, 2, "foofoofoofoofoo", 110 },
365 };
366 VariousChunkSizesTest(bound1, arraysize(bound1),
367 2, 2, "foofoofoofoofoo", 110);
368
369 // Break in first and second
370 const TestChunk bound2[] = {
371 { 0, 4, 0, 0, "", 0 },
372 { 4, 55, 1, 1, "datadatadatadat", 55 },
373 { 55, 65, 1, 2, "datadatadatadatadata", 65 },
374 { 65, 110, 2, 3, "foofoofoofoofoo", 110 },
375 };
376 VariousChunkSizesTest(bound2, arraysize(bound2),
377 2, 3, "foofoofoofoofoo", 110);
378
379 // Break in second only
380 const TestChunk bound3[] = {
381 { 0, 55, 1, 1, "datadatadatadat", 55 },
382 { 55, 110, 2, 3, "foofoofoofoofoo", 110 },
383 };
384 VariousChunkSizesTest(bound3, arraysize(bound3),
385 2, 3, "foofoofoofoofoo", 110);
386 }
387
TEST(MultipartResponseTest,BreakInHeaders)388 TEST(MultipartResponseTest, BreakInHeaders) {
389 // Break in first header
390 const TestChunk header1[] = {
391 { 0, 10, 0, 0, "", 0 },
392 { 10, 35, 1, 0, "", 0 },
393 { 35, 110, 2, 2, "foofoofoofoofoo", 110 },
394 };
395 VariousChunkSizesTest(header1, arraysize(header1),
396 2, 2, "foofoofoofoofoo", 110);
397
398 // Break in both headers
399 const TestChunk header2[] = {
400 { 0, 10, 0, 0, "", 0 },
401 { 10, 65, 1, 1, "datadatadatadatadata", 65 },
402 { 65, 110, 2, 2, "foofoofoofoofoo", 110 },
403 };
404 VariousChunkSizesTest(header2, arraysize(header2),
405 2, 2, "foofoofoofoofoo", 110);
406
407 // Break at end of a header
408 const TestChunk header3[] = {
409 { 0, 33, 1, 0, "", 0 },
410 { 33, 65, 1, 1, "datadatadatadatadata", 65 },
411 { 65, 110, 2, 2, "foofoofoofoofoo", 110 },
412 };
413 VariousChunkSizesTest(header3, arraysize(header3),
414 2, 2, "foofoofoofoofoo", 110);
415 }
416
TEST(MultipartResponseTest,BreakInData)417 TEST(MultipartResponseTest, BreakInData) {
418 // All data as one chunk
419 const TestChunk data1[] = {
420 { 0, 110, 2, 2, "foofoofoofoofoo", 110 },
421 };
422 VariousChunkSizesTest(data1, arraysize(data1),
423 2, 2, "foofoofoofoofoo", 110);
424
425 // breaks in data segment
426 const TestChunk data2[] = {
427 { 0, 35, 1, 0, "", 0 },
428 { 35, 65, 1, 1, "datadatadatadatadata", 65 },
429 { 65, 90, 2, 1, "", 65 },
430 { 90, 110, 2, 2, "foofoofoofoofoo", 110 },
431 };
432 VariousChunkSizesTest(data2, arraysize(data2),
433 2, 2, "foofoofoofoofoo", 110);
434
435 // Incomplete send
436 const TestChunk data3[] = {
437 { 0, 35, 1, 0, "", 0 },
438 { 35, 90, 2, 1, "", 90 },
439 };
440 VariousChunkSizesTest(data3, arraysize(data3),
441 2, 2, "foof", 90);
442 }
443
TEST(MultipartResponseTest,SmallChunk)444 TEST(MultipartResponseTest, SmallChunk) {
445 WebURLResponse response;
446 response.initialize();
447 response.setMIMEType("multipart/x-mixed-replace");
448 response.setHTTPHeaderField("Content-type", "text/plain");
449 MockWebURLLoaderClient client;
450 MultipartResponseDelegate delegate(&client, NULL, response, "bound");
451
452 // Test chunks of size 1, 2, and 0.
453 string data(
454 "--boundContent-type: text/plain\n\n"
455 "\n--boundContent-type: text/plain\n\n"
456 "\n\n--boundContent-type: text/plain\n\n"
457 "--boundContent-type: text/plain\n\n"
458 "end--bound--");
459 delegate.OnReceivedData(data.c_str(),
460 static_cast<int>(data.length()),
461 static_cast<int>(data.length()));
462 EXPECT_EQ(4, client.received_response_);
463 EXPECT_EQ(2, client.received_data_);
464 EXPECT_EQ(string("end"), client.data_);
465 EXPECT_EQ(static_cast<int>(data.length()), client.total_encoded_data_length_);
466
467 delegate.OnCompletedRequest();
468 EXPECT_EQ(4, client.received_response_);
469 EXPECT_EQ(2, client.received_data_);
470 }
471
TEST(MultipartResponseTest,MultipleBoundaries)472 TEST(MultipartResponseTest, MultipleBoundaries) {
473 // Test multiple boundaries back to back
474 WebURLResponse response;
475 response.initialize();
476 response.setMIMEType("multipart/x-mixed-replace");
477 MockWebURLLoaderClient client;
478 MultipartResponseDelegate delegate(&client, NULL, response, "bound");
479
480 string data("--bound\r\n\r\n--bound\r\n\r\nfoofoo--bound--");
481 delegate.OnReceivedData(data.c_str(),
482 static_cast<int>(data.length()),
483 static_cast<int>(data.length()));
484 EXPECT_EQ(2, client.received_response_);
485 EXPECT_EQ(1, client.received_data_);
486 EXPECT_EQ(string("foofoo"), client.data_);
487 EXPECT_EQ(static_cast<int>(data.length()), client.total_encoded_data_length_);
488 }
489
TEST(MultipartResponseTest,MultipartByteRangeParsingTest)490 TEST(MultipartResponseTest, MultipartByteRangeParsingTest) {
491 // Test multipart/byteranges based boundary parsing.
492 WebURLResponse response1;
493 response1.initialize();
494 response1.setMIMEType("multipart/x-mixed-replace");
495 response1.setHTTPHeaderField("Content-Length", "200");
496 response1.setHTTPHeaderField("Content-type",
497 "multipart/byteranges; boundary=--bound--");
498
499 std::string multipart_boundary;
500 bool result = MultipartResponseDelegate::ReadMultipartBoundary(
501 response1, &multipart_boundary);
502 EXPECT_EQ(result, true);
503 EXPECT_EQ(string("--bound--"),
504 multipart_boundary);
505
506 WebURLResponse response2;
507 response2.initialize();
508 response2.setMIMEType("image/png");
509
510 response2.setHTTPHeaderField("Content-Length", "300");
511 response2.setHTTPHeaderField("Last-Modified",
512 "Mon, 04 Apr 2005 20:36:01 GMT");
513 response2.setHTTPHeaderField("Date", "Thu, 11 Sep 2008 18:21:42 GMT");
514
515 multipart_boundary.clear();
516 result = MultipartResponseDelegate::ReadMultipartBoundary(
517 response2, &multipart_boundary);
518 EXPECT_EQ(result, false);
519
520 WebURLResponse response3;
521 response3.initialize();
522 response3.setMIMEType("multipart/byteranges");
523
524 response3.setHTTPHeaderField("Content-Length", "300");
525 response3.setHTTPHeaderField("Last-Modified",
526 "Mon, 04 Apr 2005 20:36:01 GMT");
527 response3.setHTTPHeaderField("Date", "Thu, 11 Sep 2008 18:21:42 GMT");
528 response3.setHTTPHeaderField("Content-type", "multipart/byteranges");
529
530 multipart_boundary.clear();
531 result = MultipartResponseDelegate::ReadMultipartBoundary(
532 response3, &multipart_boundary);
533 EXPECT_EQ(result, false);
534 EXPECT_EQ(multipart_boundary.length(), 0U);
535
536 WebURLResponse response4;
537 response4.initialize();
538 response4.setMIMEType("multipart/byteranges");
539 response4.setHTTPHeaderField("Content-Length", "200");
540 response4.setHTTPHeaderField("Content-type",
541 "multipart/byteranges; boundary=--bound--; charSet=utf8");
542
543 multipart_boundary.clear();
544
545 result = MultipartResponseDelegate::ReadMultipartBoundary(
546 response4, &multipart_boundary);
547 EXPECT_EQ(result, true);
548 EXPECT_EQ(string("--bound--"), multipart_boundary);
549
550 WebURLResponse response5;
551 response5.initialize();
552 response5.setMIMEType("multipart/byteranges");
553 response5.setHTTPHeaderField("Content-Length", "200");
554 response5.setHTTPHeaderField("Content-type",
555 "multipart/byteranges; boundary=\"--bound--\"; charSet=utf8");
556
557 multipart_boundary.clear();
558
559 result = MultipartResponseDelegate::ReadMultipartBoundary(
560 response5, &multipart_boundary);
561 EXPECT_EQ(result, true);
562 EXPECT_EQ(string("--bound--"), multipart_boundary);
563 }
564
TEST(MultipartResponseTest,MultipartContentRangesTest)565 TEST(MultipartResponseTest, MultipartContentRangesTest) {
566 WebURLResponse response1;
567 response1.initialize();
568 response1.setMIMEType("application/pdf");
569 response1.setHTTPHeaderField("Content-Length", "200");
570 response1.setHTTPHeaderField("Content-Range", "bytes 1000-1050/5000");
571
572 int content_range_lower_bound = 0;
573 int content_range_upper_bound = 0;
574 int content_range_instance_size = 0;
575
576 bool result = MultipartResponseDelegate::ReadContentRanges(
577 response1, &content_range_lower_bound,
578 &content_range_upper_bound,
579 &content_range_instance_size);
580
581 EXPECT_EQ(result, true);
582 EXPECT_EQ(content_range_lower_bound, 1000);
583 EXPECT_EQ(content_range_upper_bound, 1050);
584
585 WebURLResponse response2;
586 response2.initialize();
587 response2.setMIMEType("application/pdf");
588 response2.setHTTPHeaderField("Content-Length", "200");
589 response2.setHTTPHeaderField("Content-Range", "bytes 1000/1050");
590
591 content_range_lower_bound = 0;
592 content_range_upper_bound = 0;
593 content_range_instance_size = 0;
594
595 result = MultipartResponseDelegate::ReadContentRanges(
596 response2, &content_range_lower_bound,
597 &content_range_upper_bound,
598 &content_range_instance_size);
599
600 EXPECT_EQ(result, false);
601
602 WebURLResponse response3;
603 response3.initialize();
604 response3.setMIMEType("application/pdf");
605 response3.setHTTPHeaderField("Content-Length", "200");
606 response3.setHTTPHeaderField("Range", "bytes 1000-1050/5000");
607
608 content_range_lower_bound = 0;
609 content_range_upper_bound = 0;
610 content_range_instance_size = 0;
611
612 result = MultipartResponseDelegate::ReadContentRanges(
613 response3, &content_range_lower_bound,
614 &content_range_upper_bound,
615 &content_range_instance_size);
616
617 EXPECT_EQ(result, true);
618 EXPECT_EQ(content_range_lower_bound, 1000);
619 EXPECT_EQ(content_range_upper_bound, 1050);
620
621 WebURLResponse response4;
622 response4.initialize();
623 response4.setMIMEType("application/pdf");
624 response4.setHTTPHeaderField("Content-Length", "200");
625
626 content_range_lower_bound = 0;
627 content_range_upper_bound = 0;
628 content_range_instance_size = 0;
629
630 result = MultipartResponseDelegate::ReadContentRanges(
631 response4, &content_range_lower_bound,
632 &content_range_upper_bound,
633 &content_range_instance_size);
634
635 EXPECT_EQ(result, false);
636 }
637
TEST(MultipartResponseTest,MultipartPayloadSet)638 TEST(MultipartResponseTest, MultipartPayloadSet) {
639 WebURLResponse response;
640 response.initialize();
641 response.setMIMEType("multipart/x-mixed-replace");
642 MockWebURLLoaderClient client;
643 MultipartResponseDelegate delegate(&client, NULL, response, "bound");
644
645 string data(
646 "--bound\n"
647 "Content-type: text/plain\n\n"
648 "response data\n"
649 "--bound\n");
650 delegate.OnReceivedData(data.c_str(),
651 static_cast<int>(data.length()),
652 static_cast<int>(data.length()));
653 EXPECT_EQ(1, client.received_response_);
654 EXPECT_EQ(string("response data"), client.data_);
655 EXPECT_EQ(static_cast<int>(data.length()), client.total_encoded_data_length_);
656 EXPECT_FALSE(client.response_.isMultipartPayload());
657
658 string data2(
659 "Content-type: text/plain\n\n"
660 "response data2\n"
661 "--bound\n");
662 delegate.OnReceivedData(data2.c_str(),
663 static_cast<int>(data2.length()),
664 static_cast<int>(data2.length()));
665 EXPECT_EQ(2, client.received_response_);
666 EXPECT_EQ(string("response data2"), client.data_);
667 EXPECT_EQ(static_cast<int>(data.length()) + static_cast<int>(data2.length()),
668 client.total_encoded_data_length_);
669 EXPECT_TRUE(client.response_.isMultipartPayload());
670 }
671
672 } // namespace
673