1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/http/http_transaction_test_util.h"
6
7#include <algorithm>
8
9#include "base/bind.h"
10#include "base/message_loop/message_loop.h"
11#include "base/strings/stringprintf.h"
12#include "base/time/time.h"
13#include "net/base/load_flags.h"
14#include "net/base/load_timing_info.h"
15#include "net/base/net_errors.h"
16#include "net/disk_cache/disk_cache.h"
17#include "net/http/http_cache.h"
18#include "net/http/http_request_info.h"
19#include "net/http/http_response_info.h"
20#include "net/http/http_transaction.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23namespace {
24typedef base::hash_map<std::string, const MockTransaction*> MockTransactionMap;
25static MockTransactionMap mock_transactions;
26}  // namespace
27
28//-----------------------------------------------------------------------------
29// mock transaction data
30
31const MockTransaction kSimpleGET_Transaction = {
32  "http://www.google.com/",
33  "GET",
34  base::Time(),
35  "",
36  net::LOAD_NORMAL,
37  "HTTP/1.1 200 OK",
38  "Cache-Control: max-age=10000\n",
39  base::Time(),
40  "<html><body>Google Blah Blah</body></html>",
41  TEST_MODE_NORMAL,
42  NULL,
43  0,
44  net::OK
45};
46
47const MockTransaction kSimplePOST_Transaction = {
48  "http://bugdatabase.com/edit",
49  "POST",
50  base::Time(),
51  "",
52  net::LOAD_NORMAL,
53  "HTTP/1.1 200 OK",
54  "",
55  base::Time(),
56  "<html><body>Google Blah Blah</body></html>",
57  TEST_MODE_NORMAL,
58  NULL,
59  0,
60  net::OK
61};
62
63const MockTransaction kTypicalGET_Transaction = {
64  "http://www.example.com/~foo/bar.html",
65  "GET",
66  base::Time(),
67  "",
68  net::LOAD_NORMAL,
69  "HTTP/1.1 200 OK",
70  "Date: Wed, 28 Nov 2007 09:40:09 GMT\n"
71  "Last-Modified: Wed, 28 Nov 2007 00:40:09 GMT\n",
72  base::Time(),
73  "<html><body>Google Blah Blah</body></html>",
74  TEST_MODE_NORMAL,
75  NULL,
76  0,
77  net::OK
78};
79
80const MockTransaction kETagGET_Transaction = {
81  "http://www.google.com/foopy",
82  "GET",
83  base::Time(),
84  "",
85  net::LOAD_NORMAL,
86  "HTTP/1.1 200 OK",
87  "Cache-Control: max-age=10000\n"
88  "Etag: \"foopy\"\n",
89  base::Time(),
90  "<html><body>Google Blah Blah</body></html>",
91  TEST_MODE_NORMAL,
92  NULL,
93  0,
94  net::OK
95};
96
97const MockTransaction kRangeGET_Transaction = {
98  "http://www.google.com/",
99  "GET",
100  base::Time(),
101  "Range: 0-100\r\n",
102  net::LOAD_NORMAL,
103  "HTTP/1.1 200 OK",
104  "Cache-Control: max-age=10000\n",
105  base::Time(),
106  "<html><body>Google Blah Blah</body></html>",
107  TEST_MODE_NORMAL,
108  NULL,
109  0,
110  net::OK
111};
112
113static const MockTransaction* const kBuiltinMockTransactions[] = {
114  &kSimpleGET_Transaction,
115  &kSimplePOST_Transaction,
116  &kTypicalGET_Transaction,
117  &kETagGET_Transaction,
118  &kRangeGET_Transaction
119};
120
121const MockTransaction* FindMockTransaction(const GURL& url) {
122  // look for overrides:
123  MockTransactionMap::const_iterator it = mock_transactions.find(url.spec());
124  if (it != mock_transactions.end())
125    return it->second;
126
127  // look for builtins:
128  for (size_t i = 0; i < arraysize(kBuiltinMockTransactions); ++i) {
129    if (url == GURL(kBuiltinMockTransactions[i]->url))
130      return kBuiltinMockTransactions[i];
131  }
132  return NULL;
133}
134
135void AddMockTransaction(const MockTransaction* trans) {
136  mock_transactions[GURL(trans->url).spec()] = trans;
137}
138
139void RemoveMockTransaction(const MockTransaction* trans) {
140  mock_transactions.erase(GURL(trans->url).spec());
141}
142
143MockHttpRequest::MockHttpRequest(const MockTransaction& t) {
144  url = GURL(t.url);
145  method = t.method;
146  extra_headers.AddHeadersFromString(t.request_headers);
147  load_flags = t.load_flags;
148}
149
150//-----------------------------------------------------------------------------
151
152// static
153int TestTransactionConsumer::quit_counter_ = 0;
154
155TestTransactionConsumer::TestTransactionConsumer(
156    net::RequestPriority priority,
157    net::HttpTransactionFactory* factory)
158    : state_(IDLE), error_(net::OK) {
159  // Disregard the error code.
160  factory->CreateTransaction(priority, &trans_);
161  ++quit_counter_;
162}
163
164TestTransactionConsumer::~TestTransactionConsumer() {
165}
166
167void TestTransactionConsumer::Start(const net::HttpRequestInfo* request,
168                                    const net::BoundNetLog& net_log) {
169  state_ = STARTING;
170  int result = trans_->Start(
171      request, base::Bind(&TestTransactionConsumer::OnIOComplete,
172                          base::Unretained(this)), net_log);
173  if (result != net::ERR_IO_PENDING)
174    DidStart(result);
175}
176
177void TestTransactionConsumer::DidStart(int result) {
178  if (result != net::OK) {
179    DidFinish(result);
180  } else {
181    Read();
182  }
183}
184
185void TestTransactionConsumer::DidRead(int result) {
186  if (result <= 0) {
187    DidFinish(result);
188  } else {
189    content_.append(read_buf_->data(), result);
190    Read();
191  }
192}
193
194void TestTransactionConsumer::DidFinish(int result) {
195  state_ = DONE;
196  error_ = result;
197  if (--quit_counter_ == 0)
198    base::MessageLoop::current()->Quit();
199}
200
201void TestTransactionConsumer::Read() {
202  state_ = READING;
203  read_buf_ = new net::IOBuffer(1024);
204  int result = trans_->Read(read_buf_.get(),
205                            1024,
206                            base::Bind(&TestTransactionConsumer::OnIOComplete,
207                                       base::Unretained(this)));
208  if (result != net::ERR_IO_PENDING)
209    DidRead(result);
210}
211
212void TestTransactionConsumer::OnIOComplete(int result) {
213  switch (state_) {
214    case STARTING:
215      DidStart(result);
216      break;
217    case READING:
218      DidRead(result);
219      break;
220    default:
221      NOTREACHED();
222  }
223}
224
225MockNetworkTransaction::MockNetworkTransaction(
226    net::RequestPriority priority,
227    MockNetworkLayer* factory)
228    : request_(NULL),
229      data_cursor_(0),
230      priority_(priority),
231      websocket_handshake_stream_create_helper_(NULL),
232      transaction_factory_(factory->AsWeakPtr()),
233      received_bytes_(0),
234      socket_log_id_(net::NetLog::Source::kInvalidId),
235      weak_factory_(this) {
236}
237
238MockNetworkTransaction::~MockNetworkTransaction() {}
239
240int MockNetworkTransaction::Start(const net::HttpRequestInfo* request,
241                                  const net::CompletionCallback& callback,
242                                  const net::BoundNetLog& net_log) {
243  if (request_)
244    return net::ERR_FAILED;
245
246  request_ = request;
247  return StartInternal(request, callback, net_log);
248}
249
250int MockNetworkTransaction::RestartIgnoringLastError(
251    const net::CompletionCallback& callback) {
252  return net::ERR_FAILED;
253}
254
255int MockNetworkTransaction::RestartWithCertificate(
256    net::X509Certificate* client_cert,
257    const net::CompletionCallback& callback) {
258  return net::ERR_FAILED;
259}
260
261int MockNetworkTransaction::RestartWithAuth(
262    const net::AuthCredentials& credentials,
263    const net::CompletionCallback& callback) {
264  if (!IsReadyToRestartForAuth())
265    return net::ERR_FAILED;
266
267  net::HttpRequestInfo auth_request_info = *request_;
268  auth_request_info.extra_headers.AddHeaderFromString("Authorization: Bar");
269
270  // Let the MockTransactionHandler worry about this: the only way for this
271  // test to succeed is by using an explicit handler for the transaction so
272  // that server behavior can be simulated.
273  return StartInternal(&auth_request_info, callback, net::BoundNetLog());
274}
275
276bool MockNetworkTransaction::IsReadyToRestartForAuth() {
277  if (!request_)
278    return false;
279
280  // Only mock auth when the test asks for it.
281  return request_->extra_headers.HasHeader("X-Require-Mock-Auth");
282}
283
284int MockNetworkTransaction::Read(net::IOBuffer* buf, int buf_len,
285                                 const net::CompletionCallback& callback) {
286  int data_len = static_cast<int>(data_.size());
287  int num = std::min(buf_len, data_len - data_cursor_);
288  if (test_mode_ & TEST_MODE_SLOW_READ)
289    num = std::min(num, 1);
290  if (num) {
291    memcpy(buf->data(), data_.data() + data_cursor_, num);
292    data_cursor_ += num;
293  }
294  if (test_mode_ & TEST_MODE_SYNC_NET_READ)
295    return num;
296
297  CallbackLater(callback, num);
298  return net::ERR_IO_PENDING;
299}
300
301void MockNetworkTransaction::StopCaching() {
302  if (transaction_factory_.get())
303    transaction_factory_->TransactionStopCaching();
304}
305
306bool MockNetworkTransaction::GetFullRequestHeaders(
307    net::HttpRequestHeaders* headers) const {
308  return false;
309}
310
311int64 MockNetworkTransaction::GetTotalReceivedBytes() const {
312  return received_bytes_;
313}
314
315void MockNetworkTransaction::DoneReading() {
316  if (transaction_factory_.get())
317    transaction_factory_->TransactionDoneReading();
318}
319
320const net::HttpResponseInfo* MockNetworkTransaction::GetResponseInfo() const {
321  return &response_;
322}
323
324net::LoadState MockNetworkTransaction::GetLoadState() const {
325  if (data_cursor_)
326    return net::LOAD_STATE_READING_RESPONSE;
327  return net::LOAD_STATE_IDLE;
328}
329
330net::UploadProgress MockNetworkTransaction::GetUploadProgress() const {
331  return net::UploadProgress();
332}
333
334void MockNetworkTransaction::SetQuicServerInfo(
335    net::QuicServerInfo* quic_server_info) {}
336
337bool MockNetworkTransaction::GetLoadTimingInfo(
338    net::LoadTimingInfo* load_timing_info) const {
339  if (socket_log_id_ != net::NetLog::Source::kInvalidId) {
340    // The minimal set of times for a request that gets a response, assuming it
341    // gets a new socket.
342    load_timing_info->socket_reused = false;
343    load_timing_info->socket_log_id = socket_log_id_;
344    load_timing_info->connect_timing.connect_start = base::TimeTicks::Now();
345    load_timing_info->connect_timing.connect_end = base::TimeTicks::Now();
346    load_timing_info->send_start = base::TimeTicks::Now();
347    load_timing_info->send_end = base::TimeTicks::Now();
348  } else {
349    // If there's no valid socket ID, just use the generic socket reused values.
350    // No tests currently depend on this, just should not match the values set
351    // by a cache hit.
352    load_timing_info->socket_reused = true;
353    load_timing_info->send_start = base::TimeTicks::Now();
354    load_timing_info->send_end = base::TimeTicks::Now();
355  }
356  return true;
357}
358
359void MockNetworkTransaction::SetPriority(net::RequestPriority priority) {
360  priority_ = priority;
361}
362
363void MockNetworkTransaction::SetWebSocketHandshakeStreamCreateHelper(
364    net::WebSocketHandshakeStreamBase::CreateHelper* create_helper) {
365  websocket_handshake_stream_create_helper_ = create_helper;
366}
367
368int MockNetworkTransaction::StartInternal(
369    const net::HttpRequestInfo* request,
370    const net::CompletionCallback& callback,
371    const net::BoundNetLog& net_log) {
372  const MockTransaction* t = FindMockTransaction(request->url);
373  if (!t)
374    return net::ERR_FAILED;
375
376  test_mode_ = t->test_mode;
377
378  // Return immediately if we're returning an error.
379  if (net::OK != t->return_code) {
380    if (test_mode_ & TEST_MODE_SYNC_NET_START)
381      return t->return_code;
382    CallbackLater(callback, t->return_code);
383    return net::ERR_IO_PENDING;
384  }
385
386  std::string resp_status = t->status;
387  std::string resp_headers = t->response_headers;
388  std::string resp_data = t->data;
389  received_bytes_ = resp_status.size() + resp_headers.size() + resp_data.size();
390  if (t->handler)
391    (t->handler)(request, &resp_status, &resp_headers, &resp_data);
392
393  std::string header_data = base::StringPrintf(
394      "%s\n%s\n", resp_status.c_str(), resp_headers.c_str());
395  std::replace(header_data.begin(), header_data.end(), '\n', '\0');
396
397  response_.request_time = base::Time::Now();
398  if (!t->request_time.is_null())
399    response_.request_time = t->request_time;
400
401  response_.was_cached = false;
402  response_.network_accessed = true;
403
404  response_.response_time = base::Time::Now();
405  if (!t->response_time.is_null())
406    response_.response_time = t->response_time;
407
408  response_.headers = new net::HttpResponseHeaders(header_data);
409  response_.vary_data.Init(*request, *response_.headers.get());
410  response_.ssl_info.cert_status = t->cert_status;
411  data_ = resp_data;
412
413  if (net_log.net_log())
414    socket_log_id_ = net_log.net_log()->NextID();
415
416  if (test_mode_ & TEST_MODE_SYNC_NET_START)
417    return net::OK;
418
419  CallbackLater(callback, net::OK);
420  return net::ERR_IO_PENDING;
421}
422
423void MockNetworkTransaction::SetBeforeNetworkStartCallback(
424    const BeforeNetworkStartCallback& callback) {
425}
426
427void MockNetworkTransaction::SetBeforeProxyHeadersSentCallback(
428    const BeforeProxyHeadersSentCallback& callback) {
429}
430
431int MockNetworkTransaction::ResumeNetworkStart() {
432  // Should not get here.
433  return net::ERR_FAILED;
434}
435
436void MockNetworkTransaction::CallbackLater(
437    const net::CompletionCallback& callback, int result) {
438  base::MessageLoop::current()->PostTask(
439      FROM_HERE, base::Bind(&MockNetworkTransaction::RunCallback,
440                            weak_factory_.GetWeakPtr(), callback, result));
441}
442
443void MockNetworkTransaction::RunCallback(
444    const net::CompletionCallback& callback, int result) {
445  callback.Run(result);
446}
447
448MockNetworkLayer::MockNetworkLayer()
449    : transaction_count_(0),
450      done_reading_called_(false),
451      stop_caching_called_(false),
452      last_create_transaction_priority_(net::DEFAULT_PRIORITY) {}
453
454MockNetworkLayer::~MockNetworkLayer() {}
455
456void MockNetworkLayer::TransactionDoneReading() {
457  done_reading_called_ = true;
458}
459
460void MockNetworkLayer::TransactionStopCaching() {
461  stop_caching_called_ = true;
462}
463
464int MockNetworkLayer::CreateTransaction(
465    net::RequestPriority priority,
466    scoped_ptr<net::HttpTransaction>* trans) {
467  transaction_count_++;
468  last_create_transaction_priority_ = priority;
469  scoped_ptr<MockNetworkTransaction> mock_transaction(
470      new MockNetworkTransaction(priority, this));
471  last_transaction_ = mock_transaction->AsWeakPtr();
472  *trans = mock_transaction.Pass();
473  return net::OK;
474}
475
476net::HttpCache* MockNetworkLayer::GetCache() {
477  return NULL;
478}
479
480net::HttpNetworkSession* MockNetworkLayer::GetSession() {
481  return NULL;
482}
483
484//-----------------------------------------------------------------------------
485// helpers
486
487int ReadTransaction(net::HttpTransaction* trans, std::string* result) {
488  int rv;
489
490  net::TestCompletionCallback callback;
491
492  std::string content;
493  do {
494    scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(256));
495    rv = trans->Read(buf.get(), 256, callback.callback());
496    if (rv == net::ERR_IO_PENDING)
497      rv = callback.WaitForResult();
498
499    if (rv > 0)
500      content.append(buf->data(), rv);
501    else if (rv < 0)
502      return rv;
503  } while (rv > 0);
504
505  result->swap(content);
506  return net::OK;
507}
508