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
@@ -25,49 +25,49 @@
|
|
25
25
|
|
26
26
|
/* We always define these options no matter if ZLIB is enabled or not */
|
27
27
|
namespace uWS {
|
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
|
-
}
|
28
|
+
/* Compressor mode is 8 lowest bits where HIGH4(windowBits), LOW4(memLevel).
|
29
|
+
* Decompressor mode is 8 highest bits LOW4(windowBits).
|
30
|
+
* If compressor or decompressor bits are 1, then they are shared.
|
31
|
+
* If everything is just simply 0, then everything is disabled. */
|
32
|
+
enum CompressOptions : uint16_t {
|
33
|
+
/* These are not actual compression options */
|
34
|
+
_COMPRESSOR_MASK = 0x00FF,
|
35
|
+
_DECOMPRESSOR_MASK = 0x0F00,
|
36
|
+
/* Disabled, shared, shared are "special" values */
|
37
|
+
DISABLED = 0,
|
38
|
+
SHARED_COMPRESSOR = 1,
|
39
|
+
SHARED_DECOMPRESSOR = 1 << 8,
|
40
|
+
/* Highest 4 bits describe decompressor */
|
41
|
+
DEDICATED_DECOMPRESSOR_32KB = 15 << 8,
|
42
|
+
DEDICATED_DECOMPRESSOR_16KB = 14 << 8,
|
43
|
+
DEDICATED_DECOMPRESSOR_8KB = 13 << 8,
|
44
|
+
DEDICATED_DECOMPRESSOR_4KB = 12 << 8,
|
45
|
+
DEDICATED_DECOMPRESSOR_2KB = 11 << 8,
|
46
|
+
DEDICATED_DECOMPRESSOR_1KB = 10 << 8,
|
47
|
+
DEDICATED_DECOMPRESSOR_512B = 9 << 8,
|
48
|
+
/* Same as 32kb */
|
49
|
+
DEDICATED_DECOMPRESSOR = 15 << 8,
|
50
|
+
|
51
|
+
/* Lowest 8 bit describe compressor */
|
52
|
+
DEDICATED_COMPRESSOR_3KB = 9 << 4 | 1,
|
53
|
+
DEDICATED_COMPRESSOR_4KB = 9 << 4 | 2,
|
54
|
+
DEDICATED_COMPRESSOR_8KB = 10 << 4 | 3,
|
55
|
+
DEDICATED_COMPRESSOR_16KB = 11 << 4 | 4,
|
56
|
+
DEDICATED_COMPRESSOR_32KB = 12 << 4 | 5,
|
57
|
+
DEDICATED_COMPRESSOR_64KB = 13 << 4 | 6,
|
58
|
+
DEDICATED_COMPRESSOR_128KB = 14 << 4 | 7,
|
59
|
+
DEDICATED_COMPRESSOR_256KB = 15 << 4 | 8,
|
60
|
+
/* Same as 256kb */
|
61
|
+
DEDICATED_COMPRESSOR = 15 << 4 | 8
|
62
|
+
};
|
63
|
+
} // namespace uWS
|
64
64
|
|
65
65
|
#if !defined(UWS_NO_ZLIB) && !defined(UWS_MOCK_ZLIB)
|
66
66
|
#include <zlib.h>
|
67
67
|
#endif
|
68
68
|
|
69
|
-
#include <string>
|
70
69
|
#include <optional>
|
70
|
+
#include <string>
|
71
71
|
|
72
72
|
#ifdef UWS_USE_LIBDEFLATE
|
73
73
|
#include "libdeflate.h"
|
@@ -80,236 +80,256 @@ namespace uWS {
|
|
80
80
|
#if defined(UWS_NO_ZLIB) || defined(UWS_MOCK_ZLIB)
|
81
81
|
struct ZlibContext {};
|
82
82
|
struct InflationStream {
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
83
|
+
std::optional<std::string_view> inflate(ZlibContext * /*zlibContext*/,
|
84
|
+
std::string_view compressed,
|
85
|
+
size_t maxPayloadLength,
|
86
|
+
bool /*reset*/) {
|
87
|
+
return compressed.substr(0,
|
88
|
+
std::min(maxPayloadLength, compressed.length()));
|
89
|
+
}
|
90
|
+
InflationStream(CompressOptions /*compressOptions*/) {}
|
88
91
|
};
|
89
92
|
struct DeflationStream {
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
93
|
+
std::string_view deflate(ZlibContext * /*zlibContext*/, std::string_view raw,
|
94
|
+
bool /*reset*/) {
|
95
|
+
return raw;
|
96
|
+
}
|
97
|
+
DeflationStream(CompressOptions /*compressOptions*/) {}
|
95
98
|
};
|
96
99
|
#else
|
97
100
|
|
98
101
|
#define LARGE_BUFFER_SIZE 1024 * 16 // todo: fix this
|
99
102
|
|
100
103
|
struct ZlibContext {
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
104
|
+
/* Any returned data is valid until next same-class call.
|
105
|
+
* We need to have two classes to allow inflation followed
|
106
|
+
* by many deflations without modifying the inflation */
|
107
|
+
std::string dynamicDeflationBuffer;
|
108
|
+
std::string dynamicInflationBuffer;
|
109
|
+
char *deflationBuffer;
|
110
|
+
char *inflationBuffer;
|
108
111
|
|
109
112
|
#ifdef UWS_USE_LIBDEFLATE
|
110
|
-
|
111
|
-
|
113
|
+
libdeflate_decompressor *decompressor;
|
114
|
+
libdeflate_compressor *compressor;
|
112
115
|
#endif
|
113
116
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
+
ZlibContext() {
|
118
|
+
deflationBuffer = (char *)malloc(LARGE_BUFFER_SIZE);
|
119
|
+
inflationBuffer = (char *)malloc(LARGE_BUFFER_SIZE);
|
117
120
|
|
118
121
|
#ifdef UWS_USE_LIBDEFLATE
|
119
|
-
|
120
|
-
|
122
|
+
decompressor = libdeflate_alloc_decompressor();
|
123
|
+
compressor = libdeflate_alloc_compressor(6);
|
121
124
|
#endif
|
122
|
-
|
125
|
+
}
|
123
126
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
+
~ZlibContext() {
|
128
|
+
free(deflationBuffer);
|
129
|
+
free(inflationBuffer);
|
127
130
|
|
128
131
|
#ifdef UWS_USE_LIBDEFLATE
|
129
|
-
|
130
|
-
|
132
|
+
libdeflate_free_decompressor(decompressor);
|
133
|
+
libdeflate_free_compressor(compressor);
|
131
134
|
#endif
|
132
|
-
|
135
|
+
}
|
133
136
|
};
|
134
137
|
|
135
138
|
struct DeflationStream {
|
136
|
-
|
139
|
+
z_stream deflationStream = {};
|
137
140
|
|
138
|
-
|
141
|
+
DeflationStream(CompressOptions compressOptions) {
|
139
142
|
|
140
|
-
|
143
|
+
/* Sliding inflator should be about 44kb by default, less than compressor */
|
141
144
|
|
142
|
-
|
143
|
-
|
145
|
+
/* Memory usage is given by 2 ^ (windowBits + 2) + 2 ^ (memLevel + 9) */
|
146
|
+
int windowBits = -(int)((compressOptions & _COMPRESSOR_MASK) >> 4),
|
147
|
+
memLevel = compressOptions & 0xF;
|
144
148
|
|
145
|
-
|
149
|
+
// printf("windowBits: %d, memLevel: %d\n", windowBits, memLevel);
|
146
150
|
|
147
|
-
|
148
|
-
|
151
|
+
deflateInit2(&deflationStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
|
152
|
+
windowBits, memLevel, Z_DEFAULT_STRATEGY);
|
153
|
+
}
|
149
154
|
|
150
|
-
|
151
|
-
|
155
|
+
/* Deflate and optionally reset. You must not deflate an empty string. */
|
156
|
+
std::string_view deflate(ZlibContext *zlibContext, std::string_view raw,
|
157
|
+
bool reset) {
|
152
158
|
|
153
159
|
#ifdef UWS_USE_LIBDEFLATE
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
160
|
+
/* Run a fast path in case of shared_compressor */
|
161
|
+
if (reset) {
|
162
|
+
size_t written = 0;
|
163
|
+
static unsigned char buf[1024 + 1];
|
164
|
+
|
165
|
+
written = libdeflate_deflate_compress(zlibContext->compressor, raw.data(),
|
166
|
+
raw.length(), buf, 1024);
|
167
|
+
|
168
|
+
if (written) {
|
169
|
+
memcpy(&buf[written], "\x00", 1);
|
170
|
+
return std::string_view((char *)buf, written + 1);
|
171
|
+
}
|
172
|
+
}
|
166
173
|
#endif
|
167
174
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
deflationStream.next_in = (Bytef *) raw.data();
|
172
|
-
deflationStream.avail_in = (unsigned int) raw.length();
|
173
|
-
|
174
|
-
/* This buffer size has to be at least 6 bytes for Z_SYNC_FLUSH to work */
|
175
|
-
const int DEFLATE_OUTPUT_CHUNK = LARGE_BUFFER_SIZE;
|
175
|
+
/* Odd place to clear this one, fix */
|
176
|
+
zlibContext->dynamicDeflationBuffer.clear();
|
176
177
|
|
177
|
-
|
178
|
-
|
179
|
-
deflationStream.next_out = (Bytef *) zlibContext->deflationBuffer;
|
180
|
-
deflationStream.avail_out = DEFLATE_OUTPUT_CHUNK;
|
178
|
+
deflationStream.next_in = (Bytef *)raw.data();
|
179
|
+
deflationStream.avail_in = (unsigned int)raw.length();
|
181
180
|
|
182
|
-
|
183
|
-
|
184
|
-
zlibContext->dynamicDeflationBuffer.append(zlibContext->deflationBuffer, DEFLATE_OUTPUT_CHUNK - deflationStream.avail_out);
|
185
|
-
continue;
|
186
|
-
} else {
|
187
|
-
break;
|
188
|
-
}
|
189
|
-
} while (true);
|
181
|
+
/* This buffer size has to be at least 6 bytes for Z_SYNC_FLUSH to work */
|
182
|
+
const int DEFLATE_OUTPUT_CHUNK = LARGE_BUFFER_SIZE;
|
190
183
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
184
|
+
int err;
|
185
|
+
do {
|
186
|
+
deflationStream.next_out = (Bytef *)zlibContext->deflationBuffer;
|
187
|
+
deflationStream.avail_out = DEFLATE_OUTPUT_CHUNK;
|
195
188
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
return std::string_view((char *) zlibContext->dynamicDeflationBuffer.data(), zlibContext->dynamicDeflationBuffer.length() - 4);
|
200
|
-
}
|
201
|
-
|
202
|
-
/* Note: We will get an interger overflow resulting in heap buffer overflow if Z_BUF_ERROR is returned
|
203
|
-
* from passing 0 as avail_in. Therefore we must not deflate an empty string */
|
204
|
-
return {
|
189
|
+
err = ::deflate(&deflationStream, Z_SYNC_FLUSH);
|
190
|
+
if (Z_OK == err && deflationStream.avail_out == 0) {
|
191
|
+
zlibContext->dynamicDeflationBuffer.append(
|
205
192
|
zlibContext->deflationBuffer,
|
206
|
-
DEFLATE_OUTPUT_CHUNK - deflationStream.avail_out
|
207
|
-
|
193
|
+
DEFLATE_OUTPUT_CHUNK - deflationStream.avail_out);
|
194
|
+
continue;
|
195
|
+
} else {
|
196
|
+
break;
|
197
|
+
}
|
198
|
+
} while (true);
|
199
|
+
|
200
|
+
/* This must not change avail_out */
|
201
|
+
if (reset) {
|
202
|
+
deflateReset(&deflationStream);
|
208
203
|
}
|
209
204
|
|
210
|
-
|
211
|
-
|
205
|
+
if (zlibContext->dynamicDeflationBuffer.length()) {
|
206
|
+
zlibContext->dynamicDeflationBuffer.append(zlibContext->deflationBuffer,
|
207
|
+
DEFLATE_OUTPUT_CHUNK -
|
208
|
+
deflationStream.avail_out);
|
209
|
+
|
210
|
+
return std::string_view(
|
211
|
+
(char *)zlibContext->dynamicDeflationBuffer.data(),
|
212
|
+
zlibContext->dynamicDeflationBuffer.length() - 4);
|
212
213
|
}
|
214
|
+
|
215
|
+
/* Note: We will get an interger overflow resulting in heap buffer overflow
|
216
|
+
* if Z_BUF_ERROR is returned from passing 0 as avail_in. Therefore we must
|
217
|
+
* not deflate an empty string */
|
218
|
+
return {zlibContext->deflationBuffer,
|
219
|
+
DEFLATE_OUTPUT_CHUNK - deflationStream.avail_out - 4};
|
220
|
+
}
|
221
|
+
|
222
|
+
~DeflationStream() { deflateEnd(&deflationStream); }
|
213
223
|
};
|
214
224
|
|
215
225
|
struct InflationStream {
|
216
|
-
|
226
|
+
z_stream inflationStream = {};
|
217
227
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
228
|
+
InflationStream(CompressOptions compressOptions) {
|
229
|
+
/* Inflation windowBits are the top 8 bits of the 16 bit compressOptions */
|
230
|
+
inflateInit2(&inflationStream, -(compressOptions >> 8));
|
231
|
+
}
|
222
232
|
|
223
|
-
|
224
|
-
inflateEnd(&inflationStream);
|
225
|
-
}
|
233
|
+
~InflationStream() { inflateEnd(&inflationStream); }
|
226
234
|
|
227
|
-
|
228
|
-
|
235
|
+
/* Zero length inflates are possible and valid */
|
236
|
+
std::optional<std::string_view> inflate(ZlibContext *zlibContext,
|
237
|
+
std::string_view compressed,
|
238
|
+
size_t maxPayloadLength, bool reset) {
|
229
239
|
|
230
240
|
#ifdef UWS_USE_LIBDEFLATE
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
241
|
+
/* Try fast path first */
|
242
|
+
size_t written = 0;
|
243
|
+
static char buf[1024];
|
244
|
+
|
245
|
+
/* We have to pad 9 bytes and restore those bytes when done since 9 is more
|
246
|
+
* than 6 of next WebSocket message */
|
247
|
+
char tmp[9];
|
248
|
+
memcpy(tmp, (char *)compressed.data() + compressed.length(), 9);
|
249
|
+
memcpy((char *)compressed.data() + compressed.length(),
|
250
|
+
"\x00\x00\xff\xff\x01\x00\x00\xff\xff", 9);
|
251
|
+
libdeflate_result res = libdeflate_deflate_decompress(
|
252
|
+
zlibContext->decompressor, compressed.data(), compressed.length() + 9,
|
253
|
+
buf, 1024, &written);
|
254
|
+
memcpy((char *)compressed.data() + compressed.length(), tmp, 9);
|
255
|
+
|
256
|
+
if (res == 0) {
|
257
|
+
/* Fast path wins */
|
258
|
+
return std::string_view(buf, written);
|
259
|
+
}
|
246
260
|
#endif
|
247
261
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
/* Append tail to chunk */
|
254
|
-
unsigned char tail[4] = {0x00, 0x00, 0xff, 0xff};
|
255
|
-
memcpy(tailLocation, tail, 4);
|
256
|
-
compressed = {compressed.data(), compressed.length() + 4};
|
257
|
-
|
258
|
-
/* We clear this one here, could be done better */
|
259
|
-
zlibContext->dynamicInflationBuffer.clear();
|
262
|
+
/* Save off the bytes we're about to overwrite */
|
263
|
+
char *tailLocation = (char *)compressed.data() + compressed.length();
|
264
|
+
char preTailBytes[4];
|
265
|
+
memcpy(preTailBytes, tailLocation, 4);
|
260
266
|
|
261
|
-
|
262
|
-
|
267
|
+
/* Append tail to chunk */
|
268
|
+
unsigned char tail[4] = {0x00, 0x00, 0xff, 0xff};
|
269
|
+
memcpy(tailLocation, tail, 4);
|
270
|
+
compressed = {compressed.data(), compressed.length() + 4};
|
263
271
|
|
264
|
-
|
265
|
-
|
266
|
-
inflationStream.next_out = (Bytef *) zlibContext->inflationBuffer;
|
267
|
-
inflationStream.avail_out = LARGE_BUFFER_SIZE;
|
272
|
+
/* We clear this one here, could be done better */
|
273
|
+
zlibContext->dynamicInflationBuffer.clear();
|
268
274
|
|
269
|
-
|
270
|
-
|
271
|
-
break;
|
272
|
-
}
|
275
|
+
inflationStream.next_in = (Bytef *)compressed.data();
|
276
|
+
inflationStream.avail_in = (unsigned int)compressed.length();
|
273
277
|
|
274
|
-
|
278
|
+
int err;
|
279
|
+
do {
|
280
|
+
inflationStream.next_out = (Bytef *)zlibContext->inflationBuffer;
|
281
|
+
inflationStream.avail_out = LARGE_BUFFER_SIZE;
|
275
282
|
|
283
|
+
err = ::inflate(&inflationStream, Z_SYNC_FLUSH);
|
284
|
+
if (err == Z_OK && inflationStream.avail_out) {
|
285
|
+
break;
|
286
|
+
}
|
276
287
|
|
277
|
-
|
288
|
+
zlibContext->dynamicInflationBuffer.append(zlibContext->inflationBuffer,
|
289
|
+
LARGE_BUFFER_SIZE -
|
290
|
+
inflationStream.avail_out);
|
278
291
|
|
279
|
-
|
280
|
-
|
281
|
-
}
|
292
|
+
} while (inflationStream.avail_out == 0 &&
|
293
|
+
zlibContext->dynamicInflationBuffer.length() <= maxPayloadLength);
|
282
294
|
|
283
|
-
|
284
|
-
|
295
|
+
if (reset) {
|
296
|
+
inflateReset(&inflationStream);
|
297
|
+
}
|
285
298
|
|
286
|
-
|
287
|
-
|
288
|
-
}
|
299
|
+
/* Restore the bytes we used for the tail */
|
300
|
+
memcpy(tailLocation, preTailBytes, 4);
|
289
301
|
|
290
|
-
|
291
|
-
|
302
|
+
if ((err != Z_BUF_ERROR && err != Z_OK) ||
|
303
|
+
zlibContext->dynamicInflationBuffer.length() > maxPayloadLength) {
|
304
|
+
return std::nullopt;
|
305
|
+
}
|
292
306
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
307
|
+
if (zlibContext->dynamicInflationBuffer.length()) {
|
308
|
+
zlibContext->dynamicInflationBuffer.append(zlibContext->inflationBuffer,
|
309
|
+
LARGE_BUFFER_SIZE -
|
310
|
+
inflationStream.avail_out);
|
297
311
|
|
298
|
-
|
299
|
-
|
312
|
+
/* Let's be strict about the max size */
|
313
|
+
if (zlibContext->dynamicInflationBuffer.length() > maxPayloadLength) {
|
314
|
+
return std::nullopt;
|
315
|
+
}
|
300
316
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
}
|
317
|
+
return std::string_view(zlibContext->dynamicInflationBuffer.data(),
|
318
|
+
zlibContext->dynamicInflationBuffer.length());
|
319
|
+
}
|
305
320
|
|
306
|
-
|
321
|
+
/* Let's be strict about the max size */
|
322
|
+
if ((LARGE_BUFFER_SIZE - inflationStream.avail_out) > maxPayloadLength) {
|
323
|
+
return std::nullopt;
|
307
324
|
}
|
308
325
|
|
326
|
+
return std::string_view(zlibContext->inflationBuffer,
|
327
|
+
LARGE_BUFFER_SIZE - inflationStream.avail_out);
|
328
|
+
}
|
309
329
|
};
|
310
330
|
|
311
331
|
#endif
|
312
332
|
|
313
|
-
}
|
333
|
+
} // namespace uWS
|
314
334
|
|
315
335
|
#endif // UWS_PERMESSAGEDEFLATE_H
|