protocol-http3 0.0.1
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/ext/rakefile.rb +12 -0
- data/ext/ruby-protocol-http3-lock.yml +82 -0
- data/ext/source/Ruby/Protocol/HTTP3/Client.cpp +363 -0
- data/ext/source/Ruby/Protocol/HTTP3/Client.hpp +14 -0
- data/ext/source/Ruby/Protocol/HTTP3/Dispatcher.cpp +257 -0
- data/ext/source/Ruby/Protocol/HTTP3/Dispatcher.hpp +13 -0
- data/ext/source/Ruby/Protocol/HTTP3/Server.cpp +239 -0
- data/ext/source/Ruby/Protocol/HTTP3/Server.hpp +13 -0
- data/ext/source/Ruby/Protocol/HTTP3.cpp +28 -0
- data/ext/source/Ruby/Protocol/HTTP3.hpp +9 -0
- data/ext/source/Ruby/Protocol/QUIC/Bindings.hpp +35 -0
- data/ext/teapot.rb +48 -0
- data/lib/protocol/http3/version.rb +12 -0
- data/lib/protocol/http3.rb +11 -0
- data/license.md +21 -0
- data/readme.md +55 -0
- data/releases.md +3 -0
- data.tar.gz.sig +0 -0
- metadata +129 -0
- metadata.gz.sig +1 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 52450e9925c14c39e98b9e9a762a4f0ef69c92a1ff6c7f7898eb8d4e1c60c1e7
|
|
4
|
+
data.tar.gz: a18affd137347ef514d858c68df6be51f35683e82d13eb28abd0b89b05d55c0a
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 252b5eb914682b2797eab8b6b5c14e76efdb6f53ef7a2e527cc9358dbce83fd7953ffb7fe99e8d08ae6537f00ffb0d83dbf2aeb244bec372606e6cc98e47ae04
|
|
7
|
+
data.tar.gz: 6715a25f8dda241f3cd0029bfe8aa897524c30418723b5d249f71d2e0ae4e987e6656f213a0f49ebfb91f90d516eedaa1c3c1702b2be33b410998ad8a008b2dd
|
checksums.yaml.gz.sig
ADDED
|
Binary file
|
data/ext/rakefile.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2023-2026, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
task :default do
|
|
7
|
+
ruby_library_directory = ENV.fetch("RUBYLIBDIR"){ENV.fetch("RUBYARCHDIR")}
|
|
8
|
+
build_environment = {"RUBYLIBDIR" => ruby_library_directory}
|
|
9
|
+
|
|
10
|
+
sh build_environment, "teapot", "fetch"
|
|
11
|
+
sh build_environment, "teapot", "scheduler-ruby-library", "Ruby/Protocol/HTTP3"
|
|
12
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
platforms:
|
|
3
|
+
:commit: 53bfdd34201790980ba8f4c335dbf659d038eb06
|
|
4
|
+
:branch: master
|
|
5
|
+
build-make:
|
|
6
|
+
:commit: 50998307f3d1f462c2bda1999b42b2ea8aeb4b15
|
|
7
|
+
:branch: master
|
|
8
|
+
build-cmake:
|
|
9
|
+
:commit: 6558fdad5bbb475f0fa5584ff773de8f12ff232e
|
|
10
|
+
:branch: master
|
|
11
|
+
protocol-http3:
|
|
12
|
+
:commit: d9e1c8bc9cb301d430fb48c3aec3b938a6446277
|
|
13
|
+
:branch: main
|
|
14
|
+
ruby:
|
|
15
|
+
:commit: 685cdd5a421dae7749f368d08add9aa9709ad043
|
|
16
|
+
:branch: main
|
|
17
|
+
generate-template:
|
|
18
|
+
:commit: ad0dcfb6da64cc0508b71916b30e1050c82ecea7
|
|
19
|
+
:branch: master
|
|
20
|
+
generate-cpp-class:
|
|
21
|
+
:commit: b8996bd1404904a737b76d6893fc9f9bf78da540
|
|
22
|
+
:branch: master
|
|
23
|
+
build-compile-commands:
|
|
24
|
+
:commit: 1c4b18f86d45426d7dd284c28bc53837e5694b6c
|
|
25
|
+
:branch: main
|
|
26
|
+
variants:
|
|
27
|
+
:commit: f6a26a8ac3a47a23a213cbd15da2183239d394d1
|
|
28
|
+
:branch: master
|
|
29
|
+
platform-darwin-osx:
|
|
30
|
+
:commit: dbd14d21c11e85f6fc067529a63f81cf5e6604d2
|
|
31
|
+
:branch: master
|
|
32
|
+
platform-darwin-ios:
|
|
33
|
+
:commit: d0611a1afac738012ffb7c51185499292e9a87ba
|
|
34
|
+
:branch: master
|
|
35
|
+
build-clang:
|
|
36
|
+
:commit: 1c9be15a63c149f6decf8d0599b34755aa3b0979
|
|
37
|
+
:branch: master
|
|
38
|
+
build-darwin:
|
|
39
|
+
:commit: 0d68478a7754741dd5d360f70294161efdee030d
|
|
40
|
+
:branch: master
|
|
41
|
+
build-files:
|
|
42
|
+
:commit: 2e5392ef4e171885b621288c7829e5160f1255bf
|
|
43
|
+
:branch: master
|
|
44
|
+
executor-unix:
|
|
45
|
+
:commit: 91f433a59550b826f7bc69e36d1df9c6e5576575
|
|
46
|
+
:branch: master
|
|
47
|
+
executor-lldb:
|
|
48
|
+
:commit: 193ba0b15c532d2745b0f0bfb05cd9581e869555
|
|
49
|
+
:branch: master
|
|
50
|
+
protocol-quic:
|
|
51
|
+
:commit: 1328f66a91ba7b3e544304dde8ba7bc93d3462ec
|
|
52
|
+
:branch: main
|
|
53
|
+
scheduler:
|
|
54
|
+
:commit: 4d05a1631ac749106d268bda07425bf6ce0476dc
|
|
55
|
+
:branch: main
|
|
56
|
+
nghttp3:
|
|
57
|
+
:commit: 922c2aaca406840a63ce2c4a808d9c888538671d
|
|
58
|
+
:branch: main
|
|
59
|
+
ngtcp2:
|
|
60
|
+
:commit: c65334b60a04200b1691da3d85d38444c5ff951d
|
|
61
|
+
:branch: main
|
|
62
|
+
concurrent:
|
|
63
|
+
:commit: 5075d0f6c2c0e90dc152265ec5e236d56fd20c94
|
|
64
|
+
:branch: master
|
|
65
|
+
time:
|
|
66
|
+
:commit: c1ec0bb4fc9abca3de559a87884bdbc1413b3f1f
|
|
67
|
+
:branch: main
|
|
68
|
+
picotls:
|
|
69
|
+
:commit: 2bc03af57a8ea09f3b0bd11c47c876fd3bc1d9fc
|
|
70
|
+
:branch: main
|
|
71
|
+
coroutine:
|
|
72
|
+
:commit: 428204db9f5485d1565884c218933fd16833b439
|
|
73
|
+
:branch: master
|
|
74
|
+
openssl:
|
|
75
|
+
:commit: 2f48d686aaaf20dc6d7e8a277803657eb5951530
|
|
76
|
+
:branch: main
|
|
77
|
+
coroutine-arm64:
|
|
78
|
+
:commit: aada7d279a6c2ae79b6f8f3e45cfa44de3c432fe
|
|
79
|
+
:branch: master
|
|
80
|
+
scheduler-ruby:
|
|
81
|
+
:commit: 94e524e64912081aaa5a8cb54bad7ad73f01a51a
|
|
82
|
+
:branch: main
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
#include "Client.hpp"
|
|
2
|
+
|
|
3
|
+
#include "../QUIC/Bindings.hpp"
|
|
4
|
+
|
|
5
|
+
#include <Protocol/HTTP3/Stream.hpp>
|
|
6
|
+
|
|
7
|
+
#include <array>
|
|
8
|
+
#include <unordered_map>
|
|
9
|
+
#include <vector>
|
|
10
|
+
|
|
11
|
+
VALUE Ruby_Protocol_HTTP3_Client = Qnil;
|
|
12
|
+
|
|
13
|
+
namespace Ruby::Protocol::HTTP3 {
|
|
14
|
+
|
|
15
|
+
class Client final : public ::Protocol::QUIC::Client, public ::Protocol::HTTP3::Session {
|
|
16
|
+
public:
|
|
17
|
+
VALUE self;
|
|
18
|
+
|
|
19
|
+
private:
|
|
20
|
+
VALUE _configuration;
|
|
21
|
+
VALUE _tls_context;
|
|
22
|
+
VALUE _socket;
|
|
23
|
+
VALUE _remote_address;
|
|
24
|
+
std::unordered_map<::Protocol::QUIC::StreamID, VALUE> _streams;
|
|
25
|
+
|
|
26
|
+
public:
|
|
27
|
+
Client(VALUE self, VALUE configuration, VALUE tls_context, VALUE socket, VALUE remote_address, VALUE chosen_version) :
|
|
28
|
+
::Protocol::QUIC::Client(*Ruby_Protocol_QUIC_Configuration_get(configuration), *Ruby_Protocol_QUIC_TLS_ClientContext_get(tls_context), *Ruby_Protocol_QUIC_Socket_get(socket), *Ruby_Protocol_QUIC_Address_get(remote_address), RB_NUM2UINT(chosen_version)),
|
|
29
|
+
::Protocol::HTTP3::Session(::Protocol::HTTP3::Session::Role::CLIENT),
|
|
30
|
+
self(self),
|
|
31
|
+
_configuration(configuration),
|
|
32
|
+
_tls_context(tls_context),
|
|
33
|
+
_socket(socket),
|
|
34
|
+
_remote_address(remote_address)
|
|
35
|
+
{
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
void handshake_completed() override
|
|
39
|
+
{
|
|
40
|
+
auto control_stream = open_unidirectional_stream();
|
|
41
|
+
auto encoder_stream = open_unidirectional_stream();
|
|
42
|
+
auto decoder_stream = open_unidirectional_stream();
|
|
43
|
+
|
|
44
|
+
bind_control_stream(control_stream->stream_id());
|
|
45
|
+
bind_qpack_streams(encoder_stream->stream_id(), decoder_stream->stream_id());
|
|
46
|
+
|
|
47
|
+
send_packets();
|
|
48
|
+
|
|
49
|
+
if (rb_respond_to(self, rb_intern("handshake_completed"))) {
|
|
50
|
+
rb_funcall(self, rb_intern("handshake_completed"), 0);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
::Protocol::QUIC::Stream * create_stream(::Protocol::QUIC::StreamID stream_id) override
|
|
55
|
+
{
|
|
56
|
+
return new ::Protocol::HTTP3::Stream(*this, *this, stream_id);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
::Protocol::QUIC::Connection::Status send_stream_data() override
|
|
60
|
+
{
|
|
61
|
+
std::array<::Protocol::QUIC::Byte, 1024*64> packet;
|
|
62
|
+
std::array<nghttp3_vec, 16> http_vectors;
|
|
63
|
+
|
|
64
|
+
while (true) {
|
|
65
|
+
::Protocol::QUIC::StreamID stream_id = -1;
|
|
66
|
+
bool is_final = false;
|
|
67
|
+
|
|
68
|
+
auto vector_count = write_stream_data(stream_id, is_final, http_vectors.data(), http_vectors.size());
|
|
69
|
+
|
|
70
|
+
if (stream_id < 0) {
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
std::vector<ngtcp2_vec> stream_vectors;
|
|
75
|
+
stream_vectors.reserve(static_cast<std::size_t>(vector_count));
|
|
76
|
+
|
|
77
|
+
for (nghttp3_ssize index = 0; index < vector_count; ++index) {
|
|
78
|
+
stream_vectors.push_back(ngtcp2_vec{
|
|
79
|
+
.base = http_vectors[index].base,
|
|
80
|
+
.len = http_vectors[index].len,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
ngtcp2_path_storage path_storage;
|
|
85
|
+
ngtcp2_path_storage_zero(&path_storage);
|
|
86
|
+
ngtcp2_pkt_info packet_info;
|
|
87
|
+
ngtcp2_ssize written_length = 0;
|
|
88
|
+
::Protocol::QUIC::StreamDataFlags flags = is_final ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0;
|
|
89
|
+
|
|
90
|
+
auto result = ngtcp2_conn_writev_stream(::Protocol::QUIC::Client::native_handle(), &path_storage.path, &packet_info, packet.data(), packet.size(), &written_length, flags, stream_id, stream_vectors.data(), stream_vectors.size(), ::Protocol::QUIC::timestamp());
|
|
91
|
+
|
|
92
|
+
if (result == NGTCP2_ERR_STREAM_DATA_BLOCKED || result == NGTCP2_ERR_STREAM_SHUT_WR) {
|
|
93
|
+
block_stream(stream_id);
|
|
94
|
+
return Status(result);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (result < 0) {
|
|
98
|
+
return Status(result);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
add_write_offset(stream_id, static_cast<std::size_t>(written_length));
|
|
102
|
+
|
|
103
|
+
if (result > 0) {
|
|
104
|
+
send_packet(path_storage.path, packet_info, packet.data(), result);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (result == 0 && written_length == 0) {
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return Status::OK;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
void header_received(::Protocol::QUIC::StreamID stream_id, std::int32_t token, nghttp3_rcbuf *name, nghttp3_rcbuf *value, std::uint8_t flags, void *stream_data) override
|
|
116
|
+
{
|
|
117
|
+
(void)token;
|
|
118
|
+
(void)flags;
|
|
119
|
+
(void)stream_data;
|
|
120
|
+
|
|
121
|
+
if (!rb_respond_to(self, rb_intern("header_received"))) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
auto name_buffer = nghttp3_rcbuf_get_buf(name);
|
|
126
|
+
auto value_buffer = nghttp3_rcbuf_get_buf(value);
|
|
127
|
+
|
|
128
|
+
rb_funcall(
|
|
129
|
+
self,
|
|
130
|
+
rb_intern("header_received"),
|
|
131
|
+
3,
|
|
132
|
+
RB_LL2NUM(stream_id),
|
|
133
|
+
rb_str_new(reinterpret_cast<const char *>(name_buffer.base), name_buffer.len),
|
|
134
|
+
rb_str_new(reinterpret_cast<const char *>(value_buffer.base), value_buffer.len)
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
void headers_finished(::Protocol::QUIC::StreamID stream_id, bool is_final, void *stream_data) override
|
|
139
|
+
{
|
|
140
|
+
(void)stream_data;
|
|
141
|
+
|
|
142
|
+
if (rb_respond_to(self, rb_intern("headers_finished"))) {
|
|
143
|
+
rb_funcall(self, rb_intern("headers_finished"), 2, RB_LL2NUM(stream_id), is_final ? Qtrue : Qfalse);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
void settings_received(const nghttp3_proto_settings *settings) override
|
|
148
|
+
{
|
|
149
|
+
(void)settings;
|
|
150
|
+
|
|
151
|
+
if (rb_respond_to(self, rb_intern("settings_received"))) {
|
|
152
|
+
rb_funcall(self, rb_intern("settings_received"), 0);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
void stream_finished(::Protocol::QUIC::StreamID stream_id, void *stream_data) override
|
|
157
|
+
{
|
|
158
|
+
(void)stream_data;
|
|
159
|
+
|
|
160
|
+
if (rb_respond_to(self, rb_intern("stream_finished"))) {
|
|
161
|
+
rb_funcall(self, rb_intern("stream_finished"), 1, RB_LL2NUM(stream_id));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
void disconnect() override
|
|
166
|
+
{
|
|
167
|
+
::Protocol::QUIC::Client::disconnect();
|
|
168
|
+
_streams.clear();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
void mark()
|
|
172
|
+
{
|
|
173
|
+
rb_gc_mark_movable(self);
|
|
174
|
+
rb_gc_mark_movable(_configuration);
|
|
175
|
+
rb_gc_mark_movable(_tls_context);
|
|
176
|
+
rb_gc_mark_movable(_socket);
|
|
177
|
+
rb_gc_mark_movable(_remote_address);
|
|
178
|
+
|
|
179
|
+
for (auto & [stream_id, stream] : _streams) {
|
|
180
|
+
(void)stream_id;
|
|
181
|
+
rb_gc_mark_movable(stream);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
void compact()
|
|
186
|
+
{
|
|
187
|
+
self = rb_gc_location(self);
|
|
188
|
+
_configuration = rb_gc_location(_configuration);
|
|
189
|
+
_tls_context = rb_gc_location(_tls_context);
|
|
190
|
+
_socket = rb_gc_location(_socket);
|
|
191
|
+
_remote_address = rb_gc_location(_remote_address);
|
|
192
|
+
|
|
193
|
+
for (auto & [stream_id, stream] : _streams) {
|
|
194
|
+
(void)stream_id;
|
|
195
|
+
stream = rb_gc_location(stream);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
static void Ruby_Protocol_HTTP3_Client_mark(void *data)
|
|
203
|
+
{
|
|
204
|
+
if (data) {
|
|
205
|
+
reinterpret_cast<Ruby::Protocol::HTTP3::Client *>(data)->mark();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static void Ruby_Protocol_HTTP3_Client_compact(void *data)
|
|
210
|
+
{
|
|
211
|
+
if (data) {
|
|
212
|
+
reinterpret_cast<Ruby::Protocol::HTTP3::Client *>(data)->compact();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
static void Ruby_Protocol_HTTP3_Client_free(void *data)
|
|
217
|
+
{
|
|
218
|
+
if (data) {
|
|
219
|
+
delete reinterpret_cast<Protocol::QUIC::Client *>(data);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
static size_t Ruby_Protocol_HTTP3_Client_size(const void *data)
|
|
224
|
+
{
|
|
225
|
+
return sizeof(Ruby::Protocol::HTTP3::Client);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
static const rb_data_type_t Ruby_Protocol_HTTP3_Client_type = {
|
|
229
|
+
.wrap_struct_name = "Protocol::HTTP3::Client",
|
|
230
|
+
.function = {
|
|
231
|
+
.dmark = Ruby_Protocol_HTTP3_Client_mark,
|
|
232
|
+
.dfree = Ruby_Protocol_HTTP3_Client_free,
|
|
233
|
+
.dsize = Ruby_Protocol_HTTP3_Client_size,
|
|
234
|
+
.dcompact = Ruby_Protocol_HTTP3_Client_compact,
|
|
235
|
+
},
|
|
236
|
+
.parent = &Ruby_Protocol_QUIC_Connection_type,
|
|
237
|
+
.data = NULL,
|
|
238
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
Protocol::QUIC::Client * Ruby_Protocol_HTTP3_Client_get(VALUE self)
|
|
242
|
+
{
|
|
243
|
+
Protocol::QUIC::Client *client;
|
|
244
|
+
|
|
245
|
+
TypedData_Get_Struct(self, Protocol::QUIC::Client, &Ruby_Protocol_HTTP3_Client_type, client);
|
|
246
|
+
|
|
247
|
+
return client;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
static Ruby::Protocol::HTTP3::Client * Ruby_Protocol_HTTP3_Client_native_get(VALUE self)
|
|
251
|
+
{
|
|
252
|
+
return dynamic_cast<Ruby::Protocol::HTTP3::Client *>(Ruby_Protocol_HTTP3_Client_get(self));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
static VALUE Ruby_Protocol_HTTP3_Client_allocate(VALUE klass)
|
|
256
|
+
{
|
|
257
|
+
return TypedData_Wrap_Struct(klass, &Ruby_Protocol_HTTP3_Client_type, NULL);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
static VALUE Ruby_Protocol_HTTP3_Client_initialize(VALUE self, VALUE configuration, VALUE tls_context, VALUE socket, VALUE remote_address, VALUE chosen_version)
|
|
261
|
+
{
|
|
262
|
+
DATA_PTR(self) = new Ruby::Protocol::HTTP3::Client(self, configuration, tls_context, socket, remote_address, chosen_version);
|
|
263
|
+
|
|
264
|
+
return self;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
static VALUE Ruby_Protocol_HTTP3_Client_connect(VALUE self)
|
|
268
|
+
{
|
|
269
|
+
auto client = Ruby_Protocol_HTTP3_Client_get(self);
|
|
270
|
+
|
|
271
|
+
client->connect();
|
|
272
|
+
|
|
273
|
+
return Qnil;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
static VALUE Ruby_Protocol_HTTP3_Client_close(VALUE self)
|
|
277
|
+
{
|
|
278
|
+
auto client = Ruby_Protocol_HTTP3_Client_get(self);
|
|
279
|
+
|
|
280
|
+
client->close();
|
|
281
|
+
|
|
282
|
+
return Qnil;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
static VALUE Ruby_Protocol_HTTP3_Client_send_packets(VALUE self)
|
|
286
|
+
{
|
|
287
|
+
auto client = Ruby_Protocol_HTTP3_Client_get(self);
|
|
288
|
+
|
|
289
|
+
client->send_packets();
|
|
290
|
+
|
|
291
|
+
return Qnil;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
static VALUE Ruby_Protocol_HTTP3_Client_receive(VALUE self, VALUE ruby_socket)
|
|
295
|
+
{
|
|
296
|
+
auto client = Ruby_Protocol_HTTP3_Client_get(self);
|
|
297
|
+
auto socket = Ruby_Protocol_QUIC_Socket_get(ruby_socket);
|
|
298
|
+
|
|
299
|
+
auto path = ngtcp2_conn_get_path(client->native_handle());
|
|
300
|
+
|
|
301
|
+
if (!path) {
|
|
302
|
+
rb_raise(rb_eRuntimeError, "Could not get QUIC client path.");
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
auto status = client->receive_packets(*path, *socket);
|
|
306
|
+
|
|
307
|
+
switch (status) {
|
|
308
|
+
case Protocol::QUIC::Connection::Status::OK:
|
|
309
|
+
client->send_packets();
|
|
310
|
+
return Qtrue;
|
|
311
|
+
case Protocol::QUIC::Connection::Status::CLOSING:
|
|
312
|
+
case Protocol::QUIC::Connection::Status::DRAINING:
|
|
313
|
+
return Qfalse;
|
|
314
|
+
default:
|
|
315
|
+
rb_raise(rb_eRuntimeError, "Could not receive QUIC packet.");
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
static VALUE Ruby_Protocol_HTTP3_Client_submit_request(VALUE self, VALUE headers)
|
|
320
|
+
{
|
|
321
|
+
auto client = Ruby_Protocol_HTTP3_Client_native_get(self);
|
|
322
|
+
auto stream = client->open_bidirectional_stream();
|
|
323
|
+
auto stream_id = stream->stream_id();
|
|
324
|
+
auto count = RARRAY_LEN(headers);
|
|
325
|
+
std::vector<nghttp3_nv> native_headers;
|
|
326
|
+
native_headers.reserve(count);
|
|
327
|
+
|
|
328
|
+
for (long index = 0; index < count; ++index) {
|
|
329
|
+
VALUE pair = rb_ary_entry(headers, index);
|
|
330
|
+
VALUE name = rb_ary_entry(pair, 0);
|
|
331
|
+
VALUE value = rb_ary_entry(pair, 1);
|
|
332
|
+
|
|
333
|
+
name = rb_str_to_str(name);
|
|
334
|
+
value = rb_str_to_str(value);
|
|
335
|
+
|
|
336
|
+
native_headers.push_back(nghttp3_nv{
|
|
337
|
+
.name = reinterpret_cast<std::uint8_t *>(RSTRING_PTR(name)),
|
|
338
|
+
.value = reinterpret_cast<std::uint8_t *>(RSTRING_PTR(value)),
|
|
339
|
+
.namelen = static_cast<std::size_t>(RSTRING_LEN(name)),
|
|
340
|
+
.valuelen = static_cast<std::size_t>(RSTRING_LEN(value)),
|
|
341
|
+
.flags = NGHTTP3_NV_FLAG_NONE,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
client->submit_request(stream_id, native_headers.data(), native_headers.size());
|
|
346
|
+
client->send_packets();
|
|
347
|
+
|
|
348
|
+
return RB_LL2NUM(stream_id);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
void Init_Ruby_Protocol_HTTP3_Client(VALUE Protocol_HTTP3)
|
|
352
|
+
{
|
|
353
|
+
Ruby_Protocol_HTTP3_Client = rb_define_class_under(Protocol_HTTP3, "Client", rb_cObject);
|
|
354
|
+
|
|
355
|
+
rb_define_alloc_func(Ruby_Protocol_HTTP3_Client, Ruby_Protocol_HTTP3_Client_allocate);
|
|
356
|
+
rb_define_method(Ruby_Protocol_HTTP3_Client, "initialize", Ruby_Protocol_HTTP3_Client_initialize, 5);
|
|
357
|
+
|
|
358
|
+
rb_define_method(Ruby_Protocol_HTTP3_Client, "connect", Ruby_Protocol_HTTP3_Client_connect, 0);
|
|
359
|
+
rb_define_method(Ruby_Protocol_HTTP3_Client, "close", Ruby_Protocol_HTTP3_Client_close, 0);
|
|
360
|
+
rb_define_method(Ruby_Protocol_HTTP3_Client, "send_packets", Ruby_Protocol_HTTP3_Client_send_packets, 0);
|
|
361
|
+
rb_define_method(Ruby_Protocol_HTTP3_Client, "receive", Ruby_Protocol_HTTP3_Client_receive, 1);
|
|
362
|
+
rb_define_method(Ruby_Protocol_HTTP3_Client, "submit_request", Ruby_Protocol_HTTP3_Client_submit_request, 1);
|
|
363
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
|
|
5
|
+
#include <Protocol/HTTP3/Session.hpp>
|
|
6
|
+
#include <Protocol/QUIC/Client.hpp>
|
|
7
|
+
|
|
8
|
+
extern "C" {
|
|
9
|
+
extern VALUE Ruby_Protocol_HTTP3_Client;
|
|
10
|
+
|
|
11
|
+
void Init_Ruby_Protocol_HTTP3_Client(VALUE Protocol_HTTP3);
|
|
12
|
+
|
|
13
|
+
Protocol::QUIC::Client * Ruby_Protocol_HTTP3_Client_get(VALUE self);
|
|
14
|
+
}
|