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
HttpServer()45 HttpServer::HttpServer() : next_connection_id_(1), closing_(false) {
46 }
47
~HttpServer()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
HandleConnection(StreamInterface * stream)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
Respond(HttpServerTransaction * transaction)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
Close(int connection_id,bool force)84 HttpServer::Close(int connection_id, bool force) {
85 if (Connection* connection = Find(connection_id)) {
86 connection->InitiateClose(force);
87 }
88 }
89
90 void
CloseAll(bool force)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*
Find(int connection_id)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
Remove(int connection_id)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
Connection(int connection_id,HttpServer * server)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
~Connection()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
BeginProcess(StreamInterface * stream)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*
EndProcess()158 HttpServer::Connection::EndProcess() {
159 base_.notify(NULL);
160 base_.abort(HE_DISCONNECTED);
161 return base_.detach();
162 }
163
164 void
Respond(HttpServerTransaction * transaction)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
InitiateClose(bool force)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
onHttpHeaderComplete(bool chunked,size_t & data_size)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
onHttpComplete(HttpMode mode,HttpError err)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
onHttpClosed(HttpError err)241 HttpServer::Connection::onHttpClosed(HttpError err) {
242 UNUSED(err);
243 server_->Remove(connection_id_);
244 }
245
246 ///////////////////////////////////////////////////////////////////////////////
247 // HttpListenServer
248 ///////////////////////////////////////////////////////////////////////////////
249
HttpListenServer()250 HttpListenServer::HttpListenServer()
251 : listener_(Thread::Current()->socketserver()->CreateAsyncSocket(SOCK_STREAM)) {
252 listener_->SignalReadEvent.connect(this, &HttpListenServer::OnReadEvent);
253 SignalConnectionClosed.connect(this, &HttpListenServer::OnConnectionClosed);
254 }
255
~HttpListenServer()256 HttpListenServer::~HttpListenServer() {
257 }
258
Listen(const SocketAddress & address)259 int HttpListenServer::Listen(const SocketAddress& address) {
260 if ((listener_->Bind(address) != SOCKET_ERROR) &&
261 (listener_->Listen(5) != SOCKET_ERROR))
262 return 0;
263 return listener_->GetError();
264 }
265
GetAddress(SocketAddress * address) const266 bool HttpListenServer::GetAddress(SocketAddress* address) const {
267 *address = listener_->GetLocalAddress();
268 return !address->IsNil();
269 }
270
StopListening()271 void HttpListenServer::StopListening() {
272 listener_->Close();
273 }
274
OnReadEvent(AsyncSocket * socket)275 void HttpListenServer::OnReadEvent(AsyncSocket* socket) {
276 ASSERT(socket == listener_.get());
277 AsyncSocket* incoming = listener_->Accept(NULL);
278 if (incoming) {
279 StreamInterface* stream = new SocketStream(incoming);
280 //stream = new LoggingAdapter(stream, LS_VERBOSE, "HttpServer", false);
281 HandleConnection(stream);
282 }
283 }
284
OnConnectionClosed(HttpServer * server,int connection_id,StreamInterface * stream)285 void HttpListenServer::OnConnectionClosed(HttpServer* server,
286 int connection_id,
287 StreamInterface* stream) {
288 Thread::Current()->Dispose(stream);
289 }
290
291 ///////////////////////////////////////////////////////////////////////////////
292
293 } // namespace talk_base
294