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