1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
/*
* Copyright 2011 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef EXAMPLES_PEERCONNECTION_SERVER_DATA_SOCKET_H_
#define EXAMPLES_PEERCONNECTION_SERVER_DATA_SOCKET_H_
#ifdef WIN32
#include <winsock2.h>
typedef int socklen_t;
typedef SOCKET NativeSocket;
#else
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/socket.h>
#define closesocket close
typedef int NativeSocket;
#ifndef SOCKET_ERROR
#define SOCKET_ERROR (-1)
#endif
#ifndef INVALID_SOCKET
#define INVALID_SOCKET static_cast<NativeSocket>(-1)
#endif
#endif
#include <string>
class SocketBase {
public:
SocketBase() : socket_(INVALID_SOCKET) {}
explicit SocketBase(NativeSocket socket) : socket_(socket) {}
SocketBase(SocketBase& other) = delete;
SocketBase& operator=(const SocketBase& other) = delete;
~SocketBase() { Close(); }
NativeSocket socket() const { return socket_; }
bool valid() const { return socket_ != INVALID_SOCKET; }
bool Create();
void Close();
protected:
NativeSocket socket_;
};
// Represents an HTTP server socket.
class DataSocket : public SocketBase {
public:
enum RequestMethod {
INVALID,
GET,
POST,
OPTIONS,
};
explicit DataSocket(NativeSocket socket)
: SocketBase(socket), method_(INVALID), content_length_(0) {}
~DataSocket() {}
static const char kCrossOriginAllowHeaders[];
bool headers_received() const { return method_ != INVALID; }
RequestMethod method() const { return method_; }
const std::string& request_path() const { return request_path_; }
std::string request_arguments() const;
const std::string& data() const { return data_; }
const std::string& content_type() const { return content_type_; }
size_t content_length() const { return content_length_; }
bool request_received() const {
return headers_received() && (method_ != POST || data_received());
}
bool data_received() const {
return method_ != POST || data_.length() >= content_length_;
}
// Checks if the request path (minus arguments) matches a given path.
bool PathEquals(const char* path) const;
// Called when we have received some data from clients.
// Returns false if an error occurred.
bool OnDataAvailable(bool* close_socket);
// Send a raw buffer of bytes.
bool Send(const std::string& data) const;
// Send an HTTP response. The `status` should start with a valid HTTP
// response code, followed by a string. E.g. "200 OK".
// If `connection_close` is set to true, an extra "Connection: close" HTTP
// header will be included. `content_type` is the mime content type, not
// including the "Content-Type: " string.
// `extra_headers` should be either empty or a list of headers where each
// header terminates with "\r\n".
// `data` is the body of the message. It's length will be specified via
// a "Content-Length" header.
bool Send(const std::string& status,
bool connection_close,
const std::string& content_type,
const std::string& extra_headers,
const std::string& data) const;
// Clears all held state and prepares the socket for receiving a new request.
void Clear();
protected:
// A fairly relaxed HTTP header parser. Parses the method, path and
// content length (POST only) of a request.
// Returns true if a valid request was received and no errors occurred.
bool ParseHeaders();
// Figures out whether the request is a GET or POST and what path is
// being requested.
bool ParseMethodAndPath(const char* begin, size_t len);
// Determines the length of the body and it's mime type.
bool ParseContentLengthAndType(const char* headers, size_t length);
protected:
RequestMethod method_;
size_t content_length_;
std::string content_type_;
std::string request_path_;
std::string request_headers_;
std::string data_;
};
// The server socket. Accepts connections and generates DataSocket instances
// for each new connection.
class ListeningSocket : public SocketBase {
public:
ListeningSocket() {}
bool Listen(unsigned short port);
DataSocket* Accept() const;
};
#endif // EXAMPLES_PEERCONNECTION_SERVER_DATA_SOCKET_H_
|