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