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