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 <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #if defined(WEBRTC_POSIX)
17 #include <unistd.h>
18 #endif
19
20 #include "examples/peerconnection/server/utils.h"
21 #include "rtc_base/checks.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\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 RTC_DCHECK(!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 RTC_DCHECK(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 RTC_DCHECK(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,
123 bool connection_close,
124 const std::string& content_type,
125 const std::string& extra_headers,
126 const std::string& data) const {
127 RTC_DCHECK(valid());
128 RTC_DCHECK(!status.empty());
129 std::string buffer("HTTP/1.1 " + status + "\r\n");
130
131 buffer +=
132 "Server: PeerConnectionTestServer/0.1\r\n"
133 "Cache-Control: no-cache\r\n";
134
135 if (connection_close)
136 buffer += "Connection: close\r\n";
137
138 if (!content_type.empty())
139 buffer += "Content-Type: " + content_type + "\r\n";
140
141 buffer +=
142 "Content-Length: " + int2str(static_cast<int>(data.size())) + "\r\n";
143
144 if (!extra_headers.empty()) {
145 buffer += extra_headers;
146 // Extra headers are assumed to have a separator per header.
147 }
148
149 buffer += kCrossOriginAllowHeaders;
150
151 buffer += "\r\n";
152 buffer += data;
153
154 return Send(buffer);
155 }
156
Clear()157 void DataSocket::Clear() {
158 method_ = INVALID;
159 content_length_ = 0;
160 content_type_.clear();
161 request_path_.clear();
162 request_headers_.clear();
163 data_.clear();
164 }
165
ParseHeaders()166 bool DataSocket::ParseHeaders() {
167 RTC_DCHECK(!request_headers_.empty());
168 RTC_DCHECK_EQ(method_, INVALID);
169 size_t i = request_headers_.find("\r\n");
170 if (i == std::string::npos)
171 return false;
172
173 if (!ParseMethodAndPath(request_headers_.data(), i))
174 return false;
175
176 RTC_DCHECK_NE(method_, INVALID);
177 RTC_DCHECK(!request_path_.empty());
178
179 if (method_ == POST) {
180 const char* headers = request_headers_.data() + i + 2;
181 size_t len = request_headers_.length() - i - 2;
182 if (!ParseContentLengthAndType(headers, len))
183 return false;
184 }
185
186 return true;
187 }
188
ParseMethodAndPath(const char * begin,size_t len)189 bool DataSocket::ParseMethodAndPath(const char* begin, size_t len) {
190 struct {
191 const char* method_name;
192 size_t method_name_len;
193 RequestMethod id;
194 } supported_methods[] = {
195 {"GET", 3, GET},
196 {"POST", 4, POST},
197 {"OPTIONS", 7, OPTIONS},
198 };
199
200 const char* path = NULL;
201 for (size_t i = 0; i < ARRAYSIZE(supported_methods); ++i) {
202 if (len > supported_methods[i].method_name_len &&
203 isspace(begin[supported_methods[i].method_name_len]) &&
204 strncmp(begin, supported_methods[i].method_name,
205 supported_methods[i].method_name_len) == 0) {
206 method_ = supported_methods[i].id;
207 path = begin + supported_methods[i].method_name_len;
208 break;
209 }
210 }
211
212 const char* end = begin + len;
213 if (!path || path >= end)
214 return false;
215
216 ++path;
217 begin = path;
218 while (!isspace(*path) && path < end)
219 ++path;
220
221 request_path_.assign(begin, path - begin);
222
223 return true;
224 }
225
ParseContentLengthAndType(const char * headers,size_t length)226 bool DataSocket::ParseContentLengthAndType(const char* headers, size_t length) {
227 RTC_DCHECK_EQ(content_length_, 0);
228 RTC_DCHECK(content_type_.empty());
229
230 const char* end = headers + length;
231 while (headers && headers < end) {
232 if (!isspace(headers[0])) {
233 static const char kContentLength[] = "Content-Length:";
234 static const char kContentType[] = "Content-Type:";
235 if ((headers + ARRAYSIZE(kContentLength)) < end &&
236 strncmp(headers, kContentLength, ARRAYSIZE(kContentLength) - 1) ==
237 0) {
238 headers += ARRAYSIZE(kContentLength) - 1;
239 while (headers[0] == ' ')
240 ++headers;
241 content_length_ = atoi(headers);
242 } else if ((headers + ARRAYSIZE(kContentType)) < end &&
243 strncmp(headers, kContentType, ARRAYSIZE(kContentType) - 1) ==
244 0) {
245 headers += ARRAYSIZE(kContentType) - 1;
246 while (headers[0] == ' ')
247 ++headers;
248 const char* type_end = strstr(headers, "\r\n");
249 if (type_end == NULL)
250 type_end = end;
251 content_type_.assign(headers, type_end);
252 }
253 } else {
254 ++headers;
255 }
256 headers = strstr(headers, "\r\n");
257 if (headers)
258 headers += 2;
259 }
260
261 return !content_type_.empty() && content_length_ != 0;
262 }
263
264 //
265 // ListeningSocket
266 //
267
Listen(unsigned short port)268 bool ListeningSocket::Listen(unsigned short port) {
269 RTC_DCHECK(valid());
270 int enabled = 1;
271 if (setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
272 reinterpret_cast<const char*>(&enabled),
273 sizeof(enabled)) != 0) {
274 printf("setsockopt failed\n");
275 return false;
276 }
277 struct sockaddr_in addr = {0};
278 addr.sin_family = AF_INET;
279 addr.sin_addr.s_addr = htonl(INADDR_ANY);
280 addr.sin_port = htons(port);
281 if (bind(socket_, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr)) ==
282 SOCKET_ERROR) {
283 printf("bind failed\n");
284 return false;
285 }
286 return listen(socket_, 5) != SOCKET_ERROR;
287 }
288
Accept() const289 DataSocket* ListeningSocket::Accept() const {
290 RTC_DCHECK(valid());
291 struct sockaddr_in addr = {0};
292 socklen_t size = sizeof(addr);
293 NativeSocket client =
294 accept(socket_, reinterpret_cast<sockaddr*>(&addr), &size);
295 if (client == INVALID_SOCKET)
296 return NULL;
297
298 return new DataSocket(client);
299 }
300