Home | History | Annotate | Download | only in media
      1 // Copyright 2013 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 <algorithm>
      6 #include <string>
      7 
      8 #include "base/bind.h"
      9 #include "base/format_macros.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "content/renderer/media/buffered_resource_loader.h"
     13 #include "content/test/mock_webframeclient.h"
     14 #include "content/test/mock_weburlloader.h"
     15 #include "media/base/media_log.h"
     16 #include "media/base/seekable_buffer.h"
     17 #include "net/base/net_errors.h"
     18 #include "net/http/http_request_headers.h"
     19 #include "net/http/http_util.h"
     20 #include "third_party/WebKit/public/platform/WebString.h"
     21 #include "third_party/WebKit/public/platform/WebURLError.h"
     22 #include "third_party/WebKit/public/platform/WebURLRequest.h"
     23 #include "third_party/WebKit/public/platform/WebURLResponse.h"
     24 #include "third_party/WebKit/public/web/WebFrame.h"
     25 #include "third_party/WebKit/public/web/WebView.h"
     26 
     27 using ::testing::_;
     28 using ::testing::InSequence;
     29 using ::testing::Return;
     30 using ::testing::Truly;
     31 using ::testing::NiceMock;
     32 
     33 using blink::WebString;
     34 using blink::WebURLError;
     35 using blink::WebURLResponse;
     36 using blink::WebView;
     37 
     38 namespace content {
     39 
     40 static const char* kHttpUrl = "http://test";
     41 static const char kHttpRedirectToSameDomainUrl1[] = "http://test/ing";
     42 static const char kHttpRedirectToSameDomainUrl2[] = "http://test/ing2";
     43 static const char kHttpRedirectToDifferentDomainUrl1[] = "http://test2";
     44 
     45 static const int kDataSize = 1024;
     46 static const int kHttpOK = 200;
     47 static const int kHttpPartialContent = 206;
     48 
     49 enum NetworkState {
     50   NONE,
     51   LOADED,
     52   LOADING
     53 };
     54 
     55 // Predicate that tests that request disallows compressed data.
     56 static bool CorrectAcceptEncoding(const blink::WebURLRequest &request) {
     57   std::string value = request.httpHeaderField(
     58       WebString::fromUTF8(net::HttpRequestHeaders::kAcceptEncoding)).utf8();
     59   return (value.find("identity;q=1") != std::string::npos) &&
     60          (value.find("*;q=0") != std::string::npos);
     61 }
     62 
     63 class BufferedResourceLoaderTest : public testing::Test {
     64  public:
     65   BufferedResourceLoaderTest()
     66       : view_(WebView::create(NULL)) {
     67     view_->initializeMainFrame(&client_);
     68 
     69     for (int i = 0; i < kDataSize; ++i) {
     70       data_[i] = i;
     71     }
     72   }
     73 
     74   virtual ~BufferedResourceLoaderTest() {
     75     view_->close();
     76   }
     77 
     78   void Initialize(const char* url, int first_position, int last_position) {
     79     gurl_ = GURL(url);
     80     first_position_ = first_position;
     81     last_position_ = last_position;
     82 
     83     loader_.reset(new BufferedResourceLoader(
     84         gurl_, BufferedResourceLoader::kUnspecified,
     85         first_position_, last_position_,
     86         BufferedResourceLoader::kCapacityDefer, 0, 0,
     87         new media::MediaLog()));
     88 
     89     // |test_loader_| will be used when Start() is called.
     90     url_loader_ = new NiceMock<MockWebURLLoader>();
     91     loader_->test_loader_ = scoped_ptr<blink::WebURLLoader>(url_loader_);
     92   }
     93 
     94   void SetLoaderBuffer(int forward_capacity, int backward_capacity) {
     95     loader_->buffer_.set_forward_capacity(forward_capacity);
     96     loader_->buffer_.set_backward_capacity(backward_capacity);
     97     loader_->buffer_.Clear();
     98   }
     99 
    100   void Start() {
    101     InSequence s;
    102     EXPECT_CALL(*url_loader_, loadAsynchronously(Truly(CorrectAcceptEncoding),
    103                                                  loader_.get()));
    104 
    105     EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
    106     loader_->Start(
    107         base::Bind(&BufferedResourceLoaderTest::StartCallback,
    108                    base::Unretained(this)),
    109         base::Bind(&BufferedResourceLoaderTest::LoadingCallback,
    110                    base::Unretained(this)),
    111         base::Bind(&BufferedResourceLoaderTest::ProgressCallback,
    112                    base::Unretained(this)),
    113         view_->mainFrame());
    114   }
    115 
    116   void FullResponse(int64 instance_size) {
    117     FullResponse(instance_size, BufferedResourceLoader::kOk);
    118   }
    119 
    120   void FullResponse(int64 instance_size,
    121                     BufferedResourceLoader::Status status) {
    122     EXPECT_CALL(*this, StartCallback(status));
    123 
    124     WebURLResponse response(gurl_);
    125     response.setHTTPHeaderField(WebString::fromUTF8("Content-Length"),
    126                                 WebString::fromUTF8(base::StringPrintf("%"
    127                                     PRId64, instance_size)));
    128     response.setExpectedContentLength(instance_size);
    129     response.setHTTPStatusCode(kHttpOK);
    130     loader_->didReceiveResponse(url_loader_, response);
    131 
    132     if (status == BufferedResourceLoader::kOk) {
    133       EXPECT_EQ(instance_size, loader_->content_length());
    134       EXPECT_EQ(instance_size, loader_->instance_size());
    135     }
    136 
    137     EXPECT_FALSE(loader_->range_supported());
    138   }
    139 
    140   void PartialResponse(int64 first_position, int64 last_position,
    141                        int64 instance_size) {
    142     PartialResponse(first_position, last_position, instance_size, false, true);
    143   }
    144 
    145   void PartialResponse(int64 first_position, int64 last_position,
    146                        int64 instance_size, bool chunked, bool accept_ranges) {
    147     EXPECT_CALL(*this, StartCallback(BufferedResourceLoader::kOk));
    148 
    149     WebURLResponse response(gurl_);
    150     response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"),
    151                                 WebString::fromUTF8(base::StringPrintf("bytes "
    152                                             "%" PRId64 "-%" PRId64 "/%" PRId64,
    153                                             first_position,
    154                                             last_position,
    155                                             instance_size)));
    156 
    157     // HTTP 1.1 doesn't permit Content-Length with Transfer-Encoding: chunked.
    158     int64 content_length = -1;
    159     if (chunked) {
    160       response.setHTTPHeaderField(WebString::fromUTF8("Transfer-Encoding"),
    161                                   WebString::fromUTF8("chunked"));
    162     } else {
    163       content_length = last_position - first_position + 1;
    164     }
    165     response.setExpectedContentLength(content_length);
    166 
    167     // A server isn't required to return Accept-Ranges even though it might.
    168     if (accept_ranges) {
    169       response.setHTTPHeaderField(WebString::fromUTF8("Accept-Ranges"),
    170                                   WebString::fromUTF8("bytes"));
    171     }
    172 
    173     response.setHTTPStatusCode(kHttpPartialContent);
    174     loader_->didReceiveResponse(url_loader_, response);
    175 
    176     // XXX: what's the difference between these two? For example in the chunked
    177     // range request case, Content-Length is unspecified (because it's chunked)
    178     // but Content-Range: a-b/c can be returned, where c == Content-Length
    179     //
    180     // Can we eliminate one?
    181     EXPECT_EQ(content_length, loader_->content_length());
    182     EXPECT_EQ(instance_size, loader_->instance_size());
    183 
    184     // A valid partial response should always result in this being true.
    185     EXPECT_TRUE(loader_->range_supported());
    186   }
    187 
    188   void Redirect(const char* url) {
    189     GURL redirectUrl(url);
    190     blink::WebURLRequest newRequest(redirectUrl);
    191     blink::WebURLResponse redirectResponse(gurl_);
    192 
    193     loader_->willSendRequest(url_loader_, newRequest, redirectResponse);
    194 
    195     base::MessageLoop::current()->RunUntilIdle();
    196   }
    197 
    198   void StopWhenLoad() {
    199     InSequence s;
    200     EXPECT_CALL(*url_loader_, cancel());
    201     loader_->Stop();
    202     loader_.reset();
    203   }
    204 
    205   // Helper method to write to |loader_| from |data_|.
    206   void WriteLoader(int position, int size) {
    207     EXPECT_CALL(*this, ProgressCallback(position + size - 1));
    208     loader_->didReceiveData(url_loader_,
    209                             reinterpret_cast<char*>(data_ + position),
    210                             size,
    211                             size);
    212   }
    213 
    214   void WriteData(int size) {
    215     EXPECT_CALL(*this, ProgressCallback(_));
    216 
    217     scoped_ptr<char[]> data(new char[size]);
    218     loader_->didReceiveData(url_loader_, data.get(), size, size);
    219   }
    220 
    221   void WriteUntilThreshold() {
    222     int buffered = loader_->buffer_.forward_bytes();
    223     int capacity = loader_->buffer_.forward_capacity();
    224     CHECK_LT(buffered, capacity);
    225 
    226     EXPECT_CALL(*this, LoadingCallback(
    227         BufferedResourceLoader::kLoadingDeferred));
    228     WriteData(capacity - buffered);
    229   }
    230 
    231   // Helper method to read from |loader_|.
    232   void ReadLoader(int64 position, int size, uint8* buffer) {
    233     loader_->Read(position, size, buffer,
    234                   base::Bind(&BufferedResourceLoaderTest::ReadCallback,
    235                              base::Unretained(this)));
    236   }
    237 
    238   // Verifies that data in buffer[0...size] is equal to data_[pos...pos+size].
    239   void VerifyBuffer(uint8* buffer, int pos, int size) {
    240     EXPECT_EQ(0, memcmp(buffer, data_ + pos, size));
    241   }
    242 
    243   void ConfirmLoaderOffsets(int64 expected_offset,
    244                             int expected_first_offset,
    245                             int expected_last_offset) {
    246     EXPECT_EQ(loader_->offset_, expected_offset);
    247     EXPECT_EQ(loader_->first_offset_, expected_first_offset);
    248     EXPECT_EQ(loader_->last_offset_, expected_last_offset);
    249   }
    250 
    251   void ConfirmBufferState(int backward_bytes,
    252                           int backward_capacity,
    253                           int forward_bytes,
    254                           int forward_capacity) {
    255     EXPECT_EQ(backward_bytes, loader_->buffer_.backward_bytes());
    256     EXPECT_EQ(backward_capacity, loader_->buffer_.backward_capacity());
    257     EXPECT_EQ(forward_bytes, loader_->buffer_.forward_bytes());
    258     EXPECT_EQ(forward_capacity, loader_->buffer_.forward_capacity());
    259   }
    260 
    261   void ConfirmLoaderBufferBackwardCapacity(int expected_backward_capacity) {
    262     EXPECT_EQ(loader_->buffer_.backward_capacity(),
    263               expected_backward_capacity);
    264   }
    265 
    266   void ConfirmLoaderBufferForwardCapacity(int expected_forward_capacity) {
    267     EXPECT_EQ(loader_->buffer_.forward_capacity(), expected_forward_capacity);
    268   }
    269 
    270   // Makes sure the |loader_| buffer window is in a reasonable range.
    271   void CheckBufferWindowBounds() {
    272     // Corresponds to value defined in buffered_resource_loader.cc.
    273     static const int kMinBufferCapacity = 2 * 1024 * 1024;
    274     EXPECT_GE(loader_->buffer_.forward_capacity(), kMinBufferCapacity);
    275     EXPECT_GE(loader_->buffer_.backward_capacity(), kMinBufferCapacity);
    276 
    277     // Corresponds to value defined in buffered_resource_loader.cc.
    278     static const int kMaxBufferCapacity = 20 * 1024 * 1024;
    279     EXPECT_LE(loader_->buffer_.forward_capacity(), kMaxBufferCapacity);
    280     EXPECT_LE(loader_->buffer_.backward_capacity(), kMaxBufferCapacity);
    281   }
    282 
    283   MOCK_METHOD1(StartCallback, void(BufferedResourceLoader::Status));
    284   MOCK_METHOD2(ReadCallback, void(BufferedResourceLoader::Status, int));
    285   MOCK_METHOD1(LoadingCallback, void(BufferedResourceLoader::LoadingState));
    286   MOCK_METHOD1(ProgressCallback, void(int64));
    287 
    288  protected:
    289   GURL gurl_;
    290   int64 first_position_;
    291   int64 last_position_;
    292 
    293   scoped_ptr<BufferedResourceLoader> loader_;
    294   NiceMock<MockWebURLLoader>* url_loader_;
    295 
    296   MockWebFrameClient client_;
    297   WebView* view_;
    298 
    299   base::MessageLoop message_loop_;
    300 
    301   uint8 data_[kDataSize];
    302 
    303  private:
    304   DISALLOW_COPY_AND_ASSIGN(BufferedResourceLoaderTest);
    305 };
    306 
    307 TEST_F(BufferedResourceLoaderTest, StartStop) {
    308   Initialize(kHttpUrl, -1, -1);
    309   Start();
    310   StopWhenLoad();
    311 }
    312 
    313 // Tests that a bad HTTP response is recived, e.g. file not found.
    314 TEST_F(BufferedResourceLoaderTest, BadHttpResponse) {
    315   Initialize(kHttpUrl, -1, -1);
    316   Start();
    317 
    318   EXPECT_CALL(*this, StartCallback(BufferedResourceLoader::kFailed));
    319 
    320   WebURLResponse response(gurl_);
    321   response.setHTTPStatusCode(404);
    322   response.setHTTPStatusText("Not Found\n");
    323   loader_->didReceiveResponse(url_loader_, response);
    324   StopWhenLoad();
    325 }
    326 
    327 // Tests that partial content is requested but not fulfilled.
    328 TEST_F(BufferedResourceLoaderTest, NotPartialResponse) {
    329   Initialize(kHttpUrl, 100, -1);
    330   Start();
    331   FullResponse(1024, BufferedResourceLoader::kFailed);
    332   StopWhenLoad();
    333 }
    334 
    335 // Tests that a 200 response is received.
    336 TEST_F(BufferedResourceLoaderTest, FullResponse) {
    337   Initialize(kHttpUrl, -1, -1);
    338   Start();
    339   FullResponse(1024);
    340   StopWhenLoad();
    341 }
    342 
    343 // Tests that a partial content response is received.
    344 TEST_F(BufferedResourceLoaderTest, PartialResponse) {
    345   Initialize(kHttpUrl, 100, 200);
    346   Start();
    347   PartialResponse(100, 200, 1024);
    348   StopWhenLoad();
    349 }
    350 
    351 TEST_F(BufferedResourceLoaderTest, PartialResponse_Chunked) {
    352   Initialize(kHttpUrl, 100, 200);
    353   Start();
    354   PartialResponse(100, 200, 1024, true, true);
    355   StopWhenLoad();
    356 }
    357 
    358 TEST_F(BufferedResourceLoaderTest, PartialResponse_NoAcceptRanges) {
    359   Initialize(kHttpUrl, 100, 200);
    360   Start();
    361   PartialResponse(100, 200, 1024, false, false);
    362   StopWhenLoad();
    363 }
    364 
    365 TEST_F(BufferedResourceLoaderTest, PartialResponse_ChunkedNoAcceptRanges) {
    366   Initialize(kHttpUrl, 100, 200);
    367   Start();
    368   PartialResponse(100, 200, 1024, true, false);
    369   StopWhenLoad();
    370 }
    371 
    372 // Tests that an invalid partial response is received.
    373 TEST_F(BufferedResourceLoaderTest, InvalidPartialResponse) {
    374   Initialize(kHttpUrl, 0, 10);
    375   Start();
    376 
    377   EXPECT_CALL(*this, StartCallback(BufferedResourceLoader::kFailed));
    378 
    379   WebURLResponse response(gurl_);
    380   response.setHTTPHeaderField(WebString::fromUTF8("Content-Range"),
    381                               WebString::fromUTF8(base::StringPrintf("bytes "
    382                                   "%d-%d/%d", 1, 10, 1024)));
    383   response.setExpectedContentLength(10);
    384   response.setHTTPStatusCode(kHttpPartialContent);
    385   loader_->didReceiveResponse(url_loader_, response);
    386   StopWhenLoad();
    387 }
    388 
    389 // Tests the logic of sliding window for data buffering and reading.
    390 TEST_F(BufferedResourceLoaderTest, BufferAndRead) {
    391   Initialize(kHttpUrl, 10, 29);
    392   loader_->UpdateDeferStrategy(BufferedResourceLoader::kCapacityDefer);
    393   Start();
    394   PartialResponse(10, 29, 30);
    395 
    396   uint8 buffer[10];
    397   InSequence s;
    398 
    399   // Writes 10 bytes and read them back.
    400   WriteLoader(10, 10);
    401   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
    402   ReadLoader(10, 10, buffer);
    403   VerifyBuffer(buffer, 10, 10);
    404 
    405   // Writes 10 bytes and read 2 times.
    406   WriteLoader(20, 10);
    407   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 5));
    408   ReadLoader(20, 5, buffer);
    409   VerifyBuffer(buffer, 20, 5);
    410   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 5));
    411   ReadLoader(25, 5, buffer);
    412   VerifyBuffer(buffer, 25, 5);
    413 
    414   // Read backward within buffer.
    415   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
    416   ReadLoader(10, 10, buffer);
    417   VerifyBuffer(buffer, 10, 10);
    418 
    419   // Read backward outside buffer.
    420   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
    421   ReadLoader(9, 10, buffer);
    422 
    423   // Response has completed.
    424   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingFinished));
    425   loader_->didFinishLoading(url_loader_, 0);
    426 
    427   // Try to read 10 from position 25 will just return with 5 bytes.
    428   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 5));
    429   ReadLoader(25, 10, buffer);
    430   VerifyBuffer(buffer, 25, 5);
    431 
    432   // Try to read outside buffered range after request has completed.
    433   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
    434   ReadLoader(5, 10, buffer);
    435 
    436   // Try to read beyond the instance size.
    437   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 0));
    438   ReadLoader(30, 10, buffer);
    439 }
    440 
    441 // Tests the logic of expanding the data buffer for large reads.
    442 TEST_F(BufferedResourceLoaderTest, ReadExtendBuffer) {
    443   Initialize(kHttpUrl, 10, 0x014FFFFFF);
    444   SetLoaderBuffer(10, 20);
    445   Start();
    446   PartialResponse(10, 0x014FFFFFF, 0x015000000);
    447 
    448   uint8 buffer[20];
    449   InSequence s;
    450 
    451   // Write more than forward capacity and read it back. Ensure forward capacity
    452   // gets reset after reading.
    453   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingDeferred));
    454   WriteLoader(10, 20);
    455 
    456   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 20));
    457   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
    458   ReadLoader(10, 20, buffer);
    459 
    460   VerifyBuffer(buffer, 10, 20);
    461   ConfirmLoaderBufferForwardCapacity(10);
    462 
    463   // Make and outstanding read request larger than forward capacity. Ensure
    464   // forward capacity gets extended.
    465   ReadLoader(30, 20, buffer);
    466   ConfirmLoaderBufferForwardCapacity(20);
    467 
    468   // Fulfill outstanding request. Ensure forward capacity gets reset.
    469   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 20));
    470   WriteLoader(30, 20);
    471 
    472   VerifyBuffer(buffer, 30, 20);
    473   ConfirmLoaderBufferForwardCapacity(10);
    474 
    475   // Try to read further ahead than kForwardWaitThreshold allows. Ensure
    476   // forward capacity is not changed.
    477   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
    478   ReadLoader(0x00300000, 1, buffer);
    479 
    480   ConfirmLoaderBufferForwardCapacity(10);
    481 
    482   // Try to read more than maximum forward capacity. Ensure forward capacity is
    483   // not changed.
    484   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kFailed, 0));
    485   ReadLoader(30, 0x01400001, buffer);
    486 
    487   ConfirmLoaderBufferForwardCapacity(10);
    488 
    489   StopWhenLoad();
    490 }
    491 
    492 TEST_F(BufferedResourceLoaderTest, ReadOutsideBuffer) {
    493   Initialize(kHttpUrl, 10, 0x00FFFFFF);
    494   Start();
    495   PartialResponse(10, 0x00FFFFFF, 0x01000000);
    496 
    497   uint8 buffer[10];
    498   InSequence s;
    499 
    500   // Read very far ahead will get a cache miss.
    501   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
    502   ReadLoader(0x00FFFFFF, 1, buffer);
    503 
    504   // The following call will not call ReadCallback() because it is waiting for
    505   // data to arrive.
    506   ReadLoader(10, 10, buffer);
    507 
    508   // Writing to loader will fulfill the read request.
    509   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
    510   WriteLoader(10, 20);
    511   VerifyBuffer(buffer, 10, 10);
    512 
    513   // The following call cannot be fulfilled now.
    514   ReadLoader(25, 10, buffer);
    515 
    516   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingFinished));
    517   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 5));
    518   loader_->didFinishLoading(url_loader_, 0);
    519 }
    520 
    521 TEST_F(BufferedResourceLoaderTest, RequestFailedWhenRead) {
    522   Initialize(kHttpUrl, 10, 29);
    523   Start();
    524   PartialResponse(10, 29, 30);
    525 
    526   uint8 buffer[10];
    527   InSequence s;
    528 
    529   // We should convert any error we receive to BufferedResourceLoader::kFailed.
    530   ReadLoader(10, 10, buffer);
    531   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingFailed));
    532   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kFailed, 0));
    533   WebURLError error;
    534   error.reason = net::ERR_TIMED_OUT;
    535   error.isCancellation = false;
    536   loader_->didFail(url_loader_, error);
    537 }
    538 
    539 TEST_F(BufferedResourceLoaderTest, RequestFailedWithNoPendingReads) {
    540   Initialize(kHttpUrl, 10, 29);
    541   Start();
    542   PartialResponse(10, 29, 30);
    543 
    544   uint8 buffer[10];
    545   InSequence s;
    546 
    547   // Write enough data so that a read would technically complete had the request
    548   // not failed.
    549   WriteLoader(10, 20);
    550 
    551   // Fail without a pending read.
    552   WebURLError error;
    553   error.reason = net::ERR_TIMED_OUT;
    554   error.isCancellation = false;
    555   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingFailed));
    556   loader_->didFail(url_loader_, error);
    557 
    558   // Now we should immediately fail any read even if we have data buffered.
    559   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kFailed, 0));
    560   ReadLoader(10, 10, buffer);
    561 }
    562 
    563 TEST_F(BufferedResourceLoaderTest, RequestCancelledWhenRead) {
    564   Initialize(kHttpUrl, 10, 29);
    565   Start();
    566   PartialResponse(10, 29, 30);
    567 
    568   uint8 buffer[10];
    569   InSequence s;
    570 
    571   // We should convert any error we receive to BufferedResourceLoader::kFailed.
    572   ReadLoader(10, 10, buffer);
    573   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingFailed));
    574   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kFailed, 0));
    575   WebURLError error;
    576   error.reason = 0;
    577   error.isCancellation = true;
    578   loader_->didFail(url_loader_, error);
    579 }
    580 
    581 // Tests the data buffering logic of NeverDefer strategy.
    582 TEST_F(BufferedResourceLoaderTest, NeverDeferStrategy) {
    583   Initialize(kHttpUrl, 10, 99);
    584   SetLoaderBuffer(10, 20);
    585   loader_->UpdateDeferStrategy(BufferedResourceLoader::kNeverDefer);
    586   Start();
    587   PartialResponse(10, 99, 100);
    588 
    589   uint8 buffer[10];
    590 
    591   // Read past the buffer size; should not defer regardless.
    592   WriteLoader(10, 10);
    593   WriteLoader(20, 50);
    594 
    595   // Should move past window.
    596   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
    597   ReadLoader(10, 10, buffer);
    598 
    599   StopWhenLoad();
    600 }
    601 
    602 // Tests the data buffering logic of ReadThenDefer strategy.
    603 TEST_F(BufferedResourceLoaderTest, ReadThenDeferStrategy) {
    604   Initialize(kHttpUrl, 10, 99);
    605   SetLoaderBuffer(10, 20);
    606   loader_->UpdateDeferStrategy(BufferedResourceLoader::kReadThenDefer);
    607   Start();
    608   PartialResponse(10, 99, 100);
    609 
    610   uint8 buffer[10];
    611 
    612   // Make an outstanding read request.
    613   ReadLoader(10, 10, buffer);
    614 
    615   // Receive almost enough data to cover, shouldn't defer.
    616   WriteLoader(10, 9);
    617 
    618   // As soon as we have received enough data to fulfill the read, defer.
    619   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingDeferred));
    620   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
    621   WriteLoader(19, 1);
    622 
    623   VerifyBuffer(buffer, 10, 10);
    624 
    625   // Read again which should disable deferring since there should be nothing
    626   // left in our internal buffer.
    627   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
    628   ReadLoader(20, 10, buffer);
    629 
    630   // Over-fulfill requested bytes, then deferring should be enabled again.
    631   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingDeferred));
    632   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
    633   WriteLoader(20, 40);
    634 
    635   VerifyBuffer(buffer, 20, 10);
    636 
    637   // Read far ahead, which should disable deferring. In this case we still have
    638   // bytes in our internal buffer.
    639   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
    640   ReadLoader(80, 10, buffer);
    641 
    642   // Fulfill requested bytes, then deferring should be enabled again.
    643   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingDeferred));
    644   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
    645   WriteLoader(60, 40);
    646 
    647   VerifyBuffer(buffer, 80, 10);
    648 
    649   StopWhenLoad();
    650 }
    651 
    652 // Tests the data buffering logic of kCapacityDefer strategy.
    653 TEST_F(BufferedResourceLoaderTest, ThresholdDeferStrategy) {
    654   Initialize(kHttpUrl, 10, 99);
    655   SetLoaderBuffer(10, 20);
    656   Start();
    657   PartialResponse(10, 99, 100);
    658 
    659   uint8 buffer[10];
    660   InSequence s;
    661 
    662   // Write half of capacity: keep not deferring.
    663   WriteData(5);
    664 
    665   // Write rest of space until capacity: start deferring.
    666   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingDeferred));
    667   WriteData(5);
    668 
    669   // Read a byte from the buffer: stop deferring.
    670   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 1));
    671   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
    672   ReadLoader(10, 1, buffer);
    673 
    674   // Write a byte to hit capacity: start deferring.
    675   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoadingDeferred));
    676   WriteData(6);
    677 
    678   StopWhenLoad();
    679 }
    680 
    681 TEST_F(BufferedResourceLoaderTest, Tricky_ReadForwardsPastBuffered) {
    682   Initialize(kHttpUrl, 10, 99);
    683   SetLoaderBuffer(10, 10);
    684   Start();
    685   PartialResponse(10, 99, 100);
    686 
    687   uint8 buffer[256];
    688   InSequence s;
    689 
    690   // PRECONDITION
    691   WriteUntilThreshold();
    692   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 1));
    693   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
    694   ReadLoader(10, 1, buffer);
    695   ConfirmBufferState(1, 10, 9, 10);
    696   ConfirmLoaderOffsets(11, 0, 0);
    697 
    698   // *** TRICKY BUSINESS, PT. I ***
    699   // Read past buffered: stop deferring.
    700   //
    701   // In order for the read to complete we must:
    702   //   1) Stop deferring to receive more data.
    703   //
    704   // BEFORE
    705   //   offset=11 [xxxxxxxxx_]
    706   //                       ^ ^^^ requested 4 bytes @ offset 20
    707   // AFTER
    708   //   offset=24 [__________]
    709   //
    710   ReadLoader(20, 4, buffer);
    711 
    712   // Write a little, make sure we didn't start deferring.
    713   WriteData(2);
    714 
    715   // Write the rest, read should complete.
    716   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 4));
    717   WriteData(2);
    718 
    719   // POSTCONDITION
    720   ConfirmBufferState(4, 10, 0, 10);
    721   ConfirmLoaderOffsets(24, 0, 0);
    722 
    723   StopWhenLoad();
    724 }
    725 
    726 TEST_F(BufferedResourceLoaderTest, Tricky_ReadBackwardsPastBuffered) {
    727   Initialize(kHttpUrl, 10, 99);
    728   SetLoaderBuffer(10, 10);
    729   Start();
    730   PartialResponse(10, 99, 100);
    731 
    732   uint8 buffer[256];
    733   InSequence s;
    734 
    735   // PRECONDITION
    736   WriteUntilThreshold();
    737   ConfirmBufferState(0, 10, 10, 10);
    738   ConfirmLoaderOffsets(10, 0, 0);
    739 
    740   // *** TRICKY BUSINESS, PT. II ***
    741   // Read backwards a little too much: cache miss.
    742   //
    743   // BEFORE
    744   //   offset=10 [__________|xxxxxxxxxx]
    745   //                       ^ ^^^ requested 10 bytes @ offset 9
    746   // AFTER
    747   //   offset=10 [__________|xxxxxxxxxx]  !!! cache miss !!!
    748   //
    749   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
    750   ReadLoader(9, 4, buffer);
    751 
    752   // POSTCONDITION
    753   ConfirmBufferState(0, 10, 10, 10);
    754   ConfirmLoaderOffsets(10, 0, 0);
    755 
    756   StopWhenLoad();
    757 }
    758 
    759 TEST_F(BufferedResourceLoaderTest, Tricky_SmallReadWithinThreshold) {
    760   Initialize(kHttpUrl, 10, 99);
    761   SetLoaderBuffer(10, 10);
    762   Start();
    763   PartialResponse(10, 99, 100);
    764 
    765   uint8 buffer[256];
    766   InSequence s;
    767 
    768   // PRECONDITION
    769   WriteUntilThreshold();
    770   ConfirmBufferState(0, 10, 10, 10);
    771   ConfirmLoaderOffsets(10, 0, 0);
    772 
    773   // *** TRICKY BUSINESS, PT. III ***
    774   // Read past forward capacity but within capacity: stop deferring.
    775   //
    776   // In order for the read to complete we must:
    777   //   1) Adjust offset forward to create capacity.
    778   //   2) Stop deferring to receive more data.
    779   //
    780   // BEFORE
    781   //   offset=10 [xxxxxxxxxx]
    782   //                             ^^^^ requested 4 bytes @ offset 24
    783   // ADJUSTED OFFSET
    784   //   offset=20 [__________]
    785   //                  ^^^^ requested 4 bytes @ offset 24
    786   // AFTER
    787   //   offset=28 [__________]
    788   //
    789   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
    790   ReadLoader(24, 4, buffer);
    791   ConfirmLoaderOffsets(20, 4, 8);
    792 
    793   // Write a little, make sure we didn't start deferring.
    794   WriteData(4);
    795 
    796   // Write the rest, read should complete.
    797   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 4));
    798   WriteData(4);
    799 
    800   // POSTCONDITION
    801   ConfirmBufferState(8, 10, 0, 10);
    802   ConfirmLoaderOffsets(28, 0, 0);
    803 
    804   StopWhenLoad();
    805 }
    806 
    807 TEST_F(BufferedResourceLoaderTest, Tricky_LargeReadWithinThreshold) {
    808   Initialize(kHttpUrl, 10, 99);
    809   SetLoaderBuffer(10, 10);
    810   Start();
    811   PartialResponse(10, 99, 100);
    812 
    813   uint8 buffer[256];
    814   InSequence s;
    815 
    816   // PRECONDITION
    817   WriteUntilThreshold();
    818   ConfirmBufferState(0, 10, 10, 10);
    819   ConfirmLoaderOffsets(10, 0, 0);
    820 
    821   // *** TRICKY BUSINESS, PT. IV ***
    822   // Read a large amount past forward capacity but within
    823   // capacity: stop deferring.
    824   //
    825   // In order for the read to complete we must:
    826   //   1) Adjust offset forward to create capacity.
    827   //   2) Expand capacity to make sure we don't defer as data arrives.
    828   //   3) Stop deferring to receive more data.
    829   //
    830   // BEFORE
    831   //   offset=10 [xxxxxxxxxx]
    832   //                             ^^^^^^^^^^^^ requested 12 bytes @ offset 24
    833   // ADJUSTED OFFSET
    834   //   offset=20 [__________]
    835   //                  ^^^^^^ ^^^^^^ requested 12 bytes @ offset 24
    836   // ADJUSTED CAPACITY
    837   //   offset=20 [________________]
    838   //                  ^^^^^^^^^^^^ requested 12 bytes @ offset 24
    839   // AFTER
    840   //   offset=36 [__________]
    841   //
    842   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
    843   ReadLoader(24, 12, buffer);
    844   ConfirmLoaderOffsets(20, 4, 16);
    845   ConfirmBufferState(10, 10, 0, 16);
    846 
    847   // Write a little, make sure we didn't start deferring.
    848   WriteData(10);
    849 
    850   // Write the rest, read should complete and capacity should go back to normal.
    851   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 12));
    852   WriteData(6);
    853   ConfirmLoaderBufferForwardCapacity(10);
    854 
    855   // POSTCONDITION
    856   ConfirmBufferState(6, 10, 0, 10);
    857   ConfirmLoaderOffsets(36, 0, 0);
    858 
    859   StopWhenLoad();
    860 }
    861 
    862 TEST_F(BufferedResourceLoaderTest, Tricky_LargeReadBackwards) {
    863   Initialize(kHttpUrl, 10, 99);
    864   SetLoaderBuffer(10, 10);
    865   Start();
    866   PartialResponse(10, 99, 100);
    867 
    868   uint8 buffer[256];
    869   InSequence s;
    870 
    871   // PRECONDITION
    872   WriteUntilThreshold();
    873   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 10));
    874   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
    875   ReadLoader(10, 10, buffer);
    876   WriteUntilThreshold();
    877   ConfirmBufferState(10, 10, 10, 10);
    878   ConfirmLoaderOffsets(20, 0, 0);
    879 
    880   // *** TRICKY BUSINESS, PT. V ***
    881   // Read a large amount that involves backwards data: stop deferring.
    882   //
    883   // In order for the read to complete we must:
    884   //   1) Adjust offset *backwards* to create capacity.
    885   //   2) Expand capacity to make sure we don't defer as data arrives.
    886   //   3) Stop deferring to receive more data.
    887   //
    888   // BEFORE
    889   //   offset=20 [xxxxxxxxxx|xxxxxxxxxx]
    890   //                    ^^^^ ^^^^^^^^^^ ^^^^ requested 18 bytes @ offset 16
    891   // ADJUSTED OFFSET
    892   //   offset=16 [____xxxxxx|xxxxxxxxxx]xxxx
    893   //                         ^^^^^^^^^^ ^^^^^^^^ requested 18 bytes @ offset 16
    894   // ADJUSTED CAPACITY
    895   //   offset=16 [____xxxxxx|xxxxxxxxxxxxxx____]
    896   //                         ^^^^^^^^^^^^^^^^^^ requested 18 bytes @ offset 16
    897   // AFTER
    898   //   offset=34 [xxxxxxxxxx|__________]
    899   //
    900   EXPECT_CALL(*this, LoadingCallback(BufferedResourceLoader::kLoading));
    901   ReadLoader(16, 18, buffer);
    902   ConfirmLoaderOffsets(16, 0, 18);
    903   ConfirmBufferState(6, 10, 14, 18);
    904 
    905   // Write a little, make sure we didn't start deferring.
    906   WriteData(2);
    907 
    908   // Write the rest, read should complete and capacity should go back to normal.
    909   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kOk, 18));
    910   WriteData(2);
    911   ConfirmLoaderBufferForwardCapacity(10);
    912 
    913   // POSTCONDITION
    914   ConfirmBufferState(4, 10, 0, 10);
    915   ConfirmLoaderOffsets(34, 0, 0);
    916 
    917   StopWhenLoad();
    918 }
    919 
    920 TEST_F(BufferedResourceLoaderTest, Tricky_ReadPastThreshold) {
    921   const int kSize = 5 * 1024 * 1024;
    922   const int kThreshold = 2 * 1024 * 1024;
    923 
    924   Initialize(kHttpUrl, 10, kSize);
    925   SetLoaderBuffer(10, 10);
    926   Start();
    927   PartialResponse(10, kSize - 1, kSize);
    928 
    929   uint8 buffer[256];
    930   InSequence s;
    931 
    932   // PRECONDITION
    933   WriteUntilThreshold();
    934   ConfirmBufferState(0, 10, 10, 10);
    935   ConfirmLoaderOffsets(10, 0, 0);
    936 
    937   // *** TRICKY BUSINESS, PT. VI ***
    938   // Read past the forward wait threshold: cache miss.
    939   //
    940   // BEFORE
    941   //   offset=10 [xxxxxxxxxx] ...
    942   //                              ^^^^ requested 10 bytes @ threshold
    943   // AFTER
    944   //   offset=10 [xxxxxxxxxx]  !!! cache miss !!!
    945   //
    946   EXPECT_CALL(*this, ReadCallback(BufferedResourceLoader::kCacheMiss, 0));
    947   ReadLoader(kThreshold + 20, 10, buffer);
    948 
    949   // POSTCONDITION
    950   ConfirmBufferState(0, 10, 10, 10);
    951   ConfirmLoaderOffsets(10, 0, 0);
    952 
    953   StopWhenLoad();
    954 }
    955 
    956 TEST_F(BufferedResourceLoaderTest, HasSingleOrigin) {
    957   // Make sure no redirect case works as expected.
    958   Initialize(kHttpUrl, -1, -1);
    959   Start();
    960   FullResponse(1024);
    961   EXPECT_TRUE(loader_->HasSingleOrigin());
    962   StopWhenLoad();
    963 
    964   // Test redirect to the same domain.
    965   Initialize(kHttpUrl, -1, -1);
    966   Start();
    967   Redirect(kHttpRedirectToSameDomainUrl1);
    968   FullResponse(1024);
    969   EXPECT_TRUE(loader_->HasSingleOrigin());
    970   StopWhenLoad();
    971 
    972   // Test redirect twice to the same domain.
    973   Initialize(kHttpUrl, -1, -1);
    974   Start();
    975   Redirect(kHttpRedirectToSameDomainUrl1);
    976   Redirect(kHttpRedirectToSameDomainUrl2);
    977   FullResponse(1024);
    978   EXPECT_TRUE(loader_->HasSingleOrigin());
    979   StopWhenLoad();
    980 
    981   // Test redirect to a different domain.
    982   Initialize(kHttpUrl, -1, -1);
    983   Start();
    984   Redirect(kHttpRedirectToDifferentDomainUrl1);
    985   FullResponse(1024);
    986   EXPECT_FALSE(loader_->HasSingleOrigin());
    987   StopWhenLoad();
    988 
    989   // Test redirect to the same domain and then to a different domain.
    990   Initialize(kHttpUrl, -1, -1);
    991   Start();
    992   Redirect(kHttpRedirectToSameDomainUrl1);
    993   Redirect(kHttpRedirectToDifferentDomainUrl1);
    994   FullResponse(1024);
    995   EXPECT_FALSE(loader_->HasSingleOrigin());
    996   StopWhenLoad();
    997 }
    998 
    999 TEST_F(BufferedResourceLoaderTest, BufferWindow_Default) {
   1000   Initialize(kHttpUrl, -1, -1);
   1001   Start();
   1002 
   1003   // Test ensures that default construction of a BufferedResourceLoader has sane
   1004   // values.
   1005   //
   1006   // Please do not change these values in order to make a test pass! Instead,
   1007   // start a conversation on what the default buffer window capacities should
   1008   // be.
   1009   ConfirmLoaderBufferBackwardCapacity(2 * 1024 * 1024);
   1010   ConfirmLoaderBufferForwardCapacity(2 * 1024 * 1024);
   1011 
   1012   StopWhenLoad();
   1013 }
   1014 
   1015 TEST_F(BufferedResourceLoaderTest, BufferWindow_Bitrate_Unknown) {
   1016   Initialize(kHttpUrl, -1, -1);
   1017   Start();
   1018   loader_->SetBitrate(0);
   1019   CheckBufferWindowBounds();
   1020   StopWhenLoad();
   1021 }
   1022 
   1023 TEST_F(BufferedResourceLoaderTest, BufferWindow_Bitrate_BelowLowerBound) {
   1024   Initialize(kHttpUrl, -1, -1);
   1025   Start();
   1026   loader_->SetBitrate(1024 * 8);  // 1 Kbps.
   1027   CheckBufferWindowBounds();
   1028   StopWhenLoad();
   1029 }
   1030 
   1031 TEST_F(BufferedResourceLoaderTest, BufferWindow_Bitrate_WithinBounds) {
   1032   Initialize(kHttpUrl, -1, -1);
   1033   Start();
   1034   loader_->SetBitrate(2 * 1024 * 1024 * 8);  // 2 Mbps.
   1035   CheckBufferWindowBounds();
   1036   StopWhenLoad();
   1037 }
   1038 
   1039 TEST_F(BufferedResourceLoaderTest, BufferWindow_Bitrate_AboveUpperBound) {
   1040   Initialize(kHttpUrl, -1, -1);
   1041   Start();
   1042   loader_->SetBitrate(100 * 1024 * 1024 * 8);  // 100 Mbps.
   1043   CheckBufferWindowBounds();
   1044   StopWhenLoad();
   1045 }
   1046 
   1047 TEST_F(BufferedResourceLoaderTest, BufferWindow_PlaybackRate_Negative) {
   1048   Initialize(kHttpUrl, -1, -1);
   1049   Start();
   1050   loader_->SetPlaybackRate(-10);
   1051   CheckBufferWindowBounds();
   1052   StopWhenLoad();
   1053 }
   1054 
   1055 TEST_F(BufferedResourceLoaderTest, BufferWindow_PlaybackRate_Zero) {
   1056   Initialize(kHttpUrl, -1, -1);
   1057   Start();
   1058   loader_->SetPlaybackRate(0);
   1059   CheckBufferWindowBounds();
   1060   StopWhenLoad();
   1061 }
   1062 
   1063 TEST_F(BufferedResourceLoaderTest, BufferWindow_PlaybackRate_BelowLowerBound) {
   1064   Initialize(kHttpUrl, -1, -1);
   1065   Start();
   1066   loader_->SetPlaybackRate(0.1f);
   1067   CheckBufferWindowBounds();
   1068   StopWhenLoad();
   1069 }
   1070 
   1071 TEST_F(BufferedResourceLoaderTest, BufferWindow_PlaybackRate_WithinBounds) {
   1072   Initialize(kHttpUrl, -1, -1);
   1073   Start();
   1074   loader_->SetPlaybackRate(10);
   1075   CheckBufferWindowBounds();
   1076   StopWhenLoad();
   1077 }
   1078 
   1079 TEST_F(BufferedResourceLoaderTest, BufferWindow_PlaybackRate_AboveUpperBound) {
   1080   Initialize(kHttpUrl, -1, -1);
   1081   Start();
   1082   loader_->SetPlaybackRate(100);
   1083   CheckBufferWindowBounds();
   1084   StopWhenLoad();
   1085 }
   1086 
   1087 static void ExpectContentRange(
   1088     const std::string& str, bool expect_success,
   1089     int64 expected_first, int64 expected_last, int64 expected_size) {
   1090   int64 first, last, size;
   1091   ASSERT_EQ(expect_success, BufferedResourceLoader::ParseContentRange(
   1092       str, &first, &last, &size)) << str;
   1093   if (!expect_success)
   1094     return;
   1095   EXPECT_EQ(first, expected_first);
   1096   EXPECT_EQ(last, expected_last);
   1097   EXPECT_EQ(size, expected_size);
   1098 }
   1099 
   1100 static void ExpectContentRangeFailure(const std::string& str) {
   1101   ExpectContentRange(str, false, 0, 0, 0);
   1102 }
   1103 
   1104 static void ExpectContentRangeSuccess(
   1105     const std::string& str,
   1106     int64 expected_first, int64 expected_last, int64 expected_size) {
   1107   ExpectContentRange(str, true, expected_first, expected_last, expected_size);
   1108 }
   1109 
   1110 TEST(BufferedResourceLoaderStandaloneTest, ParseContentRange) {
   1111   ExpectContentRangeFailure("cytes 0-499/500");
   1112   ExpectContentRangeFailure("bytes 0499/500");
   1113   ExpectContentRangeFailure("bytes 0-499500");
   1114   ExpectContentRangeFailure("bytes 0-499/500-blorg");
   1115   ExpectContentRangeFailure("bytes 0-499/500-1");
   1116   ExpectContentRangeFailure("bytes 0-499/400");
   1117   ExpectContentRangeFailure("bytes 0-/400");
   1118   ExpectContentRangeFailure("bytes -300/400");
   1119   ExpectContentRangeFailure("bytes 20-10/400");
   1120 
   1121   ExpectContentRangeSuccess("bytes 0-499/500", 0, 499, 500);
   1122   ExpectContentRangeSuccess("bytes 0-0/500", 0, 0, 500);
   1123   ExpectContentRangeSuccess("bytes 10-11/50", 10, 11, 50);
   1124   ExpectContentRangeSuccess("bytes 10-11/*", 10, 11,
   1125                             kPositionNotSpecified);
   1126 }
   1127 
   1128 }  // namespace content
   1129