| OLD | NEW |
| 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/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 | 186 |
| 187 void EmbeddedTestServer::StartThread() { | 187 void EmbeddedTestServer::StartThread() { |
| 188 DCHECK(!io_thread_.get()); | 188 DCHECK(!io_thread_.get()); |
| 189 base::Thread::Options thread_options; | 189 base::Thread::Options thread_options; |
| 190 thread_options.message_loop_type = base::MessageLoop::TYPE_IO; | 190 thread_options.message_loop_type = base::MessageLoop::TYPE_IO; |
| 191 io_thread_.reset(new base::Thread("EmbeddedTestServer io thread")); | 191 io_thread_.reset(new base::Thread("EmbeddedTestServer io thread")); |
| 192 CHECK(io_thread_->StartWithOptions(thread_options)); | 192 CHECK(io_thread_->StartWithOptions(thread_options)); |
| 193 } | 193 } |
| 194 | 194 |
| 195 void EmbeddedTestServer::InitializeOnIOThread() { | 195 void EmbeddedTestServer::InitializeOnIOThread() { |
| 196 DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); | 196 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); |
| 197 DCHECK(!Started()); | 197 DCHECK(!Started()); |
| 198 | 198 |
| 199 SocketDescriptor socket_descriptor = | 199 SocketDescriptor socket_descriptor = |
| 200 TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port_); | 200 TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port_); |
| 201 if (socket_descriptor == kInvalidSocket) | 201 if (socket_descriptor == kInvalidSocket) |
| 202 return; | 202 return; |
| 203 | 203 |
| 204 listen_socket_.reset(new HttpListenSocket(socket_descriptor, this)); | 204 listen_socket_.reset(new HttpListenSocket(socket_descriptor, this)); |
| 205 listen_socket_->Listen(); | 205 listen_socket_->Listen(); |
| 206 | 206 |
| 207 IPEndPoint address; | 207 IPEndPoint address; |
| 208 int result = listen_socket_->GetLocalAddress(&address); | 208 int result = listen_socket_->GetLocalAddress(&address); |
| 209 if (result == OK) { | 209 if (result == OK) { |
| 210 base_url_ = GURL(std::string("http://") + address.ToString()); | 210 base_url_ = GURL(std::string("http://") + address.ToString()); |
| 211 } else { | 211 } else { |
| 212 LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result); | 212 LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result); |
| 213 } | 213 } |
| 214 } | 214 } |
| 215 | 215 |
| 216 void EmbeddedTestServer::ListenOnIOThread() { | 216 void EmbeddedTestServer::ListenOnIOThread() { |
| 217 DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); | 217 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); |
| 218 DCHECK(Started()); | 218 DCHECK(Started()); |
| 219 listen_socket_->ListenOnIOThread(); | 219 listen_socket_->ListenOnIOThread(); |
| 220 } | 220 } |
| 221 | 221 |
| 222 void EmbeddedTestServer::ShutdownOnIOThread() { | 222 void EmbeddedTestServer::ShutdownOnIOThread() { |
| 223 DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); | 223 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); |
| 224 | 224 |
| 225 listen_socket_.reset(); | 225 listen_socket_.reset(); |
| 226 STLDeleteContainerPairSecondPointers(connections_.begin(), | 226 STLDeleteContainerPairSecondPointers(connections_.begin(), |
| 227 connections_.end()); | 227 connections_.end()); |
| 228 connections_.clear(); | 228 connections_.clear(); |
| 229 } | 229 } |
| 230 | 230 |
| 231 void EmbeddedTestServer::HandleRequest(HttpConnection* connection, | 231 void EmbeddedTestServer::HandleRequest(HttpConnection* connection, |
| 232 scoped_ptr<HttpRequest> request) { | 232 scoped_ptr<HttpRequest> request) { |
| 233 DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); | 233 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); |
| 234 | 234 |
| 235 bool request_handled = false; | 235 bool request_handled = false; |
| 236 | 236 |
| 237 for (size_t i = 0; i < request_handlers_.size(); ++i) { | 237 for (size_t i = 0; i < request_handlers_.size(); ++i) { |
| 238 scoped_ptr<HttpResponse> response = | 238 scoped_ptr<HttpResponse> response = |
| 239 request_handlers_[i].Run(*request.get()); | 239 request_handlers_[i].Run(*request.get()); |
| 240 if (response.get()) { | 240 if (response.get()) { |
| 241 connection->SendResponse(response.Pass()); | 241 connection->SendResponse(response.Pass()); |
| 242 request_handled = true; | 242 request_handled = true; |
| 243 break; | 243 break; |
| 244 } | 244 } |
| 245 } | 245 } |
| 246 | 246 |
| 247 if (!request_handled) { | 247 if (!request_handled) { |
| 248 LOG(WARNING) << "Request not handled. Returning 404: " | 248 LOG(WARNING) << "Request not handled. Returning 404: " |
| 249 << request->relative_url; | 249 << request->relative_url; |
| 250 scoped_ptr<BasicHttpResponse> not_found_response(new BasicHttpResponse); | 250 scoped_ptr<BasicHttpResponse> not_found_response(new BasicHttpResponse); |
| 251 not_found_response->set_code(HTTP_NOT_FOUND); | 251 not_found_response->set_code(HTTP_NOT_FOUND); |
| 252 connection->SendResponse(not_found_response.Pass()); | 252 connection->SendResponse(not_found_response.Pass()); |
| 253 } | 253 } |
| 254 | 254 |
| 255 // Drop the connection, since we do not support multiple requests per | 255 // Drop the connection, since we do not support multiple requests per |
| 256 // connection. | 256 // connection. |
| 257 connections_.erase(connection->socket_.get()); | 257 connections_.erase(connection->socket_.get()); |
| 258 delete connection; | 258 delete connection; |
| 259 } | 259 } |
| 260 | 260 |
| 261 GURL EmbeddedTestServer::GetURL(const std::string& relative_url) const { | 261 GURL EmbeddedTestServer::GetURL(const std::string& relative_url) const { |
| 262 DCHECK(Started()) << "You must start the server first."; | 262 DCHECK(Started()) << "You must start the server first."; |
| 263 DCHECK(StartsWithASCII(relative_url, "/", true /* case_sensitive */)) | 263 DCHECK(base::StartsWith(relative_url, "/", base::CompareCase::SENSITIVE)) |
| 264 << relative_url; | 264 << relative_url; |
| 265 return base_url_.Resolve(relative_url); | 265 return base_url_.Resolve(relative_url); |
| 266 } | 266 } |
| 267 | 267 |
| 268 GURL EmbeddedTestServer::GetURL( | 268 GURL EmbeddedTestServer::GetURL( |
| 269 const std::string& hostname, | 269 const std::string& hostname, |
| 270 const std::string& relative_url) const { | 270 const std::string& relative_url) const { |
| 271 GURL local_url = GetURL(relative_url); | 271 GURL local_url = GetURL(relative_url); |
| 272 GURL::Replacements replace_host; | 272 GURL::Replacements replace_host; |
| 273 replace_host.SetHostStr(hostname); | 273 replace_host.SetHostStr(hostname); |
| 274 return local_url.ReplaceComponents(replace_host); | 274 return local_url.ReplaceComponents(replace_host); |
| 275 } | 275 } |
| 276 | 276 |
| 277 void EmbeddedTestServer::ServeFilesFromDirectory( | 277 void EmbeddedTestServer::ServeFilesFromDirectory( |
| 278 const base::FilePath& directory) { | 278 const base::FilePath& directory) { |
| 279 RegisterRequestHandler(base::Bind(&HandleFileRequest, directory)); | 279 RegisterRequestHandler(base::Bind(&HandleFileRequest, directory)); |
| 280 } | 280 } |
| 281 | 281 |
| 282 void EmbeddedTestServer::RegisterRequestHandler( | 282 void EmbeddedTestServer::RegisterRequestHandler( |
| 283 const HandleRequestCallback& callback) { | 283 const HandleRequestCallback& callback) { |
| 284 request_handlers_.push_back(callback); | 284 request_handlers_.push_back(callback); |
| 285 } | 285 } |
| 286 | 286 |
| 287 void EmbeddedTestServer::DidAccept( | 287 void EmbeddedTestServer::DidAccept( |
| 288 StreamListenSocket* server, | 288 StreamListenSocket* server, |
| 289 scoped_ptr<StreamListenSocket> connection) { | 289 scoped_ptr<StreamListenSocket> connection) { |
| 290 DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); | 290 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); |
| 291 | 291 |
| 292 HttpConnection* http_connection = new HttpConnection( | 292 HttpConnection* http_connection = new HttpConnection( |
| 293 connection.Pass(), | 293 connection.Pass(), |
| 294 base::Bind(&EmbeddedTestServer::HandleRequest, | 294 base::Bind(&EmbeddedTestServer::HandleRequest, |
| 295 weak_factory_.GetWeakPtr())); | 295 weak_factory_.GetWeakPtr())); |
| 296 // TODO(szym): Make HttpConnection the StreamListenSocket delegate. | 296 // TODO(szym): Make HttpConnection the StreamListenSocket delegate. |
| 297 connections_[http_connection->socket_.get()] = http_connection; | 297 connections_[http_connection->socket_.get()] = http_connection; |
| 298 } | 298 } |
| 299 | 299 |
| 300 void EmbeddedTestServer::DidRead(StreamListenSocket* connection, | 300 void EmbeddedTestServer::DidRead(StreamListenSocket* connection, |
| 301 const char* data, | 301 const char* data, |
| 302 int length) { | 302 int length) { |
| 303 DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); | 303 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); |
| 304 | 304 |
| 305 HttpConnection* http_connection = FindConnection(connection); | 305 HttpConnection* http_connection = FindConnection(connection); |
| 306 if (http_connection == NULL) { | 306 if (http_connection == NULL) { |
| 307 LOG(WARNING) << "Unknown connection."; | 307 LOG(WARNING) << "Unknown connection."; |
| 308 return; | 308 return; |
| 309 } | 309 } |
| 310 http_connection->ReceiveData(std::string(data, length)); | 310 http_connection->ReceiveData(std::string(data, length)); |
| 311 } | 311 } |
| 312 | 312 |
| 313 void EmbeddedTestServer::DidClose(StreamListenSocket* connection) { | 313 void EmbeddedTestServer::DidClose(StreamListenSocket* connection) { |
| 314 DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); | 314 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); |
| 315 | 315 |
| 316 HttpConnection* http_connection = FindConnection(connection); | 316 HttpConnection* http_connection = FindConnection(connection); |
| 317 if (http_connection == NULL) { | 317 if (http_connection == NULL) { |
| 318 LOG(WARNING) << "Unknown connection."; | 318 LOG(WARNING) << "Unknown connection."; |
| 319 return; | 319 return; |
| 320 } | 320 } |
| 321 delete http_connection; | 321 delete http_connection; |
| 322 connections_.erase(connection); | 322 connections_.erase(connection); |
| 323 } | 323 } |
| 324 | 324 |
| 325 HttpConnection* EmbeddedTestServer::FindConnection( | 325 HttpConnection* EmbeddedTestServer::FindConnection( |
| 326 StreamListenSocket* socket) { | 326 StreamListenSocket* socket) { |
| 327 DCHECK(io_thread_->message_loop_proxy()->BelongsToCurrentThread()); | 327 DCHECK(io_thread_->task_runner()->BelongsToCurrentThread()); |
| 328 | 328 |
| 329 std::map<StreamListenSocket*, HttpConnection*>::iterator it = | 329 std::map<StreamListenSocket*, HttpConnection*>::iterator it = |
| 330 connections_.find(socket); | 330 connections_.find(socket); |
| 331 if (it == connections_.end()) { | 331 if (it == connections_.end()) { |
| 332 return NULL; | 332 return NULL; |
| 333 } | 333 } |
| 334 return it->second; | 334 return it->second; |
| 335 } | 335 } |
| 336 | 336 |
| 337 bool EmbeddedTestServer::PostTaskToIOThreadAndWait( | 337 bool EmbeddedTestServer::PostTaskToIOThreadAndWait( |
| 338 const base::Closure& closure) { | 338 const base::Closure& closure) { |
| 339 // Note that PostTaskAndReply below requires base::MessageLoopProxy::current() | 339 // Note that PostTaskAndReply below requires base::MessageLoop::current() |
| 340 // to return a loop for posting the reply task. However, in order to make | 340 // to return a loop for posting the reply task. However, in order to make |
| 341 // EmbeddedTestServer universally usable, it needs to cope with the situation | 341 // EmbeddedTestServer universally usable, it needs to cope with the situation |
| 342 // where it's running on a thread on which a message loop is not (yet) | 342 // where it's running on a thread on which a message loop is not (yet) |
| 343 // available or as has been destroyed already. | 343 // available or as has been destroyed already. |
| 344 // | 344 // |
| 345 // To handle this situation, create temporary message loop to support the | 345 // To handle this situation, create temporary message loop to support the |
| 346 // PostTaskAndReply operation if the current thread as no message loop. | 346 // PostTaskAndReply operation if the current thread as no message loop. |
| 347 scoped_ptr<base::MessageLoop> temporary_loop; | 347 scoped_ptr<base::MessageLoop> temporary_loop; |
| 348 if (!base::MessageLoop::current()) | 348 if (!base::MessageLoop::current()) |
| 349 temporary_loop.reset(new base::MessageLoop()); | 349 temporary_loop.reset(new base::MessageLoop()); |
| 350 | 350 |
| 351 base::RunLoop run_loop; | 351 base::RunLoop run_loop; |
| 352 if (!io_thread_->message_loop_proxy()->PostTaskAndReply( | 352 if (!io_thread_->task_runner()->PostTaskAndReply(FROM_HERE, closure, |
| 353 FROM_HERE, closure, run_loop.QuitClosure())) { | 353 run_loop.QuitClosure())) { |
| 354 return false; | 354 return false; |
| 355 } | 355 } |
| 356 run_loop.Run(); | 356 run_loop.Run(); |
| 357 | 357 |
| 358 return true; | 358 return true; |
| 359 } | 359 } |
| 360 | 360 |
| 361 } // namespace test_server | 361 } // namespace test_server |
| 362 } // namespace net | 362 } // namespace net |
| OLD | NEW |