Home | History | Annotate | Download | only in base
      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(&current_->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(&current_->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(&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 
    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