quicsilver 0.3.0 → 0.5.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +9 -1
  3. data/.github/workflows/cibuildgem.yaml +117 -0
  4. data/.gitignore +8 -1
  5. data/CHANGELOG.md +82 -0
  6. data/Gemfile.lock +27 -2
  7. data/README.md +205 -29
  8. data/Rakefile +75 -3
  9. data/benchmarks/baseline.rb +175 -0
  10. data/benchmarks/compare.rb +398 -0
  11. data/benchmarks/helpers.rb +138 -64
  12. data/benchmarks/latency.rb +128 -0
  13. data/benchmarks/loss.rb +193 -0
  14. data/benchmarks/mobile.rb +125 -0
  15. data/docs/connection_identity.md +141 -0
  16. data/examples/README.md +44 -91
  17. data/examples/benchmark.rb +191 -0
  18. data/examples/connection_pool_demo.rb +47 -0
  19. data/examples/example_helper.rb +69 -0
  20. data/examples/falcon_middleware.rb +44 -0
  21. data/examples/feature_demo.rb +125 -0
  22. data/examples/grpc_style.rb +97 -0
  23. data/examples/latency_aware_routing.rb +382 -0
  24. data/examples/lifecycle_drain.rb +264 -0
  25. data/examples/minimal_http3_server.rb +6 -18
  26. data/examples/priorities.rb +60 -0
  27. data/examples/protocol_http_server.rb +31 -0
  28. data/examples/rack_http3_server.rb +8 -20
  29. data/examples/rails_feature_test.rb +280 -0
  30. data/examples/server_stats.rb +117 -0
  31. data/examples/simple_client_test.rb +5 -5
  32. data/examples/streaming_sse.rb +33 -0
  33. data/examples/trailers.rb +69 -0
  34. data/examples/webtransport_smoke.rb +546 -0
  35. data/examples/worker_load_balancing.rb +425 -0
  36. data/ext/quicsilver/extconf.rb +111 -12
  37. data/ext/quicsilver/include/msquic.h +2226 -0
  38. data/ext/quicsilver/include/msquic_posix.h +696 -0
  39. data/ext/quicsilver/include/quic_sal_stub.h +314 -0
  40. data/ext/quicsilver/msquic_patch.rb +68 -0
  41. data/ext/quicsilver/patches/reliable-reset.patch +723 -0
  42. data/ext/quicsilver/patches/stream-final-size.patch +47 -0
  43. data/ext/quicsilver/quicsilver.c +1646 -189
  44. data/lib/quicsilver/client/client.rb +546 -88
  45. data/lib/quicsilver/client/connection_pool.rb +202 -0
  46. data/lib/quicsilver/client/request.rb +106 -14
  47. data/lib/quicsilver/errors.rb +39 -0
  48. data/lib/quicsilver/libmsquic.2.dylib +0 -0
  49. data/lib/quicsilver/protocol/adapter.rb +196 -0
  50. data/lib/quicsilver/protocol/capsule.rb +38 -0
  51. data/lib/quicsilver/protocol/connect_stream_decoder.rb +75 -0
  52. data/lib/quicsilver/protocol/control_stream_parser.rb +117 -0
  53. data/lib/quicsilver/protocol/datagram.rb +40 -0
  54. data/lib/quicsilver/protocol/frame_parser.rb +141 -0
  55. data/lib/quicsilver/protocol/frame_reader.rb +84 -0
  56. data/lib/quicsilver/protocol/frames.rb +137 -10
  57. data/lib/quicsilver/protocol/priority.rb +65 -0
  58. data/lib/quicsilver/protocol/qpack/decoder.rb +4 -42
  59. data/lib/quicsilver/protocol/qpack/encoder.rb +49 -21
  60. data/lib/quicsilver/protocol/qpack/header_block_decoder.rb +16 -1
  61. data/lib/quicsilver/protocol/qpack/huffman.rb +4 -4
  62. data/lib/quicsilver/protocol/request_encoder.rb +6 -3
  63. data/lib/quicsilver/protocol/request_parser.rb +43 -141
  64. data/lib/quicsilver/protocol/response_encoder.rb +40 -5
  65. data/lib/quicsilver/protocol/response_parser.rb +26 -128
  66. data/lib/quicsilver/protocol/stream_input.rb +98 -0
  67. data/lib/quicsilver/protocol/stream_output.rb +59 -0
  68. data/lib/quicsilver/protocol/unidirectional_stream.rb +12 -0
  69. data/lib/quicsilver/protocol/web_transport.rb +214 -0
  70. data/lib/quicsilver/rack/context.rb +33 -0
  71. data/lib/quicsilver/response.rb +40 -0
  72. data/lib/quicsilver/server/rack_adapter.rb +77 -0
  73. data/lib/quicsilver/server/receive_queue.rb +106 -0
  74. data/lib/quicsilver/server/request_handler.rb +111 -48
  75. data/lib/quicsilver/server/request_registry.rb +18 -5
  76. data/lib/quicsilver/server/scheduler.rb +50 -0
  77. data/lib/quicsilver/server/schedulers/fiber_scheduler.rb +79 -0
  78. data/lib/quicsilver/server/schedulers/thread_scheduler.rb +76 -0
  79. data/lib/quicsilver/server/server.rb +848 -104
  80. data/lib/quicsilver/server/web_transport_flow_control.rb +270 -0
  81. data/lib/quicsilver/server/web_transport_manager.rb +281 -0
  82. data/lib/quicsilver/server/web_transport_registry.rb +40 -0
  83. data/lib/quicsilver/server/web_transport_session.rb +812 -0
  84. data/lib/quicsilver/server/web_transport_stream.rb +326 -0
  85. data/lib/quicsilver/transport/configuration.rb +113 -11
  86. data/lib/quicsilver/transport/connection.rb +376 -132
  87. data/lib/quicsilver/transport/connection_stats.rb +53 -0
  88. data/lib/quicsilver/transport/event_loop.rb +36 -0
  89. data/lib/quicsilver/transport/inbound_stream.rb +21 -1
  90. data/lib/quicsilver/transport/stream.rb +18 -3
  91. data/lib/quicsilver/transport/stream_event.rb +25 -2
  92. data/lib/quicsilver/transport/stream_id.rb +26 -0
  93. data/lib/quicsilver/version.rb +1 -1
  94. data/lib/quicsilver.rb +45 -11
  95. data/lib/rackup/handler/quicsilver.rb +57 -38
  96. data/quicsilver.gemspec +17 -2
  97. metadata +120 -10
  98. data/benchmarks/concurrent.rb +0 -110
  99. data/benchmarks/quicsilver_server.rb +0 -46
  100. data/benchmarks/rails.rb +0 -170
  101. data/benchmarks/throughput.rb +0 -113
  102. data/examples/setup_certs.sh +0 -57
@@ -0,0 +1,314 @@
1
+ /*++
2
+
3
+ Copyright (c) Microsoft Corporation.
4
+ Licensed under the MIT License.
5
+
6
+ --*/
7
+
8
+ #ifndef _SAL_STUB_H
9
+ #define _SAL_STUB_H
10
+
11
+ #pragma once
12
+
13
+ //
14
+ // Necessary when SAL isn't supported to tell compiler it's not necessary.
15
+ //
16
+ #define INIT_NO_SAL(X) = X
17
+
18
+ #ifndef _Must_inspect_result_
19
+ #define _Must_inspect_result_
20
+ #endif
21
+
22
+ #ifndef _Pre_defensive_
23
+ #define _Pre_defensive_
24
+ #endif
25
+
26
+ #ifndef _Ret_notnull_
27
+ #define _Ret_notnull_
28
+ #endif
29
+
30
+ #ifndef _IRQL_requires_max_
31
+ #define _IRQL_requires_max_(...)
32
+ #endif
33
+
34
+ #ifndef _Function_class_
35
+ #define _Function_class_(...)
36
+ #endif
37
+
38
+ #ifndef _In_
39
+ #define _In_
40
+ #endif
41
+
42
+ #ifndef _In_opt_
43
+ #define _In_opt_
44
+ #endif
45
+
46
+ #ifndef _In_opt_z_
47
+ #define _In_opt_z_
48
+ #endif
49
+
50
+ #ifndef _Inout_
51
+ #define _Inout_
52
+ #endif
53
+
54
+ #ifndef _Inout_opt_
55
+ #define _Inout_opt_
56
+ #endif
57
+
58
+ #ifndef _In_z_
59
+ #define _In_z_
60
+ #endif
61
+
62
+ #ifndef _Out_
63
+ #define _Out_
64
+ #endif
65
+
66
+ #ifndef _Out_range_
67
+ #define _Out_range_(...)
68
+ #endif
69
+
70
+ #ifndef _Field_size_
71
+ #define _Field_size_(...)
72
+ #endif
73
+
74
+ #ifndef _Field_size_opt_
75
+ #define _Field_size_opt_(...)
76
+ #endif
77
+
78
+ #ifndef _Field_size_bytes_
79
+ #define _Field_size_bytes_(...)
80
+ #endif
81
+
82
+ #ifndef _Field_size_bytes_opt_
83
+ #define _Field_size_bytes_opt_(...)
84
+ #endif
85
+
86
+ #ifndef _In_reads_
87
+ #define _In_reads_(...)
88
+ #endif
89
+
90
+ #ifndef _In_reads_bytes_
91
+ #define _In_reads_bytes_(...)
92
+ #endif
93
+
94
+ #ifndef _In_reads_z_
95
+ #define _In_reads_z_(...)
96
+ #endif
97
+
98
+ #ifndef _In_reads_opt_z_
99
+ #define _In_reads_opt_z_(...)
100
+ #endif
101
+
102
+ #ifndef _In_reads_or_z_opt_
103
+ #define _In_reads_or_z_opt_(...)
104
+ #endif
105
+
106
+ #ifndef _Out_writes_bytes_opt_
107
+ #define _Out_writes_bytes_opt_(...)
108
+ #endif
109
+
110
+ #ifndef _Null_terminated_
111
+ #define _Null_terminated_
112
+ #endif
113
+
114
+ #ifndef _NullNull_terminated_
115
+ #define _NullNull_terminated_
116
+ #endif
117
+
118
+ #ifndef _Out_writes_bytes_
119
+ #define _Out_writes_bytes_(...)
120
+ #endif
121
+
122
+ #ifndef _Field_size_
123
+ #define _Field_size_(...)
124
+ #endif
125
+
126
+ #ifndef _Success_
127
+ #define _Success_(...)
128
+ #endif
129
+
130
+ #ifndef _Field_range_
131
+ #define _Field_range_(...)
132
+ #endif
133
+
134
+ #ifndef _In_reads_bytes_opt_
135
+ #define _In_reads_bytes_opt_(...)
136
+ #endif
137
+
138
+ #ifndef _Out_writes_bytes_to_
139
+ #define _Out_writes_bytes_to_(...)
140
+ #endif
141
+
142
+ #ifndef _Out_writes_bytes_to_opt_
143
+ #define _Out_writes_bytes_to_opt_(...)
144
+ #endif
145
+
146
+ #ifndef _Deref_pre_opt_count_
147
+ #define _Deref_pre_opt_count_(...)
148
+ #endif
149
+
150
+ #ifndef _Deref_post_opt_count_
151
+ #define _Deref_post_opt_count_(...)
152
+ #endif
153
+
154
+ #ifndef _Outptr_result_buffer_
155
+ #define _Outptr_result_buffer_(...)
156
+ #endif
157
+
158
+ #ifndef _Outptr_result_buffer_maybenull_
159
+ #define _Outptr_result_buffer_maybenull_(...)
160
+ #endif
161
+
162
+ #ifndef _Inout_updates_bytes_
163
+ #define _Inout_updates_bytes_(...)
164
+ #endif
165
+
166
+ #ifndef _Inout_updates_bytes_opt_
167
+ #define _Inout_updates_bytes_opt_(...)
168
+ #endif
169
+
170
+ #ifndef _Inout_updates_
171
+ #define _Inout_updates_(...)
172
+ #endif
173
+
174
+ #ifndef _Out_opt_
175
+ #define _Out_opt_
176
+ #endif
177
+
178
+ #ifndef _Outptr_result_maybenull_
179
+ #define _Outptr_result_maybenull_
180
+ #endif
181
+
182
+ #ifndef _Outptr_
183
+ #define _Outptr_
184
+ #endif
185
+
186
+ #ifndef _Ret_maybenull_
187
+ #define _Ret_maybenull_
188
+ #endif
189
+
190
+ #ifndef _Must_inspect_result_
191
+ #define _Must_inspect_result_
192
+ #endif
193
+
194
+ #ifndef _Post_invalid_
195
+ #define _Post_invalid_
196
+ #endif
197
+
198
+ #ifndef _Post_writable_byte_size_
199
+ #define _Post_writable_byte_size_(...)
200
+ #endif
201
+
202
+ #ifndef __drv_allocatesMem
203
+ #define __drv_allocatesMem(...)
204
+ #endif
205
+
206
+ #ifndef __drv_freesMem
207
+ #define __drv_freesMem(...)
208
+ #endif
209
+
210
+ #ifndef __drv_aliasesMem
211
+ #define __drv_aliasesMem
212
+ #endif
213
+
214
+ #ifndef _Frees_ptr_
215
+ #define _Frees_ptr_
216
+ #endif
217
+
218
+ #ifndef _Frees_ptr_opt_
219
+ #define _Frees_ptr_opt_
220
+ #endif
221
+
222
+ #ifndef _In_range_
223
+ #define _In_range_(...)
224
+ #endif
225
+
226
+ #ifndef _When_
227
+ #define _When_(...)
228
+ #endif
229
+
230
+ #ifndef _Post_equal_to_
231
+ #define _Post_equal_to_(...)
232
+ #endif
233
+
234
+ #ifndef _Deref_in_range_
235
+ #define _Deref_in_range_(...)
236
+ #endif
237
+
238
+ #ifndef _Deref_out_range_
239
+ #define _Deref_out_range_(...)
240
+ #endif
241
+
242
+ #ifndef _Out_writes_all_
243
+ #define _Out_writes_all_(...)
244
+ #endif
245
+
246
+ #ifndef _Out_writes_to_
247
+ #define _Out_writes_to_(...)
248
+ #endif
249
+
250
+ #ifndef _Out_writes_
251
+ #define _Out_writes_(...)
252
+ #endif
253
+
254
+ #ifndef _Field_z_
255
+ #define _Field_z_
256
+ #endif
257
+
258
+ #ifndef __analysis_assume
259
+ #define __analysis_assume(expr)
260
+ #endif
261
+
262
+ #ifndef _Out_writes_bytes_all_
263
+ #define _Out_writes_bytes_all_(...)
264
+ #endif
265
+
266
+ #ifndef _Analysis_assume_
267
+ #define _Analysis_assume_(expr)
268
+ #endif
269
+
270
+ #ifndef _Ret_range_
271
+ #define _Ret_range_(...)
272
+ #endif
273
+
274
+ #ifndef _Ret_writes_bytes_
275
+ #define _Ret_writes_bytes_(...)
276
+ #endif
277
+
278
+ #ifndef _Printf_format_string_
279
+ #define _Printf_format_string_
280
+ #endif
281
+
282
+ #ifndef _Interlocked_operand_
283
+ #define _Interlocked_operand_
284
+ #endif
285
+
286
+ #ifndef _In_reads_opt_
287
+ #define _In_reads_opt_(...)
288
+ #endif
289
+
290
+ #ifndef _At_
291
+ #define _At_(...)
292
+ #endif
293
+
294
+ #ifndef _At_buffer_
295
+ #define _At_buffer_(...)
296
+ #endif
297
+
298
+ #ifndef _Check_return_
299
+ #define _Check_return_
300
+ #endif
301
+
302
+ #ifndef _Requires_lock_held_
303
+ #define _Requires_lock_held_(...)
304
+ #endif
305
+
306
+ #ifndef _Requires_exclusive_lock_held_
307
+ #define _Requires_exclusive_lock_held_(...)
308
+ #endif
309
+
310
+ #ifndef _Requires_shared_lock_held_
311
+ #define _Requires_shared_lock_held_(...)
312
+ #endif
313
+
314
+ #endif // _SAL_STUB_H
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+ require "open3"
5
+
6
+ # Keep the vendored revision pinned; carry our MsQuic changes as reviewable
7
+ # patches until upstream provides the required wire format and accessors.
8
+ #
9
+ # Each patch is applied and checked independently so one can be dropped when
10
+ # it lands upstream without disturbing the others. The build stamp digests all
11
+ # of them together: any change to any patch invalidates the built tree.
12
+ #
13
+ # REVIEW THIS ON EVERY MsQuic UPGRADE. A failed `git apply` is loud, but not
14
+ # every conflict is:
15
+ #
16
+ # 1. Did upstream implement what a patch works around? Delete the patch
17
+ # rather than carrying a shim that shadows the real feature.
18
+ # 2. stream-final-size.patch adds a field to the PEER_SEND_ABORTED event
19
+ # struct. Check upstream has not added its own field there, and that
20
+ # QuicStreamIndicatePeerSendAbortedEvent still has the stream in scope.
21
+ # 3. A patch can still apply cleanly onto changed semantics. Re-read the hunks
22
+ # against the new source; "it applied" is not "it is still correct".
23
+ # 4. Re-run the tests that prove each patch does its job, not just the suite.
24
+ # For final size: test/integration/stream_lifetime_test.rb -n /final_size/.
25
+ module MsquicPatch
26
+ PATCHES = [
27
+ # RESET_STREAM_AT wire format and semantics.
28
+ File.expand_path("patches/reliable-reset.patch", __dir__),
29
+ # Read the settled final size of a received stream, which WT_MAX_DATA
30
+ # session accounting needs (draft-ietf-webtrans-http3-16 5.4).
31
+ File.expand_path("patches/stream-final-size.patch", __dir__)
32
+ ].freeze
33
+
34
+ STAMP = ".quicsilver-patch"
35
+
36
+ def self.apply!(source)
37
+ PATCHES.each do |patch|
38
+ next if check(source, patch, "--reverse")
39
+
40
+ unless check(source, patch)
41
+ raise "MsQuic patch #{File.basename(patch)} does not apply cleanly; " \
42
+ "check the vendored revision and local edits"
43
+ end
44
+
45
+ output, status = Open3.capture2e("git", "apply", patch, chdir: source)
46
+ raise "MsQuic patch #{File.basename(patch)} failed: #{output}" unless status.success?
47
+ end
48
+ end
49
+
50
+ def self.check(source, patch, *options)
51
+ _output, status = Open3.capture2e("git", "apply", "--check", *options, patch, chdir: source)
52
+ status.success?
53
+ end
54
+
55
+ def self.digest
56
+ Digest::SHA256.hexdigest(PATCHES.map { |patch| Digest::SHA256.file(patch).hexdigest }.join)
57
+ end
58
+
59
+ def self.built?(source)
60
+ File.read(File.join(source, "build", STAMP)) == digest
61
+ rescue Errno::ENOENT
62
+ false
63
+ end
64
+
65
+ def self.record_build!(source)
66
+ File.write(File.join(source, "build", STAMP), digest)
67
+ end
68
+ end