http3 0.0.3 → 0.0.4
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 +4 -4
- data/CHANGELOG.md +46 -0
- data/README.md +66 -9
- data/ext/http3/nghttp3.c +20 -1
- data/ext/http3/nghttp3.h +35 -2
- data/ext/http3/nghttp3_connection.c +377 -205
- data/ext/http3/nghttp3_nv.c +53 -20
- data/ext/http3/nghttp3_qpack.c +64 -20
- data/ext/http3/session.c +197 -48
- data/lib/http3/rack_adapter.rb +141 -26
- data/lib/http3/server.rb +187 -17
- data/lib/http3/session.rb +211 -32
- data/lib/http3/version.rb +1 -1
- data/sig/http3/nghttp3/connection.rbs +43 -9
- data/sig/http3/nghttp3/nv.rbs +4 -0
- data/sig/http3/nghttp3/qpack.rbs +10 -3
- data/sig/http3/rack_adapter.rbs +17 -2
- data/sig/http3/server.rbs +6 -0
- data/sig/http3/session.rbs +52 -8
- data/sig/http3.rbs +3 -0
- metadata +3 -3
|
@@ -102,6 +102,12 @@ static VALUE connection_alloc(VALUE klass) {
|
|
|
102
102
|
obj->pending_exc = Qnil;
|
|
103
103
|
obj->is_closed = 0;
|
|
104
104
|
obj->is_server = 0;
|
|
105
|
+
obj->entered = CONN_IDLE;
|
|
106
|
+
obj->failed = 0;
|
|
107
|
+
obj->ctrl_bound = 0;
|
|
108
|
+
obj->qpack_bound = 0;
|
|
109
|
+
obj->goaway = 0;
|
|
110
|
+
obj->max_client_streams = 0;
|
|
105
111
|
obj->pending = st_init_numtable();
|
|
106
112
|
obj->stream_data_readers = rb_hash_new();
|
|
107
113
|
obj->stream_user_data = rb_hash_new();
|
|
@@ -134,6 +140,92 @@ static void connection_raise_pending(ConnectionObj *obj) {
|
|
|
134
140
|
rb_exc_raise(exc);
|
|
135
141
|
}
|
|
136
142
|
|
|
143
|
+
/* The connection of self, for a method about to call into nghttp3. Raises
|
|
144
|
+
* InvalidStateError if the connection is closed or has failed, or if this
|
|
145
|
+
* is a callback of a call into nghttp3 that does not allow the method:
|
|
146
|
+
* inside read_stream only the methods allowed_in_read, and inside any other
|
|
147
|
+
* call none. Called once the arguments are converted, since to_int and
|
|
148
|
+
* to_str may run Ruby code that closes the connection.
|
|
149
|
+
*
|
|
150
|
+
* Around the call into nghttp3, the method sets obj->entered to the kind of
|
|
151
|
+
* call (CONN_IN_READ for read_stream, CONN_IN_OTHER otherwise) and puts the
|
|
152
|
+
* value before back as soon as nghttp3 returns. */
|
|
153
|
+
/* Note that the connection has failed if rv, which a call into nghttp3
|
|
154
|
+
* other than read_stream or writev_stream returned, is a fatal error. */
|
|
155
|
+
static void connection_check_fatal(ConnectionObj *obj, int rv) {
|
|
156
|
+
if (nghttp3_err_is_fatal(rv)) {
|
|
157
|
+
obj->failed = 1;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/* The name of the method being run, for messages. */
|
|
162
|
+
static VALUE this_method(void) { return rb_id2str(rb_frame_this_func()); }
|
|
163
|
+
|
|
164
|
+
static ConnectionObj *connection_enter(VALUE self, int allowed_in_read) {
|
|
165
|
+
ConnectionObj *obj;
|
|
166
|
+
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
167
|
+
if (obj->conn == NULL || obj->is_closed) {
|
|
168
|
+
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
169
|
+
}
|
|
170
|
+
if (obj->failed) {
|
|
171
|
+
rb_raise(rb_eNghttp3InvalidStateError,
|
|
172
|
+
"the connection has failed; only #close is allowed");
|
|
173
|
+
}
|
|
174
|
+
if (obj->entered == CONN_IN_OTHER ||
|
|
175
|
+
(obj->entered == CONN_IN_READ && !allowed_in_read)) {
|
|
176
|
+
rb_raise(rb_eNghttp3InvalidStateError,
|
|
177
|
+
"#%" PRIsVALUE
|
|
178
|
+
" cannot be called from inside a callback of this connection",
|
|
179
|
+
this_method());
|
|
180
|
+
}
|
|
181
|
+
return obj;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/* What nghttp3 asserts of its callers, which would abort the process,
|
|
185
|
+
* checked here first: the kind of a stream id (its range is checked by
|
|
186
|
+
* nghttp3_rb_stream_id), the role of the connection and the calls that must
|
|
187
|
+
* or must not have come before. Each raises for the method being run. */
|
|
188
|
+
|
|
189
|
+
NORETURN(static void raise_stream_kind(VALUE rb_id, const char *kind));
|
|
190
|
+
static void raise_stream_kind(VALUE rb_id, const char *kind) {
|
|
191
|
+
rb_raise(rb_eArgError, "stream_id %" PRIsVALUE " is not a %s stream", rb_id,
|
|
192
|
+
kind);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/* A unidirectional stream opened by this end, for the bind_* methods. */
|
|
196
|
+
static void check_own_uni_stream(ConnectionObj *obj, VALUE rb_id, int64_t id) {
|
|
197
|
+
if (obj->is_server && (id & 3) != 3) {
|
|
198
|
+
raise_stream_kind(rb_id, "server-initiated unidirectional");
|
|
199
|
+
}
|
|
200
|
+
if (!obj->is_server && (id & 3) != 2) {
|
|
201
|
+
raise_stream_kind(rb_id, "client-initiated unidirectional");
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
static void check_server(ConnectionObj *obj) {
|
|
206
|
+
if (!obj->is_server) {
|
|
207
|
+
rb_raise(rb_eNghttp3InvalidStateError,
|
|
208
|
+
"#%" PRIsVALUE " is for a server connection", this_method());
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
static void check_done(int done, const char *first) {
|
|
213
|
+
if (!done) {
|
|
214
|
+
rb_raise(rb_eNghttp3InvalidStateError, "#%" PRIsVALUE " needs #%s first",
|
|
215
|
+
this_method(), first);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* nghttp3 asserts that the id of each GOAWAY is no larger than the one
|
|
220
|
+
* before. A server's shutdown sends one past the largest stream it has
|
|
221
|
+
* seen, which may have grown since, and a shutdown notice sends the largest
|
|
222
|
+
* id there is, so neither may follow a shutdown. */
|
|
223
|
+
static void check_no_shutdown(ConnectionObj *obj) {
|
|
224
|
+
if (obj->goaway == 2) {
|
|
225
|
+
rb_raise(rb_eNghttp3InvalidStateError, "#shutdown has been called already");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
137
229
|
static PendingStream *pending_lookup(ConnectionObj *obj, int64_t stream_id) {
|
|
138
230
|
st_data_t value;
|
|
139
231
|
if (!st_lookup(obj->pending, (st_data_t)stream_id, &value)) {
|
|
@@ -294,21 +386,23 @@ static VALUE rb_nghttp3_connection_bind_control_stream(VALUE self,
|
|
|
294
386
|
VALUE rb_stream_id) {
|
|
295
387
|
ConnectionObj *obj;
|
|
296
388
|
int64_t stream_id;
|
|
297
|
-
int rv;
|
|
298
|
-
|
|
299
|
-
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
389
|
+
int rv, entered;
|
|
300
390
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
391
|
+
stream_id = nghttp3_rb_stream_id(rb_stream_id);
|
|
392
|
+
obj = connection_enter(self, 0);
|
|
393
|
+
check_own_uni_stream(obj, rb_stream_id, stream_id);
|
|
304
394
|
|
|
305
|
-
|
|
395
|
+
entered = obj->entered;
|
|
396
|
+
obj->entered = CONN_IN_OTHER;
|
|
306
397
|
rv = nghttp3_conn_bind_control_stream(obj->conn, stream_id);
|
|
398
|
+
obj->entered = entered;
|
|
399
|
+
connection_check_fatal(obj, rv);
|
|
307
400
|
|
|
308
401
|
if (rv != 0) {
|
|
309
402
|
nghttp3_rb_raise(rv, "Failed to bind control stream");
|
|
310
403
|
}
|
|
311
404
|
|
|
405
|
+
obj->ctrl_bound = 1;
|
|
312
406
|
return self;
|
|
313
407
|
}
|
|
314
408
|
|
|
@@ -324,23 +418,25 @@ static VALUE rb_nghttp3_connection_bind_qpack_streams(VALUE self,
|
|
|
324
418
|
VALUE rb_dec_stream_id) {
|
|
325
419
|
ConnectionObj *obj;
|
|
326
420
|
int64_t enc_stream_id, dec_stream_id;
|
|
327
|
-
int rv;
|
|
421
|
+
int rv, entered;
|
|
328
422
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
enc_stream_id = NUM2LL(rb_enc_stream_id);
|
|
336
|
-
dec_stream_id = NUM2LL(rb_dec_stream_id);
|
|
423
|
+
enc_stream_id = nghttp3_rb_stream_id(rb_enc_stream_id);
|
|
424
|
+
dec_stream_id = nghttp3_rb_stream_id(rb_dec_stream_id);
|
|
425
|
+
obj = connection_enter(self, 0);
|
|
426
|
+
check_own_uni_stream(obj, rb_enc_stream_id, enc_stream_id);
|
|
427
|
+
check_own_uni_stream(obj, rb_dec_stream_id, dec_stream_id);
|
|
337
428
|
|
|
429
|
+
entered = obj->entered;
|
|
430
|
+
obj->entered = CONN_IN_OTHER;
|
|
338
431
|
rv = nghttp3_conn_bind_qpack_streams(obj->conn, enc_stream_id, dec_stream_id);
|
|
432
|
+
obj->entered = entered;
|
|
433
|
+
connection_check_fatal(obj, rv);
|
|
339
434
|
|
|
340
435
|
if (rv != 0) {
|
|
341
436
|
nghttp3_rb_raise(rv, "Failed to bind QPACK streams");
|
|
342
437
|
}
|
|
343
438
|
|
|
439
|
+
obj->qpack_bound = 1;
|
|
344
440
|
return self;
|
|
345
441
|
}
|
|
346
442
|
|
|
@@ -349,13 +445,20 @@ static VALUE rb_nghttp3_connection_bind_qpack_streams(VALUE self,
|
|
|
349
445
|
* connection.close -> nil
|
|
350
446
|
*
|
|
351
447
|
* Explicitly closes the connection and frees resources.
|
|
352
|
-
* After calling this, the connection object cannot be used.
|
|
448
|
+
* After calling this, the connection object cannot be used. Closing a
|
|
449
|
+
* closed connection does nothing; closing it from inside one of its
|
|
450
|
+
* callbacks, while nghttp3 still uses it, raises InvalidStateError.
|
|
353
451
|
*/
|
|
354
452
|
static VALUE rb_nghttp3_connection_close(VALUE self) {
|
|
355
453
|
ConnectionObj *obj;
|
|
356
454
|
|
|
357
455
|
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
358
456
|
|
|
457
|
+
if (obj->entered != CONN_IDLE) {
|
|
458
|
+
rb_raise(rb_eNghttp3InvalidStateError,
|
|
459
|
+
"#close cannot be called from inside a callback of this "
|
|
460
|
+
"connection");
|
|
461
|
+
}
|
|
359
462
|
if (obj->conn != NULL && !obj->is_closed) {
|
|
360
463
|
nghttp3_conn_del(obj->conn);
|
|
361
464
|
obj->conn = NULL;
|
|
@@ -413,15 +516,22 @@ struct read_stream_args {
|
|
|
413
516
|
ConnectionObj *obj;
|
|
414
517
|
int64_t stream_id;
|
|
415
518
|
VALUE data;
|
|
519
|
+
int locked; /* read_stream locked data, and read_stream_unlock unlocks it */
|
|
416
520
|
int fin;
|
|
417
521
|
nghttp3_tstamp ts;
|
|
418
522
|
};
|
|
419
523
|
|
|
420
524
|
static VALUE read_stream_body(VALUE arg) {
|
|
421
525
|
struct read_stream_args *a = (struct read_stream_args *)arg;
|
|
526
|
+
int entered = a->obj->entered;
|
|
527
|
+
a->obj->entered = CONN_IN_READ;
|
|
422
528
|
nghttp3_ssize rv = nghttp3_conn_read_stream2(
|
|
423
529
|
a->obj->conn, a->stream_id, (const uint8_t *)RSTRING_PTR(a->data),
|
|
424
530
|
(size_t)RSTRING_LEN(a->data), a->fin, a->ts);
|
|
531
|
+
a->obj->entered = entered;
|
|
532
|
+
if (rv < 0) {
|
|
533
|
+
a->obj->failed = 1;
|
|
534
|
+
}
|
|
425
535
|
connection_raise_pending(a->obj);
|
|
426
536
|
if (rv < 0) {
|
|
427
537
|
nghttp3_rb_raise((int)rv, "Failed to read stream");
|
|
@@ -430,7 +540,10 @@ static VALUE read_stream_body(VALUE arg) {
|
|
|
430
540
|
}
|
|
431
541
|
|
|
432
542
|
static VALUE read_stream_unlock(VALUE arg) {
|
|
433
|
-
|
|
543
|
+
struct read_stream_args *a = (struct read_stream_args *)arg;
|
|
544
|
+
if (a->locked) {
|
|
545
|
+
rb_str_unlocktmp(a->data);
|
|
546
|
+
}
|
|
434
547
|
return Qnil;
|
|
435
548
|
}
|
|
436
549
|
|
|
@@ -449,7 +562,6 @@ static VALUE rb_nghttp3_connection_read_stream(int argc, VALUE *argv,
|
|
|
449
562
|
VALUE rb_stream_id, rb_data, rb_opts;
|
|
450
563
|
VALUE rb_fin = Qfalse;
|
|
451
564
|
VALUE rb_ts = Qnil;
|
|
452
|
-
ConnectionObj *obj;
|
|
453
565
|
|
|
454
566
|
rb_scan_args(argc, argv, "2:", &rb_stream_id, &rb_data, &rb_opts);
|
|
455
567
|
|
|
@@ -461,23 +573,32 @@ static VALUE rb_nghttp3_connection_read_stream(int argc, VALUE *argv,
|
|
|
461
573
|
rb_ts = rb_hash_aref(rb_opts, ID2SYM(rb_intern("ts")));
|
|
462
574
|
}
|
|
463
575
|
|
|
464
|
-
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
465
|
-
|
|
466
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
467
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
468
|
-
}
|
|
469
|
-
|
|
470
576
|
Check_Type(rb_data, T_STRING);
|
|
471
577
|
|
|
472
578
|
struct read_stream_args args;
|
|
473
|
-
args.
|
|
474
|
-
args.stream_id = NUM2LL(rb_stream_id);
|
|
579
|
+
args.stream_id = nghttp3_rb_stream_id(rb_stream_id);
|
|
475
580
|
args.data = rb_data;
|
|
476
581
|
args.fin = RTEST(rb_fin) ? 1 : 0;
|
|
477
582
|
args.ts = NIL_P(rb_ts) ? monotonic_now() : (nghttp3_tstamp)NUM2ULL(rb_ts);
|
|
583
|
+
args.obj = connection_enter(self, 0);
|
|
584
|
+
/* Data comes in on the streams of the other end and the request streams;
|
|
585
|
+
* nghttp3 asserts that a stream it knows is one of those. */
|
|
586
|
+
if (args.obj->is_server && (args.stream_id & 1) != 0) {
|
|
587
|
+
raise_stream_kind(rb_stream_id, "client-initiated");
|
|
588
|
+
}
|
|
589
|
+
if (!args.obj->is_server && (args.stream_id & 3) != 0 &&
|
|
590
|
+
(args.stream_id & 3) != 3) {
|
|
591
|
+
raise_stream_kind(
|
|
592
|
+
rb_stream_id,
|
|
593
|
+
"client-initiated bidirectional or server-initiated unidirectional");
|
|
594
|
+
}
|
|
478
595
|
|
|
479
|
-
/* Callbacks run Ruby code, which must not change data under nghttp3.
|
|
480
|
-
|
|
596
|
+
/* Callbacks run Ruby code, which must not change data under nghttp3. A
|
|
597
|
+
* frozen String cannot be changed, and rb_str_locktmp refuses one. */
|
|
598
|
+
args.locked = !OBJ_FROZEN(rb_data);
|
|
599
|
+
if (args.locked) {
|
|
600
|
+
rb_str_locktmp(rb_data);
|
|
601
|
+
}
|
|
481
602
|
return rb_ensure(read_stream_body, (VALUE)&args, read_stream_unlock,
|
|
482
603
|
(VALUE)&args);
|
|
483
604
|
}
|
|
@@ -494,17 +615,19 @@ static VALUE rb_nghttp3_connection_writev_stream(VALUE self) {
|
|
|
494
615
|
nghttp3_vec vec[16];
|
|
495
616
|
nghttp3_ssize rv;
|
|
496
617
|
int64_t stream_id;
|
|
497
|
-
int fin;
|
|
618
|
+
int fin, entered;
|
|
498
619
|
VALUE rb_result, rb_data;
|
|
499
620
|
size_t i, total_len;
|
|
500
621
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
504
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
505
|
-
}
|
|
622
|
+
obj = connection_enter(self, 0);
|
|
506
623
|
|
|
624
|
+
entered = obj->entered;
|
|
625
|
+
obj->entered = CONN_IN_OTHER;
|
|
507
626
|
rv = nghttp3_conn_writev_stream(obj->conn, &stream_id, &fin, vec, 16);
|
|
627
|
+
obj->entered = entered;
|
|
628
|
+
if (rv < 0) {
|
|
629
|
+
obj->failed = 1;
|
|
630
|
+
}
|
|
508
631
|
connection_raise_pending(obj);
|
|
509
632
|
|
|
510
633
|
if (rv < 0) {
|
|
@@ -544,20 +667,19 @@ static VALUE rb_nghttp3_connection_add_write_offset(VALUE self,
|
|
|
544
667
|
VALUE rb_stream_id,
|
|
545
668
|
VALUE rb_n) {
|
|
546
669
|
ConnectionObj *obj;
|
|
547
|
-
int rv;
|
|
670
|
+
int rv, entered;
|
|
548
671
|
int64_t stream_id;
|
|
549
672
|
size_t n;
|
|
550
673
|
|
|
551
|
-
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
552
|
-
|
|
553
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
554
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
555
|
-
}
|
|
556
|
-
|
|
557
674
|
stream_id = NUM2LL(rb_stream_id);
|
|
558
675
|
n = NUM2SIZET(rb_n);
|
|
676
|
+
obj = connection_enter(self, 0);
|
|
559
677
|
|
|
678
|
+
entered = obj->entered;
|
|
679
|
+
obj->entered = CONN_IN_OTHER;
|
|
560
680
|
rv = nghttp3_conn_add_write_offset(obj->conn, stream_id, n);
|
|
681
|
+
obj->entered = entered;
|
|
682
|
+
connection_check_fatal(obj, rv);
|
|
561
683
|
connection_raise_pending(obj);
|
|
562
684
|
|
|
563
685
|
if (rv != 0) {
|
|
@@ -577,20 +699,19 @@ static VALUE rb_nghttp3_connection_add_ack_offset(VALUE self,
|
|
|
577
699
|
VALUE rb_stream_id,
|
|
578
700
|
VALUE rb_n) {
|
|
579
701
|
ConnectionObj *obj;
|
|
580
|
-
int rv;
|
|
702
|
+
int rv, entered;
|
|
581
703
|
int64_t stream_id;
|
|
582
704
|
uint64_t n;
|
|
583
705
|
|
|
584
|
-
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
585
|
-
|
|
586
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
587
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
588
|
-
}
|
|
589
|
-
|
|
590
706
|
stream_id = NUM2LL(rb_stream_id);
|
|
591
707
|
n = NUM2ULL(rb_n);
|
|
708
|
+
obj = connection_enter(self, 0);
|
|
592
709
|
|
|
710
|
+
entered = obj->entered;
|
|
711
|
+
obj->entered = CONN_IN_OTHER;
|
|
593
712
|
rv = nghttp3_conn_add_ack_offset(obj->conn, stream_id, n);
|
|
713
|
+
obj->entered = entered;
|
|
714
|
+
connection_check_fatal(obj, rv);
|
|
594
715
|
connection_raise_pending(obj);
|
|
595
716
|
|
|
596
717
|
if (rv != 0) {
|
|
@@ -610,15 +731,15 @@ static VALUE rb_nghttp3_connection_block_stream(VALUE self,
|
|
|
610
731
|
VALUE rb_stream_id) {
|
|
611
732
|
ConnectionObj *obj;
|
|
612
733
|
int64_t stream_id;
|
|
613
|
-
|
|
614
|
-
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
615
|
-
|
|
616
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
617
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
618
|
-
}
|
|
734
|
+
int entered;
|
|
619
735
|
|
|
620
736
|
stream_id = NUM2LL(rb_stream_id);
|
|
737
|
+
obj = connection_enter(self, 1);
|
|
738
|
+
|
|
739
|
+
entered = obj->entered;
|
|
740
|
+
obj->entered = CONN_IN_OTHER;
|
|
621
741
|
nghttp3_conn_block_stream(obj->conn, stream_id);
|
|
742
|
+
obj->entered = entered;
|
|
622
743
|
|
|
623
744
|
return self;
|
|
624
745
|
}
|
|
@@ -632,17 +753,17 @@ static VALUE rb_nghttp3_connection_block_stream(VALUE self,
|
|
|
632
753
|
static VALUE rb_nghttp3_connection_unblock_stream(VALUE self,
|
|
633
754
|
VALUE rb_stream_id) {
|
|
634
755
|
ConnectionObj *obj;
|
|
635
|
-
int rv;
|
|
756
|
+
int rv, entered;
|
|
636
757
|
int64_t stream_id;
|
|
637
758
|
|
|
638
|
-
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
639
|
-
|
|
640
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
641
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
642
|
-
}
|
|
643
|
-
|
|
644
759
|
stream_id = NUM2LL(rb_stream_id);
|
|
760
|
+
obj = connection_enter(self, 1);
|
|
761
|
+
|
|
762
|
+
entered = obj->entered;
|
|
763
|
+
obj->entered = CONN_IN_OTHER;
|
|
645
764
|
rv = nghttp3_conn_unblock_stream(obj->conn, stream_id);
|
|
765
|
+
obj->entered = entered;
|
|
766
|
+
connection_check_fatal(obj, rv);
|
|
646
767
|
connection_raise_pending(obj);
|
|
647
768
|
|
|
648
769
|
if (rv != 0) {
|
|
@@ -662,16 +783,15 @@ static VALUE rb_nghttp3_connection_stream_writable_p(VALUE self,
|
|
|
662
783
|
VALUE rb_stream_id) {
|
|
663
784
|
ConnectionObj *obj;
|
|
664
785
|
int64_t stream_id;
|
|
665
|
-
int rv;
|
|
666
|
-
|
|
667
|
-
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
668
|
-
|
|
669
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
670
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
671
|
-
}
|
|
786
|
+
int rv, entered;
|
|
672
787
|
|
|
673
788
|
stream_id = NUM2LL(rb_stream_id);
|
|
789
|
+
obj = connection_enter(self, 1);
|
|
790
|
+
|
|
791
|
+
entered = obj->entered;
|
|
792
|
+
obj->entered = CONN_IN_OTHER;
|
|
674
793
|
rv = nghttp3_conn_is_stream_writable(obj->conn, stream_id);
|
|
794
|
+
obj->entered = entered;
|
|
675
795
|
|
|
676
796
|
return rv ? Qtrue : Qfalse;
|
|
677
797
|
}
|
|
@@ -685,20 +805,19 @@ static VALUE rb_nghttp3_connection_stream_writable_p(VALUE self,
|
|
|
685
805
|
static VALUE rb_nghttp3_connection_close_stream(VALUE self, VALUE rb_stream_id,
|
|
686
806
|
VALUE rb_error_code) {
|
|
687
807
|
ConnectionObj *obj;
|
|
688
|
-
int rv;
|
|
808
|
+
int rv, entered;
|
|
689
809
|
int64_t stream_id;
|
|
690
810
|
uint64_t app_error_code;
|
|
691
811
|
|
|
692
|
-
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
693
|
-
|
|
694
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
695
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
696
|
-
}
|
|
697
|
-
|
|
698
812
|
stream_id = NUM2LL(rb_stream_id);
|
|
699
813
|
app_error_code = NUM2ULL(rb_error_code);
|
|
814
|
+
obj = connection_enter(self, 0);
|
|
700
815
|
|
|
816
|
+
entered = obj->entered;
|
|
817
|
+
obj->entered = CONN_IN_OTHER;
|
|
701
818
|
rv = nghttp3_conn_close_stream(obj->conn, stream_id, app_error_code);
|
|
819
|
+
obj->entered = entered;
|
|
820
|
+
connection_check_fatal(obj, rv);
|
|
702
821
|
connection_raise_pending(obj);
|
|
703
822
|
|
|
704
823
|
if (rv != 0) {
|
|
@@ -718,15 +837,15 @@ static VALUE rb_nghttp3_connection_shutdown_stream_write(VALUE self,
|
|
|
718
837
|
VALUE rb_stream_id) {
|
|
719
838
|
ConnectionObj *obj;
|
|
720
839
|
int64_t stream_id;
|
|
721
|
-
|
|
722
|
-
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
723
|
-
|
|
724
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
725
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
726
|
-
}
|
|
840
|
+
int entered;
|
|
727
841
|
|
|
728
842
|
stream_id = NUM2LL(rb_stream_id);
|
|
843
|
+
obj = connection_enter(self, 1);
|
|
844
|
+
|
|
845
|
+
entered = obj->entered;
|
|
846
|
+
obj->entered = CONN_IN_OTHER;
|
|
729
847
|
nghttp3_conn_shutdown_stream_write(obj->conn, stream_id);
|
|
848
|
+
obj->entered = entered;
|
|
730
849
|
connection_raise_pending(obj);
|
|
731
850
|
|
|
732
851
|
return self;
|
|
@@ -741,17 +860,17 @@ static VALUE rb_nghttp3_connection_shutdown_stream_write(VALUE self,
|
|
|
741
860
|
static VALUE rb_nghttp3_connection_resume_stream(VALUE self,
|
|
742
861
|
VALUE rb_stream_id) {
|
|
743
862
|
ConnectionObj *obj;
|
|
744
|
-
int rv;
|
|
863
|
+
int rv, entered;
|
|
745
864
|
int64_t stream_id;
|
|
746
865
|
|
|
747
|
-
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
748
|
-
|
|
749
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
750
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
751
|
-
}
|
|
752
|
-
|
|
753
866
|
stream_id = NUM2LL(rb_stream_id);
|
|
867
|
+
obj = connection_enter(self, 1);
|
|
868
|
+
|
|
869
|
+
entered = obj->entered;
|
|
870
|
+
obj->entered = CONN_IN_OTHER;
|
|
754
871
|
rv = nghttp3_conn_resume_stream(obj->conn, stream_id);
|
|
872
|
+
obj->entered = entered;
|
|
873
|
+
connection_check_fatal(obj, rv);
|
|
755
874
|
connection_raise_pending(obj);
|
|
756
875
|
|
|
757
876
|
if (rv != 0) {
|
|
@@ -835,6 +954,31 @@ static nghttp3_ssize read_data_callback(nghttp3_conn *conn, int64_t stream_id,
|
|
|
835
954
|
static const nghttp3_data_reader data_reader = {.read_data =
|
|
836
955
|
read_data_callback};
|
|
837
956
|
|
|
957
|
+
/* The body of a submit_request or submit_response: a frozen copy of body:,
|
|
958
|
+
* so that the application cannot change the bytes nghttp3 will read, or the
|
|
959
|
+
* block, or Qnil for none. StringValue may run Ruby code (to_str). */
|
|
960
|
+
static VALUE submit_body_reader(VALUE rb_opts) {
|
|
961
|
+
VALUE rb_body = Qnil;
|
|
962
|
+
if (!NIL_P(rb_opts)) {
|
|
963
|
+
rb_body = rb_hash_aref(rb_opts, ID2SYM(rb_intern("body")));
|
|
964
|
+
}
|
|
965
|
+
if (!NIL_P(rb_body)) {
|
|
966
|
+
StringValue(rb_body);
|
|
967
|
+
return rb_str_new_frozen(rb_body);
|
|
968
|
+
}
|
|
969
|
+
return rb_block_given_p() ? rb_block_proc() : Qnil;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
/*
|
|
973
|
+
* The submit_* methods take the pointers into the header Strings only once
|
|
974
|
+
* nothing more can run Ruby code or allocate before nghttp3 copies them: Ruby
|
|
975
|
+
* code could change or drop the Strings, and an allocation could start a GC
|
|
976
|
+
* that moves them. So they first convert their arguments, which may call
|
|
977
|
+
* to_int and to_str, then check the connection, which that Ruby code may
|
|
978
|
+
* have closed, then allocate (the header array, and the reader entry), and
|
|
979
|
+
* only then fill the array and call nghttp3.
|
|
980
|
+
*/
|
|
981
|
+
|
|
838
982
|
/*
|
|
839
983
|
* call-seq:
|
|
840
984
|
* connection.submit_request(stream_id, headers, body: nil) -> self
|
|
@@ -845,59 +989,57 @@ static const nghttp3_data_reader data_reader = {.read_data =
|
|
|
845
989
|
*/
|
|
846
990
|
static VALUE rb_nghttp3_connection_submit_request(int argc, VALUE *argv,
|
|
847
991
|
VALUE self) {
|
|
848
|
-
VALUE rb_stream_id, rb_headers, rb_opts,
|
|
992
|
+
VALUE rb_stream_id, rb_headers, rb_opts, reader;
|
|
849
993
|
ConnectionObj *obj;
|
|
850
994
|
int64_t stream_id;
|
|
851
995
|
nghttp3_nv *nva;
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
int
|
|
996
|
+
VALUE nva_buf;
|
|
997
|
+
long nvlen, bad;
|
|
998
|
+
int rv, entered;
|
|
855
999
|
|
|
856
1000
|
rb_scan_args(argc, argv, "2:", &rb_stream_id, &rb_headers, &rb_opts);
|
|
857
1001
|
|
|
858
1002
|
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
859
1003
|
|
|
860
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
861
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
862
|
-
}
|
|
863
|
-
|
|
864
1004
|
if (obj->is_server) {
|
|
865
1005
|
rb_raise(rb_eNghttp3InvalidStateError,
|
|
866
1006
|
"submit_request can only be called on client connections");
|
|
867
1007
|
}
|
|
868
1008
|
|
|
869
|
-
stream_id =
|
|
1009
|
+
stream_id = nghttp3_rb_stream_id(rb_stream_id);
|
|
870
1010
|
Check_Type(rb_headers, T_ARRAY);
|
|
871
|
-
|
|
1011
|
+
reader = submit_body_reader(rb_opts);
|
|
872
1012
|
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
VALUE rb_nv = rb_ary_entry(rb_headers, i);
|
|
877
|
-
nva[i] = nghttp3_rb_nv_to_c(rb_nv);
|
|
1013
|
+
connection_enter(self, 1);
|
|
1014
|
+
if ((stream_id & 3) != 0) {
|
|
1015
|
+
raise_stream_kind(rb_stream_id, "client-initiated bidirectional");
|
|
878
1016
|
}
|
|
1017
|
+
check_done(obj->qpack_bound, "bind_qpack_streams");
|
|
879
1018
|
|
|
880
|
-
/*
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
1019
|
+
/* On the heap: a Ruby thread's machine stack is too small for a long
|
|
1020
|
+
* list. */
|
|
1021
|
+
nvlen = RARRAY_LEN(rb_headers);
|
|
1022
|
+
nva = ALLOCV_N(nghttp3_nv, nva_buf, nvlen);
|
|
1023
|
+
if (!NIL_P(reader)) {
|
|
1024
|
+
rb_hash_aset(obj->stream_data_readers, LL2NUM(stream_id), reader);
|
|
884
1025
|
}
|
|
885
1026
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
1027
|
+
bad = nghttp3_rb_nva_fill(rb_headers, nva, nvlen);
|
|
1028
|
+
if (bad >= 0) {
|
|
1029
|
+
ALLOCV_END(nva_buf);
|
|
1030
|
+
if (!NIL_P(reader)) {
|
|
1031
|
+
rb_hash_delete(obj->stream_data_readers, LL2NUM(stream_id));
|
|
1032
|
+
}
|
|
1033
|
+
nghttp3_rb_raise_bad_nv(bad);
|
|
1034
|
+
}
|
|
1035
|
+
entered = obj->entered;
|
|
1036
|
+
obj->entered = CONN_IN_OTHER;
|
|
1037
|
+
rv = nghttp3_conn_submit_request(obj->conn, stream_id, nva, (size_t)nvlen,
|
|
1038
|
+
NIL_P(reader) ? NULL : &data_reader, NULL);
|
|
1039
|
+
obj->entered = entered;
|
|
1040
|
+
connection_check_fatal(obj, rv);
|
|
1041
|
+
ALLOCV_END(nva_buf);
|
|
1042
|
+
RB_GC_GUARD(rb_headers);
|
|
901
1043
|
connection_raise_pending(obj);
|
|
902
1044
|
|
|
903
1045
|
if (rv != 0) {
|
|
@@ -918,22 +1060,18 @@ static VALUE rb_nghttp3_connection_submit_request(int argc, VALUE *argv,
|
|
|
918
1060
|
*/
|
|
919
1061
|
static VALUE rb_nghttp3_connection_submit_response(int argc, VALUE *argv,
|
|
920
1062
|
VALUE self) {
|
|
921
|
-
VALUE rb_stream_id, rb_headers, rb_opts,
|
|
1063
|
+
VALUE rb_stream_id, rb_headers, rb_opts, reader;
|
|
922
1064
|
ConnectionObj *obj;
|
|
923
1065
|
int64_t stream_id;
|
|
924
1066
|
nghttp3_nv *nva;
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
int
|
|
1067
|
+
VALUE nva_buf;
|
|
1068
|
+
long nvlen, bad;
|
|
1069
|
+
int rv, entered;
|
|
928
1070
|
|
|
929
1071
|
rb_scan_args(argc, argv, "2:", &rb_stream_id, &rb_headers, &rb_opts);
|
|
930
1072
|
|
|
931
1073
|
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
932
1074
|
|
|
933
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
934
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
935
|
-
}
|
|
936
|
-
|
|
937
1075
|
if (!obj->is_server) {
|
|
938
1076
|
rb_raise(rb_eNghttp3InvalidStateError,
|
|
939
1077
|
"submit_response can only be called on server connections");
|
|
@@ -941,36 +1079,33 @@ static VALUE rb_nghttp3_connection_submit_response(int argc, VALUE *argv,
|
|
|
941
1079
|
|
|
942
1080
|
stream_id = NUM2LL(rb_stream_id);
|
|
943
1081
|
Check_Type(rb_headers, T_ARRAY);
|
|
944
|
-
|
|
1082
|
+
reader = submit_body_reader(rb_opts);
|
|
945
1083
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
for (i = 0; i < nvlen; i++) {
|
|
949
|
-
VALUE rb_nv = rb_ary_entry(rb_headers, i);
|
|
950
|
-
nva[i] = nghttp3_rb_nv_to_c(rb_nv);
|
|
951
|
-
}
|
|
1084
|
+
connection_enter(self, 1);
|
|
1085
|
+
check_done(obj->qpack_bound, "bind_qpack_streams");
|
|
952
1086
|
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
if (!NIL_P(
|
|
956
|
-
|
|
1087
|
+
nvlen = RARRAY_LEN(rb_headers);
|
|
1088
|
+
nva = ALLOCV_N(nghttp3_nv, nva_buf, nvlen);
|
|
1089
|
+
if (!NIL_P(reader)) {
|
|
1090
|
+
rb_hash_aset(obj->stream_data_readers, LL2NUM(stream_id), reader);
|
|
957
1091
|
}
|
|
958
1092
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1093
|
+
bad = nghttp3_rb_nva_fill(rb_headers, nva, nvlen);
|
|
1094
|
+
if (bad >= 0) {
|
|
1095
|
+
ALLOCV_END(nva_buf);
|
|
1096
|
+
if (!NIL_P(reader)) {
|
|
1097
|
+
rb_hash_delete(obj->stream_data_readers, LL2NUM(stream_id));
|
|
1098
|
+
}
|
|
1099
|
+
nghttp3_rb_raise_bad_nv(bad);
|
|
1100
|
+
}
|
|
1101
|
+
entered = obj->entered;
|
|
1102
|
+
obj->entered = CONN_IN_OTHER;
|
|
1103
|
+
rv = nghttp3_conn_submit_response(obj->conn, stream_id, nva, (size_t)nvlen,
|
|
1104
|
+
NIL_P(reader) ? NULL : &data_reader);
|
|
1105
|
+
obj->entered = entered;
|
|
1106
|
+
connection_check_fatal(obj, rv);
|
|
1107
|
+
ALLOCV_END(nva_buf);
|
|
1108
|
+
RB_GC_GUARD(rb_headers);
|
|
974
1109
|
connection_raise_pending(obj);
|
|
975
1110
|
|
|
976
1111
|
if (rv != 0) {
|
|
@@ -993,26 +1128,35 @@ static VALUE rb_nghttp3_connection_submit_info(VALUE self, VALUE rb_stream_id,
|
|
|
993
1128
|
ConnectionObj *obj;
|
|
994
1129
|
int64_t stream_id;
|
|
995
1130
|
nghttp3_nv *nva;
|
|
996
|
-
|
|
997
|
-
|
|
1131
|
+
VALUE nva_buf;
|
|
1132
|
+
long nvlen, bad;
|
|
1133
|
+
int rv, entered;
|
|
998
1134
|
|
|
999
1135
|
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
1000
1136
|
|
|
1001
|
-
|
|
1002
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
1003
|
-
}
|
|
1137
|
+
check_server(obj);
|
|
1004
1138
|
|
|
1005
1139
|
stream_id = NUM2LL(rb_stream_id);
|
|
1006
1140
|
Check_Type(rb_headers, T_ARRAY);
|
|
1007
|
-
nvlen = RARRAY_LEN(rb_headers);
|
|
1008
1141
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
VALUE rb_nv = rb_ary_entry(rb_headers, i);
|
|
1012
|
-
nva[i] = nghttp3_rb_nv_to_c(rb_nv);
|
|
1013
|
-
}
|
|
1142
|
+
connection_enter(self, 1);
|
|
1143
|
+
check_done(obj->qpack_bound, "bind_qpack_streams");
|
|
1014
1144
|
|
|
1015
|
-
|
|
1145
|
+
nvlen = RARRAY_LEN(rb_headers);
|
|
1146
|
+
nva = ALLOCV_N(nghttp3_nv, nva_buf, nvlen);
|
|
1147
|
+
|
|
1148
|
+
bad = nghttp3_rb_nva_fill(rb_headers, nva, nvlen);
|
|
1149
|
+
if (bad >= 0) {
|
|
1150
|
+
ALLOCV_END(nva_buf);
|
|
1151
|
+
nghttp3_rb_raise_bad_nv(bad);
|
|
1152
|
+
}
|
|
1153
|
+
entered = obj->entered;
|
|
1154
|
+
obj->entered = CONN_IN_OTHER;
|
|
1155
|
+
rv = nghttp3_conn_submit_info(obj->conn, stream_id, nva, (size_t)nvlen);
|
|
1156
|
+
obj->entered = entered;
|
|
1157
|
+
connection_check_fatal(obj, rv);
|
|
1158
|
+
ALLOCV_END(nva_buf);
|
|
1159
|
+
RB_GC_GUARD(rb_headers);
|
|
1016
1160
|
connection_raise_pending(obj);
|
|
1017
1161
|
|
|
1018
1162
|
if (rv != 0) {
|
|
@@ -1036,26 +1180,33 @@ static VALUE rb_nghttp3_connection_submit_trailers(VALUE self,
|
|
|
1036
1180
|
ConnectionObj *obj;
|
|
1037
1181
|
int64_t stream_id;
|
|
1038
1182
|
nghttp3_nv *nva;
|
|
1039
|
-
|
|
1040
|
-
|
|
1183
|
+
VALUE nva_buf;
|
|
1184
|
+
long nvlen, bad;
|
|
1185
|
+
int rv, entered;
|
|
1041
1186
|
|
|
1042
1187
|
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
1043
1188
|
|
|
1044
|
-
if (obj->conn == NULL || obj->is_closed) {
|
|
1045
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
1189
|
stream_id = NUM2LL(rb_stream_id);
|
|
1049
1190
|
Check_Type(rb_trailers, T_ARRAY);
|
|
1050
|
-
nvlen = RARRAY_LEN(rb_trailers);
|
|
1051
1191
|
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
VALUE rb_nv = rb_ary_entry(rb_trailers, i);
|
|
1055
|
-
nva[i] = nghttp3_rb_nv_to_c(rb_nv);
|
|
1056
|
-
}
|
|
1192
|
+
connection_enter(self, 1);
|
|
1193
|
+
check_done(obj->qpack_bound, "bind_qpack_streams");
|
|
1057
1194
|
|
|
1058
|
-
|
|
1195
|
+
nvlen = RARRAY_LEN(rb_trailers);
|
|
1196
|
+
nva = ALLOCV_N(nghttp3_nv, nva_buf, nvlen);
|
|
1197
|
+
|
|
1198
|
+
bad = nghttp3_rb_nva_fill(rb_trailers, nva, nvlen);
|
|
1199
|
+
if (bad >= 0) {
|
|
1200
|
+
ALLOCV_END(nva_buf);
|
|
1201
|
+
nghttp3_rb_raise_bad_nv(bad);
|
|
1202
|
+
}
|
|
1203
|
+
entered = obj->entered;
|
|
1204
|
+
obj->entered = CONN_IN_OTHER;
|
|
1205
|
+
rv = nghttp3_conn_submit_trailers(obj->conn, stream_id, nva, (size_t)nvlen);
|
|
1206
|
+
obj->entered = entered;
|
|
1207
|
+
connection_check_fatal(obj, rv);
|
|
1208
|
+
ALLOCV_END(nva_buf);
|
|
1209
|
+
RB_GC_GUARD(rb_trailers);
|
|
1059
1210
|
connection_raise_pending(obj);
|
|
1060
1211
|
|
|
1061
1212
|
if (rv != 0) {
|
|
@@ -1074,21 +1225,24 @@ static VALUE rb_nghttp3_connection_submit_trailers(VALUE self,
|
|
|
1074
1225
|
*/
|
|
1075
1226
|
static VALUE rb_nghttp3_connection_submit_shutdown_notice(VALUE self) {
|
|
1076
1227
|
ConnectionObj *obj;
|
|
1077
|
-
int rv;
|
|
1228
|
+
int rv, entered;
|
|
1078
1229
|
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
1083
|
-
}
|
|
1230
|
+
obj = connection_enter(self, 1);
|
|
1231
|
+
check_done(obj->ctrl_bound, "bind_control_stream");
|
|
1232
|
+
check_no_shutdown(obj);
|
|
1084
1233
|
|
|
1234
|
+
entered = obj->entered;
|
|
1235
|
+
obj->entered = CONN_IN_OTHER;
|
|
1085
1236
|
rv = nghttp3_conn_submit_shutdown_notice(obj->conn);
|
|
1237
|
+
obj->entered = entered;
|
|
1238
|
+
connection_check_fatal(obj, rv);
|
|
1086
1239
|
connection_raise_pending(obj);
|
|
1087
1240
|
|
|
1088
1241
|
if (rv != 0) {
|
|
1089
1242
|
nghttp3_rb_raise(rv, "Failed to submit shutdown notice");
|
|
1090
1243
|
}
|
|
1091
1244
|
|
|
1245
|
+
obj->goaway = 1;
|
|
1092
1246
|
return self;
|
|
1093
1247
|
}
|
|
1094
1248
|
|
|
@@ -1100,21 +1254,24 @@ static VALUE rb_nghttp3_connection_submit_shutdown_notice(VALUE self) {
|
|
|
1100
1254
|
*/
|
|
1101
1255
|
static VALUE rb_nghttp3_connection_shutdown(VALUE self) {
|
|
1102
1256
|
ConnectionObj *obj;
|
|
1103
|
-
int rv;
|
|
1257
|
+
int rv, entered;
|
|
1104
1258
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
rb_raise(rb_eNghttp3InvalidStateError, "Connection is closed");
|
|
1109
|
-
}
|
|
1259
|
+
obj = connection_enter(self, 1);
|
|
1260
|
+
check_done(obj->ctrl_bound, "bind_control_stream");
|
|
1261
|
+
check_no_shutdown(obj);
|
|
1110
1262
|
|
|
1263
|
+
entered = obj->entered;
|
|
1264
|
+
obj->entered = CONN_IN_OTHER;
|
|
1111
1265
|
rv = nghttp3_conn_shutdown(obj->conn);
|
|
1266
|
+
obj->entered = entered;
|
|
1267
|
+
connection_check_fatal(obj, rv);
|
|
1112
1268
|
connection_raise_pending(obj);
|
|
1113
1269
|
|
|
1114
1270
|
if (rv != 0) {
|
|
1115
1271
|
nghttp3_rb_raise(rv, "Failed to shutdown connection");
|
|
1116
1272
|
}
|
|
1117
1273
|
|
|
1274
|
+
obj->goaway = 2;
|
|
1118
1275
|
return self;
|
|
1119
1276
|
}
|
|
1120
1277
|
|
|
@@ -1128,15 +1285,17 @@ static VALUE rb_nghttp3_connection_shutdown(VALUE self) {
|
|
|
1128
1285
|
static VALUE rb_nghttp3_connection_shutdown_stream_read(VALUE self,
|
|
1129
1286
|
VALUE rb_stream_id) {
|
|
1130
1287
|
ConnectionObj *obj;
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
1288
|
+
int64_t stream_id;
|
|
1289
|
+
int rv, entered;
|
|
1134
1290
|
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
}
|
|
1291
|
+
stream_id = nghttp3_rb_stream_id(rb_stream_id);
|
|
1292
|
+
obj = connection_enter(self, 1);
|
|
1138
1293
|
|
|
1139
|
-
|
|
1294
|
+
entered = obj->entered;
|
|
1295
|
+
obj->entered = CONN_IN_OTHER;
|
|
1296
|
+
rv = nghttp3_conn_shutdown_stream_read(obj->conn, stream_id);
|
|
1297
|
+
obj->entered = entered;
|
|
1298
|
+
connection_check_fatal(obj, rv);
|
|
1140
1299
|
connection_raise_pending(obj);
|
|
1141
1300
|
|
|
1142
1301
|
if (rv != 0) {
|
|
@@ -1152,21 +1311,34 @@ static VALUE rb_nghttp3_connection_shutdown_stream_read(VALUE self,
|
|
|
1152
1311
|
*
|
|
1153
1312
|
* Tells a server connection the cumulative number of bidirectional streams
|
|
1154
1313
|
* the client may open, as QUIC's MAX_STREAMS allows. nghttp3 uses it for
|
|
1155
|
-
* graceful shutdown.
|
|
1314
|
+
* graceful shutdown. Like MAX_STREAMS, it never goes down.
|
|
1156
1315
|
*/
|
|
1157
1316
|
static VALUE
|
|
1158
1317
|
rb_nghttp3_connection_set_max_client_streams_bidi(VALUE self,
|
|
1159
1318
|
VALUE rb_max_streams) {
|
|
1160
1319
|
ConnectionObj *obj;
|
|
1320
|
+
uint64_t max_streams;
|
|
1321
|
+
int entered;
|
|
1161
1322
|
|
|
1162
1323
|
TypedData_Get_Struct(self, ConnectionObj, &connection_data_type, obj);
|
|
1163
1324
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1325
|
+
check_server(obj);
|
|
1326
|
+
|
|
1327
|
+
max_streams = NUM2ULL(rb_max_streams);
|
|
1328
|
+
connection_enter(self, 1);
|
|
1329
|
+
if (max_streams < obj->max_client_streams) {
|
|
1330
|
+
rb_raise(rb_eArgError,
|
|
1331
|
+
"max_client_streams_bidi cannot go down (from %" PRIsVALUE
|
|
1332
|
+
" to %" PRIsVALUE ")",
|
|
1333
|
+
ULL2NUM(obj->max_client_streams), rb_max_streams);
|
|
1166
1334
|
}
|
|
1167
1335
|
|
|
1168
|
-
|
|
1336
|
+
entered = obj->entered;
|
|
1337
|
+
obj->entered = CONN_IN_OTHER;
|
|
1338
|
+
nghttp3_conn_set_max_client_streams_bidi(obj->conn, max_streams);
|
|
1339
|
+
obj->entered = entered;
|
|
1169
1340
|
|
|
1341
|
+
obj->max_client_streams = max_streams;
|
|
1170
1342
|
return self;
|
|
1171
1343
|
}
|
|
1172
1344
|
|