Home | History | Annotate | Download | only in server
      1 /*
      2  * libjingle
      3  * Copyright 2011, 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 "talk/examples/peerconnection/server/data_socket.h"
     29 
     30 #include <ctype.h>
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #if defined(POSIX)
     35 #include <unistd.h>
     36 #endif
     37 
     38 #include "talk/examples/peerconnection/server/utils.h"
     39 
     40 static const char kHeaderTerminator[] = "\r\n\r\n";
     41 static const int kHeaderTerminatorLength = sizeof(kHeaderTerminator) - 1;
     42 
     43 // static
     44 const char DataSocket::kCrossOriginAllowHeaders[] =
     45     "Access-Control-Allow-Origin: *\r\n"
     46     "Access-Control-Allow-Credentials: true\r\n"
     47     "Access-Control-Allow-Methods: POST, GET, OPTIONS\r\n"
     48     "Access-Control-Allow-Headers: Content-Type, "
     49         "Content-Length, Connection, Cache-Control\r\n"
     50     "Access-Control-Expose-Headers: Content-Length, X-Peer-Id\r\n";
     51 
     52 #if defined(WIN32)
     53 class WinsockInitializer {
     54   static WinsockInitializer singleton;
     55 
     56   WinsockInitializer() {
     57     WSADATA data;
     58     WSAStartup(MAKEWORD(1, 0), &data);
     59   }
     60 
     61  public:
     62   ~WinsockInitializer() { WSACleanup(); }
     63 };
     64 WinsockInitializer WinsockInitializer::singleton;
     65 #endif
     66 
     67 //
     68 // SocketBase
     69 //
     70 
     71 bool SocketBase::Create() {
     72   assert(!valid());
     73   socket_ = ::socket(AF_INET, SOCK_STREAM, 0);
     74   return valid();
     75 }
     76 
     77 void SocketBase::Close() {
     78   if (socket_ != INVALID_SOCKET) {
     79     closesocket(socket_);
     80     socket_ = INVALID_SOCKET;
     81   }
     82 }
     83 
     84 //
     85 // DataSocket
     86 //
     87 
     88 std::string DataSocket::request_arguments() const {
     89   size_t args = request_path_.find('?');
     90   if (args != std::string::npos)
     91     return request_path_.substr(args + 1);
     92   return "";
     93 }
     94 
     95 bool DataSocket::PathEquals(const char* path) const {
     96   assert(path);
     97   size_t args = request_path_.find('?');
     98   if (args != std::string::npos)
     99     return request_path_.substr(0, args).compare(path) == 0;
    100   return request_path_.compare(path) == 0;
    101 }
    102 
    103 bool DataSocket::OnDataAvailable(bool* close_socket) {
    104   assert(valid());
    105   char buffer[0xfff] = {0};
    106   int bytes = recv(socket_, buffer, sizeof(buffer), 0);
    107   if (bytes == SOCKET_ERROR || bytes == 0) {
    108     *close_socket = true;
    109     return false;
    110   }
    111 
    112   *close_socket = false;
    113 
    114   bool ret = true;
    115   if (headers_received()) {
    116     if (method_ != POST) {
    117       // unexpectedly received data.
    118       ret = false;
    119     } else {
    120       data_.append(buffer, bytes);
    121     }
    122   } else {
    123     request_headers_.append(buffer, bytes);
    124     size_t found = request_headers_.find(kHeaderTerminator);
    125     if (found != std::string::npos) {
    126       data_ = request_headers_.substr(found + kHeaderTerminatorLength);
    127       request_headers_.resize(found + kHeaderTerminatorLength);
    128       ret = ParseHeaders();
    129     }
    130   }
    131   return ret;
    132 }
    133 
    134 bool DataSocket::Send(const std::string& data) const {
    135   return send(socket_, data.data(), static_cast<int>(data.length()), 0) !=
    136       SOCKET_ERROR;
    137 }
    138 
    139 bool DataSocket::Send(const std::string& status, bool connection_close,
    140                       const std::string& content_type,
    141                       const std::string& extra_headers,
    142                       const std::string& data) const {
    143   assert(valid());
    144   assert(!status.empty());
    145   std::string buffer("HTTP/1.1 " + status + "\r\n");
    146 
    147   buffer += "Server: PeerConnectionTestServer/0.1\r\n"
    148             "Cache-Control: no-cache\r\n";
    149 
    150   if (connection_close)
    151     buffer += "Connection: close\r\n";
    152 
    153   if (!content_type.empty())
    154     buffer += "Content-Type: " + content_type + "\r\n";
    155 
    156   buffer += "Content-Length: " + int2str(static_cast<int>(data.size())) +
    157             "\r\n";
    158 
    159   if (!extra_headers.empty()) {
    160     buffer += extra_headers;
    161     // Extra headers are assumed to have a separator per header.
    162   }
    163 
    164   buffer += kCrossOriginAllowHeaders;
    165 
    166   buffer += "\r\n";
    167   buffer += data;
    168 
    169   return Send(buffer);
    170 }
    171 
    172 void DataSocket::Clear() {
    173   method_ = INVALID;
    174   content_length_ = 0;
    175   content_type_.clear();
    176   request_path_.clear();
    177   request_headers_.clear();
    178   data_.clear();
    179 }
    180 
    181 bool DataSocket::ParseHeaders() {
    182   assert(!request_headers_.empty());
    183   assert(method_ == INVALID);
    184   size_t i = request_headers_.find("\r\n");
    185   if (i == std::string::npos)
    186     return false;
    187 
    188   if (!ParseMethodAndPath(request_headers_.data(), i))
    189     return false;
    190 
    191   assert(method_ != INVALID);
    192   assert(!request_path_.empty());
    193 
    194   if (method_ == POST) {
    195     const char* headers = request_headers_.data() + i + 2;
    196     size_t len = request_headers_.length() - i - 2;
    197     if (!ParseContentLengthAndType(headers, len))
    198       return false;
    199   }
    200 
    201   return true;
    202 }
    203 
    204 bool DataSocket::ParseMethodAndPath(const char* begin, size_t len) {
    205   struct {
    206     const char* method_name;
    207     size_t method_name_len;
    208     RequestMethod id;
    209   } supported_methods[] = {
    210     { "GET", 3, GET },
    211     { "POST", 4, POST },
    212     { "OPTIONS", 7, OPTIONS },
    213   };
    214 
    215   const char* path = NULL;
    216   for (size_t i = 0; i < ARRAYSIZE(supported_methods); ++i) {
    217     if (len > supported_methods[i].method_name_len &&
    218         isspace(begin[supported_methods[i].method_name_len]) &&
    219         strncmp(begin, supported_methods[i].method_name,
    220                 supported_methods[i].method_name_len) == 0) {
    221       method_ = supported_methods[i].id;
    222       path = begin + supported_methods[i].method_name_len;
    223       break;
    224     }
    225   }
    226 
    227   const char* end = begin + len;
    228   if (!path || path >= end)
    229     return false;
    230 
    231   ++path;
    232   begin = path;
    233   while (!isspace(*path) && path < end)
    234     ++path;
    235 
    236   request_path_.assign(begin, path - begin);
    237 
    238   return true;
    239 }
    240 
    241 bool DataSocket::ParseContentLengthAndType(const char* headers, size_t length) {
    242   assert(content_length_ == 0);
    243   assert(content_type_.empty());
    244 
    245   const char* end = headers + length;
    246   while (headers && headers < end) {
    247     if (!isspace(headers[0])) {
    248       static const char kContentLength[] = "Content-Length:";
    249       static const char kContentType[] = "Content-Type:";
    250       if ((headers + ARRAYSIZE(kContentLength)) < end &&
    251           strncmp(headers, kContentLength,
    252                   ARRAYSIZE(kContentLength) - 1) == 0) {
    253         headers += ARRAYSIZE(kContentLength) - 1;
    254         while (headers[0] == ' ')
    255           ++headers;
    256         content_length_ = atoi(headers);
    257       } else if ((headers + ARRAYSIZE(kContentType)) < end &&
    258                  strncmp(headers, kContentType,
    259                          ARRAYSIZE(kContentType) - 1) == 0) {
    260         headers += ARRAYSIZE(kContentType) - 1;
    261         while (headers[0] == ' ')
    262           ++headers;
    263         const char* type_end = strstr(headers, "\r\n");
    264         if (type_end == NULL)
    265           type_end = end;
    266         content_type_.assign(headers, type_end);
    267       }
    268     } else {
    269       ++headers;
    270     }
    271     headers = strstr(headers, "\r\n");
    272     if (headers)
    273       headers += 2;
    274   }
    275 
    276   return !content_type_.empty() && content_length_ != 0;
    277 }
    278 
    279 //
    280 // ListeningSocket
    281 //
    282 
    283 bool ListeningSocket::Listen(unsigned short port) {
    284   assert(valid());
    285   int enabled = 1;
    286   setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
    287       reinterpret_cast<const char*>(&enabled), sizeof(enabled));
    288   struct sockaddr_in addr = {0};
    289   addr.sin_family = AF_INET;
    290   addr.sin_addr.s_addr = htonl(INADDR_ANY);
    291   addr.sin_port = htons(port);
    292   if (bind(socket_, reinterpret_cast<const sockaddr*>(&addr),
    293            sizeof(addr)) == SOCKET_ERROR) {
    294     printf("bind failed\n");
    295     return false;
    296   }
    297   return listen(socket_, 5) != SOCKET_ERROR;
    298 }
    299 
    300 DataSocket* ListeningSocket::Accept() const {
    301   assert(valid());
    302   struct sockaddr_in addr = {0};
    303   socklen_t size = sizeof(addr);
    304   int client = accept(socket_, reinterpret_cast<sockaddr*>(&addr), &size);
    305   if (client == INVALID_SOCKET)
    306     return NULL;
    307 
    308   return new DataSocket(client);
    309 }
    310