Home | History | Annotate | Download | only in base
      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 
     22 namespace rtc {
     23 
     24 ///////////////////////////////////////////////////////////////////////////////
     25 // HttpServer
     26 ///////////////////////////////////////////////////////////////////////////////
     27 
     28 HttpServer::HttpServer() : next_connection_id_(1), closing_(false) {
     29 }
     30 
     31 HttpServer::~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 
     44 int
     45 HttpServer::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 
     54 void
     55 HttpServer::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 
     66 void
     67 HttpServer::Close(int connection_id, bool force) {
     68   if (Connection* connection = Find(connection_id)) {
     69     connection->InitiateClose(force);
     70   }
     71 }
     72 
     73 void
     74 HttpServer::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 
     91 HttpServer::Connection*
     92 HttpServer::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 
     99 void
    100 HttpServer::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 
    120 HttpServer::Connection::Connection(int connection_id, HttpServer* server)
    121   : connection_id_(connection_id), server_(server),
    122     current_(NULL), signalling_(false), close_(false) {
    123 }
    124 
    125 HttpServer::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 
    131 void
    132 HttpServer::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 
    140 StreamInterface*
    141 HttpServer::Connection::EndProcess() {
    142   base_.notify(NULL);
    143   base_.abort(HE_DISCONNECTED);
    144   return base_.detach();
    145 }
    146 
    147 void
    148 HttpServer::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 
    162 void
    163 HttpServer::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 
    176 HttpError
    177 HttpServer::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 
    190 void
    191 HttpServer::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 
    223 void
    224 HttpServer::Connection::onHttpClosed(HttpError err) {
    225   RTC_UNUSED(err);
    226   server_->Remove(connection_id_);
    227 }
    228 
    229 ///////////////////////////////////////////////////////////////////////////////
    230 // HttpListenServer
    231 ///////////////////////////////////////////////////////////////////////////////
    232 
    233 HttpListenServer::HttpListenServer() {
    234   SignalConnectionClosed.connect(this, &HttpListenServer::OnConnectionClosed);
    235 }
    236 
    237 HttpListenServer::~HttpListenServer() {
    238 }
    239 
    240 int 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 
    255 bool HttpListenServer::GetAddress(SocketAddress* address) const {
    256   if (!listener_) {
    257     return false;
    258   }
    259   *address = listener_->GetLocalAddress();
    260   return !address->IsNil();
    261 }
    262 
    263 void HttpListenServer::StopListening() {
    264   if (listener_) {
    265     listener_->Close();
    266   }
    267 }
    268 
    269 void 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 
    280 void HttpListenServer::OnConnectionClosed(HttpServer* server,
    281                                           int connection_id,
    282                                           StreamInterface* stream) {
    283   Thread::Current()->Dispose(stream);
    284 }
    285 
    286 ///////////////////////////////////////////////////////////////////////////////
    287 
    288 }  // namespace rtc
    289