• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors
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/test/url_request/url_request_mock_data_job.h"
6 
7 #include <memory>
8 
9 #include "base/functional/bind.h"
10 #include "base/location.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/task/single_thread_task_runner.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/url_util.h"
16 #include "net/cert/x509_certificate.h"
17 #include "net/http/http_request_headers.h"
18 #include "net/http/http_response_headers.h"
19 #include "net/http/http_util.h"
20 #include "net/ssl/ssl_cert_request_info.h"
21 #include "net/ssl/ssl_private_key.h"
22 #include "net/url_request/url_request_filter.h"
23 
24 namespace net {
25 namespace {
26 
27 const char kMockHostname[] = "mock.data";
28 
29 // Gets the data from URL of the form:
30 // scheme://kMockHostname/?data=abc&repeat_count=nnn.
GetDataFromRequest(const URLRequest & request)31 std::string GetDataFromRequest(const URLRequest& request) {
32   std::string value;
33   if (!GetValueForKeyInQuery(request.url(), "data", &value))
34     return "default_data";
35   return value;
36 }
37 
38 // Gets the numeric repeat count from URL of the form:
39 // scheme://kMockHostname/?data=abc&repeat_count=nnn.
GetRepeatCountFromRequest(const URLRequest & request)40 int GetRepeatCountFromRequest(const URLRequest& request) {
41   std::string value;
42   if (!GetValueForKeyInQuery(request.url(), "repeat", &value))
43     return 1;
44 
45   int repeat_count;
46   if (!base::StringToInt(value, &repeat_count))
47     return 1;
48 
49   DCHECK_GT(repeat_count, 0);
50 
51   return repeat_count;
52 }
53 
54 // Gets the requestcert flag from URL.
GetRequestClientCertificate(const URLRequest & request)55 bool GetRequestClientCertificate(const URLRequest& request) {
56   std::string ignored_value;
57   return GetValueForKeyInQuery(request.url(), "requestcert", &ignored_value);
58 }
59 
GetMockUrl(const std::string & scheme,const std::string & hostname,const std::string & data,int data_repeat_count,bool request_client_certificate)60 GURL GetMockUrl(const std::string& scheme,
61                 const std::string& hostname,
62                 const std::string& data,
63                 int data_repeat_count,
64                 bool request_client_certificate) {
65   DCHECK_GT(data_repeat_count, 0);
66   std::string url(scheme + "://" + hostname + "/");
67   url.append("?data=");
68   url.append(data);
69   url.append("&repeat=");
70   url.append(base::NumberToString(data_repeat_count));
71   if (request_client_certificate)
72     url += "&requestcert=1";
73   return GURL(url);
74 }
75 
76 class MockJobInterceptor : public URLRequestInterceptor {
77  public:
78   MockJobInterceptor() = default;
79 
80   MockJobInterceptor(const MockJobInterceptor&) = delete;
81   MockJobInterceptor& operator=(const MockJobInterceptor&) = delete;
82 
83   ~MockJobInterceptor() override = default;
84 
85   // URLRequestInterceptor implementation
MaybeInterceptRequest(URLRequest * request) const86   std::unique_ptr<URLRequestJob> MaybeInterceptRequest(
87       URLRequest* request) const override {
88     return std::make_unique<URLRequestMockDataJob>(
89         request, GetDataFromRequest(*request),
90         GetRepeatCountFromRequest(*request),
91         GetRequestClientCertificate(*request));
92   }
93 };
94 
95 }  // namespace
96 
URLRequestMockDataJob(URLRequest * request,const std::string & data,int data_repeat_count,bool request_client_certificate)97 URLRequestMockDataJob::URLRequestMockDataJob(URLRequest* request,
98                                              const std::string& data,
99                                              int data_repeat_count,
100                                              bool request_client_certificate)
101     : URLRequestJob(request),
102       request_client_certificate_(request_client_certificate) {
103   DCHECK_GT(data_repeat_count, 0);
104   for (int i = 0; i < data_repeat_count; ++i) {
105     data_.append(data);
106   }
107 }
108 
109 URLRequestMockDataJob::~URLRequestMockDataJob() = default;
110 
OverrideResponseHeaders(const std::string & headers)111 void URLRequestMockDataJob::OverrideResponseHeaders(
112     const std::string& headers) {
113   headers_ = headers;
114 }
115 
Start()116 void URLRequestMockDataJob::Start() {
117   // Start reading asynchronously so that all error reporting and data
118   // callbacks happen as they would for network requests.
119   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
120       FROM_HERE, base::BindOnce(&URLRequestMockDataJob::StartAsync,
121                                 weak_factory_.GetWeakPtr()));
122 }
123 
ReadRawData(IOBuffer * buf,int buf_size)124 int URLRequestMockDataJob::ReadRawData(IOBuffer* buf, int buf_size) {
125   int bytes_read =
126       std::min(static_cast<size_t>(buf_size), data_.length() - data_offset_);
127   memcpy(buf->data(), data_.c_str() + data_offset_, bytes_read);
128   data_offset_ += bytes_read;
129   return bytes_read;
130 }
131 
ContinueWithCertificate(scoped_refptr<X509Certificate> client_cert,scoped_refptr<SSLPrivateKey> client_private_key)132 void URLRequestMockDataJob::ContinueWithCertificate(
133     scoped_refptr<X509Certificate> client_cert,
134     scoped_refptr<SSLPrivateKey> client_private_key) {
135   DCHECK(request_client_certificate_);
136   NotifyHeadersComplete();
137 }
138 
139 // Public virtual version.
GetResponseInfo(HttpResponseInfo * info)140 void URLRequestMockDataJob::GetResponseInfo(HttpResponseInfo* info) {
141   // Forward to private const version.
142   GetResponseInfoConst(info);
143 }
144 
145 // Private const version.
GetResponseInfoConst(HttpResponseInfo * info) const146 void URLRequestMockDataJob::GetResponseInfoConst(HttpResponseInfo* info) const {
147   // Send back mock headers.
148   std::string raw_headers;
149   if (headers_.has_value()) {
150     raw_headers = headers_.value();
151   } else {
152     raw_headers.append(
153         "HTTP/1.1 200 OK\n"
154         "Content-type: text/plain\n");
155     raw_headers.append(base::StringPrintf("Content-Length: %1d\n",
156                                           static_cast<int>(data_.length())));
157   }
158   info->headers = base::MakeRefCounted<HttpResponseHeaders>(
159       HttpUtil::AssembleRawHeaders(raw_headers));
160 }
161 
StartAsync()162 void URLRequestMockDataJob::StartAsync() {
163   if (!request_)
164     return;
165 
166   set_expected_content_size(data_.length());
167   if (request_client_certificate_) {
168     auto request_all = base::MakeRefCounted<SSLCertRequestInfo>();
169     NotifyCertificateRequested(request_all.get());
170     return;
171   }
172   NotifyHeadersComplete();
173 }
174 
175 // static
AddUrlHandler()176 void URLRequestMockDataJob::AddUrlHandler() {
177   return AddUrlHandlerForHostname(kMockHostname);
178 }
179 
180 // static
AddUrlHandlerForHostname(const std::string & hostname)181 void URLRequestMockDataJob::AddUrlHandlerForHostname(
182     const std::string& hostname) {
183   // Add |hostname| to URLRequestFilter for HTTP and HTTPS.
184   URLRequestFilter* filter = URLRequestFilter::GetInstance();
185   filter->AddHostnameInterceptor("http", hostname,
186                                  std::make_unique<MockJobInterceptor>());
187   filter->AddHostnameInterceptor("https", hostname,
188                                  std::make_unique<MockJobInterceptor>());
189 }
190 
191 // static
GetMockHttpUrl(const std::string & data,int repeat_count)192 GURL URLRequestMockDataJob::GetMockHttpUrl(const std::string& data,
193                                            int repeat_count) {
194   return GetMockHttpUrlForHostname(kMockHostname, data, repeat_count);
195 }
196 
197 // static
GetMockHttpsUrl(const std::string & data,int repeat_count)198 GURL URLRequestMockDataJob::GetMockHttpsUrl(const std::string& data,
199                                             int repeat_count) {
200   return GetMockHttpsUrlForHostname(kMockHostname, data, repeat_count);
201 }
202 
GetMockUrlForClientCertificateRequest()203 GURL URLRequestMockDataJob::GetMockUrlForClientCertificateRequest() {
204   return GetMockUrl("https", kMockHostname, "data", 1, true);
205 }
206 
207 // static
GetMockHttpUrlForHostname(const std::string & hostname,const std::string & data,int repeat_count)208 GURL URLRequestMockDataJob::GetMockHttpUrlForHostname(
209     const std::string& hostname,
210     const std::string& data,
211     int repeat_count) {
212   return GetMockUrl("http", hostname, data, repeat_count, false);
213 }
214 
215 // static
GetMockHttpsUrlForHostname(const std::string & hostname,const std::string & data,int repeat_count)216 GURL URLRequestMockDataJob::GetMockHttpsUrlForHostname(
217     const std::string& hostname,
218     const std::string& data,
219     int repeat_count) {
220   return GetMockUrl("https", hostname, data, repeat_count, false);
221 }
222 
223 }  // namespace net
224