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