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