1/*
2 *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include <algorithm>
12
13#include "webrtc/base/httpcommon-inl.h"
14
15#include "webrtc/base/asyncsocket.h"
16#include "webrtc/base/common.h"
17#include "webrtc/base/httpserver.h"
18#include "webrtc/base/logging.h"
19#include "webrtc/base/socketstream.h"
20#include "webrtc/base/thread.h"
21
22namespace rtc {
23
24///////////////////////////////////////////////////////////////////////////////
25// HttpServer
26///////////////////////////////////////////////////////////////////////////////
27
28HttpServer::HttpServer() : next_connection_id_(1), closing_(false) {
29}
30
31HttpServer::~HttpServer() {
32  if (closing_) {
33    LOG(LS_WARNING) << "HttpServer::CloseAll has not completed";
34  }
35  for (ConnectionMap::iterator it = connections_.begin();
36       it != connections_.end();
37       ++it) {
38    StreamInterface* stream = it->second->EndProcess();
39    delete stream;
40    delete it->second;
41  }
42}
43
44int
45HttpServer::HandleConnection(StreamInterface* stream) {
46  int connection_id = next_connection_id_++;
47  ASSERT(connection_id != HTTP_INVALID_CONNECTION_ID);
48  Connection* connection = new Connection(connection_id, this);
49  connections_.insert(ConnectionMap::value_type(connection_id, connection));
50  connection->BeginProcess(stream);
51  return connection_id;
52}
53
54void
55HttpServer::Respond(HttpServerTransaction* transaction) {
56  int connection_id = transaction->connection_id();
57  if (Connection* connection = Find(connection_id)) {
58    connection->Respond(transaction);
59  } else {
60    delete transaction;
61    // We may be tempted to SignalHttpComplete, but that implies that a
62    // connection still exists.
63  }
64}
65
66void
67HttpServer::Close(int connection_id, bool force) {
68  if (Connection* connection = Find(connection_id)) {
69    connection->InitiateClose(force);
70  }
71}
72
73void
74HttpServer::CloseAll(bool force) {
75  if (connections_.empty()) {
76    SignalCloseAllComplete(this);
77    return;
78  }
79  closing_ = true;
80  std::list<Connection*> connections;
81  for (ConnectionMap::const_iterator it = connections_.begin();
82       it != connections_.end(); ++it) {
83    connections.push_back(it->second);
84  }
85  for (std::list<Connection*>::const_iterator it = connections.begin();
86      it != connections.end(); ++it) {
87    (*it)->InitiateClose(force);
88  }
89}
90
91HttpServer::Connection*
92HttpServer::Find(int connection_id) {
93  ConnectionMap::iterator it = connections_.find(connection_id);
94  if (it == connections_.end())
95    return NULL;
96  return it->second;
97}
98
99void
100HttpServer::Remove(int connection_id) {
101  ConnectionMap::iterator it = connections_.find(connection_id);
102  if (it == connections_.end()) {
103    ASSERT(false);
104    return;
105  }
106  Connection* connection = it->second;
107  connections_.erase(it);
108  SignalConnectionClosed(this, connection_id, connection->EndProcess());
109  delete connection;
110  if (closing_ && connections_.empty()) {
111    closing_ = false;
112    SignalCloseAllComplete(this);
113  }
114}
115
116///////////////////////////////////////////////////////////////////////////////
117// HttpServer::Connection
118///////////////////////////////////////////////////////////////////////////////
119
120HttpServer::Connection::Connection(int connection_id, HttpServer* server)
121  : connection_id_(connection_id), server_(server),
122    current_(NULL), signalling_(false), close_(false) {
123}
124
125HttpServer::Connection::~Connection() {
126  // It's possible that an object hosted inside this transaction signalled
127  // an event which caused the connection to close.
128  Thread::Current()->Dispose(current_);
129}
130
131void
132HttpServer::Connection::BeginProcess(StreamInterface* stream) {
133  base_.notify(this);
134  base_.attach(stream);
135  current_ = new HttpServerTransaction(connection_id_);
136  if (base_.mode() != HM_CONNECT)
137    base_.recv(&current_->request);
138}
139
140StreamInterface*
141HttpServer::Connection::EndProcess() {
142  base_.notify(NULL);
143  base_.abort(HE_DISCONNECTED);
144  return base_.detach();
145}
146
147void
148HttpServer::Connection::Respond(HttpServerTransaction* transaction) {
149  ASSERT(current_ == NULL);
150  current_ = transaction;
151  if (current_->response.begin() == current_->response.end()) {
152    current_->response.set_error(HC_INTERNAL_SERVER_ERROR);
153  }
154  bool keep_alive = HttpShouldKeepAlive(current_->request);
155  current_->response.setHeader(HH_CONNECTION,
156                               keep_alive ? "Keep-Alive" : "Close",
157                               false);
158  close_ = !HttpShouldKeepAlive(current_->response);
159  base_.send(&current_->response);
160}
161
162void
163HttpServer::Connection::InitiateClose(bool force) {
164  bool request_in_progress = (HM_SEND == base_.mode()) || (NULL == current_);
165  if (!signalling_ && (force || !request_in_progress)) {
166    server_->Remove(connection_id_);
167  } else {
168    close_ = true;
169  }
170}
171
172//
173// IHttpNotify Implementation
174//
175
176HttpError
177HttpServer::Connection::onHttpHeaderComplete(bool chunked, size_t& data_size) {
178  if (data_size == SIZE_UNKNOWN) {
179    data_size = 0;
180  }
181  ASSERT(current_ != NULL);
182  bool custom_document = false;
183  server_->SignalHttpRequestHeader(server_, current_, &custom_document);
184  if (!custom_document) {
185    current_->request.document.reset(new MemoryStream);
186  }
187  return HE_NONE;
188}
189
190void
191HttpServer::Connection::onHttpComplete(HttpMode mode, HttpError err) {
192  if (mode == HM_SEND) {
193    ASSERT(current_ != NULL);
194    signalling_ = true;
195    server_->SignalHttpRequestComplete(server_, current_, err);
196    signalling_ = false;
197    if (close_) {
198      // Force a close
199      err = HE_DISCONNECTED;
200    }
201  }
202  if (err != HE_NONE) {
203    server_->Remove(connection_id_);
204  } else if (mode == HM_CONNECT) {
205    base_.recv(&current_->request);
206  } else if (mode == HM_RECV) {
207    ASSERT(current_ != NULL);
208    // TODO: do we need this?
209    //request_.document_->rewind();
210    HttpServerTransaction* transaction = current_;
211    current_ = NULL;
212    server_->SignalHttpRequest(server_, transaction);
213  } else if (mode == HM_SEND) {
214    Thread::Current()->Dispose(current_->response.document.release());
215    current_->request.clear(true);
216    current_->response.clear(true);
217    base_.recv(&current_->request);
218  } else {
219    ASSERT(false);
220  }
221}
222
223void
224HttpServer::Connection::onHttpClosed(HttpError err) {
225  RTC_UNUSED(err);
226  server_->Remove(connection_id_);
227}
228
229///////////////////////////////////////////////////////////////////////////////
230// HttpListenServer
231///////////////////////////////////////////////////////////////////////////////
232
233HttpListenServer::HttpListenServer() {
234  SignalConnectionClosed.connect(this, &HttpListenServer::OnConnectionClosed);
235}
236
237HttpListenServer::~HttpListenServer() {
238}
239
240int HttpListenServer::Listen(const SocketAddress& address) {
241  AsyncSocket* sock =
242      Thread::Current()->socketserver()->CreateAsyncSocket(address.family(),
243                                                           SOCK_STREAM);
244  if (!sock) {
245    return SOCKET_ERROR;
246  }
247  listener_.reset(sock);
248  listener_->SignalReadEvent.connect(this, &HttpListenServer::OnReadEvent);
249  if ((listener_->Bind(address) != SOCKET_ERROR) &&
250      (listener_->Listen(5) != SOCKET_ERROR))
251    return 0;
252  return listener_->GetError();
253}
254
255bool HttpListenServer::GetAddress(SocketAddress* address) const {
256  if (!listener_) {
257    return false;
258  }
259  *address = listener_->GetLocalAddress();
260  return !address->IsNil();
261}
262
263void HttpListenServer::StopListening() {
264  if (listener_) {
265    listener_->Close();
266  }
267}
268
269void HttpListenServer::OnReadEvent(AsyncSocket* socket) {
270  ASSERT(socket == listener_.get());
271  ASSERT(listener_);
272  AsyncSocket* incoming = listener_->Accept(NULL);
273  if (incoming) {
274    StreamInterface* stream = new SocketStream(incoming);
275    //stream = new LoggingAdapter(stream, LS_VERBOSE, "HttpServer", false);
276    HandleConnection(stream);
277  }
278}
279
280void HttpListenServer::OnConnectionClosed(HttpServer* server,
281                                          int connection_id,
282                                          StreamInterface* stream) {
283  Thread::Current()->Dispose(stream);
284}
285
286///////////////////////////////////////////////////////////////////////////////
287
288}  // namespace rtc
289