• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 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 "net/url_request/url_request_http_job.h"
6 
7 #include <cstddef>
8 
9 #include "base/compiler_specific.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/run_loop.h"
13 #include "net/base/auth.h"
14 #include "net/base/request_priority.h"
15 #include "net/http/http_transaction_factory.h"
16 #include "net/http/http_transaction_test_util.h"
17 #include "net/socket/socket_test_util.h"
18 #include "net/url_request/url_request.h"
19 #include "net/url_request/url_request_status.h"
20 #include "net/url_request/url_request_test_util.h"
21 #include "net/websockets/websocket_handshake_stream_base.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "url/gurl.h"
25 
26 namespace net {
27 
28 namespace {
29 
30 using ::testing::Return;
31 
32 // Inherit from URLRequestHttpJob to expose the priority and some
33 // other hidden functions.
34 class TestURLRequestHttpJob : public URLRequestHttpJob {
35  public:
TestURLRequestHttpJob(URLRequest * request)36   explicit TestURLRequestHttpJob(URLRequest* request)
37       : URLRequestHttpJob(request, request->context()->network_delegate(),
38                           request->context()->http_user_agent_settings()) {}
39 
40   using URLRequestHttpJob::SetPriority;
41   using URLRequestHttpJob::Start;
42   using URLRequestHttpJob::Kill;
43   using URLRequestHttpJob::priority;
44 
45  protected:
~TestURLRequestHttpJob()46   virtual ~TestURLRequestHttpJob() {}
47 };
48 
49 class URLRequestHttpJobTest : public ::testing::Test {
50  protected:
URLRequestHttpJobTest()51   URLRequestHttpJobTest()
52       : req_(context_.CreateRequest(GURL("http://www.example.com"),
53                                     DEFAULT_PRIORITY,
54                                     &delegate_,
55                                     NULL)) {
56     context_.set_http_transaction_factory(&network_layer_);
57   }
58 
TransactionAcceptsSdchEncoding()59   bool TransactionAcceptsSdchEncoding() {
60     base::WeakPtr<MockNetworkTransaction> transaction(
61         network_layer_.last_transaction());
62     EXPECT_TRUE(transaction);
63     if (!transaction) return false;
64 
65     const HttpRequestInfo* request_info = transaction->request();
66     EXPECT_TRUE(request_info);
67     if (!request_info) return false;
68 
69     std::string encoding_headers;
70     bool get_success = request_info->extra_headers.GetHeader(
71         "Accept-Encoding", &encoding_headers);
72     EXPECT_TRUE(get_success);
73     if (!get_success) return false;
74 
75     // This check isn't wrapped with EXPECT* macros because different
76     // results from this function may be expected in different tests.
77     std::vector<std::string> tokens;
78     size_t num_tokens = Tokenize(encoding_headers, ", ", &tokens);
79     for (size_t i = 0; i < num_tokens; i++) {
80       if (!base::strncasecmp(tokens[i].data(), "sdch", tokens[i].length()))
81         return true;
82     }
83     return false;
84   }
85 
EnableSdch()86   void EnableSdch() {
87     context_.SetSdchManager(scoped_ptr<SdchManager>(new SdchManager).Pass());
88   }
89 
90   MockNetworkLayer network_layer_;
91   TestURLRequestContext context_;
92   TestDelegate delegate_;
93   scoped_ptr<URLRequest> req_;
94 };
95 
96 // Make sure that SetPriority actually sets the URLRequestHttpJob's
97 // priority, both before and after start.
TEST_F(URLRequestHttpJobTest,SetPriorityBasic)98 TEST_F(URLRequestHttpJobTest, SetPriorityBasic) {
99   scoped_refptr<TestURLRequestHttpJob> job(
100       new TestURLRequestHttpJob(req_.get()));
101   EXPECT_EQ(DEFAULT_PRIORITY, job->priority());
102 
103   job->SetPriority(LOWEST);
104   EXPECT_EQ(LOWEST, job->priority());
105 
106   job->SetPriority(LOW);
107   EXPECT_EQ(LOW, job->priority());
108 
109   job->Start();
110   EXPECT_EQ(LOW, job->priority());
111 
112   job->SetPriority(MEDIUM);
113   EXPECT_EQ(MEDIUM, job->priority());
114 }
115 
116 // Make sure that URLRequestHttpJob passes on its priority to its
117 // transaction on start.
TEST_F(URLRequestHttpJobTest,SetTransactionPriorityOnStart)118 TEST_F(URLRequestHttpJobTest, SetTransactionPriorityOnStart) {
119   scoped_refptr<TestURLRequestHttpJob> job(
120       new TestURLRequestHttpJob(req_.get()));
121   job->SetPriority(LOW);
122 
123   EXPECT_FALSE(network_layer_.last_transaction());
124 
125   job->Start();
126 
127   ASSERT_TRUE(network_layer_.last_transaction());
128   EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
129 }
130 
131 // Make sure that URLRequestHttpJob passes on its priority updates to
132 // its transaction.
TEST_F(URLRequestHttpJobTest,SetTransactionPriority)133 TEST_F(URLRequestHttpJobTest, SetTransactionPriority) {
134   scoped_refptr<TestURLRequestHttpJob> job(
135       new TestURLRequestHttpJob(req_.get()));
136   job->SetPriority(LOW);
137   job->Start();
138   ASSERT_TRUE(network_layer_.last_transaction());
139   EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
140 
141   job->SetPriority(HIGHEST);
142   EXPECT_EQ(HIGHEST, network_layer_.last_transaction()->priority());
143 }
144 
145 // Make sure that URLRequestHttpJob passes on its priority updates to
146 // newly-created transactions after the first one.
TEST_F(URLRequestHttpJobTest,SetSubsequentTransactionPriority)147 TEST_F(URLRequestHttpJobTest, SetSubsequentTransactionPriority) {
148   scoped_refptr<TestURLRequestHttpJob> job(
149       new TestURLRequestHttpJob(req_.get()));
150   job->Start();
151 
152   job->SetPriority(LOW);
153   ASSERT_TRUE(network_layer_.last_transaction());
154   EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
155 
156   job->Kill();
157   network_layer_.ClearLastTransaction();
158 
159   // Creates a second transaction.
160   job->Start();
161   ASSERT_TRUE(network_layer_.last_transaction());
162   EXPECT_EQ(LOW, network_layer_.last_transaction()->priority());
163 }
164 
165 // Confirm we do advertise SDCH encoding in the case of a GET.
TEST_F(URLRequestHttpJobTest,SdchAdvertisementGet)166 TEST_F(URLRequestHttpJobTest, SdchAdvertisementGet) {
167   EnableSdch();
168   req_->set_method("GET");  // Redundant with default.
169   scoped_refptr<TestURLRequestHttpJob> job(
170       new TestURLRequestHttpJob(req_.get()));
171   job->Start();
172   EXPECT_TRUE(TransactionAcceptsSdchEncoding());
173 }
174 
175 // Confirm we don't advertise SDCH encoding in the case of a POST.
TEST_F(URLRequestHttpJobTest,SdchAdvertisementPost)176 TEST_F(URLRequestHttpJobTest, SdchAdvertisementPost) {
177   EnableSdch();
178   req_->set_method("POST");
179   scoped_refptr<TestURLRequestHttpJob> job(
180       new TestURLRequestHttpJob(req_.get()));
181   job->Start();
182   EXPECT_FALSE(TransactionAcceptsSdchEncoding());
183 }
184 
185 // This base class just serves to set up some things before the TestURLRequest
186 // constructor is called.
187 class URLRequestHttpJobWebSocketTestBase : public ::testing::Test {
188  protected:
URLRequestHttpJobWebSocketTestBase()189   URLRequestHttpJobWebSocketTestBase() : socket_data_(NULL, 0, NULL, 0),
190                                          context_(true) {
191     // A Network Delegate is required for the WebSocketHandshakeStreamBase
192     // object to be passed on to the HttpNetworkTransaction.
193     context_.set_network_delegate(&network_delegate_);
194 
195     // Attempting to create real ClientSocketHandles is not going to work out so
196     // well. Set up a fake socket factory.
197     socket_factory_.AddSocketDataProvider(&socket_data_);
198     context_.set_client_socket_factory(&socket_factory_);
199     context_.Init();
200   }
201 
202   StaticSocketDataProvider socket_data_;
203   TestNetworkDelegate network_delegate_;
204   MockClientSocketFactory socket_factory_;
205   TestURLRequestContext context_;
206 };
207 
208 class URLRequestHttpJobWebSocketTest
209     : public URLRequestHttpJobWebSocketTestBase {
210  protected:
URLRequestHttpJobWebSocketTest()211   URLRequestHttpJobWebSocketTest()
212       : req_(context_.CreateRequest(GURL("ws://www.example.com"),
213                                     DEFAULT_PRIORITY,
214                                     &delegate_,
215                                     NULL)) {
216     // The TestNetworkDelegate expects a call to NotifyBeforeURLRequest before
217     // anything else happens.
218     GURL url("ws://localhost/");
219     TestCompletionCallback dummy;
220     network_delegate_.NotifyBeforeURLRequest(
221         req_.get(), dummy.callback(), &url);
222   }
223 
224   TestDelegate delegate_;
225   scoped_ptr<URLRequest> req_;
226 };
227 
228 class MockCreateHelper : public WebSocketHandshakeStreamBase::CreateHelper {
229  public:
230   // GoogleMock does not appear to play nicely with move-only types like
231   // scoped_ptr, so this forwarding method acts as a workaround.
CreateBasicStream(scoped_ptr<ClientSocketHandle> connection,bool using_proxy)232   virtual WebSocketHandshakeStreamBase* CreateBasicStream(
233       scoped_ptr<ClientSocketHandle> connection,
234       bool using_proxy) OVERRIDE {
235     // Discard the arguments since we don't need them anyway.
236     return CreateBasicStreamMock();
237   }
238 
239   MOCK_METHOD0(CreateBasicStreamMock,
240                WebSocketHandshakeStreamBase*());
241 
242   MOCK_METHOD2(CreateSpdyStream,
243                WebSocketHandshakeStreamBase*(const base::WeakPtr<SpdySession>&,
244                                              bool));
245 };
246 
247 class FakeWebSocketHandshakeStream : public WebSocketHandshakeStreamBase {
248  public:
FakeWebSocketHandshakeStream()249   FakeWebSocketHandshakeStream() : initialize_stream_was_called_(false) {}
250 
initialize_stream_was_called() const251   bool initialize_stream_was_called() const {
252     return initialize_stream_was_called_;
253   }
254 
255   // Fake implementation of HttpStreamBase methods.
InitializeStream(const HttpRequestInfo * request_info,RequestPriority priority,const BoundNetLog & net_log,const CompletionCallback & callback)256   virtual int InitializeStream(const HttpRequestInfo* request_info,
257                                RequestPriority priority,
258                                const BoundNetLog& net_log,
259                                const CompletionCallback& callback) OVERRIDE {
260     initialize_stream_was_called_ = true;
261     return ERR_IO_PENDING;
262   }
263 
SendRequest(const HttpRequestHeaders & request_headers,HttpResponseInfo * response,const CompletionCallback & callback)264   virtual int SendRequest(const HttpRequestHeaders& request_headers,
265                           HttpResponseInfo* response,
266                           const CompletionCallback& callback) OVERRIDE {
267     return ERR_IO_PENDING;
268   }
269 
ReadResponseHeaders(const CompletionCallback & callback)270   virtual int ReadResponseHeaders(const CompletionCallback& callback) OVERRIDE {
271     return ERR_IO_PENDING;
272   }
273 
ReadResponseBody(IOBuffer * buf,int buf_len,const CompletionCallback & callback)274   virtual int ReadResponseBody(IOBuffer* buf,
275                                int buf_len,
276                                const CompletionCallback& callback) OVERRIDE {
277     return ERR_IO_PENDING;
278   }
279 
Close(bool not_reusable)280   virtual void Close(bool not_reusable) OVERRIDE {}
281 
IsResponseBodyComplete() const282   virtual bool IsResponseBodyComplete() const OVERRIDE { return false; }
283 
CanFindEndOfResponse() const284   virtual bool CanFindEndOfResponse() const OVERRIDE { return false; }
285 
IsConnectionReused() const286   virtual bool IsConnectionReused() const OVERRIDE { return false; }
SetConnectionReused()287   virtual void SetConnectionReused() OVERRIDE {}
288 
IsConnectionReusable() const289   virtual bool IsConnectionReusable() const OVERRIDE { return false; }
290 
GetTotalReceivedBytes() const291   virtual int64 GetTotalReceivedBytes() const OVERRIDE { return 0; }
292 
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const293   virtual bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const
294       OVERRIDE {
295     return false;
296   }
297 
GetSSLInfo(SSLInfo * ssl_info)298   virtual void GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {}
299 
GetSSLCertRequestInfo(SSLCertRequestInfo * cert_request_info)300   virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info)
301       OVERRIDE {}
302 
IsSpdyHttpStream() const303   virtual bool IsSpdyHttpStream() const OVERRIDE { return false; }
304 
Drain(HttpNetworkSession * session)305   virtual void Drain(HttpNetworkSession* session) OVERRIDE {}
306 
SetPriority(RequestPriority priority)307   virtual void SetPriority(RequestPriority priority) OVERRIDE {}
308 
309   // Fake implementation of WebSocketHandshakeStreamBase method(s)
Upgrade()310   virtual scoped_ptr<WebSocketStream> Upgrade() OVERRIDE {
311     return scoped_ptr<WebSocketStream>();
312   }
313 
314  private:
315   bool initialize_stream_was_called_;
316 };
317 
TEST_F(URLRequestHttpJobWebSocketTest,RejectedWithoutCreateHelper)318 TEST_F(URLRequestHttpJobWebSocketTest, RejectedWithoutCreateHelper) {
319   scoped_refptr<TestURLRequestHttpJob> job(
320       new TestURLRequestHttpJob(req_.get()));
321   job->Start();
322   base::RunLoop().RunUntilIdle();
323   EXPECT_EQ(URLRequestStatus::FAILED, req_->status().status());
324   EXPECT_EQ(ERR_DISALLOWED_URL_SCHEME, req_->status().error());
325 }
326 
TEST_F(URLRequestHttpJobWebSocketTest,CreateHelperPassedThrough)327 TEST_F(URLRequestHttpJobWebSocketTest, CreateHelperPassedThrough) {
328   scoped_refptr<TestURLRequestHttpJob> job(
329       new TestURLRequestHttpJob(req_.get()));
330   scoped_ptr<MockCreateHelper> create_helper(
331       new ::testing::StrictMock<MockCreateHelper>());
332   FakeWebSocketHandshakeStream* fake_handshake_stream(
333       new FakeWebSocketHandshakeStream);
334   // Ownership of fake_handshake_stream is transferred when CreateBasicStream()
335   // is called.
336   EXPECT_CALL(*create_helper, CreateBasicStreamMock())
337       .WillOnce(Return(fake_handshake_stream));
338   req_->SetUserData(WebSocketHandshakeStreamBase::CreateHelper::DataKey(),
339                     create_helper.release());
340   req_->SetLoadFlags(LOAD_DISABLE_CACHE);
341   job->Start();
342   base::RunLoop().RunUntilIdle();
343   EXPECT_EQ(URLRequestStatus::IO_PENDING, req_->status().status());
344   EXPECT_TRUE(fake_handshake_stream->initialize_stream_was_called());
345 }
346 
347 }  // namespace
348 
349 }  // namespace net
350