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