| 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/file_util.h" | 8 #include "base/file_util.h" |
| 9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 92 | 92 |
| 93 void HttpListenSocket::Listen() { | 93 void HttpListenSocket::Listen() { |
| 94 DCHECK(thread_checker_.CalledOnValidThread()); | 94 DCHECK(thread_checker_.CalledOnValidThread()); |
| 95 TCPListenSocket::Listen(); | 95 TCPListenSocket::Listen(); |
| 96 } | 96 } |
| 97 | 97 |
| 98 HttpListenSocket::~HttpListenSocket() { | 98 HttpListenSocket::~HttpListenSocket() { |
| 99 DCHECK(thread_checker_.CalledOnValidThread()); | 99 DCHECK(thread_checker_.CalledOnValidThread()); |
| 100 } | 100 } |
| 101 | 101 |
| 102 EmbeddedTestServer::EmbeddedTestServer( | 102 EmbeddedTestServer::EmbeddedTestServer() |
| 103 const scoped_refptr<base::SingleThreadTaskRunner>& io_thread) | 103 : io_thread_("EmbeddedTestServer io thread"), |
| 104 : io_thread_(io_thread), | |
| 105 port_(-1), | 104 port_(-1), |
| 106 weak_factory_(this) { | 105 weak_factory_(this) { |
| 107 DCHECK(io_thread_.get()); | |
| 108 DCHECK(thread_checker_.CalledOnValidThread()); | 106 DCHECK(thread_checker_.CalledOnValidThread()); |
| 107 |
| 108 base::Thread::Options thread_options; |
| 109 thread_options.message_loop_type = base::MessageLoop::TYPE_IO; |
| 110 CHECK(io_thread_.StartWithOptions(thread_options)); |
| 109 } | 111 } |
| 110 | 112 |
| 111 EmbeddedTestServer::~EmbeddedTestServer() { | 113 EmbeddedTestServer::~EmbeddedTestServer() { |
| 112 DCHECK(thread_checker_.CalledOnValidThread()); | 114 DCHECK(thread_checker_.CalledOnValidThread()); |
| 113 | 115 |
| 114 if (Started() && !ShutdownAndWaitUntilComplete()) { | 116 if (Started() && !ShutdownAndWaitUntilComplete()) { |
| 115 LOG(ERROR) << "EmbeddedTestServer failed to shut down."; | 117 LOG(ERROR) << "EmbeddedTestServer failed to shut down."; |
| 116 } | 118 } |
| 117 } | 119 } |
| 118 | 120 |
| 119 bool EmbeddedTestServer::InitializeAndWaitUntilReady() { | 121 bool EmbeddedTestServer::InitializeAndWaitUntilReady() { |
| 120 DCHECK(thread_checker_.CalledOnValidThread()); | 122 DCHECK(thread_checker_.CalledOnValidThread()); |
| 121 | 123 |
| 122 if (!PostTaskToIOThreadAndWait(base::Bind( | 124 if (!PostTaskToIOThreadAndWait(base::Bind( |
| 123 &EmbeddedTestServer::InitializeOnIOThread, base::Unretained(this)))) { | 125 &EmbeddedTestServer::InitializeOnIOThread, base::Unretained(this)))) { |
| 124 return false; | 126 return false; |
| 125 } | 127 } |
| 126 | 128 |
| 127 return Started() && base_url_.is_valid(); | 129 return Started() && base_url_.is_valid(); |
| 128 } | 130 } |
| 129 | 131 |
| 130 bool EmbeddedTestServer::ShutdownAndWaitUntilComplete() { | 132 bool EmbeddedTestServer::ShutdownAndWaitUntilComplete() { |
| 131 DCHECK(thread_checker_.CalledOnValidThread()); | 133 DCHECK(thread_checker_.CalledOnValidThread()); |
| 132 | 134 |
| 133 return PostTaskToIOThreadAndWait(base::Bind( | 135 return PostTaskToIOThreadAndWait(base::Bind( |
| 134 &EmbeddedTestServer::ShutdownOnIOThread, base::Unretained(this))); | 136 &EmbeddedTestServer::ShutdownOnIOThread, base::Unretained(this))); |
| 135 } | 137 } |
| 136 | 138 |
| 137 void EmbeddedTestServer::InitializeOnIOThread() { | 139 void EmbeddedTestServer::InitializeOnIOThread() { |
| 138 DCHECK(io_thread_->BelongsToCurrentThread()); | 140 DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 139 DCHECK(!Started()); | 141 DCHECK(!Started()); |
| 140 | 142 |
| 141 SocketDescriptor socket_descriptor = | 143 SocketDescriptor socket_descriptor = |
| 142 TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port_); | 144 TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port_); |
| 143 if (socket_descriptor == kInvalidSocket) | 145 if (socket_descriptor == kInvalidSocket) |
| 144 return; | 146 return; |
| 145 | 147 |
| 146 listen_socket_.reset(new HttpListenSocket(socket_descriptor, this)); | 148 listen_socket_.reset(new HttpListenSocket(socket_descriptor, this)); |
| 147 listen_socket_->Listen(); | 149 listen_socket_->Listen(); |
| 148 | 150 |
| 149 IPEndPoint address; | 151 IPEndPoint address; |
| 150 int result = listen_socket_->GetLocalAddress(&address); | 152 int result = listen_socket_->GetLocalAddress(&address); |
| 151 if (result == OK) { | 153 if (result == OK) { |
| 152 base_url_ = GURL(std::string("http://") + address.ToString()); | 154 base_url_ = GURL(std::string("http://") + address.ToString()); |
| 153 } else { | 155 } else { |
| 154 LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result); | 156 LOG(ERROR) << "GetLocalAddress failed: " << ErrorToString(result); |
| 155 } | 157 } |
| 156 } | 158 } |
| 157 | 159 |
| 158 void EmbeddedTestServer::ShutdownOnIOThread() { | 160 void EmbeddedTestServer::ShutdownOnIOThread() { |
| 159 DCHECK(io_thread_->BelongsToCurrentThread()); | 161 DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 160 | 162 |
| 161 listen_socket_.reset(); | 163 listen_socket_.reset(); |
| 162 STLDeleteContainerPairSecondPointers(connections_.begin(), | 164 STLDeleteContainerPairSecondPointers(connections_.begin(), |
| 163 connections_.end()); | 165 connections_.end()); |
| 164 connections_.clear(); | 166 connections_.clear(); |
| 165 } | 167 } |
| 166 | 168 |
| 167 void EmbeddedTestServer::HandleRequest(HttpConnection* connection, | 169 void EmbeddedTestServer::HandleRequest(HttpConnection* connection, |
| 168 scoped_ptr<HttpRequest> request) { | 170 scoped_ptr<HttpRequest> request) { |
| 169 DCHECK(io_thread_->BelongsToCurrentThread()); | 171 DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 170 | 172 |
| 171 bool request_handled = false; | 173 bool request_handled = false; |
| 172 | 174 |
| 173 for (size_t i = 0; i < request_handlers_.size(); ++i) { | 175 for (size_t i = 0; i < request_handlers_.size(); ++i) { |
| 174 scoped_ptr<HttpResponse> response = | 176 scoped_ptr<HttpResponse> response = |
| 175 request_handlers_[i].Run(*request.get()); | 177 request_handlers_[i].Run(*request.get()); |
| 176 if (response.get()) { | 178 if (response.get()) { |
| 177 connection->SendResponse(response.Pass()); | 179 connection->SendResponse(response.Pass()); |
| 178 request_handled = true; | 180 request_handled = true; |
| 179 break; | 181 break; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 208 } | 210 } |
| 209 | 211 |
| 210 void EmbeddedTestServer::RegisterRequestHandler( | 212 void EmbeddedTestServer::RegisterRequestHandler( |
| 211 const HandleRequestCallback& callback) { | 213 const HandleRequestCallback& callback) { |
| 212 request_handlers_.push_back(callback); | 214 request_handlers_.push_back(callback); |
| 213 } | 215 } |
| 214 | 216 |
| 215 void EmbeddedTestServer::DidAccept( | 217 void EmbeddedTestServer::DidAccept( |
| 216 StreamListenSocket* server, | 218 StreamListenSocket* server, |
| 217 scoped_ptr<StreamListenSocket> connection) { | 219 scoped_ptr<StreamListenSocket> connection) { |
| 218 DCHECK(io_thread_->BelongsToCurrentThread()); | 220 DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 219 | 221 |
| 220 HttpConnection* http_connection = new HttpConnection( | 222 HttpConnection* http_connection = new HttpConnection( |
| 221 connection.Pass(), | 223 connection.Pass(), |
| 222 base::Bind(&EmbeddedTestServer::HandleRequest, | 224 base::Bind(&EmbeddedTestServer::HandleRequest, |
| 223 weak_factory_.GetWeakPtr())); | 225 weak_factory_.GetWeakPtr())); |
| 224 // TODO(szym): Make HttpConnection the StreamListenSocket delegate. | 226 // TODO(szym): Make HttpConnection the StreamListenSocket delegate. |
| 225 connections_[http_connection->socket_.get()] = http_connection; | 227 connections_[http_connection->socket_.get()] = http_connection; |
| 226 } | 228 } |
| 227 | 229 |
| 228 void EmbeddedTestServer::DidRead(StreamListenSocket* connection, | 230 void EmbeddedTestServer::DidRead(StreamListenSocket* connection, |
| 229 const char* data, | 231 const char* data, |
| 230 int length) { | 232 int length) { |
| 231 DCHECK(io_thread_->BelongsToCurrentThread()); | 233 DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 232 | 234 |
| 233 HttpConnection* http_connection = FindConnection(connection); | 235 HttpConnection* http_connection = FindConnection(connection); |
| 234 if (http_connection == NULL) { | 236 if (http_connection == NULL) { |
| 235 LOG(WARNING) << "Unknown connection."; | 237 LOG(WARNING) << "Unknown connection."; |
| 236 return; | 238 return; |
| 237 } | 239 } |
| 238 http_connection->ReceiveData(std::string(data, length)); | 240 http_connection->ReceiveData(std::string(data, length)); |
| 239 } | 241 } |
| 240 | 242 |
| 241 void EmbeddedTestServer::DidClose(StreamListenSocket* connection) { | 243 void EmbeddedTestServer::DidClose(StreamListenSocket* connection) { |
| 242 DCHECK(io_thread_->BelongsToCurrentThread()); | 244 DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 243 | 245 |
| 244 HttpConnection* http_connection = FindConnection(connection); | 246 HttpConnection* http_connection = FindConnection(connection); |
| 245 if (http_connection == NULL) { | 247 if (http_connection == NULL) { |
| 246 LOG(WARNING) << "Unknown connection."; | 248 LOG(WARNING) << "Unknown connection."; |
| 247 return; | 249 return; |
| 248 } | 250 } |
| 249 delete http_connection; | 251 delete http_connection; |
| 250 connections_.erase(connection); | 252 connections_.erase(connection); |
| 251 } | 253 } |
| 252 | 254 |
| 253 HttpConnection* EmbeddedTestServer::FindConnection( | 255 HttpConnection* EmbeddedTestServer::FindConnection( |
| 254 StreamListenSocket* socket) { | 256 StreamListenSocket* socket) { |
| 255 DCHECK(io_thread_->BelongsToCurrentThread()); | 257 DCHECK(io_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 256 | 258 |
| 257 std::map<StreamListenSocket*, HttpConnection*>::iterator it = | 259 std::map<StreamListenSocket*, HttpConnection*>::iterator it = |
| 258 connections_.find(socket); | 260 connections_.find(socket); |
| 259 if (it == connections_.end()) { | 261 if (it == connections_.end()) { |
| 260 return NULL; | 262 return NULL; |
| 261 } | 263 } |
| 262 return it->second; | 264 return it->second; |
| 263 } | 265 } |
| 264 | 266 |
| 265 bool EmbeddedTestServer::PostTaskToIOThreadAndWait( | 267 bool EmbeddedTestServer::PostTaskToIOThreadAndWait( |
| 266 const base::Closure& closure) { | 268 const base::Closure& closure) { |
| 267 // Note that PostTaskAndReply below requires base::MessageLoopProxy::current() | 269 // Note that PostTaskAndReply below requires base::MessageLoopProxy::current() |
| 268 // to return a loop for posting the reply task. However, in order to make | 270 // to return a loop for posting the reply task. However, in order to make |
| 269 // EmbeddedTestServer universally usable, it needs to cope with the situation | 271 // EmbeddedTestServer universally usable, it needs to cope with the situation |
| 270 // where it's running on a thread on which a message loop is not (yet) | 272 // where it's running on a thread on which a message loop is not (yet) |
| 271 // available or as has been destroyed already. | 273 // available or as has been destroyed already. |
| 272 // | 274 // |
| 273 // To handle this situation, create temporary message loop to support the | 275 // To handle this situation, create temporary message loop to support the |
| 274 // PostTaskAndReply operation if the current thread as no message loop. | 276 // PostTaskAndReply operation if the current thread as no message loop. |
| 275 scoped_ptr<base::MessageLoop> temporary_loop; | 277 scoped_ptr<base::MessageLoop> temporary_loop; |
| 276 if (!base::MessageLoop::current()) | 278 if (!base::MessageLoop::current()) |
| 277 temporary_loop.reset(new base::MessageLoop()); | 279 temporary_loop.reset(new base::MessageLoop()); |
| 278 | 280 |
| 279 base::RunLoop run_loop; | 281 base::RunLoop run_loop; |
| 280 if (!io_thread_->PostTaskAndReply(FROM_HERE, closure, run_loop.QuitClosure())) | 282 if (!io_thread_.message_loop_proxy()->PostTaskAndReply( |
| 283 FROM_HERE, closure, run_loop.QuitClosure())) { |
| 281 return false; | 284 return false; |
| 285 } |
| 282 run_loop.Run(); | 286 run_loop.Run(); |
| 283 | 287 |
| 284 return true; | 288 return true; |
| 285 } | 289 } |
| 286 | 290 |
| 287 } // namespace test_server | 291 } // namespace test_server |
| 288 } // namespace net | 292 } // namespace net |
| OLD | NEW |