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