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