1 /* 2 * libjingle 3 * Copyright 2004--2005, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <algorithm> 29 30 #include "talk/base/httpcommon-inl.h" 31 32 #include "talk/base/asyncsocket.h" 33 #include "talk/base/common.h" 34 #include "talk/base/httpserver.h" 35 #include "talk/base/logging.h" 36 #include "talk/base/socketstream.h" 37 #include "talk/base/thread.h" 38 39 namespace talk_base { 40 41 /////////////////////////////////////////////////////////////////////////////// 42 // HttpServer 43 /////////////////////////////////////////////////////////////////////////////// 44 45 HttpServer::HttpServer() : next_connection_id_(1), closing_(false) { 46 } 47 48 HttpServer::~HttpServer() { 49 if (closing_) { 50 LOG(LS_WARNING) << "HttpServer::CloseAll has not completed"; 51 } 52 for (ConnectionMap::iterator it = connections_.begin(); 53 it != connections_.end(); 54 ++it) { 55 StreamInterface* stream = it->second->EndProcess(); 56 delete stream; 57 delete it->second; 58 } 59 } 60 61 int 62 HttpServer::HandleConnection(StreamInterface* stream) { 63 int connection_id = next_connection_id_++; 64 ASSERT(connection_id != HTTP_INVALID_CONNECTION_ID); 65 Connection* connection = new Connection(connection_id, this); 66 connections_.insert(ConnectionMap::value_type(connection_id, connection)); 67 connection->BeginProcess(stream); 68 return connection_id; 69 } 70 71 void 72 HttpServer::Respond(HttpServerTransaction* transaction) { 73 int connection_id = transaction->connection_id(); 74 if (Connection* connection = Find(connection_id)) { 75 connection->Respond(transaction); 76 } else { 77 delete transaction; 78 // We may be tempted to SignalHttpComplete, but that implies that a 79 // connection still exists. 80 } 81 } 82 83 void 84 HttpServer::Close(int connection_id, bool force) { 85 if (Connection* connection = Find(connection_id)) { 86 connection->InitiateClose(force); 87 } 88 } 89 90 void 91 HttpServer::CloseAll(bool force) { 92 if (connections_.empty()) { 93 SignalCloseAllComplete(this); 94 return; 95 } 96 closing_ = true; 97 std::list<Connection*> connections; 98 for (ConnectionMap::const_iterator it = connections_.begin(); 99 it != connections_.end(); ++it) { 100 connections.push_back(it->second); 101 } 102 for (std::list<Connection*>::const_iterator it = connections.begin(); 103 it != connections.end(); ++it) { 104 (*it)->InitiateClose(force); 105 } 106 } 107 108 HttpServer::Connection* 109 HttpServer::Find(int connection_id) { 110 ConnectionMap::iterator it = connections_.find(connection_id); 111 if (it == connections_.end()) 112 return NULL; 113 return it->second; 114 } 115 116 void 117 HttpServer::Remove(int connection_id) { 118 ConnectionMap::iterator it = connections_.find(connection_id); 119 if (it == connections_.end()) { 120 ASSERT(false); 121 return; 122 } 123 Connection* connection = it->second; 124 connections_.erase(it); 125 SignalConnectionClosed(this, connection_id, connection->EndProcess()); 126 delete connection; 127 if (closing_ && connections_.empty()) { 128 closing_ = false; 129 SignalCloseAllComplete(this); 130 } 131 } 132 133 /////////////////////////////////////////////////////////////////////////////// 134 // HttpServer::Connection 135 /////////////////////////////////////////////////////////////////////////////// 136 137 HttpServer::Connection::Connection(int connection_id, HttpServer* server) 138 : connection_id_(connection_id), server_(server), 139 current_(NULL), signalling_(false), close_(false) { 140 } 141 142 HttpServer::Connection::~Connection() { 143 // It's possible that an object hosted inside this transaction signalled 144 // an event which caused the connection to close. 145 Thread::Current()->Dispose(current_); 146 } 147 148 void 149 HttpServer::Connection::BeginProcess(StreamInterface* stream) { 150 base_.notify(this); 151 base_.attach(stream); 152 current_ = new HttpServerTransaction(connection_id_); 153 if (base_.mode() != HM_CONNECT) 154 base_.recv(¤t_->request); 155 } 156 157 StreamInterface* 158 HttpServer::Connection::EndProcess() { 159 base_.notify(NULL); 160 base_.abort(HE_DISCONNECTED); 161 return base_.detach(); 162 } 163 164 void 165 HttpServer::Connection::Respond(HttpServerTransaction* transaction) { 166 ASSERT(current_ == NULL); 167 current_ = transaction; 168 if (current_->response.begin() == current_->response.end()) { 169 current_->response.set_error(HC_INTERNAL_SERVER_ERROR); 170 } 171 bool keep_alive = HttpShouldKeepAlive(current_->request); 172 current_->response.setHeader(HH_CONNECTION, 173 keep_alive ? "Keep-Alive" : "Close", 174 false); 175 close_ = !HttpShouldKeepAlive(current_->response); 176 base_.send(¤t_->response); 177 } 178 179 void 180 HttpServer::Connection::InitiateClose(bool force) { 181 bool request_in_progress = (HM_SEND == base_.mode()) || (NULL == current_); 182 if (!signalling_ && (force || !request_in_progress)) { 183 server_->Remove(connection_id_); 184 } else { 185 close_ = true; 186 } 187 } 188 189 // 190 // IHttpNotify Implementation 191 // 192 193 HttpError 194 HttpServer::Connection::onHttpHeaderComplete(bool chunked, size_t& data_size) { 195 if (data_size == SIZE_UNKNOWN) { 196 data_size = 0; 197 } 198 ASSERT(current_ != NULL); 199 bool custom_document = false; 200 server_->SignalHttpRequestHeader(server_, current_, &custom_document); 201 if (!custom_document) { 202 current_->request.document.reset(new MemoryStream); 203 } 204 return HE_NONE; 205 } 206 207 void 208 HttpServer::Connection::onHttpComplete(HttpMode mode, HttpError err) { 209 if (mode == HM_SEND) { 210 ASSERT(current_ != NULL); 211 signalling_ = true; 212 server_->SignalHttpRequestComplete(server_, current_, err); 213 signalling_ = false; 214 if (close_) { 215 // Force a close 216 err = HE_DISCONNECTED; 217 } 218 } 219 if (err != HE_NONE) { 220 server_->Remove(connection_id_); 221 } else if (mode == HM_CONNECT) { 222 base_.recv(¤t_->request); 223 } else if (mode == HM_RECV) { 224 ASSERT(current_ != NULL); 225 // TODO: do we need this? 226 //request_.document_->rewind(); 227 HttpServerTransaction* transaction = current_; 228 current_ = NULL; 229 server_->SignalHttpRequest(server_, transaction); 230 } else if (mode == HM_SEND) { 231 Thread::Current()->Dispose(current_->response.document.release()); 232 current_->request.clear(true); 233 current_->response.clear(true); 234 base_.recv(¤t_->request); 235 } else { 236 ASSERT(false); 237 } 238 } 239 240 void 241 HttpServer::Connection::onHttpClosed(HttpError err) { 242 UNUSED(err); 243 server_->Remove(connection_id_); 244 } 245 246 /////////////////////////////////////////////////////////////////////////////// 247 // HttpListenServer 248 /////////////////////////////////////////////////////////////////////////////// 249 250 HttpListenServer::HttpListenServer() { 251 SignalConnectionClosed.connect(this, &HttpListenServer::OnConnectionClosed); 252 } 253 254 HttpListenServer::~HttpListenServer() { 255 } 256 257 int HttpListenServer::Listen(const SocketAddress& address) { 258 AsyncSocket* sock = 259 Thread::Current()->socketserver()->CreateAsyncSocket(address.family(), 260 SOCK_STREAM); 261 if (!sock) { 262 return SOCKET_ERROR; 263 } 264 listener_.reset(sock); 265 listener_->SignalReadEvent.connect(this, &HttpListenServer::OnReadEvent); 266 if ((listener_->Bind(address) != SOCKET_ERROR) && 267 (listener_->Listen(5) != SOCKET_ERROR)) 268 return 0; 269 return listener_->GetError(); 270 } 271 272 bool HttpListenServer::GetAddress(SocketAddress* address) const { 273 if (!listener_) { 274 return false; 275 } 276 *address = listener_->GetLocalAddress(); 277 return !address->IsNil(); 278 } 279 280 void HttpListenServer::StopListening() { 281 if (listener_) { 282 listener_->Close(); 283 } 284 } 285 286 void HttpListenServer::OnReadEvent(AsyncSocket* socket) { 287 ASSERT(socket == listener_.get()); 288 ASSERT(listener_); 289 AsyncSocket* incoming = listener_->Accept(NULL); 290 if (incoming) { 291 StreamInterface* stream = new SocketStream(incoming); 292 //stream = new LoggingAdapter(stream, LS_VERBOSE, "HttpServer", false); 293 HandleConnection(stream); 294 } 295 } 296 297 void HttpListenServer::OnConnectionClosed(HttpServer* server, 298 int connection_id, 299 StreamInterface* stream) { 300 Thread::Current()->Dispose(stream); 301 } 302 303 /////////////////////////////////////////////////////////////////////////////// 304 305 } // namespace talk_base 306