blob: 7d467c39fa2f3b84c7de13de8010444ef207ada8 [file] [log] [blame]
henrike@webrtc.org0e118e72013-07-10 00:45:36 +00001/*
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
39namespace talk_base {
40
41///////////////////////////////////////////////////////////////////////////////
42// HttpServer
43///////////////////////////////////////////////////////////////////////////////
44
45HttpServer::HttpServer() : next_connection_id_(1), closing_(false) {
46}
47
48HttpServer::~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
61int
62HttpServer::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
71void
72HttpServer::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
83void
84HttpServer::Close(int connection_id, bool force) {
85 if (Connection* connection = Find(connection_id)) {
86 connection->InitiateClose(force);
87 }
88}
89
90void
91HttpServer::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
108HttpServer::Connection*
109HttpServer::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
116void
117HttpServer::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
137HttpServer::Connection::Connection(int connection_id, HttpServer* server)
138 : connection_id_(connection_id), server_(server),
139 current_(NULL), signalling_(false), close_(false) {
140}
141
142HttpServer::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
148void
149HttpServer::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(&current_->request);
155}
156
157StreamInterface*
158HttpServer::Connection::EndProcess() {
159 base_.notify(NULL);
160 base_.abort(HE_DISCONNECTED);
161 return base_.detach();
162}
163
164void
165HttpServer::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(&current_->response);
177}
178
179void
180HttpServer::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
193HttpError
194HttpServer::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
207void
208HttpServer::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(&current_->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(&current_->request);
235 } else {
236 ASSERT(false);
237 }
238}
239
240void
241HttpServer::Connection::onHttpClosed(HttpError err) {
242 UNUSED(err);
243 server_->Remove(connection_id_);
244}
245
246///////////////////////////////////////////////////////////////////////////////
247// HttpListenServer
248///////////////////////////////////////////////////////////////////////////////
249
250HttpListenServer::HttpListenServer() {
251 SignalConnectionClosed.connect(this, &HttpListenServer::OnConnectionClosed);
252}
253
254HttpListenServer::~HttpListenServer() {
255}
256
257int 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
272bool HttpListenServer::GetAddress(SocketAddress* address) const {
273 if (!listener_) {
274 return false;
275 }
276 *address = listener_->GetLocalAddress();
277 return !address->IsNil();
278}
279
280void HttpListenServer::StopListening() {
281 if (listener_) {
282 listener_->Close();
283 }
284}
285
286void 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
297void HttpListenServer::OnConnectionClosed(HttpServer* server,
298 int connection_id,
299 StreamInterface* stream) {
300 Thread::Current()->Dispose(stream);
301}
302
303///////////////////////////////////////////////////////////////////////////////
304
305} // namespace talk_base