| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/streams/stream_url_request_job.h" |
| |
| #include "base/memory/ptr_util.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/run_loop.h" |
| #include "base/test/test_simple_task_runner.h" |
| #include "content/browser/streams/stream.h" |
| #include "content/browser/streams/stream_metadata.h" |
| #include "content/browser/streams/stream_registry.h" |
| #include "content/browser/streams/stream_write_observer.h" |
| #include "net/base/request_priority.h" |
| #include "net/http/http_byte_range.h" |
| #include "net/http/http_response_headers.h" |
| #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
| #include "net/url_request/url_request.h" |
| #include "net/url_request/url_request_context.h" |
| #include "net/url_request/url_request_job_factory_impl.h" |
| #include "net/url_request/url_request_test_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| const int kBufferSize = 1024; |
| const char kTestData1[] = "Hello"; |
| const char kTestData2[] = "Here it is data."; |
| |
| const GURL kStreamURL("blob://stream"); |
| |
| } // namespace |
| |
| class StreamURLRequestJobTest : public testing::Test { |
| public: |
| // A simple ProtocolHandler implementation to create StreamURLRequestJob. |
| class MockProtocolHandler : |
| public net::URLRequestJobFactory::ProtocolHandler { |
| public: |
| MockProtocolHandler(StreamRegistry* registry) : registry_(registry) {} |
| |
| // net::URLRequestJobFactory::ProtocolHandler override. |
| net::URLRequestJob* MaybeCreateJob( |
| net::URLRequest* request, |
| net::NetworkDelegate* network_delegate) const override { |
| scoped_refptr<Stream> stream = registry_->GetStream(request->url()); |
| if (stream.get()) |
| return new StreamURLRequestJob(request, network_delegate, stream); |
| return nullptr; |
| } |
| |
| private: |
| StreamRegistry* registry_; |
| }; |
| |
| StreamURLRequestJobTest() {} |
| |
| void SetUp() override { |
| registry_.reset(new StreamRegistry()); |
| |
| url_request_job_factory_.SetProtocolHandler( |
| "blob", std::make_unique<MockProtocolHandler>(registry_.get())); |
| url_request_context_.set_job_factory(&url_request_job_factory_); |
| } |
| |
| void TearDown() override {} |
| |
| void TestSuccessRequest(const GURL& url, |
| const std::string& expected_response) { |
| TestRequest("GET", url, net::HttpRequestHeaders(), 200, net::OK, |
| expected_response); |
| } |
| |
| std::unique_ptr<net::HttpResponseInfo> BuildResponseInfo() { |
| auto response_info = std::make_unique<net::HttpResponseInfo>(); |
| response_info->headers = new net::HttpResponseHeaders("HTTP/1.1 200 OK"); |
| return response_info; |
| } |
| |
| void TestRequest(const std::string& method, |
| const GURL& url, |
| const net::HttpRequestHeaders& extra_headers, |
| int expected_status_code, |
| int expected_error_code, |
| const std::string& expected_response) { |
| net::TestDelegate delegate; |
| request_ = url_request_context_.CreateRequest( |
| url, net::DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS); |
| request_->set_method(method); |
| if (!extra_headers.IsEmpty()) |
| request_->SetExtraRequestHeaders(extra_headers); |
| request_->Start(); |
| |
| base::RunLoop().RunUntilIdle(); |
| |
| // Verify response. |
| if (expected_error_code) |
| EXPECT_EQ(expected_error_code, request_->status().error()); |
| else |
| EXPECT_TRUE(request_->status().is_success()); |
| ASSERT_TRUE(request_->response_headers()); |
| EXPECT_EQ(expected_status_code, |
| request_->response_headers()->response_code()); |
| EXPECT_EQ(expected_response, delegate.data_received()); |
| } |
| |
| protected: |
| base::MessageLoopForIO message_loop_; |
| std::unique_ptr<StreamRegistry> registry_; |
| |
| net::URLRequestContext url_request_context_; |
| net::URLRequestJobFactoryImpl url_request_job_factory_; |
| std::unique_ptr<net::URLRequest> request_; |
| }; |
| |
| TEST_F(StreamURLRequestJobTest, TestGetSimpleDataRequest) { |
| scoped_refptr<Stream> stream( |
| new Stream(registry_.get(), nullptr, kStreamURL)); |
| stream->OnResponseStarted(*BuildResponseInfo()); |
| |
| scoped_refptr<net::StringIOBuffer> buffer( |
| new net::StringIOBuffer(kTestData1)); |
| |
| stream->AddData(buffer, buffer->size()); |
| stream->Finalize(net::OK); |
| |
| TestSuccessRequest(kStreamURL, kTestData1); |
| } |
| |
| TEST_F(StreamURLRequestJobTest, TestGetLargeStreamRequest) { |
| scoped_refptr<Stream> stream( |
| new Stream(registry_.get(), nullptr, kStreamURL)); |
| stream->OnResponseStarted(*BuildResponseInfo()); |
| |
| std::string large_data; |
| large_data.reserve(kBufferSize * 5); |
| for (int i = 0; i < kBufferSize * 5; ++i) |
| large_data.append(1, static_cast<char>(i % 256)); |
| |
| scoped_refptr<net::StringIOBuffer> buffer( |
| new net::StringIOBuffer(large_data)); |
| |
| stream->AddData(buffer, buffer->size()); |
| stream->Finalize(net::OK); |
| TestSuccessRequest(kStreamURL, large_data); |
| } |
| |
| TEST_F(StreamURLRequestJobTest, TestGetNonExistentStreamRequest) { |
| net::TestDelegate delegate; |
| request_ = url_request_context_.CreateRequest( |
| kStreamURL, net::DEFAULT_PRIORITY, &delegate, |
| TRAFFIC_ANNOTATION_FOR_TESTS); |
| request_->set_method("GET"); |
| request_->Start(); |
| |
| base::RunLoop().RunUntilIdle(); |
| |
| // Verify response. |
| EXPECT_FALSE(request_->status().is_success()); |
| } |
| |
| TEST_F(StreamURLRequestJobTest, TestRangeDataRequest) { |
| scoped_refptr<Stream> stream( |
| new Stream(registry_.get(), nullptr, kStreamURL)); |
| stream->OnResponseStarted(*BuildResponseInfo()); |
| |
| scoped_refptr<net::StringIOBuffer> buffer( |
| new net::StringIOBuffer(kTestData2)); |
| |
| stream->AddData(buffer, buffer->size()); |
| stream->Finalize(net::OK); |
| |
| net::HttpRequestHeaders extra_headers; |
| extra_headers.SetHeader(net::HttpRequestHeaders::kRange, |
| net::HttpByteRange::Bounded(0, 3).GetHeaderValue()); |
| TestRequest("GET", kStreamURL, extra_headers, |
| 200, net::OK, std::string(kTestData2, 4)); |
| } |
| |
| TEST_F(StreamURLRequestJobTest, TestInvalidRangeDataRequest) { |
| scoped_refptr<Stream> stream( |
| new Stream(registry_.get(), nullptr, kStreamURL)); |
| stream->OnResponseStarted(*BuildResponseInfo()); |
| scoped_refptr<net::StringIOBuffer> buffer( |
| new net::StringIOBuffer(kTestData2)); |
| |
| stream->AddData(buffer, buffer->size()); |
| stream->Finalize(net::OK); |
| |
| net::HttpRequestHeaders extra_headers; |
| extra_headers.SetHeader(net::HttpRequestHeaders::kRange, |
| net::HttpByteRange::Bounded(1, 3).GetHeaderValue()); |
| TestRequest("GET", kStreamURL, extra_headers, 405, |
| net::ERR_METHOD_NOT_SUPPORTED, std::string()); |
| } |
| |
| } // namespace content |