Home | History | Annotate | Download | only in child
      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