Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(698)

Side by Side Diff: net/test/embedded_test_server/embedded_test_server.cc

Issue 1421903008: Revert of SSL in EmbeddedTestServer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/test/embedded_test_server/embedded_test_server.h" 5 #include "net/test/embedded_test_server/embedded_test_server.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/files/file_path.h" 8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h" 9 #include "base/files/file_util.h"
10 #include "base/location.h" 10 #include "base/location.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h" 12 #include "base/message_loop/message_loop.h"
13 #include "base/path_service.h"
14 #include "base/process/process_metrics.h" 13 #include "base/process/process_metrics.h"
15 #include "base/run_loop.h" 14 #include "base/run_loop.h"
16 #include "base/stl_util.h" 15 #include "base/stl_util.h"
17 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
18 #include "base/strings/stringprintf.h" 17 #include "base/strings/stringprintf.h"
19 #include "base/thread_task_runner_handle.h" 18 #include "base/thread_task_runner_handle.h"
20 #include "base/threading/thread_restrictions.h" 19 #include "base/threading/thread_restrictions.h"
21 #include "crypto/rsa_private_key.h"
22 #include "net/base/ip_endpoint.h" 20 #include "net/base/ip_endpoint.h"
23 #include "net/base/net_errors.h" 21 #include "net/base/net_errors.h"
24 #include "net/base/test_data_directory.h"
25 #include "net/cert/pem_tokenizer.h"
26 #include "net/cert/test_root_certs.h"
27 #include "net/socket/ssl_server_socket.h"
28 #include "net/socket/stream_socket.h" 22 #include "net/socket/stream_socket.h"
29 #include "net/socket/tcp_server_socket.h" 23 #include "net/socket/tcp_server_socket.h"
30 #include "net/ssl/ssl_server_config.h"
31 #include "net/test/cert_test_util.h"
32 #include "net/test/embedded_test_server/embedded_test_server_connection_listener .h" 24 #include "net/test/embedded_test_server/embedded_test_server_connection_listener .h"
33 #include "net/test/embedded_test_server/http_connection.h" 25 #include "net/test/embedded_test_server/http_connection.h"
34 #include "net/test/embedded_test_server/http_request.h" 26 #include "net/test/embedded_test_server/http_request.h"
35 #include "net/test/embedded_test_server/http_response.h" 27 #include "net/test/embedded_test_server/http_response.h"
36 #include "net/test/embedded_test_server/request_handler_util.h"
37 28
38 namespace net { 29 namespace net {
39 namespace test_server { 30 namespace test_server {
40 31
41 EmbeddedTestServer::EmbeddedTestServer() : EmbeddedTestServer(TYPE_HTTP) {} 32 namespace {
42 33
43 EmbeddedTestServer::EmbeddedTestServer(Type type) 34 class CustomHttpResponse : public HttpResponse {
44 : is_using_ssl_(type == TYPE_HTTPS), 35 public:
45 connection_listener_(nullptr), 36 CustomHttpResponse(const std::string& headers, const std::string& contents)
46 port_(0), 37 : headers_(headers), contents_(contents) {
47 cert_(CERT_OK) { 38 }
39
40 std::string ToResponseString() const override {
41 return headers_ + "\r\n" + contents_;
42 }
43
44 private:
45 std::string headers_;
46 std::string contents_;
47
48 DISALLOW_COPY_AND_ASSIGN(CustomHttpResponse);
49 };
50
51 // Handles |request| by serving a file from under |server_root|.
52 scoped_ptr<HttpResponse> HandleFileRequest(
53 const base::FilePath& server_root,
54 const HttpRequest& request) {
55 // This is a test-only server. Ignore I/O thread restrictions.
56 base::ThreadRestrictions::ScopedAllowIO allow_io;
57
58 std::string relative_url(request.relative_url);
59 // A proxy request will have an absolute path. Simulate the proxy by stripping
60 // the scheme, host, and port.
61 GURL relative_gurl(relative_url);
62 if (relative_gurl.is_valid())
63 relative_url = relative_gurl.PathForRequest();
64
65 // Trim the first byte ('/').
66 std::string request_path = relative_url.substr(1);
67
68 // Remove the query string if present.
69 size_t query_pos = request_path.find('?');
70 if (query_pos != std::string::npos)
71 request_path = request_path.substr(0, query_pos);
72
73 base::FilePath file_path(server_root.AppendASCII(request_path));
74 std::string file_contents;
75 if (!base::ReadFileToString(file_path, &file_contents))
76 return scoped_ptr<HttpResponse>();
77
78 base::FilePath headers_path(
79 file_path.AddExtension(FILE_PATH_LITERAL("mock-http-headers")));
80
81 if (base::PathExists(headers_path)) {
82 std::string headers_contents;
83 if (!base::ReadFileToString(headers_path, &headers_contents))
84 return scoped_ptr<HttpResponse>();
85
86 scoped_ptr<CustomHttpResponse> http_response(
87 new CustomHttpResponse(headers_contents, file_contents));
88 return http_response.Pass();
89 }
90
91 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
92 http_response->set_code(HTTP_OK);
93 http_response->set_content(file_contents);
94 return http_response.Pass();
95 }
96
97 } // namespace
98
99 EmbeddedTestServer::EmbeddedTestServer()
100 : connection_listener_(nullptr), port_(0) {
48 DCHECK(thread_checker_.CalledOnValidThread()); 101 DCHECK(thread_checker_.CalledOnValidThread());
49
50 if (is_using_ssl_) {
51 TestRootCerts* root_certs = TestRootCerts::GetInstance();
52 base::FilePath certs_dir(GetTestCertsDirectory());
53 root_certs->AddFromFile(certs_dir.AppendASCII("root_ca_cert.pem"));
54 }
55 } 102 }
56 103
57 EmbeddedTestServer::~EmbeddedTestServer() { 104 EmbeddedTestServer::~EmbeddedTestServer() {
58 DCHECK(thread_checker_.CalledOnValidThread()); 105 DCHECK(thread_checker_.CalledOnValidThread());
59 106
60 if (Started() && !ShutdownAndWaitUntilComplete()) { 107 if (Started() && !ShutdownAndWaitUntilComplete()) {
61 LOG(ERROR) << "EmbeddedTestServer failed to shut down."; 108 LOG(ERROR) << "EmbeddedTestServer failed to shut down.";
62 } 109 }
63 } 110 }
64 111
65 void EmbeddedTestServer::SetConnectionListener( 112 void EmbeddedTestServer::SetConnectionListener(
66 EmbeddedTestServerConnectionListener* listener) { 113 EmbeddedTestServerConnectionListener* listener) {
67 DCHECK(!Started()); 114 DCHECK(!Started());
68 connection_listener_ = listener; 115 connection_listener_ = listener;
69 } 116 }
70 117
71 bool EmbeddedTestServer::Start() { 118 bool EmbeddedTestServer::InitializeAndWaitUntilReady() {
72 bool success = InitializeAndListen(); 119 bool success = InitializeAndListen();
73 if (!success) 120 if (!success)
74 return false; 121 return false;
75 StartAcceptingConnections(); 122 StartAcceptingConnections();
76 return true; 123 return true;
77 } 124 }
78 125
79 bool EmbeddedTestServer::InitializeAndWaitUntilReady() {
80 return Start();
81 }
82
83 bool EmbeddedTestServer::InitializeAndListen() { 126 bool EmbeddedTestServer::InitializeAndListen() {
84 DCHECK(!Started()); 127 DCHECK(!Started());
85 128
86 listen_socket_.reset(new TCPServerSocket(nullptr, NetLog::Source())); 129 listen_socket_.reset(new TCPServerSocket(nullptr, NetLog::Source()));
87 130
88 int result = listen_socket_->ListenWithAddressAndPort("127.0.0.1", 0, 10); 131 int result = listen_socket_->ListenWithAddressAndPort("127.0.0.1", 0, 10);
89 if (result) { 132 if (result) {
90 LOG(ERROR) << "Listen failed: " << ErrorToString(result); 133 LOG(ERROR) << "Listen failed: " << ErrorToString(result);
91 listen_socket_.reset(); 134 listen_socket_.reset();
92 return false; 135 return false;
93 } 136 }
94 137
95 result = listen_socket_->GetLocalAddress(&local_endpoint_); 138 result = listen_socket_->GetLocalAddress(&local_endpoint_);
96 if (result != OK) { 139 if (result != OK) {
97 LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result); 140 LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result);
98 listen_socket_.reset(); 141 listen_socket_.reset();
99 return false; 142 return false;
100 } 143 }
101 144
102 if (is_using_ssl_) { 145 base_url_ = GURL(std::string("http://") + local_endpoint_.ToString());
103 base_url_ = GURL("https://" + local_endpoint_.ToString());
104 if (cert_ == CERT_MISMATCHED_NAME || cert_ == CERT_COMMON_NAME_IS_DOMAIN) {
105 base_url_ = GURL(
106 base::StringPrintf("https://localhost:%d", local_endpoint_.port()));
107 }
108 } else {
109 base_url_ = GURL("http://" + local_endpoint_.ToString());
110 }
111 port_ = local_endpoint_.port(); 146 port_ = local_endpoint_.port();
112 147
113 listen_socket_->DetachFromThread(); 148 listen_socket_->DetachFromThread();
114 return true; 149 return true;
115 } 150 }
116 151
117 void EmbeddedTestServer::StartAcceptingConnections() { 152 void EmbeddedTestServer::StartAcceptingConnections() {
118 DCHECK(!io_thread_.get()); 153 DCHECK(!io_thread_.get());
119 base::Thread::Options thread_options; 154 base::Thread::Options thread_options;
120 thread_options.message_loop_type = base::MessageLoop::TYPE_IO; 155 thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
(...skipping 20 matching lines...) Expand all
141 connections_.end()); 176 connections_.end());
142 connections_.clear(); 177 connections_.clear();
143 } 178 }
144 179
145 void EmbeddedTestServer::HandleRequest(HttpConnection* connection, 180 void EmbeddedTestServer::HandleRequest(HttpConnection* connection,
146 scoped_ptr<HttpRequest> request) { 181 scoped_ptr<HttpRequest> request) {
147 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); 182 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
148 183
149 scoped_ptr<HttpResponse> response; 184 scoped_ptr<HttpResponse> response;
150 185
151 for (const auto& handler : request_handlers_) { 186 for (size_t i = 0; i < request_handlers_.size(); ++i) {
152 response = handler.Run(*request); 187 response = request_handlers_[i].Run(*request);
153 if (response) 188 if (response)
154 break; 189 break;
155 } 190 }
156 191
157 if (!response) { 192 if (!response) {
158 for (const auto& handler : default_request_handlers_) {
159 response = handler.Run(*request);
160 if (response)
161 break;
162 }
163 }
164
165 if (!response) {
166 LOG(WARNING) << "Request not handled. Returning 404: " 193 LOG(WARNING) << "Request not handled. Returning 404: "
167 << request->relative_url; 194 << request->relative_url;
168 scoped_ptr<BasicHttpResponse> not_found_response(new BasicHttpResponse); 195 scoped_ptr<BasicHttpResponse> not_found_response(new BasicHttpResponse);
169 not_found_response->set_code(HTTP_NOT_FOUND); 196 not_found_response->set_code(HTTP_NOT_FOUND);
170 response = not_found_response.Pass(); 197 response = not_found_response.Pass();
171 } 198 }
172 199
173 response->SendResponse(base::Bind(&HttpConnection::SendResponseBytes, 200 connection->SendResponse(response.Pass(),
174 base::Unretained(connection)), 201 base::Bind(&EmbeddedTestServer::DidClose,
175 base::Bind(&EmbeddedTestServer::DidClose, 202 base::Unretained(this), connection));
176 base::Unretained(this), connection));
177 } 203 }
178 204
179 GURL EmbeddedTestServer::GetURL(const std::string& relative_url) const { 205 GURL EmbeddedTestServer::GetURL(const std::string& relative_url) const {
180 DCHECK(Started()) << "You must start the server first."; 206 DCHECK(Started()) << "You must start the server first.";
181 DCHECK(base::StartsWith(relative_url, "/", base::CompareCase::SENSITIVE)) 207 DCHECK(base::StartsWith(relative_url, "/", base::CompareCase::SENSITIVE))
182 << relative_url; 208 << relative_url;
183 return base_url_.Resolve(relative_url); 209 return base_url_.Resolve(relative_url);
184 } 210 }
185 211
186 GURL EmbeddedTestServer::GetURL( 212 GURL EmbeddedTestServer::GetURL(
187 const std::string& hostname, 213 const std::string& hostname,
188 const std::string& relative_url) const { 214 const std::string& relative_url) const {
189 GURL local_url = GetURL(relative_url); 215 GURL local_url = GetURL(relative_url);
190 GURL::Replacements replace_host; 216 GURL::Replacements replace_host;
191 replace_host.SetHostStr(hostname); 217 replace_host.SetHostStr(hostname);
192 return local_url.ReplaceComponents(replace_host); 218 return local_url.ReplaceComponents(replace_host);
193 } 219 }
194 220
195 bool EmbeddedTestServer::GetAddressList(AddressList* address_list) const { 221 bool EmbeddedTestServer::GetAddressList(AddressList* address_list) const {
196 *address_list = AddressList(local_endpoint_); 222 *address_list = AddressList(local_endpoint_);
197 return true; 223 return true;
198 } 224 }
199 225
200 void EmbeddedTestServer::SetSSLConfig(ServerCertificate cert,
201 const SSLServerConfig& ssl_config) {
202 DCHECK(!Started());
203 cert_ = cert;
204 ssl_config_ = ssl_config;
205 }
206
207 void EmbeddedTestServer::SetSSLConfig(ServerCertificate cert) {
208 SetSSLConfig(cert, SSLServerConfig());
209 }
210
211 std::string EmbeddedTestServer::GetCertificateName() const {
212 DCHECK(is_using_ssl_);
213 switch (cert_) {
214 case CERT_OK:
215 case CERT_MISMATCHED_NAME:
216 return "ok_cert.pem";
217 case CERT_COMMON_NAME_IS_DOMAIN:
218 return "localhost_cert.pem";
219 case CERT_EXPIRED:
220 return "expired_cert.pem";
221 case CERT_CHAIN_WRONG_ROOT:
222 return "redundant-server-chain.pem";
223 case CERT_BAD_VALIDITY:
224 return "bad_validity.pem";
225 }
226
227 return "ok_cert.pem";
228 }
229
230 scoped_refptr<X509Certificate> EmbeddedTestServer::GetCertificate() const {
231 DCHECK(is_using_ssl_);
232 base::FilePath certs_dir(GetTestCertsDirectory());
233 return ImportCertFromFile(certs_dir, GetCertificateName());
234 }
235
236 void EmbeddedTestServer::ServeFilesFromDirectory( 226 void EmbeddedTestServer::ServeFilesFromDirectory(
237 const base::FilePath& directory) { 227 const base::FilePath& directory) {
238 RegisterRequestHandler(base::Bind(&HandleFileRequest, directory)); 228 RegisterRequestHandler(base::Bind(&HandleFileRequest, directory));
239 } 229 }
240 230
241 void EmbeddedTestServer::ServeFilesFromSourceDirectory(
242 const std::string& relative) {
243 base::FilePath test_data_dir;
244 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
245 ServeFilesFromDirectory(test_data_dir.AppendASCII(relative));
246 }
247
248 void EmbeddedTestServer::ServeFilesFromSourceDirectory(
249 const base::FilePath& relative) {
250 base::FilePath test_data_dir;
251 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
252 ServeFilesFromDirectory(test_data_dir.Append(relative));
253 }
254
255 void EmbeddedTestServer::AddDefaultHandlers(const base::FilePath& directory) {
256 // TODO(svaldez): Add additional default handlers.
257 ServeFilesFromSourceDirectory(directory);
258 }
259
260 void EmbeddedTestServer::RegisterRequestHandler( 231 void EmbeddedTestServer::RegisterRequestHandler(
261 const HandleRequestCallback& callback) { 232 const HandleRequestCallback& callback) {
262 // TODO(svaldez): Add check to prevent RegisterHandler from being called
263 // after the server has started. https://crbug.com/546060
264 request_handlers_.push_back(callback); 233 request_handlers_.push_back(callback);
265 } 234 }
266 235
267 void EmbeddedTestServer::RegisterDefaultHandler(
268 const HandleRequestCallback& callback) {
269 // TODO(svaldez): Add check to prevent RegisterHandler from being called
270 // after the server has started. https://crbug.com/546060
271 default_request_handlers_.push_back(callback);
272 }
273
274 scoped_ptr<StreamSocket> EmbeddedTestServer::DoSSLUpgrade(
275 scoped_ptr<StreamSocket> connection) {
276 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
277
278 base::FilePath certs_dir(GetTestCertsDirectory());
279 std::string cert_name = GetCertificateName();
280
281 base::FilePath key_path = certs_dir.AppendASCII(cert_name);
282 std::string key_string;
283 CHECK(base::ReadFileToString(key_path, &key_string));
284 std::vector<std::string> headers;
285 headers.push_back("PRIVATE KEY");
286 PEMTokenizer pem_tokenizer(key_string, headers);
287 pem_tokenizer.GetNext();
288 std::vector<uint8_t> key_vector;
289 key_vector.assign(pem_tokenizer.data().begin(), pem_tokenizer.data().end());
290
291 scoped_ptr<crypto::RSAPrivateKey> server_key(
292 crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_vector));
293
294 return CreateSSLServerSocket(connection.Pass(), GetCertificate().get(),
295 server_key.get(), ssl_config_);
296 }
297
298 void EmbeddedTestServer::DoAcceptLoop() { 236 void EmbeddedTestServer::DoAcceptLoop() {
299 int rv = OK; 237 int rv = OK;
300 while (rv == OK) { 238 while (rv == OK) {
301 rv = listen_socket_->Accept( 239 rv = listen_socket_->Accept(
302 &accepted_socket_, base::Bind(&EmbeddedTestServer::OnAcceptCompleted, 240 &accepted_socket_, base::Bind(&EmbeddedTestServer::OnAcceptCompleted,
303 base::Unretained(this))); 241 base::Unretained(this)));
304 if (rv == ERR_IO_PENDING) 242 if (rv == ERR_IO_PENDING)
305 return; 243 return;
306 HandleAcceptResult(accepted_socket_.Pass()); 244 HandleAcceptResult(accepted_socket_.Pass());
307 } 245 }
308 } 246 }
309 247
310 void EmbeddedTestServer::OnAcceptCompleted(int rv) { 248 void EmbeddedTestServer::OnAcceptCompleted(int rv) {
311 DCHECK_NE(ERR_IO_PENDING, rv); 249 DCHECK_NE(ERR_IO_PENDING, rv);
312 HandleAcceptResult(accepted_socket_.Pass()); 250 HandleAcceptResult(accepted_socket_.Pass());
313 DoAcceptLoop(); 251 DoAcceptLoop();
314 } 252 }
315 253
316 void EmbeddedTestServer::OnHandshakeDone(HttpConnection* connection, int rv) {
317 if (connection->socket_->IsConnected())
318 ReadData(connection);
319 else
320 DidClose(connection);
321 }
322
323 void EmbeddedTestServer::HandleAcceptResult(scoped_ptr<StreamSocket> socket) { 254 void EmbeddedTestServer::HandleAcceptResult(scoped_ptr<StreamSocket> socket) {
324 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); 255 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
325 if (connection_listener_) 256 if (connection_listener_)
326 connection_listener_->AcceptedSocket(*socket); 257 connection_listener_->AcceptedSocket(*socket);
327 258
328 if (is_using_ssl_)
329 socket = DoSSLUpgrade(socket.Pass());
330
331 HttpConnection* http_connection = new HttpConnection( 259 HttpConnection* http_connection = new HttpConnection(
332 socket.Pass(), 260 socket.Pass(),
333 base::Bind(&EmbeddedTestServer::HandleRequest, base::Unretained(this))); 261 base::Bind(&EmbeddedTestServer::HandleRequest, base::Unretained(this)));
334 connections_[http_connection->socket_.get()] = http_connection; 262 connections_[http_connection->socket_.get()] = http_connection;
335 263
336 if (is_using_ssl_) { 264 ReadData(http_connection);
337 SSLServerSocket* ssl_socket =
338 static_cast<SSLServerSocket*>(http_connection->socket_.get());
339 int rv = ssl_socket->Handshake(
340 base::Bind(&EmbeddedTestServer::OnHandshakeDone, base::Unretained(this),
341 http_connection));
342 if (rv != ERR_IO_PENDING)
343 OnHandshakeDone(http_connection, rv);
344 } else {
345 ReadData(http_connection);
346 }
347 } 265 }
348 266
349 void EmbeddedTestServer::ReadData(HttpConnection* connection) { 267 void EmbeddedTestServer::ReadData(HttpConnection* connection) {
350 while (true) { 268 while (true) {
351 int rv = 269 int rv =
352 connection->ReadData(base::Bind(&EmbeddedTestServer::OnReadCompleted, 270 connection->ReadData(base::Bind(&EmbeddedTestServer::OnReadCompleted,
353 base::Unretained(this), connection)); 271 base::Unretained(this), connection));
354 if (rv == ERR_IO_PENDING) 272 if (rv == ERR_IO_PENDING)
355 return; 273 return;
356 if (!HandleReadResult(connection, rv)) 274 if (!HandleReadResult(connection, rv))
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
421 run_loop.QuitClosure())) { 339 run_loop.QuitClosure())) {
422 return false; 340 return false;
423 } 341 }
424 run_loop.Run(); 342 run_loop.Run();
425 343
426 return true; 344 return true;
427 } 345 }
428 346
429 } // namespace test_server 347 } // namespace test_server
430 } // namespace net 348 } // namespace net
OLDNEW
« no previous file with comments | « net/test/embedded_test_server/embedded_test_server.h ('k') | net/test/embedded_test_server/embedded_test_server_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698