tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

data_socket.cc (8121B)


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