1 // Copyright (c) 2011 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 "testing/gtest/include/gtest/gtest.h" 9 #include "third_party/WebKit/public/platform/WebString.h" 10 #include "third_party/WebKit/public/platform/WebURL.h" 11 #include "third_party/WebKit/public/platform/WebURLLoaderClient.h" 12 #include "third_party/WebKit/public/platform/WebURLResponse.h" 13 #include "webkit/child/multipart_response_delegate.h" 14 15 using std::string; 16 using blink::WebString; 17 using blink::WebURL; 18 using blink::WebURLError; 19 using blink::WebURLLoader; 20 using blink::WebURLLoaderClient; 21 using blink::WebURLRequest; 22 using blink::WebURLResponse; 23 using webkit_glue::MultipartResponseDelegate; 24 using webkit_glue::MultipartResponseDelegateTester; 25 26 namespace webkit_glue { 27 28 class MultipartResponseDelegateTester { 29 public: 30 MultipartResponseDelegateTester(MultipartResponseDelegate* delegate) 31 : delegate_(delegate) { 32 } 33 34 int PushOverLine(const std::string& data, size_t pos) { 35 return delegate_->PushOverLine(data, pos); 36 } 37 38 bool ParseHeaders() { return delegate_->ParseHeaders(); } 39 size_t FindBoundary() { return delegate_->FindBoundary(); } 40 std::string& boundary() { return delegate_->boundary_; } 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: 56 MockWebURLLoaderClient() { Reset(); } 57 58 virtual void willSendRequest( 59 WebURLLoader*, WebURLRequest&, const WebURLResponse&) {} 60 virtual void didSendData( 61 WebURLLoader*, unsigned long long, unsigned long long) {} 62 63 virtual void didReceiveResponse(WebURLLoader* loader, 64 const WebURLResponse& response) { 65 ++received_response_; 66 response_ = response; 67 data_.clear(); 68 } 69 virtual void didReceiveData( 70 blink::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 } 78 virtual void didFinishLoading(WebURLLoader*, double finishTime) {} 79 virtual void didFail(WebURLLoader*, const WebURLError&) {} 80 81 void Reset() { 82 received_response_ = received_data_ = total_encoded_data_length_ = 0; 83 data_.clear(); 84 response_.reset(); 85 } 86 87 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. 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 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 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 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 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 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 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 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 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 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 565 TEST(MultipartResponseTest, MultipartContentRangesTest) { 566 WebURLResponse response1; 567 response1.initialize(); 568 response1.setMIMEType("application/pdf"); 569 response1.setHTTPHeaderField("Content-Length", "200"); // Ignored! 570 // Use intentionally >32bit values to check they are handled correctly. 571 response1.setHTTPHeaderField("Content-Range", 572 "bytes 5000000000-5000000050/6000000000"); 573 574 int64 content_range_lower_bound = 0; 575 int64 content_range_upper_bound = 0; 576 int64 content_range_instance_size = 0; 577 578 bool result = MultipartResponseDelegate::ReadContentRanges( 579 response1, &content_range_lower_bound, 580 &content_range_upper_bound, 581 &content_range_instance_size); 582 583 EXPECT_EQ(result, true); 584 EXPECT_EQ(content_range_lower_bound, 5e9); 585 EXPECT_EQ(content_range_upper_bound, 5e9+50); 586 EXPECT_EQ(content_range_instance_size, 6e9); 587 588 WebURLResponse response2; 589 response2.initialize(); 590 response2.setMIMEType("application/pdf"); 591 response2.setHTTPHeaderField("Content-Length", "200"); 592 response2.setHTTPHeaderField("Content-Range", "bytes 1000/1050"); 593 594 content_range_lower_bound = 0; 595 content_range_upper_bound = 0; 596 content_range_instance_size = 0; 597 598 result = MultipartResponseDelegate::ReadContentRanges( 599 response2, &content_range_lower_bound, 600 &content_range_upper_bound, 601 &content_range_instance_size); 602 603 EXPECT_EQ(result, false); 604 605 WebURLResponse response3; 606 response3.initialize(); 607 response3.setMIMEType("application/pdf"); 608 response3.setHTTPHeaderField("Content-Length", "200"); 609 response3.setHTTPHeaderField("Range", "bytes 1000-1050/5000"); 610 611 content_range_lower_bound = 0; 612 content_range_upper_bound = 0; 613 content_range_instance_size = 0; 614 615 result = MultipartResponseDelegate::ReadContentRanges( 616 response3, &content_range_lower_bound, 617 &content_range_upper_bound, 618 &content_range_instance_size); 619 620 EXPECT_EQ(result, true); 621 EXPECT_EQ(content_range_lower_bound, 1000); 622 EXPECT_EQ(content_range_upper_bound, 1050); 623 624 WebURLResponse response4; 625 response4.initialize(); 626 response4.setMIMEType("application/pdf"); 627 response4.setHTTPHeaderField("Content-Length", "200"); 628 629 content_range_lower_bound = 0; 630 content_range_upper_bound = 0; 631 content_range_instance_size = 0; 632 633 result = MultipartResponseDelegate::ReadContentRanges( 634 response4, &content_range_lower_bound, 635 &content_range_upper_bound, 636 &content_range_instance_size); 637 638 EXPECT_EQ(result, false); 639 } 640 641 TEST(MultipartResponseTest, MultipartPayloadSet) { 642 WebURLResponse response; 643 response.initialize(); 644 response.setMIMEType("multipart/x-mixed-replace"); 645 MockWebURLLoaderClient client; 646 MultipartResponseDelegate delegate(&client, NULL, response, "bound"); 647 648 string data( 649 "--bound\n" 650 "Content-type: text/plain\n\n" 651 "response data\n" 652 "--bound\n"); 653 delegate.OnReceivedData(data.c_str(), 654 static_cast<int>(data.length()), 655 static_cast<int>(data.length())); 656 EXPECT_EQ(1, client.received_response_); 657 EXPECT_EQ(string("response data"), client.data_); 658 EXPECT_EQ(static_cast<int>(data.length()), client.total_encoded_data_length_); 659 EXPECT_FALSE(client.response_.isMultipartPayload()); 660 661 string data2( 662 "Content-type: text/plain\n\n" 663 "response data2\n" 664 "--bound\n"); 665 delegate.OnReceivedData(data2.c_str(), 666 static_cast<int>(data2.length()), 667 static_cast<int>(data2.length())); 668 EXPECT_EQ(2, client.received_response_); 669 EXPECT_EQ(string("response data2"), client.data_); 670 EXPECT_EQ(static_cast<int>(data.length()) + static_cast<int>(data2.length()), 671 client.total_encoded_data_length_); 672 EXPECT_TRUE(client.response_.isMultipartPayload()); 673 } 674 675 } // namespace 676