iodine 0.7.59 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +15 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -3
  5. data/CHANGELOG.md +132 -12
  6. data/Gemfile +5 -7
  7. data/LICENSE.txt +1 -1
  8. data/README.md +147 -671
  9. data/Rakefile +9 -16
  10. data/examples/chatroom.nru +9 -0
  11. data/examples/client +74 -0
  12. data/examples/config-hello.nru +9 -0
  13. data/examples/config-hello.ru +11 -0
  14. data/examples/config-hijack.ru +13 -0
  15. data/examples/config-shootout.ru +43 -0
  16. data/examples/config.nru +120 -0
  17. data/examples/config.rb +37 -0
  18. data/examples/config.ru +42 -53
  19. data/examples/fake +24 -0
  20. data/examples/hello_neorack +137 -0
  21. data/examples/routes.nru +29 -0
  22. data/examples/routes.ru +42 -0
  23. data/exe/iodine +218 -258
  24. data/ext/iodine/extconf.rb +27 -100
  25. data/ext/iodine/fio-stl.h +128336 -0
  26. data/ext/iodine/fio-stl.md +26396 -0
  27. data/ext/iodine/iodine.c +213 -1393
  28. data/ext/iodine/iodine.h +250 -55
  29. data/ext/iodine/iodine_arg_helper.h +329 -0
  30. data/ext/iodine/iodine_caller.h +234 -25
  31. data/ext/iodine/iodine_cli.h +434 -0
  32. data/ext/iodine/iodine_compression.h +312 -0
  33. data/ext/iodine/iodine_connection.h +3484 -34
  34. data/ext/iodine/iodine_core.h +363 -0
  35. data/ext/iodine/iodine_crypto.h +1441 -0
  36. data/ext/iodine/iodine_defer.h +225 -4
  37. data/ext/iodine/iodine_json.h +738 -4
  38. data/ext/iodine/iodine_listener.h +263 -0
  39. data/ext/iodine/iodine_log.h +297 -0
  40. data/ext/iodine/iodine_minimap.h +543 -0
  41. data/ext/iodine/iodine_mustache.h +461 -4
  42. data/ext/iodine/iodine_pubsub_eng.h +729 -0
  43. data/ext/iodine/iodine_pubsub_history.h +547 -0
  44. data/ext/iodine/iodine_pubsub_msg.h +228 -0
  45. data/ext/iodine/iodine_redis.h +322 -0
  46. data/ext/iodine/iodine_store.h +418 -16
  47. data/ext/iodine/iodine_threads.h +279 -0
  48. data/ext/iodine/iodine_tls.h +515 -6
  49. data/ext/iodine/iodine_utils.h +923 -0
  50. data/iodine.gemspec +37 -42
  51. data/lib/iodine/benchmark.rb +1690 -0
  52. data/lib/iodine/documentation.rb +3085 -0
  53. data/lib/iodine/version.rb +17 -1
  54. data/lib/iodine.rb +54 -255
  55. data/logo.svg +36 -0
  56. data/mustache.md +55 -0
  57. data/sig/iodine.rbs +4 -0
  58. metadata +58 -184
  59. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  60. data/.github/workflows/ruby.yml +0 -42
  61. data/.gitignore +0 -20
  62. data/LIMITS.md +0 -41
  63. data/SPEC-PubSub-Draft.md +0 -159
  64. data/SPEC-WebSocket-Draft.md +0 -239
  65. data/bin/console +0 -22
  66. data/bin/info.md +0 -353
  67. data/bin/mustache_bench.rb +0 -100
  68. data/bin/poc/Gemfile.lock +0 -23
  69. data/bin/poc/README.md +0 -37
  70. data/bin/poc/config.ru +0 -66
  71. data/bin/poc/gemfile +0 -1
  72. data/bin/poc/www/index.html +0 -57
  73. data/examples/async_task.ru +0 -92
  74. data/examples/bates/README.md +0 -3
  75. data/examples/bates/config.ru +0 -342
  76. data/examples/bates/david+bold.pdf +0 -0
  77. data/examples/bates/public/drop-pdf.png +0 -0
  78. data/examples/bates/public/index.html +0 -600
  79. data/examples/echo.ru +0 -59
  80. data/examples/etag.ru +0 -16
  81. data/examples/hello.ru +0 -29
  82. data/examples/pubsub_engine.ru +0 -81
  83. data/examples/rack3.ru +0 -12
  84. data/examples/redis.ru +0 -70
  85. data/examples/shootout.ru +0 -73
  86. data/examples/sub-protocols.ru +0 -90
  87. data/examples/tcp_client.rb +0 -66
  88. data/examples/x-sendfile.ru +0 -14
  89. data/ext/iodine/fio.c +0 -11995
  90. data/ext/iodine/fio.h +0 -6371
  91. data/ext/iodine/fio_cli.c +0 -431
  92. data/ext/iodine/fio_cli.h +0 -189
  93. data/ext/iodine/fio_json_parser.h +0 -688
  94. data/ext/iodine/fio_siphash.c +0 -157
  95. data/ext/iodine/fio_siphash.h +0 -37
  96. data/ext/iodine/fio_tls.h +0 -129
  97. data/ext/iodine/fio_tls_missing.c +0 -649
  98. data/ext/iodine/fio_tls_openssl.c +0 -1106
  99. data/ext/iodine/fio_tmpfile.h +0 -50
  100. data/ext/iodine/fiobj.h +0 -44
  101. data/ext/iodine/fiobj4fio.h +0 -21
  102. data/ext/iodine/fiobj_ary.c +0 -333
  103. data/ext/iodine/fiobj_ary.h +0 -139
  104. data/ext/iodine/fiobj_data.c +0 -1187
  105. data/ext/iodine/fiobj_data.h +0 -167
  106. data/ext/iodine/fiobj_hash.c +0 -409
  107. data/ext/iodine/fiobj_hash.h +0 -176
  108. data/ext/iodine/fiobj_json.c +0 -622
  109. data/ext/iodine/fiobj_json.h +0 -68
  110. data/ext/iodine/fiobj_mem.h +0 -71
  111. data/ext/iodine/fiobj_mustache.c +0 -317
  112. data/ext/iodine/fiobj_mustache.h +0 -62
  113. data/ext/iodine/fiobj_numbers.c +0 -344
  114. data/ext/iodine/fiobj_numbers.h +0 -127
  115. data/ext/iodine/fiobj_str.c +0 -433
  116. data/ext/iodine/fiobj_str.h +0 -172
  117. data/ext/iodine/fiobject.c +0 -620
  118. data/ext/iodine/fiobject.h +0 -655
  119. data/ext/iodine/hpack.h +0 -1923
  120. data/ext/iodine/http.c +0 -2743
  121. data/ext/iodine/http.h +0 -1002
  122. data/ext/iodine/http1.c +0 -910
  123. data/ext/iodine/http1.h +0 -29
  124. data/ext/iodine/http1_parser.h +0 -878
  125. data/ext/iodine/http_internal.c +0 -1279
  126. data/ext/iodine/http_internal.h +0 -237
  127. data/ext/iodine/http_mime_parser.h +0 -350
  128. data/ext/iodine/iodine_caller.c +0 -230
  129. data/ext/iodine/iodine_connection.c +0 -941
  130. data/ext/iodine/iodine_defer.c +0 -420
  131. data/ext/iodine/iodine_fiobj2rb.h +0 -120
  132. data/ext/iodine/iodine_helpers.c +0 -282
  133. data/ext/iodine/iodine_helpers.h +0 -12
  134. data/ext/iodine/iodine_http.c +0 -1181
  135. data/ext/iodine/iodine_http.h +0 -23
  136. data/ext/iodine/iodine_json.c +0 -302
  137. data/ext/iodine/iodine_mustache.c +0 -567
  138. data/ext/iodine/iodine_pubsub.c +0 -580
  139. data/ext/iodine/iodine_pubsub.h +0 -26
  140. data/ext/iodine/iodine_rack_io.c +0 -273
  141. data/ext/iodine/iodine_rack_io.h +0 -20
  142. data/ext/iodine/iodine_store.c +0 -146
  143. data/ext/iodine/iodine_tcp.c +0 -346
  144. data/ext/iodine/iodine_tcp.h +0 -13
  145. data/ext/iodine/iodine_tls.c +0 -261
  146. data/ext/iodine/mustache_parser.h +0 -1546
  147. data/ext/iodine/redis_engine.c +0 -957
  148. data/ext/iodine/redis_engine.h +0 -79
  149. data/ext/iodine/resp_parser.h +0 -317
  150. data/ext/iodine/websocket_parser.h +0 -506
  151. data/ext/iodine/websockets.c +0 -743
  152. data/ext/iodine/websockets.h +0 -185
  153. data/lib/iodine/connection.rb +0 -61
  154. data/lib/iodine/json.rb +0 -42
  155. data/lib/iodine/mustache.rb +0 -113
  156. data/lib/iodine/pubsub.rb +0 -55
  157. data/lib/iodine/rack_utils.rb +0 -43
  158. data/lib/iodine/tls.rb +0 -16
  159. data/lib/rack/handler/iodine.rb +0 -33
  160. data/logo.png +0 -0
@@ -0,0 +1,312 @@
1
+ #ifndef H___IODINE_COMPRESSION___H
2
+ #define H___IODINE_COMPRESSION___H
3
+ #include "iodine.h"
4
+
5
+ /* *****************************************************************************
6
+ Iodine::Base::Compression - Data Compression
7
+
8
+ Provides access to compression/decompression algorithms:
9
+ - Deflate: Raw DEFLATE (RFC 1951) - no headers
10
+ - Gzip: GZIP format (RFC 1952) - deflate with gzip wrapper
11
+ - Brotli: Brotli compression (RFC 7932)
12
+ ***************************************************************************** */
13
+
14
+ static VALUE iodine_rb_COMPRESSION;
15
+ static VALUE iodine_rb_DEFLATE;
16
+ static VALUE iodine_rb_GZIP;
17
+ static VALUE iodine_rb_BROTLI;
18
+
19
+ /* Bound decompression of untrusted streams before allocating output. Callers
20
+ * processing larger trusted data may raise this limit explicitly. */
21
+ #define IODINE_COMPRESSION_MAX_OUTPUT (64 * 1024 * 1024)
22
+
23
+ typedef size_t (*iodine_decompress_fn)(void *, size_t, const void *, size_t);
24
+
25
+ FIO_SFUNC VALUE iodine_compression_decompress(fio_buf_info_s data,
26
+ size_t max_output,
27
+ iodine_decompress_fn decode,
28
+ const char *name) {
29
+ if (!data.len)
30
+ rb_raise(rb_eRuntimeError, "%s decompression failed (empty input)", name);
31
+ size_t required = decode(NULL, 0, data.buf, data.len);
32
+ if (!required) {
33
+ /* Upstream returns 0 both for invalid input and valid empty output.
34
+ * Recognize the canonical empty streams our encoders emit. */
35
+ static const uint8_t raw_empty[] = {1, 0, 0, 255, 255};
36
+ static const uint8_t gzip_empty[] = {0x1f, 0x8b, 8, 0, 0, 0, 0, 0, 0, 255,
37
+ 1, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0};
38
+ static const uint8_t brotli_empty[] = {6};
39
+ if ((decode == fio_deflate_decompress && data.len == sizeof(raw_empty) &&
40
+ !memcmp(data.buf, raw_empty, sizeof(raw_empty))) ||
41
+ (decode == fio_gzip_decompress && data.len == sizeof(gzip_empty) &&
42
+ !memcmp(data.buf, gzip_empty, sizeof(gzip_empty))) ||
43
+ (decode == fio_brotli_decompress && data.len == sizeof(brotli_empty) &&
44
+ !memcmp(data.buf, brotli_empty, sizeof(brotli_empty))))
45
+ return rb_str_new("", 0);
46
+ rb_raise(rb_eRuntimeError, "%s decompression failed (invalid data)", name);
47
+ }
48
+ if (required > max_output)
49
+ rb_raise(rb_eArgError, "%s output exceeds max_output", name);
50
+ if (required > LONG_MAX)
51
+ rb_raise(rb_eArgError, "%s output exceeds Ruby string limit", name);
52
+ VALUE result = rb_str_buf_new((long)required);
53
+ size_t written = decode(RSTRING_PTR(result), required, data.buf, data.len);
54
+ if (!written || written > required)
55
+ rb_raise(rb_eRuntimeError, "%s decompression failed (invalid data)", name);
56
+ rb_str_set_len(result, (long)written);
57
+ return result;
58
+ }
59
+
60
+ FIO_SFUNC long iodine_compression_bound(size_t input, size_t bound) {
61
+ /* Ruby strings and rb_str_buf_new use long lengths. */
62
+ if (bound < input || bound > LONG_MAX)
63
+ rb_raise(rb_eArgError, "compressed output exceeds Ruby string limit");
64
+ return (long)bound;
65
+ }
66
+
67
+ /* *****************************************************************************
68
+ Deflate - Raw DEFLATE compression (RFC 1951)
69
+ ***************************************************************************** */
70
+
71
+ /**
72
+ * Compresses data using raw DEFLATE (no headers).
73
+ *
74
+ * @param data [String] Data to compress
75
+ * @param level: [Integer] Compression level 0-9 (default: 3)
76
+ * @return [String] Compressed data
77
+ * @raise [RuntimeError] if compression fails
78
+ */
79
+ FIO_SFUNC VALUE iodine_deflate_compress(int argc, VALUE *argv, VALUE self) {
80
+ fio_buf_info_s data = FIO_BUF_INFO0;
81
+ int64_t level = 3;
82
+
83
+ iodine_rb2c_arg(argc,
84
+ argv,
85
+ IODINE_ARG_BUF(data, 0, NULL, 1),
86
+ IODINE_ARG_NUM(level, 0, "level", 0));
87
+
88
+ if (level < 0 || level > 9)
89
+ rb_raise(rb_eArgError,
90
+ "level must be between 0 and 9 (got %" PRId64 ")",
91
+ level);
92
+
93
+ /* Check before calling the upstream bound (which uses size_t arithmetic). */
94
+ if (data.len > LONG_MAX / 2)
95
+ rb_raise(rb_eArgError, "compressed output exceeds Ruby string limit");
96
+ size_t out_len = fio_deflate_compress_bound(data.len);
97
+ VALUE result = rb_str_buf_new(iodine_compression_bound(data.len, out_len));
98
+
99
+ size_t written = fio_deflate_compress(RSTRING_PTR(result),
100
+ out_len,
101
+ data.buf,
102
+ data.len,
103
+ (int)level);
104
+ if (!written)
105
+ rb_raise(rb_eRuntimeError, "Deflate compression failed");
106
+
107
+ rb_str_set_len(result, written);
108
+ return result;
109
+ (void)self;
110
+ }
111
+
112
+ /**
113
+ * Decompresses raw DEFLATE data.
114
+ *
115
+ * @param data [String] Compressed data (raw DEFLATE, no headers)
116
+ * @param max_output: [Integer] Maximum output bytes (default: 64 MiB)
117
+ * @return [String] Decompressed data
118
+ * @raise [RuntimeError] if decompression fails
119
+ */
120
+ FIO_SFUNC VALUE iodine_deflate_decompress(int argc, VALUE *argv, VALUE self) {
121
+ fio_buf_info_s data = FIO_BUF_INFO0;
122
+ size_t max_output = IODINE_COMPRESSION_MAX_OUTPUT;
123
+
124
+ iodine_rb2c_arg(argc, argv,
125
+ IODINE_ARG_BUF(data, 0, NULL, 1),
126
+ IODINE_ARG_SIZE_T(max_output, 0, "max_output", 0));
127
+
128
+ return iodine_compression_decompress(data, max_output,
129
+ fio_deflate_decompress, "Deflate");
130
+ (void)self;
131
+ }
132
+
133
+ /* *****************************************************************************
134
+ Gzip - GZIP compression (RFC 1952)
135
+ ***************************************************************************** */
136
+
137
+ /**
138
+ * Compresses data using GZIP format.
139
+ *
140
+ * @param data [String] Data to compress
141
+ * @param level: [Integer] Compression level 0-9 (default: 3)
142
+ * @return [String] GZIP-compressed data
143
+ * @raise [RuntimeError] if compression fails
144
+ */
145
+ FIO_SFUNC VALUE iodine_gzip_compress(int argc, VALUE *argv, VALUE self) {
146
+ fio_buf_info_s data = FIO_BUF_INFO0;
147
+ int64_t level = 3;
148
+
149
+ iodine_rb2c_arg(argc,
150
+ argv,
151
+ IODINE_ARG_BUF(data, 0, NULL, 1),
152
+ IODINE_ARG_NUM(level, 0, "level", 0));
153
+
154
+ if (level < 0 || level > 9)
155
+ rb_raise(rb_eArgError,
156
+ "level must be between 0 and 9 (got %" PRId64 ")",
157
+ level);
158
+
159
+ /* gzip adds an 18-byte header/trailer around deflate data */
160
+ /* Check before calling the upstream bound (which uses size_t arithmetic). */
161
+ if (data.len > LONG_MAX / 2)
162
+ rb_raise(rb_eArgError, "compressed output exceeds Ruby string limit");
163
+ size_t out_len = fio_deflate_compress_bound(data.len) + 18;
164
+ VALUE result = rb_str_buf_new(iodine_compression_bound(data.len, out_len));
165
+
166
+ size_t written = fio_gzip_compress(RSTRING_PTR(result),
167
+ out_len,
168
+ data.buf,
169
+ data.len,
170
+ (int)level);
171
+ if (!written)
172
+ rb_raise(rb_eRuntimeError, "Gzip compression failed");
173
+
174
+ rb_str_set_len(result, written);
175
+ return result;
176
+ (void)self;
177
+ }
178
+
179
+ /**
180
+ * Decompresses GZIP data.
181
+ *
182
+ * @param data [String] GZIP-compressed data
183
+ * @param max_output: [Integer] Maximum output bytes (default: 64 MiB)
184
+ * @return [String] Decompressed data
185
+ * @raise [RuntimeError] if decompression fails
186
+ */
187
+ FIO_SFUNC VALUE iodine_gzip_decompress(int argc, VALUE *argv, VALUE self) {
188
+ fio_buf_info_s data = FIO_BUF_INFO0;
189
+ size_t max_output = IODINE_COMPRESSION_MAX_OUTPUT;
190
+
191
+ iodine_rb2c_arg(argc, argv,
192
+ IODINE_ARG_BUF(data, 0, NULL, 1),
193
+ IODINE_ARG_SIZE_T(max_output, 0, "max_output", 0));
194
+
195
+ return iodine_compression_decompress(data, max_output,
196
+ fio_gzip_decompress, "Gzip");
197
+ (void)self;
198
+ }
199
+
200
+ /* *****************************************************************************
201
+ Brotli - Brotli compression (RFC 7932)
202
+ ***************************************************************************** */
203
+
204
+ /**
205
+ * Compresses data using Brotli.
206
+ *
207
+ * @param data [String] Data to compress
208
+ * @param quality: [Integer] Compression quality 1-6 (default: 3)
209
+ * @return [String] Brotli-compressed data
210
+ * @raise [RuntimeError] if compression fails
211
+ */
212
+ FIO_SFUNC VALUE iodine_brotli_compress(int argc, VALUE *argv, VALUE self) {
213
+ fio_buf_info_s data = FIO_BUF_INFO0;
214
+ int64_t quality = 3;
215
+
216
+ iodine_rb2c_arg(argc,
217
+ argv,
218
+ IODINE_ARG_BUF(data, 0, NULL, 1),
219
+ IODINE_ARG_NUM(quality, 0, "quality", 0));
220
+
221
+ if (quality < 1 || quality > 6)
222
+ rb_raise(rb_eArgError,
223
+ "quality must be between 1 and 6 (got %" PRId64 ")",
224
+ quality);
225
+
226
+ if (data.len > LONG_MAX - (data.len >> 2) - 1024)
227
+ rb_raise(rb_eArgError, "compressed output exceeds Ruby string limit");
228
+ size_t out_len = fio_brotli_compress_bound(data.len);
229
+ VALUE result = rb_str_buf_new(iodine_compression_bound(data.len, out_len));
230
+
231
+ size_t written = fio_brotli_compress(RSTRING_PTR(result),
232
+ out_len,
233
+ data.buf,
234
+ data.len,
235
+ (int)quality);
236
+ if (!written)
237
+ rb_raise(rb_eRuntimeError, "Brotli compression failed");
238
+
239
+ rb_str_set_len(result, written);
240
+ return result;
241
+ (void)self;
242
+ }
243
+
244
+ /**
245
+ * Decompresses Brotli data.
246
+ *
247
+ * @param data [String] Brotli-compressed data
248
+ * @param max_output: [Integer] Maximum output bytes (default: 64 MiB)
249
+ * @return [String] Decompressed data
250
+ * @raise [RuntimeError] if decompression fails
251
+ */
252
+ FIO_SFUNC VALUE iodine_brotli_decompress(int argc, VALUE *argv, VALUE self) {
253
+ fio_buf_info_s data = FIO_BUF_INFO0;
254
+ size_t max_output = IODINE_COMPRESSION_MAX_OUTPUT;
255
+
256
+ iodine_rb2c_arg(argc, argv,
257
+ IODINE_ARG_BUF(data, 0, NULL, 1),
258
+ IODINE_ARG_SIZE_T(max_output, 0, "max_output", 0));
259
+
260
+ return iodine_compression_decompress(data, max_output,
261
+ fio_brotli_decompress, "Brotli");
262
+ (void)self;
263
+ }
264
+
265
+ /* *****************************************************************************
266
+ Module Initialization
267
+ ***************************************************************************** */
268
+
269
+ static void Init_Iodine_Compression(void) {
270
+ /* Iodine::Base::Compression */
271
+ iodine_rb_COMPRESSION =
272
+ rb_define_module_under(iodine_rb_IODINE_BASE, "Compression");
273
+ STORE.hold(iodine_rb_COMPRESSION);
274
+
275
+ /* Iodine::Base::Compression::Deflate */
276
+ iodine_rb_DEFLATE = rb_define_module_under(iodine_rb_COMPRESSION, "Deflate");
277
+ STORE.hold(iodine_rb_DEFLATE);
278
+ rb_define_module_function(iodine_rb_DEFLATE,
279
+ "compress",
280
+ iodine_deflate_compress,
281
+ -1);
282
+ rb_define_module_function(iodine_rb_DEFLATE,
283
+ "decompress",
284
+ iodine_deflate_decompress,
285
+ -1);
286
+
287
+ /* Iodine::Base::Compression::Gzip */
288
+ iodine_rb_GZIP = rb_define_module_under(iodine_rb_COMPRESSION, "Gzip");
289
+ STORE.hold(iodine_rb_GZIP);
290
+ rb_define_module_function(iodine_rb_GZIP,
291
+ "compress",
292
+ iodine_gzip_compress,
293
+ -1);
294
+ rb_define_module_function(iodine_rb_GZIP,
295
+ "decompress",
296
+ iodine_gzip_decompress,
297
+ -1);
298
+
299
+ /* Iodine::Base::Compression::Brotli */
300
+ iodine_rb_BROTLI = rb_define_module_under(iodine_rb_COMPRESSION, "Brotli");
301
+ STORE.hold(iodine_rb_BROTLI);
302
+ rb_define_module_function(iodine_rb_BROTLI,
303
+ "compress",
304
+ iodine_brotli_compress,
305
+ -1);
306
+ rb_define_module_function(iodine_rb_BROTLI,
307
+ "decompress",
308
+ iodine_brotli_decompress,
309
+ -1);
310
+ }
311
+
312
+ #endif /* H___IODINE_COMPRESSION___H */