opal-up 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/up_ext/App.h +665 -544
- data/ext/up_ext/AsyncSocket.h +307 -284
- data/ext/up_ext/AsyncSocketData.h +35 -51
- data/ext/up_ext/BloomFilter.h +37 -42
- data/ext/up_ext/ChunkedEncoding.h +174 -175
- data/ext/up_ext/ClientApp.h +20 -23
- data/ext/up_ext/HttpContext.h +476 -381
- data/ext/up_ext/HttpContextData.h +20 -20
- data/ext/up_ext/HttpErrors.h +14 -10
- data/ext/up_ext/HttpParser.h +631 -563
- data/ext/up_ext/HttpResponse.h +526 -460
- data/ext/up_ext/HttpResponseData.h +59 -55
- data/ext/up_ext/HttpRouter.h +328 -310
- data/ext/up_ext/Loop.h +174 -168
- data/ext/up_ext/LoopData.h +60 -67
- data/ext/up_ext/MoveOnlyFunction.h +71 -80
- data/ext/up_ext/PerMessageDeflate.h +218 -198
- data/ext/up_ext/ProxyParser.h +100 -99
- data/ext/up_ext/QueryParser.h +91 -84
- data/ext/up_ext/TopicTree.h +273 -268
- data/ext/up_ext/Utilities.h +25 -25
- data/ext/up_ext/WebSocket.h +376 -310
- data/ext/up_ext/WebSocketContext.h +487 -372
- data/ext/up_ext/WebSocketContextData.h +74 -62
- data/ext/up_ext/WebSocketData.h +53 -46
- data/ext/up_ext/WebSocketExtensions.h +194 -178
- data/ext/up_ext/WebSocketHandshake.h +115 -110
- data/ext/up_ext/WebSocketProtocol.h +441 -398
- data/ext/up_ext/up_ext.c +43 -5
- data/lib/up/ruby/cluster.rb +29 -6
- data/lib/up/version.rb +1 -1
- metadata +2 -2
data/ext/up_ext/ProxyParser.h
CHANGED
@@ -25,139 +25,140 @@
|
|
25
25
|
namespace uWS {
|
26
26
|
|
27
27
|
struct proxy_hdr_v2 {
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
uint8_t sig[12]; /* hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A */
|
29
|
+
uint8_t ver_cmd; /* protocol version and command */
|
30
|
+
uint8_t fam; /* protocol family and address */
|
31
|
+
uint16_t len; /* number of following bytes part of the header */
|
32
32
|
};
|
33
33
|
|
34
34
|
union proxy_addr {
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
35
|
+
struct { /* for TCP/UDP over IPv4, len = 12 */
|
36
|
+
uint32_t src_addr;
|
37
|
+
uint32_t dst_addr;
|
38
|
+
uint16_t src_port;
|
39
|
+
uint16_t dst_port;
|
40
|
+
} ipv4_addr;
|
41
|
+
struct { /* for TCP/UDP over IPv6, len = 36 */
|
42
|
+
uint8_t src_addr[16];
|
43
|
+
uint8_t dst_addr[16];
|
44
|
+
uint16_t src_port;
|
45
|
+
uint16_t dst_port;
|
46
|
+
} ipv6_addr;
|
47
47
|
};
|
48
48
|
|
49
49
|
/* Byte swap for little-endian systems */
|
50
50
|
/* Todo: This functions should be shared with the one in WebSocketProtocol.h! */
|
51
|
-
template <typename T>
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
dst.b[i] = src.b[sizeof(value) - 1 - i];
|
62
|
-
}
|
63
|
-
|
64
|
-
return dst.i;
|
51
|
+
template <typename T> T _cond_byte_swap(T value) {
|
52
|
+
uint32_t endian_test = 1;
|
53
|
+
if (*((char *)&endian_test)) {
|
54
|
+
union {
|
55
|
+
T i;
|
56
|
+
uint8_t b[sizeof(T)];
|
57
|
+
} src = {value}, dst;
|
58
|
+
|
59
|
+
for (unsigned int i = 0; i < sizeof(value); i++) {
|
60
|
+
dst.b[i] = src.b[sizeof(value) - 1 - i];
|
65
61
|
}
|
66
|
-
|
62
|
+
|
63
|
+
return dst.i;
|
64
|
+
}
|
65
|
+
return value;
|
67
66
|
}
|
68
67
|
|
69
68
|
struct ProxyParser {
|
70
69
|
private:
|
71
|
-
|
70
|
+
union proxy_addr addr;
|
72
71
|
|
73
|
-
|
74
|
-
|
72
|
+
/* Default family of 0 signals no proxy address */
|
73
|
+
uint8_t family = 0;
|
75
74
|
|
76
75
|
public:
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
}
|
84
|
-
|
85
|
-
if ((family & 0xf0) >> 4 == 1) {
|
86
|
-
/* Family 1 is INET4 */
|
87
|
-
return {(char *) &addr.ipv4_addr.src_addr, 4};
|
88
|
-
} else {
|
89
|
-
/* Family 2 is INET6 */
|
90
|
-
return {(char *) &addr.ipv6_addr.src_addr, 16};
|
91
|
-
}
|
76
|
+
/* Returns 4 or 16 bytes source address */
|
77
|
+
std::string_view getSourceAddress() {
|
78
|
+
|
79
|
+
// UNSPEC family and protocol
|
80
|
+
if (family == 0) {
|
81
|
+
return {};
|
92
82
|
}
|
93
83
|
|
94
|
-
|
95
|
-
|
84
|
+
if ((family & 0xf0) >> 4 == 1) {
|
85
|
+
/* Family 1 is INET4 */
|
86
|
+
return {(char *)&addr.ipv4_addr.src_addr, 4};
|
87
|
+
} else {
|
88
|
+
/* Family 2 is INET6 */
|
89
|
+
return {(char *)&addr.ipv6_addr.src_addr, 16};
|
90
|
+
}
|
91
|
+
}
|
96
92
|
|
97
|
-
|
98
|
-
|
99
|
-
return {false, 0};
|
100
|
-
}
|
93
|
+
/* Returns [done, consumed] where done = false on failure */
|
94
|
+
std::pair<bool, unsigned int> parse(std::string_view data) {
|
101
95
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
}
|
96
|
+
/* We require at least four bytes to determine protocol */
|
97
|
+
if (data.length() < 4) {
|
98
|
+
return {false, 0};
|
99
|
+
}
|
107
100
|
|
108
|
-
|
101
|
+
/* HTTP can never start with "\r\n\r\n", but PROXY always does */
|
102
|
+
if (memcmp(data.data(), "\r\n\r\n", 4)) {
|
103
|
+
/* This is HTTP, so be done */
|
104
|
+
return {true, 0};
|
105
|
+
}
|
109
106
|
|
110
|
-
|
111
|
-
if (data.length() < 16) {
|
112
|
-
return {false, 0};
|
113
|
-
}
|
107
|
+
/* We assume we are parsing PROXY V2 here */
|
114
108
|
|
115
|
-
|
116
|
-
|
117
|
-
|
109
|
+
/* We require 16 bytes here */
|
110
|
+
if (data.length() < 16) {
|
111
|
+
return {false, 0};
|
112
|
+
}
|
118
113
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
}
|
114
|
+
/* Header is 16 bytes */
|
115
|
+
struct proxy_hdr_v2 header;
|
116
|
+
memcpy(&header, data.data(), 16);
|
123
117
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
118
|
+
if (memcmp(header.sig, "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A",
|
119
|
+
12)) {
|
120
|
+
/* This is not PROXY protocol at all */
|
121
|
+
return {false, 0};
|
122
|
+
}
|
128
123
|
|
129
|
-
|
130
|
-
|
124
|
+
/* We only support version 2 */
|
125
|
+
if ((header.ver_cmd & 0xf0) >> 4 != 2) {
|
126
|
+
return {false, 0};
|
127
|
+
}
|
128
|
+
|
129
|
+
// printf("Version: %d\n", (header.ver_cmd & 0xf0) >> 4);
|
130
|
+
// printf("Command: %d\n", (header.ver_cmd & 0x0f));
|
131
131
|
|
132
|
-
|
133
|
-
|
132
|
+
/* We get length in network byte order (todo: share this function with the
|
133
|
+
* rest) */
|
134
|
+
uint16_t hostLength = _cond_byte_swap<uint16_t>(header.len);
|
134
135
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
136
|
+
/* We must have all the data available */
|
137
|
+
if (data.length() < 16u + hostLength) {
|
138
|
+
return {false, 0};
|
139
|
+
}
|
139
140
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
141
|
+
/* Payload cannot be more than sizeof proxy_addr */
|
142
|
+
if (sizeof(proxy_addr) < hostLength) {
|
143
|
+
return {false, 0};
|
144
|
+
}
|
144
145
|
|
145
|
-
|
146
|
-
|
146
|
+
// printf("Family: %d\n", (header.fam & 0xf0) >> 4);
|
147
|
+
// printf("Transport: %d\n", (header.fam & 0x0f));
|
147
148
|
|
148
|
-
|
149
|
-
|
149
|
+
/* We have 0 family by default, and UNSPEC is 0 as well */
|
150
|
+
family = header.fam;
|
150
151
|
|
151
|
-
|
152
|
-
|
152
|
+
/* Copy payload */
|
153
|
+
memcpy(&addr, data.data() + 16, hostLength);
|
153
154
|
|
154
|
-
|
155
|
-
|
156
|
-
|
155
|
+
/* We consumed everything */
|
156
|
+
return {true, 16 + hostLength};
|
157
|
+
}
|
157
158
|
};
|
158
159
|
|
159
|
-
}
|
160
|
+
} // namespace uWS
|
160
161
|
|
161
162
|
#endif
|
162
163
|
|
163
|
-
#endif // UWS_PROXY_PARSER_H
|
164
|
+
#endif // UWS_PROXY_PARSER_H
|
data/ext/up_ext/QueryParser.h
CHANGED
@@ -24,97 +24,104 @@
|
|
24
24
|
|
25
25
|
namespace uWS {
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
/* Takes raw query including initial '?' sign. Will inplace decode, so input
|
28
|
+
* will mutate */
|
29
|
+
static inline std::string_view getDecodedQueryValue(std::string_view key,
|
30
|
+
std::string_view rawQuery) {
|
31
|
+
|
32
|
+
/* Can't have a value without a key */
|
33
|
+
if (!key.length()) {
|
34
|
+
return {};
|
35
|
+
}
|
36
|
+
|
37
|
+
/* Start with the whole querystring including initial '?' */
|
38
|
+
std::string_view queryString = rawQuery;
|
39
|
+
|
40
|
+
/* List of key, value could be cached for repeated fetches similar to how
|
41
|
+
* headers are, todo! */
|
42
|
+
while (queryString.length()) {
|
43
|
+
/* Find boundaries of this statement */
|
44
|
+
std::string_view statement =
|
45
|
+
queryString.substr(1, queryString.find('&', 1) - 1);
|
46
|
+
|
47
|
+
/* Only bother if first char of key match (early exit) */
|
48
|
+
if (statement.length() && statement[0] == key[0]) {
|
49
|
+
/* Equal sign must be present and not in the end of statement */
|
50
|
+
auto equality = statement.find('=');
|
51
|
+
if (equality != std::string_view::npos) {
|
52
|
+
|
53
|
+
std::string_view statementKey = statement.substr(0, equality);
|
54
|
+
std::string_view statementValue = statement.substr(equality + 1);
|
55
|
+
|
56
|
+
/* String comparison */
|
57
|
+
if (key == statementKey) {
|
58
|
+
|
59
|
+
/* Decode value inplace, put null at end if before length of original
|
60
|
+
*/
|
61
|
+
char *in = (char *)statementValue.data();
|
62
|
+
|
63
|
+
/* Write offset */
|
64
|
+
unsigned int out = 0;
|
65
|
+
|
66
|
+
/* Walk over all chars until end or null char, decoding in place */
|
67
|
+
for (unsigned int i = 0; i < statementValue.length() && in[i]; i++) {
|
68
|
+
/* Only bother with '%' */
|
69
|
+
if (in[i] == '%') {
|
70
|
+
/* Do we have enough data for two bytes hex? */
|
71
|
+
if (i + 2 >= statementValue.length()) {
|
72
|
+
return {};
|
73
|
+
}
|
74
|
+
|
75
|
+
/* Two bytes hex */
|
76
|
+
int hex1 = in[i + 1] - '0';
|
77
|
+
if (hex1 > 9) {
|
78
|
+
hex1 &= 223;
|
79
|
+
hex1 -= 7;
|
80
|
+
}
|
81
|
+
|
82
|
+
int hex2 = in[i + 2] - '0';
|
83
|
+
if (hex2 > 9) {
|
84
|
+
hex2 &= 223;
|
85
|
+
hex2 -= 7;
|
86
|
+
}
|
87
|
+
|
88
|
+
*((unsigned char *)&in[out]) = (unsigned char)(hex1 * 16 + hex2);
|
89
|
+
i += 2;
|
90
|
+
} else {
|
91
|
+
/* Is this even a rule? */
|
92
|
+
if (in[i] == '+') {
|
93
|
+
in[out] = ' ';
|
94
|
+
} else {
|
95
|
+
in[out] = in[i];
|
96
|
+
}
|
97
|
+
}
|
29
98
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
}
|
99
|
+
/* We always only write one char */
|
100
|
+
out++;
|
101
|
+
}
|
34
102
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
/* Find boundaries of this statement */
|
41
|
-
std::string_view statement = queryString.substr(1, queryString.find('&', 1) - 1);
|
42
|
-
|
43
|
-
/* Only bother if first char of key match (early exit) */
|
44
|
-
if (statement.length() && statement[0] == key[0]) {
|
45
|
-
/* Equal sign must be present and not in the end of statement */
|
46
|
-
auto equality = statement.find('=');
|
47
|
-
if (equality != std::string_view::npos) {
|
48
|
-
|
49
|
-
std::string_view statementKey = statement.substr(0, equality);
|
50
|
-
std::string_view statementValue = statement.substr(equality + 1);
|
51
|
-
|
52
|
-
/* String comparison */
|
53
|
-
if (key == statementKey) {
|
54
|
-
|
55
|
-
/* Decode value inplace, put null at end if before length of original */
|
56
|
-
char *in = (char *) statementValue.data();
|
57
|
-
|
58
|
-
/* Write offset */
|
59
|
-
unsigned int out = 0;
|
60
|
-
|
61
|
-
/* Walk over all chars until end or null char, decoding in place */
|
62
|
-
for (unsigned int i = 0; i < statementValue.length() && in[i]; i++) {
|
63
|
-
/* Only bother with '%' */
|
64
|
-
if (in[i] == '%') {
|
65
|
-
/* Do we have enough data for two bytes hex? */
|
66
|
-
if (i + 2 >= statementValue.length()) {
|
67
|
-
return {};
|
68
|
-
}
|
69
|
-
|
70
|
-
/* Two bytes hex */
|
71
|
-
int hex1 = in[i + 1] - '0';
|
72
|
-
if (hex1 > 9) {
|
73
|
-
hex1 &= 223;
|
74
|
-
hex1 -= 7;
|
75
|
-
}
|
76
|
-
|
77
|
-
int hex2 = in[i + 2] - '0';
|
78
|
-
if (hex2 > 9) {
|
79
|
-
hex2 &= 223;
|
80
|
-
hex2 -= 7;
|
81
|
-
}
|
82
|
-
|
83
|
-
*((unsigned char *) &in[out]) = (unsigned char) (hex1 * 16 + hex2);
|
84
|
-
i += 2;
|
85
|
-
} else {
|
86
|
-
/* Is this even a rule? */
|
87
|
-
if (in[i] == '+') {
|
88
|
-
in[out] = ' ';
|
89
|
-
} else {
|
90
|
-
in[out] = in[i];
|
91
|
-
}
|
92
|
-
}
|
93
|
-
|
94
|
-
/* We always only write one char */
|
95
|
-
out++;
|
96
|
-
}
|
97
|
-
|
98
|
-
/* If decoded string is shorter than original, put null char to stop next read */
|
99
|
-
if (out < statementValue.length()) {
|
100
|
-
in[out] = 0;
|
101
|
-
}
|
102
|
-
|
103
|
-
return statementValue.substr(0, out);
|
104
|
-
}
|
105
|
-
} else {
|
106
|
-
/* This querystring is invalid, cannot parse it */
|
107
|
-
return {nullptr, 0};
|
108
|
-
}
|
109
|
-
}
|
103
|
+
/* If decoded string is shorter than original, put null char to stop
|
104
|
+
* next read */
|
105
|
+
if (out < statementValue.length()) {
|
106
|
+
in[out] = 0;
|
107
|
+
}
|
110
108
|
|
111
|
-
|
109
|
+
return statementValue.substr(0, out);
|
112
110
|
}
|
113
|
-
|
114
|
-
/*
|
111
|
+
} else {
|
112
|
+
/* This querystring is invalid, cannot parse it */
|
115
113
|
return {nullptr, 0};
|
114
|
+
}
|
116
115
|
}
|
117
116
|
|
117
|
+
queryString.remove_prefix(statement.length() + 1);
|
118
|
+
}
|
119
|
+
|
120
|
+
/* Nothing found is given as nullptr, while empty string is given as some
|
121
|
+
* pointer to the given buffer */
|
122
|
+
return {nullptr, 0};
|
118
123
|
}
|
119
124
|
|
125
|
+
} // namespace uWS
|
126
|
+
|
120
127
|
#endif
|