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
15using std::string;
16using WebKit::WebString;
17using WebKit::WebURL;
18using WebKit::WebURLError;
19using WebKit::WebURLLoader;
20using WebKit::WebURLLoaderClient;
21using WebKit::WebURLRequest;
22using WebKit::WebURLResponse;
23using webkit_glue::MultipartResponseDelegate;
24using webkit_glue::MultipartResponseDelegateTester;
25
26namespace webkit_glue {
27
28class 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
49namespace {
50
51class MultipartResponseTest : public testing::Test {
52};
53
54class 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.
98TEST(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
204TEST(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
277TEST(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.
309struct 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
318void 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
360TEST(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
388TEST(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
417TEST(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
444TEST(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
472TEST(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
490TEST(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
565TEST(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
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