1 /*
2 * nghttp3
3 *
4 * Copyright (c) 2019 nghttp3 contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include "nghttp3_stream.h"
26
27 #include <string.h>
28 #include <assert.h>
29 #include <stdio.h>
30
31 #include "nghttp3_conv.h"
32 #include "nghttp3_macro.h"
33 #include "nghttp3_frame.h"
34 #include "nghttp3_conn.h"
35 #include "nghttp3_str.h"
36 #include "nghttp3_http.h"
37 #include "nghttp3_vec.h"
38
39 /* NGHTTP3_STREAM_MAX_COPY_THRES is the maximum size of buffer which
40 makes a copy to outq. */
41 #define NGHTTP3_STREAM_MAX_COPY_THRES 128
42
43 /* NGHTTP3_MIN_RBLEN is the minimum length of nghttp3_ringbuf */
44 #define NGHTTP3_MIN_RBLEN 4
45
nghttp3_stream_new(nghttp3_stream ** pstream,int64_t stream_id,uint64_t seq,const nghttp3_stream_callbacks * callbacks,const nghttp3_mem * mem)46 int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id,
47 uint64_t seq, const nghttp3_stream_callbacks *callbacks,
48 const nghttp3_mem *mem) {
49 int rv;
50 nghttp3_stream *stream = nghttp3_mem_calloc(mem, 1, sizeof(nghttp3_stream));
51 nghttp3_node_id nid;
52
53 if (stream == NULL) {
54 return NGHTTP3_ERR_NOMEM;
55 }
56
57 nghttp3_tnode_init(
58 &stream->node,
59 nghttp3_node_id_init(&nid, NGHTTP3_NODE_ID_TYPE_STREAM, stream_id), seq,
60 NGHTTP3_DEFAULT_URGENCY);
61
62 rv = nghttp3_ringbuf_init(&stream->frq, 0, sizeof(nghttp3_frame_entry), mem);
63 if (rv != 0) {
64 goto frq_init_fail;
65 }
66
67 rv = nghttp3_ringbuf_init(&stream->chunks, 0, sizeof(nghttp3_buf), mem);
68 if (rv != 0) {
69 goto chunks_init_fail;
70 }
71
72 rv = nghttp3_ringbuf_init(&stream->outq, 0, sizeof(nghttp3_typed_buf), mem);
73 if (rv != 0) {
74 goto outq_init_fail;
75 }
76
77 rv = nghttp3_ringbuf_init(&stream->inq, 0, sizeof(nghttp3_buf), mem);
78 if (rv != 0) {
79 goto inq_init_fail;
80 }
81
82 nghttp3_qpack_stream_context_init(&stream->qpack_sctx, stream_id, mem);
83
84 stream->qpack_blocked_pe.index = NGHTTP3_PQ_BAD_INDEX;
85 stream->mem = mem;
86 stream->tx.offset = 0;
87 stream->rx.http.status_code = -1;
88 stream->rx.http.content_length = -1;
89 stream->rx.http.pri = NGHTTP3_DEFAULT_URGENCY;
90 stream->error_code = NGHTTP3_H3_NO_ERROR;
91
92 if (callbacks) {
93 stream->callbacks = *callbacks;
94 }
95
96 *pstream = stream;
97
98 return 0;
99
100 inq_init_fail:
101 nghttp3_ringbuf_free(&stream->outq);
102 outq_init_fail:
103 nghttp3_ringbuf_free(&stream->chunks);
104 chunks_init_fail:
105 nghttp3_ringbuf_free(&stream->frq);
106 frq_init_fail:
107 nghttp3_mem_free(mem, stream);
108
109 return rv;
110 }
111
delete_outq(nghttp3_ringbuf * outq,const nghttp3_mem * mem)112 static void delete_outq(nghttp3_ringbuf *outq, const nghttp3_mem *mem) {
113 nghttp3_typed_buf *tbuf;
114 size_t i, len = nghttp3_ringbuf_len(outq);
115
116 for (i = 0; i < len; ++i) {
117 tbuf = nghttp3_ringbuf_get(outq, i);
118 if (tbuf->type == NGHTTP3_BUF_TYPE_PRIVATE) {
119 nghttp3_buf_free(&tbuf->buf, mem);
120 }
121 }
122
123 nghttp3_ringbuf_free(outq);
124 }
125
delete_chunks(nghttp3_ringbuf * chunks,const nghttp3_mem * mem)126 static void delete_chunks(nghttp3_ringbuf *chunks, const nghttp3_mem *mem) {
127 nghttp3_buf *buf;
128 size_t i, len = nghttp3_ringbuf_len(chunks);
129
130 for (i = 0; i < len; ++i) {
131 buf = nghttp3_ringbuf_get(chunks, i);
132 nghttp3_buf_free(buf, mem);
133 }
134
135 nghttp3_ringbuf_free(chunks);
136 }
137
delete_frq(nghttp3_ringbuf * frq,const nghttp3_mem * mem)138 static void delete_frq(nghttp3_ringbuf *frq, const nghttp3_mem *mem) {
139 nghttp3_frame_entry *frent;
140 size_t i, len = nghttp3_ringbuf_len(frq);
141
142 for (i = 0; i < len; ++i) {
143 frent = nghttp3_ringbuf_get(frq, i);
144 switch (frent->fr.hd.type) {
145 case NGHTTP3_FRAME_HEADERS:
146 nghttp3_frame_headers_free(&frent->fr.headers, mem);
147 break;
148 default:
149 break;
150 }
151 }
152
153 nghttp3_ringbuf_free(frq);
154 }
155
nghttp3_stream_del(nghttp3_stream * stream)156 void nghttp3_stream_del(nghttp3_stream *stream) {
157 if (stream == NULL) {
158 return;
159 }
160
161 nghttp3_qpack_stream_context_free(&stream->qpack_sctx);
162 delete_chunks(&stream->inq, stream->mem);
163 delete_outq(&stream->outq, stream->mem);
164 delete_chunks(&stream->chunks, stream->mem);
165 delete_frq(&stream->frq, stream->mem);
166 nghttp3_tnode_free(&stream->node);
167
168 nghttp3_mem_free(stream->mem, stream);
169 }
170
nghttp3_varint_read_state_reset(nghttp3_varint_read_state * rvint)171 void nghttp3_varint_read_state_reset(nghttp3_varint_read_state *rvint) {
172 memset(rvint, 0, sizeof(*rvint));
173 }
174
nghttp3_stream_read_state_reset(nghttp3_stream_read_state * rstate)175 void nghttp3_stream_read_state_reset(nghttp3_stream_read_state *rstate) {
176 memset(rstate, 0, sizeof(*rstate));
177 }
178
nghttp3_read_varint(nghttp3_varint_read_state * rvint,const uint8_t * src,size_t srclen,int fin)179 nghttp3_ssize nghttp3_read_varint(nghttp3_varint_read_state *rvint,
180 const uint8_t *src, size_t srclen, int fin) {
181 size_t nread = 0;
182 size_t n;
183 size_t i;
184
185 assert(srclen > 0);
186
187 if (rvint->left == 0) {
188 assert(rvint->acc == 0);
189
190 rvint->left = nghttp3_get_varint_len(src);
191 if (rvint->left <= srclen) {
192 rvint->acc = nghttp3_get_varint(&nread, src);
193 rvint->left = 0;
194 return (nghttp3_ssize)nread;
195 }
196
197 if (fin) {
198 return NGHTTP3_ERR_INVALID_ARGUMENT;
199 }
200
201 rvint->acc = nghttp3_get_varint_fb(src);
202 nread = 1;
203 ++src;
204 --srclen;
205 --rvint->left;
206 }
207
208 n = nghttp3_min(rvint->left, srclen);
209
210 for (i = 0; i < n; ++i) {
211 rvint->acc = (rvint->acc << 8) + src[i];
212 }
213
214 rvint->left -= n;
215 nread += n;
216
217 if (fin && rvint->left) {
218 return NGHTTP3_ERR_INVALID_ARGUMENT;
219 }
220
221 return (nghttp3_ssize)nread;
222 }
223
nghttp3_stream_frq_add(nghttp3_stream * stream,const nghttp3_frame_entry * frent)224 int nghttp3_stream_frq_add(nghttp3_stream *stream,
225 const nghttp3_frame_entry *frent) {
226 nghttp3_ringbuf *frq = &stream->frq;
227 nghttp3_frame_entry *dest;
228 int rv;
229
230 if (nghttp3_ringbuf_full(frq)) {
231 size_t nlen = nghttp3_max(NGHTTP3_MIN_RBLEN, nghttp3_ringbuf_len(frq) * 2);
232 rv = nghttp3_ringbuf_reserve(frq, nlen);
233 if (rv != 0) {
234 return rv;
235 }
236 }
237
238 dest = nghttp3_ringbuf_push_back(frq);
239 *dest = *frent;
240
241 return 0;
242 }
243
nghttp3_stream_fill_outq(nghttp3_stream * stream)244 int nghttp3_stream_fill_outq(nghttp3_stream *stream) {
245 nghttp3_ringbuf *frq = &stream->frq;
246 nghttp3_frame_entry *frent;
247 int data_eof;
248 int rv;
249
250 for (; nghttp3_ringbuf_len(frq) && !nghttp3_stream_outq_is_full(stream) &&
251 stream->unsent_bytes < NGHTTP3_MIN_UNSENT_BYTES;) {
252 frent = nghttp3_ringbuf_get(frq, 0);
253
254 switch (frent->fr.hd.type) {
255 case NGHTTP3_FRAME_SETTINGS:
256 rv = nghttp3_stream_write_settings(stream, frent);
257 if (rv != 0) {
258 return rv;
259 }
260 break;
261 case NGHTTP3_FRAME_HEADERS:
262 rv = nghttp3_stream_write_headers(stream, frent);
263 if (rv != 0) {
264 return rv;
265 }
266 nghttp3_frame_headers_free(&frent->fr.headers, stream->mem);
267 break;
268 case NGHTTP3_FRAME_DATA:
269 rv = nghttp3_stream_write_data(stream, &data_eof, frent);
270 if (rv != 0) {
271 return rv;
272 }
273 if (stream->flags & NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED) {
274 return 0;
275 }
276 if (!data_eof) {
277 return 0;
278 }
279 break;
280 case NGHTTP3_FRAME_GOAWAY:
281 rv = nghttp3_stream_write_goaway(stream, frent);
282 if (rv != 0) {
283 return rv;
284 }
285 break;
286 case NGHTTP3_FRAME_PRIORITY_UPDATE:
287 rv = nghttp3_stream_write_priority_update(stream, frent);
288 if (rv != 0) {
289 return rv;
290 }
291 break;
292 default:
293 /* TODO Not implemented */
294 break;
295 }
296
297 nghttp3_ringbuf_pop_front(frq);
298 }
299
300 return 0;
301 }
302
typed_buf_shared_init(nghttp3_typed_buf * tbuf,const nghttp3_buf * chunk)303 static void typed_buf_shared_init(nghttp3_typed_buf *tbuf,
304 const nghttp3_buf *chunk) {
305 nghttp3_typed_buf_init(tbuf, chunk, NGHTTP3_BUF_TYPE_SHARED);
306 tbuf->buf.pos = tbuf->buf.last;
307 }
308
nghttp3_stream_write_stream_type(nghttp3_stream * stream)309 int nghttp3_stream_write_stream_type(nghttp3_stream *stream) {
310 size_t len = nghttp3_put_varint_len((int64_t)stream->type);
311 nghttp3_buf *chunk;
312 nghttp3_typed_buf tbuf;
313 int rv;
314
315 rv = nghttp3_stream_ensure_chunk(stream, len);
316 if (rv != 0) {
317 return rv;
318 }
319
320 chunk = nghttp3_stream_get_chunk(stream);
321 typed_buf_shared_init(&tbuf, chunk);
322
323 chunk->last = nghttp3_put_varint(chunk->last, (int64_t)stream->type);
324 tbuf.buf.last = chunk->last;
325
326 return nghttp3_stream_outq_add(stream, &tbuf);
327 }
328
nghttp3_stream_write_settings(nghttp3_stream * stream,nghttp3_frame_entry * frent)329 int nghttp3_stream_write_settings(nghttp3_stream *stream,
330 nghttp3_frame_entry *frent) {
331 size_t len;
332 int rv;
333 nghttp3_buf *chunk;
334 nghttp3_typed_buf tbuf;
335 struct {
336 nghttp3_frame_settings settings;
337 nghttp3_settings_entry iv[15];
338 } fr;
339 nghttp3_settings_entry *iv;
340 nghttp3_settings *local_settings = frent->aux.settings.local_settings;
341
342 fr.settings.hd.type = NGHTTP3_FRAME_SETTINGS;
343 fr.settings.niv = 3;
344 iv = &fr.settings.iv[0];
345
346 iv[0].id = NGHTTP3_SETTINGS_ID_MAX_FIELD_SECTION_SIZE;
347 iv[0].value = local_settings->max_field_section_size;
348 iv[1].id = NGHTTP3_SETTINGS_ID_QPACK_MAX_TABLE_CAPACITY;
349 iv[1].value = local_settings->qpack_max_table_capacity;
350 iv[2].id = NGHTTP3_SETTINGS_ID_QPACK_BLOCKED_STREAMS;
351 iv[2].value = local_settings->qpack_blocked_streams;
352
353 if (local_settings->enable_connect_protocol) {
354 ++fr.settings.niv;
355 iv[3].id = NGHTTP3_SETTINGS_ID_ENABLE_CONNECT_PROTOCOL;
356 iv[3].value = 1;
357 }
358
359 len = nghttp3_frame_write_settings_len(&fr.settings.hd.length, &fr.settings);
360
361 rv = nghttp3_stream_ensure_chunk(stream, len);
362 if (rv != 0) {
363 return rv;
364 }
365
366 chunk = nghttp3_stream_get_chunk(stream);
367 typed_buf_shared_init(&tbuf, chunk);
368
369 chunk->last = nghttp3_frame_write_settings(chunk->last, &fr.settings);
370
371 tbuf.buf.last = chunk->last;
372
373 return nghttp3_stream_outq_add(stream, &tbuf);
374 }
375
nghttp3_stream_write_goaway(nghttp3_stream * stream,nghttp3_frame_entry * frent)376 int nghttp3_stream_write_goaway(nghttp3_stream *stream,
377 nghttp3_frame_entry *frent) {
378 nghttp3_frame_goaway *fr = &frent->fr.goaway;
379 size_t len;
380 int rv;
381 nghttp3_buf *chunk;
382 nghttp3_typed_buf tbuf;
383
384 len = nghttp3_frame_write_goaway_len(&fr->hd.length, fr);
385
386 rv = nghttp3_stream_ensure_chunk(stream, len);
387 if (rv != 0) {
388 return rv;
389 }
390
391 chunk = nghttp3_stream_get_chunk(stream);
392 typed_buf_shared_init(&tbuf, chunk);
393
394 chunk->last = nghttp3_frame_write_goaway(chunk->last, fr);
395
396 tbuf.buf.last = chunk->last;
397
398 return nghttp3_stream_outq_add(stream, &tbuf);
399 }
400
nghttp3_stream_write_priority_update(nghttp3_stream * stream,nghttp3_frame_entry * frent)401 int nghttp3_stream_write_priority_update(nghttp3_stream *stream,
402 nghttp3_frame_entry *frent) {
403 nghttp3_frame_priority_update *fr = &frent->fr.priority_update;
404 size_t len;
405 int rv;
406 nghttp3_buf *chunk;
407 nghttp3_typed_buf tbuf;
408
409 len = nghttp3_frame_write_priority_update_len(&fr->hd.length, fr);
410
411 rv = nghttp3_stream_ensure_chunk(stream, len);
412 if (rv != 0) {
413 return rv;
414 }
415
416 chunk = nghttp3_stream_get_chunk(stream);
417 typed_buf_shared_init(&tbuf, chunk);
418
419 chunk->last = nghttp3_frame_write_priority_update(chunk->last, fr);
420
421 tbuf.buf.last = chunk->last;
422
423 return nghttp3_stream_outq_add(stream, &tbuf);
424 }
425
nghttp3_stream_write_headers(nghttp3_stream * stream,nghttp3_frame_entry * frent)426 int nghttp3_stream_write_headers(nghttp3_stream *stream,
427 nghttp3_frame_entry *frent) {
428 nghttp3_frame_headers *fr = &frent->fr.headers;
429 nghttp3_conn *conn = stream->conn;
430
431 assert(conn);
432
433 return nghttp3_stream_write_header_block(
434 stream, &conn->qenc, conn->tx.qenc, &conn->tx.qpack.rbuf,
435 &conn->tx.qpack.ebuf, NGHTTP3_FRAME_HEADERS, fr->nva, fr->nvlen);
436 }
437
nghttp3_stream_write_header_block(nghttp3_stream * stream,nghttp3_qpack_encoder * qenc,nghttp3_stream * qenc_stream,nghttp3_buf * rbuf,nghttp3_buf * ebuf,int64_t frame_type,const nghttp3_nv * nva,size_t nvlen)438 int nghttp3_stream_write_header_block(nghttp3_stream *stream,
439 nghttp3_qpack_encoder *qenc,
440 nghttp3_stream *qenc_stream,
441 nghttp3_buf *rbuf, nghttp3_buf *ebuf,
442 int64_t frame_type, const nghttp3_nv *nva,
443 size_t nvlen) {
444 nghttp3_buf pbuf;
445 int rv;
446 size_t len;
447 nghttp3_buf *chunk;
448 nghttp3_typed_buf tbuf;
449 nghttp3_frame_hd hd;
450 uint8_t raw_pbuf[16];
451 size_t pbuflen, rbuflen, ebuflen;
452
453 nghttp3_buf_wrap_init(&pbuf, raw_pbuf, sizeof(raw_pbuf));
454
455 rv = nghttp3_qpack_encoder_encode(qenc, &pbuf, rbuf, ebuf,
456 stream->node.nid.id, nva, nvlen);
457 if (rv != 0) {
458 goto fail;
459 }
460
461 pbuflen = nghttp3_buf_len(&pbuf);
462 rbuflen = nghttp3_buf_len(rbuf);
463 ebuflen = nghttp3_buf_len(ebuf);
464
465 hd.type = frame_type;
466 hd.length = (int64_t)(pbuflen + rbuflen);
467
468 len = nghttp3_frame_write_hd_len(&hd) + pbuflen;
469
470 if (rbuflen <= NGHTTP3_STREAM_MAX_COPY_THRES) {
471 len += rbuflen;
472 }
473
474 rv = nghttp3_stream_ensure_chunk(stream, len);
475 if (rv != 0) {
476 goto fail;
477 }
478
479 chunk = nghttp3_stream_get_chunk(stream);
480 typed_buf_shared_init(&tbuf, chunk);
481
482 chunk->last = nghttp3_frame_write_hd(chunk->last, &hd);
483
484 chunk->last = nghttp3_cpymem(chunk->last, pbuf.pos, pbuflen);
485 nghttp3_buf_init(&pbuf);
486
487 if (rbuflen > NGHTTP3_STREAM_MAX_COPY_THRES) {
488 tbuf.buf.last = chunk->last;
489
490 rv = nghttp3_stream_outq_add(stream, &tbuf);
491 if (rv != 0) {
492 goto fail;
493 }
494
495 nghttp3_typed_buf_init(&tbuf, rbuf, NGHTTP3_BUF_TYPE_PRIVATE);
496 rv = nghttp3_stream_outq_add(stream, &tbuf);
497 if (rv != 0) {
498 goto fail;
499 }
500 nghttp3_buf_init(rbuf);
501 } else if (rbuflen) {
502 chunk->last = nghttp3_cpymem(chunk->last, rbuf->pos, rbuflen);
503 tbuf.buf.last = chunk->last;
504
505 rv = nghttp3_stream_outq_add(stream, &tbuf);
506 if (rv != 0) {
507 goto fail;
508 }
509 nghttp3_buf_reset(rbuf);
510 }
511
512 if (ebuflen > NGHTTP3_STREAM_MAX_COPY_THRES) {
513 assert(qenc_stream);
514
515 nghttp3_typed_buf_init(&tbuf, ebuf, NGHTTP3_BUF_TYPE_PRIVATE);
516 rv = nghttp3_stream_outq_add(qenc_stream, &tbuf);
517 if (rv != 0) {
518 return rv;
519 }
520 nghttp3_buf_init(ebuf);
521 } else if (ebuflen) {
522 assert(qenc_stream);
523
524 rv = nghttp3_stream_ensure_chunk(qenc_stream, ebuflen);
525 if (rv != 0) {
526 goto fail;
527 }
528
529 chunk = nghttp3_stream_get_chunk(qenc_stream);
530 typed_buf_shared_init(&tbuf, chunk);
531
532 chunk->last = nghttp3_cpymem(chunk->last, ebuf->pos, ebuflen);
533 tbuf.buf.last = chunk->last;
534
535 rv = nghttp3_stream_outq_add(qenc_stream, &tbuf);
536 if (rv != 0) {
537 goto fail;
538 }
539 nghttp3_buf_reset(ebuf);
540 }
541
542 assert(0 == nghttp3_buf_len(&pbuf));
543 assert(0 == nghttp3_buf_len(rbuf));
544 assert(0 == nghttp3_buf_len(ebuf));
545
546 return 0;
547
548 fail:
549
550 return rv;
551 }
552
nghttp3_stream_write_data(nghttp3_stream * stream,int * peof,nghttp3_frame_entry * frent)553 int nghttp3_stream_write_data(nghttp3_stream *stream, int *peof,
554 nghttp3_frame_entry *frent) {
555 int rv;
556 size_t len;
557 nghttp3_typed_buf tbuf;
558 nghttp3_buf buf;
559 nghttp3_buf *chunk;
560 nghttp3_read_data_callback read_data = frent->aux.data.dr.read_data;
561 nghttp3_conn *conn = stream->conn;
562 int64_t datalen;
563 uint32_t flags = 0;
564 nghttp3_frame_hd hd;
565 nghttp3_vec vec[8];
566 nghttp3_vec *v;
567 nghttp3_ssize sveccnt;
568 size_t i;
569
570 assert(!(stream->flags & NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED));
571 assert(read_data);
572 assert(conn);
573
574 *peof = 0;
575
576 sveccnt = read_data(conn, stream->node.nid.id, vec, nghttp3_arraylen(vec),
577 &flags, conn->user_data, stream->user_data);
578 if (sveccnt < 0) {
579 if (sveccnt == NGHTTP3_ERR_WOULDBLOCK) {
580 stream->flags |= NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED;
581 return 0;
582 }
583 return NGHTTP3_ERR_CALLBACK_FAILURE;
584 }
585
586 datalen = nghttp3_vec_len_varint(vec, (size_t)sveccnt);
587 if (datalen == -1) {
588 return NGHTTP3_ERR_STREAM_DATA_OVERFLOW;
589 }
590
591 assert(datalen || flags & NGHTTP3_DATA_FLAG_EOF);
592
593 if (flags & NGHTTP3_DATA_FLAG_EOF) {
594 *peof = 1;
595 if (!(flags & NGHTTP3_DATA_FLAG_NO_END_STREAM)) {
596 stream->flags |= NGHTTP3_STREAM_FLAG_WRITE_END_STREAM;
597 if (datalen == 0) {
598 if (nghttp3_stream_outq_write_done(stream)) {
599 /* If this is the last data and its is 0 length, we don't
600 need send DATA frame. We rely on the non-emptiness of
601 outq to schedule stream, so add empty tbuf to outq to
602 just send fin. */
603 nghttp3_buf_init(&buf);
604 nghttp3_typed_buf_init(&tbuf, &buf, NGHTTP3_BUF_TYPE_PRIVATE);
605 return nghttp3_stream_outq_add(stream, &tbuf);
606 }
607 return 0;
608 }
609 }
610
611 if (datalen == 0) {
612 /* We are going to send more frames, but no DATA frame this
613 time. */
614 return 0;
615 }
616 }
617
618 hd.type = NGHTTP3_FRAME_DATA;
619 hd.length = datalen;
620
621 len = nghttp3_frame_write_hd_len(&hd);
622
623 rv = nghttp3_stream_ensure_chunk(stream, len);
624 if (rv != 0) {
625 return rv;
626 }
627
628 chunk = nghttp3_stream_get_chunk(stream);
629 typed_buf_shared_init(&tbuf, chunk);
630
631 chunk->last = nghttp3_frame_write_hd(chunk->last, &hd);
632
633 tbuf.buf.last = chunk->last;
634
635 rv = nghttp3_stream_outq_add(stream, &tbuf);
636 if (rv != 0) {
637 return rv;
638 }
639
640 if (datalen) {
641 for (i = 0; i < (size_t)sveccnt; ++i) {
642 v = &vec[i];
643 if (v->len == 0) {
644 continue;
645 }
646 nghttp3_buf_wrap_init(&buf, v->base, v->len);
647 buf.last = buf.end;
648 nghttp3_typed_buf_init(&tbuf, &buf, NGHTTP3_BUF_TYPE_ALIEN);
649 rv = nghttp3_stream_outq_add(stream, &tbuf);
650 if (rv != 0) {
651 return rv;
652 }
653 }
654 }
655
656 return 0;
657 }
658
nghttp3_stream_write_qpack_decoder_stream(nghttp3_stream * stream)659 int nghttp3_stream_write_qpack_decoder_stream(nghttp3_stream *stream) {
660 nghttp3_qpack_decoder *qdec;
661 nghttp3_buf *chunk;
662 int rv;
663 nghttp3_typed_buf tbuf;
664 size_t len;
665
666 assert(stream->conn);
667 assert(stream->conn->tx.qdec == stream);
668
669 qdec = &stream->conn->qdec;
670
671 assert(qdec);
672
673 len = nghttp3_qpack_decoder_get_decoder_streamlen(qdec);
674 if (len == 0) {
675 return 0;
676 }
677
678 rv = nghttp3_stream_ensure_chunk(stream, len);
679 if (rv != 0) {
680 return rv;
681 }
682
683 chunk = nghttp3_stream_get_chunk(stream);
684 typed_buf_shared_init(&tbuf, chunk);
685
686 nghttp3_qpack_decoder_write_decoder(qdec, chunk);
687
688 tbuf.buf.last = chunk->last;
689
690 return nghttp3_stream_outq_add(stream, &tbuf);
691 }
692
nghttp3_stream_outq_is_full(nghttp3_stream * stream)693 int nghttp3_stream_outq_is_full(nghttp3_stream *stream) {
694 /* TODO Verify that the limit is reasonable. */
695 return nghttp3_ringbuf_len(&stream->outq) >= 1024;
696 }
697
nghttp3_stream_outq_add(nghttp3_stream * stream,const nghttp3_typed_buf * tbuf)698 int nghttp3_stream_outq_add(nghttp3_stream *stream,
699 const nghttp3_typed_buf *tbuf) {
700 nghttp3_ringbuf *outq = &stream->outq;
701 int rv;
702 nghttp3_typed_buf *dest;
703 size_t len = nghttp3_ringbuf_len(outq);
704 size_t buflen = nghttp3_buf_len(&tbuf->buf);
705
706 if (buflen > NGHTTP3_MAX_VARINT - stream->tx.offset) {
707 return NGHTTP3_ERR_STREAM_DATA_OVERFLOW;
708 }
709
710 stream->tx.offset += buflen;
711 stream->unsent_bytes += buflen;
712
713 if (len) {
714 dest = nghttp3_ringbuf_get(outq, len - 1);
715 if (dest->type == tbuf->type && dest->type == NGHTTP3_BUF_TYPE_SHARED &&
716 dest->buf.begin == tbuf->buf.begin && dest->buf.last == tbuf->buf.pos) {
717 /* If we have already written last entry, adjust outq_idx and
718 offset so that this entry is eligible to send. */
719 if (len == stream->outq_idx) {
720 --stream->outq_idx;
721 stream->outq_offset = nghttp3_buf_len(&dest->buf);
722 }
723
724 dest->buf.last = tbuf->buf.last;
725 /* TODO Is this required? */
726 dest->buf.end = tbuf->buf.end;
727
728 return 0;
729 }
730 }
731
732 if (nghttp3_ringbuf_full(outq)) {
733 size_t nlen = nghttp3_max(NGHTTP3_MIN_RBLEN, len * 2);
734 rv = nghttp3_ringbuf_reserve(outq, nlen);
735 if (rv != 0) {
736 return rv;
737 }
738 }
739
740 dest = nghttp3_ringbuf_push_back(outq);
741 *dest = *tbuf;
742
743 return 0;
744 }
745
nghttp3_stream_ensure_chunk(nghttp3_stream * stream,size_t need)746 int nghttp3_stream_ensure_chunk(nghttp3_stream *stream, size_t need) {
747 nghttp3_ringbuf *chunks = &stream->chunks;
748 nghttp3_buf *chunk;
749 size_t len = nghttp3_ringbuf_len(chunks);
750 uint8_t *p;
751 int rv;
752 size_t n = NGHTTP3_STREAM_MIN_CHUNK_SIZE;
753
754 if (len) {
755 chunk = nghttp3_ringbuf_get(chunks, len - 1);
756 if (nghttp3_buf_left(chunk) >= need) {
757 return 0;
758 }
759 }
760
761 for (; n < need; n *= 2)
762 ;
763
764 p = nghttp3_mem_malloc(stream->mem, n);
765 if (p == NULL) {
766 return NGHTTP3_ERR_NOMEM;
767 }
768
769 if (nghttp3_ringbuf_full(chunks)) {
770 size_t nlen = nghttp3_max(NGHTTP3_MIN_RBLEN, len * 2);
771 rv = nghttp3_ringbuf_reserve(chunks, nlen);
772 if (rv != 0) {
773 return rv;
774 }
775 }
776
777 chunk = nghttp3_ringbuf_push_back(chunks);
778 nghttp3_buf_wrap_init(chunk, p, n);
779
780 return 0;
781 }
782
nghttp3_stream_get_chunk(nghttp3_stream * stream)783 nghttp3_buf *nghttp3_stream_get_chunk(nghttp3_stream *stream) {
784 nghttp3_ringbuf *chunks = &stream->chunks;
785 size_t len = nghttp3_ringbuf_len(chunks);
786
787 assert(len);
788
789 return nghttp3_ringbuf_get(chunks, len - 1);
790 }
791
nghttp3_stream_is_blocked(nghttp3_stream * stream)792 int nghttp3_stream_is_blocked(nghttp3_stream *stream) {
793 return (stream->flags & NGHTTP3_STREAM_FLAG_FC_BLOCKED) ||
794 (stream->flags & NGHTTP3_STREAM_FLAG_SHUT_WR) ||
795 (stream->flags & NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED);
796 }
797
nghttp3_stream_require_schedule(nghttp3_stream * stream)798 int nghttp3_stream_require_schedule(nghttp3_stream *stream) {
799 return (!nghttp3_stream_outq_write_done(stream) &&
800 !(stream->flags & NGHTTP3_STREAM_FLAG_FC_BLOCKED) &&
801 !(stream->flags & NGHTTP3_STREAM_FLAG_SHUT_WR)) ||
802 (nghttp3_ringbuf_len(&stream->frq) &&
803 !(stream->flags & NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED));
804 }
805
nghttp3_stream_writev(nghttp3_stream * stream,int * pfin,nghttp3_vec * vec,size_t veccnt)806 nghttp3_ssize nghttp3_stream_writev(nghttp3_stream *stream, int *pfin,
807 nghttp3_vec *vec, size_t veccnt) {
808 nghttp3_ringbuf *outq = &stream->outq;
809 size_t len = nghttp3_ringbuf_len(outq);
810 size_t i;
811 uint64_t offset = stream->outq_offset;
812 size_t buflen;
813 nghttp3_vec *vbegin = vec, *vend = vec + veccnt;
814 nghttp3_typed_buf *tbuf;
815
816 assert(veccnt > 0);
817
818 for (i = stream->outq_idx; i < len; ++i) {
819 tbuf = nghttp3_ringbuf_get(outq, i);
820 buflen = nghttp3_buf_len(&tbuf->buf);
821 if (offset >= buflen) {
822 offset -= buflen;
823 continue;
824 }
825
826 vec->base = tbuf->buf.pos + offset;
827 vec->len = (size_t)(buflen - offset);
828 ++vec;
829 ++i;
830 break;
831 }
832
833 for (; i < len && vec != vend; ++i, ++vec) {
834 tbuf = nghttp3_ringbuf_get(outq, i);
835 vec->base = tbuf->buf.pos;
836 vec->len = nghttp3_buf_len(&tbuf->buf);
837 }
838
839 /* TODO Rework this if we have finished implementing HTTP
840 messaging */
841 *pfin = nghttp3_ringbuf_len(&stream->frq) == 0 && i == len &&
842 (stream->flags & NGHTTP3_STREAM_FLAG_WRITE_END_STREAM);
843
844 return vec - vbegin;
845 }
846
nghttp3_stream_add_outq_offset(nghttp3_stream * stream,size_t n)847 int nghttp3_stream_add_outq_offset(nghttp3_stream *stream, size_t n) {
848 nghttp3_ringbuf *outq = &stream->outq;
849 size_t i;
850 size_t len = nghttp3_ringbuf_len(outq);
851 uint64_t offset = stream->outq_offset + n;
852 size_t buflen;
853 nghttp3_typed_buf *tbuf;
854
855 for (i = stream->outq_idx; i < len; ++i) {
856 tbuf = nghttp3_ringbuf_get(outq, i);
857 buflen = nghttp3_buf_len(&tbuf->buf);
858 if (offset >= buflen) {
859 offset -= buflen;
860 continue;
861 }
862
863 break;
864 }
865
866 assert(i < len || offset == 0);
867
868 stream->unsent_bytes -= n;
869 stream->outq_idx = i;
870 stream->outq_offset = offset;
871
872 return 0;
873 }
874
nghttp3_stream_outq_write_done(nghttp3_stream * stream)875 int nghttp3_stream_outq_write_done(nghttp3_stream *stream) {
876 nghttp3_ringbuf *outq = &stream->outq;
877 size_t len = nghttp3_ringbuf_len(outq);
878
879 return len == 0 || stream->outq_idx >= len;
880 }
881
stream_pop_outq_entry(nghttp3_stream * stream,nghttp3_typed_buf * tbuf)882 static int stream_pop_outq_entry(nghttp3_stream *stream,
883 nghttp3_typed_buf *tbuf) {
884 nghttp3_ringbuf *chunks = &stream->chunks;
885 nghttp3_buf *chunk;
886
887 switch (tbuf->type) {
888 case NGHTTP3_BUF_TYPE_PRIVATE:
889 nghttp3_buf_free(&tbuf->buf, stream->mem);
890 break;
891 case NGHTTP3_BUF_TYPE_ALIEN:
892 break;
893 default:
894 assert(nghttp3_ringbuf_len(chunks));
895
896 chunk = nghttp3_ringbuf_get(chunks, 0);
897
898 assert(chunk->begin == tbuf->buf.begin);
899 assert(chunk->end == tbuf->buf.end);
900
901 if (chunk->last == tbuf->buf.last) {
902 nghttp3_buf_free(chunk, stream->mem);
903 nghttp3_ringbuf_pop_front(chunks);
904 }
905 };
906
907 nghttp3_ringbuf_pop_front(&stream->outq);
908
909 return 0;
910 }
911
nghttp3_stream_add_ack_offset(nghttp3_stream * stream,uint64_t n)912 int nghttp3_stream_add_ack_offset(nghttp3_stream *stream, uint64_t n) {
913 nghttp3_ringbuf *outq = &stream->outq;
914 uint64_t offset = stream->ack_offset + n;
915 size_t buflen;
916 size_t npopped = 0;
917 uint64_t nack;
918 nghttp3_typed_buf *tbuf;
919 int rv;
920
921 for (; nghttp3_ringbuf_len(outq);) {
922 tbuf = nghttp3_ringbuf_get(outq, 0);
923 buflen = nghttp3_buf_len(&tbuf->buf);
924
925 if (tbuf->type == NGHTTP3_BUF_TYPE_ALIEN) {
926 nack = nghttp3_min(offset, (uint64_t)buflen) - stream->ack_done;
927 if (stream->callbacks.acked_data) {
928 rv = stream->callbacks.acked_data(stream, stream->node.nid.id, nack,
929 stream->user_data);
930 if (rv != 0) {
931 return NGHTTP3_ERR_CALLBACK_FAILURE;
932 }
933 }
934 stream->ack_done += nack;
935 }
936
937 if (offset >= buflen) {
938 rv = stream_pop_outq_entry(stream, tbuf);
939 if (rv != 0) {
940 return rv;
941 }
942
943 offset -= buflen;
944 ++npopped;
945 stream->ack_done = 0;
946
947 if (stream->outq_idx + 1 == npopped) {
948 stream->outq_offset = 0;
949 break;
950 }
951
952 continue;
953 }
954
955 break;
956 }
957
958 assert(stream->outq_idx + 1 >= npopped);
959 if (stream->outq_idx >= npopped) {
960 stream->outq_idx -= npopped;
961 } else {
962 stream->outq_idx = 0;
963 }
964
965 stream->ack_offset = offset;
966
967 return 0;
968 }
969
nghttp3_stream_buffer_data(nghttp3_stream * stream,const uint8_t * data,size_t datalen)970 int nghttp3_stream_buffer_data(nghttp3_stream *stream, const uint8_t *data,
971 size_t datalen) {
972 nghttp3_ringbuf *inq = &stream->inq;
973 size_t len = nghttp3_ringbuf_len(inq);
974 nghttp3_buf *buf;
975 size_t nwrite;
976 uint8_t *rawbuf;
977 size_t bufleft;
978 int rv;
979
980 if (len) {
981 buf = nghttp3_ringbuf_get(inq, len - 1);
982 bufleft = nghttp3_buf_left(buf);
983 nwrite = nghttp3_min(datalen, bufleft);
984 buf->last = nghttp3_cpymem(buf->last, data, nwrite);
985 data += nwrite;
986 datalen -= nwrite;
987 }
988
989 for (; datalen;) {
990 if (nghttp3_ringbuf_full(inq)) {
991 size_t nlen =
992 nghttp3_max(NGHTTP3_MIN_RBLEN, nghttp3_ringbuf_len(inq) * 2);
993 rv = nghttp3_ringbuf_reserve(inq, nlen);
994 if (rv != 0) {
995 return rv;
996 }
997 }
998
999 rawbuf = nghttp3_mem_malloc(stream->mem, 16384);
1000 if (rawbuf == NULL) {
1001 return NGHTTP3_ERR_NOMEM;
1002 }
1003
1004 buf = nghttp3_ringbuf_push_back(inq);
1005 nghttp3_buf_wrap_init(buf, rawbuf, 16384);
1006 bufleft = nghttp3_buf_left(buf);
1007 nwrite = nghttp3_min(datalen, bufleft);
1008 buf->last = nghttp3_cpymem(buf->last, data, nwrite);
1009 data += nwrite;
1010 datalen -= nwrite;
1011 }
1012
1013 return 0;
1014 }
1015
nghttp3_stream_get_buffered_datalen(nghttp3_stream * stream)1016 size_t nghttp3_stream_get_buffered_datalen(nghttp3_stream *stream) {
1017 nghttp3_ringbuf *inq = &stream->inq;
1018 size_t len = nghttp3_ringbuf_len(inq);
1019 size_t i, n = 0;
1020 nghttp3_buf *buf;
1021
1022 for (i = 0; i < len; ++i) {
1023 buf = nghttp3_ringbuf_get(inq, i);
1024 n += nghttp3_buf_len(buf);
1025 }
1026
1027 return n;
1028 }
1029
nghttp3_stream_transit_rx_http_state(nghttp3_stream * stream,nghttp3_stream_http_event event)1030 int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream,
1031 nghttp3_stream_http_event event) {
1032 int rv;
1033
1034 switch (stream->rx.hstate) {
1035 case NGHTTP3_HTTP_STATE_NONE:
1036 return NGHTTP3_ERR_H3_INTERNAL_ERROR;
1037 case NGHTTP3_HTTP_STATE_REQ_INITIAL:
1038 switch (event) {
1039 case NGHTTP3_HTTP_EVENT_HEADERS_BEGIN:
1040 stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN;
1041 return 0;
1042 default:
1043 return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1044 }
1045 case NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN:
1046 if (event != NGHTTP3_HTTP_EVENT_HEADERS_END) {
1047 return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
1048 }
1049 stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_HEADERS_END;
1050 return 0;
1051 case NGHTTP3_HTTP_STATE_REQ_HEADERS_END:
1052 switch (event) {
1053 case NGHTTP3_HTTP_EVENT_HEADERS_BEGIN:
1054 /* TODO Better to check status code */
1055 if (stream->rx.http.flags & NGHTTP3_HTTP_FLAG_METH_CONNECT) {
1056 return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1057 }
1058 rv = nghttp3_http_on_remote_end_stream(stream);
1059 if (rv != 0) {
1060 return rv;
1061 }
1062 stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN;
1063 return 0;
1064 case NGHTTP3_HTTP_EVENT_DATA_BEGIN:
1065 stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_DATA_BEGIN;
1066 return 0;
1067 case NGHTTP3_HTTP_EVENT_MSG_END:
1068 stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_END;
1069 return 0;
1070 default:
1071 return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1072 }
1073 case NGHTTP3_HTTP_STATE_REQ_DATA_BEGIN:
1074 if (event != NGHTTP3_HTTP_EVENT_DATA_END) {
1075 return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
1076 }
1077 stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_DATA_END;
1078 return 0;
1079 case NGHTTP3_HTTP_STATE_REQ_DATA_END:
1080 switch (event) {
1081 case NGHTTP3_HTTP_EVENT_DATA_BEGIN:
1082 stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_DATA_BEGIN;
1083 return 0;
1084 case NGHTTP3_HTTP_EVENT_HEADERS_BEGIN:
1085 /* TODO Better to check status code */
1086 if (stream->rx.http.flags & NGHTTP3_HTTP_FLAG_METH_CONNECT) {
1087 return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1088 }
1089 rv = nghttp3_http_on_remote_end_stream(stream);
1090 if (rv != 0) {
1091 return rv;
1092 }
1093 stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN;
1094 return 0;
1095 case NGHTTP3_HTTP_EVENT_MSG_END:
1096 stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_END;
1097 return 0;
1098 default:
1099 return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1100 }
1101 case NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN:
1102 if (event != NGHTTP3_HTTP_EVENT_HEADERS_END) {
1103 return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
1104 }
1105 stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_TRAILERS_END;
1106 return 0;
1107 case NGHTTP3_HTTP_STATE_REQ_TRAILERS_END:
1108 if (event != NGHTTP3_HTTP_EVENT_MSG_END) {
1109 /* TODO Should ignore unexpected frame in this state as per
1110 spec. */
1111 return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1112 }
1113 stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_END;
1114 return 0;
1115 case NGHTTP3_HTTP_STATE_REQ_END:
1116 return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
1117 case NGHTTP3_HTTP_STATE_RESP_INITIAL:
1118 if (event != NGHTTP3_HTTP_EVENT_HEADERS_BEGIN) {
1119 return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1120 }
1121 stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN;
1122 return 0;
1123 case NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN:
1124 if (event != NGHTTP3_HTTP_EVENT_HEADERS_END) {
1125 return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
1126 }
1127 stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_HEADERS_END;
1128 return 0;
1129 case NGHTTP3_HTTP_STATE_RESP_HEADERS_END:
1130 switch (event) {
1131 case NGHTTP3_HTTP_EVENT_HEADERS_BEGIN:
1132 if (stream->rx.http.status_code == -1) {
1133 stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN;
1134 return 0;
1135 }
1136 if ((stream->rx.http.flags & NGHTTP3_HTTP_FLAG_METH_CONNECT) &&
1137 stream->rx.http.status_code / 100 == 2) {
1138 return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1139 }
1140 rv = nghttp3_http_on_remote_end_stream(stream);
1141 if (rv != 0) {
1142 return rv;
1143 }
1144 stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN;
1145 return 0;
1146 case NGHTTP3_HTTP_EVENT_DATA_BEGIN:
1147 if (stream->rx.http.flags & NGHTTP3_HTTP_FLAG_EXPECT_FINAL_RESPONSE) {
1148 return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1149 }
1150 stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_DATA_BEGIN;
1151 return 0;
1152 case NGHTTP3_HTTP_EVENT_MSG_END:
1153 stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_END;
1154 return 0;
1155 default:
1156 return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1157 }
1158 case NGHTTP3_HTTP_STATE_RESP_DATA_BEGIN:
1159 if (event != NGHTTP3_HTTP_EVENT_DATA_END) {
1160 return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
1161 }
1162 stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_DATA_END;
1163 return 0;
1164 case NGHTTP3_HTTP_STATE_RESP_DATA_END:
1165 switch (event) {
1166 case NGHTTP3_HTTP_EVENT_DATA_BEGIN:
1167 stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_DATA_BEGIN;
1168 return 0;
1169 case NGHTTP3_HTTP_EVENT_HEADERS_BEGIN:
1170 if ((stream->rx.http.flags & NGHTTP3_HTTP_FLAG_METH_CONNECT) &&
1171 stream->rx.http.status_code / 100 == 2) {
1172 return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1173 }
1174 rv = nghttp3_http_on_remote_end_stream(stream);
1175 if (rv != 0) {
1176 return rv;
1177 }
1178 stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN;
1179 return 0;
1180 case NGHTTP3_HTTP_EVENT_MSG_END:
1181 stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_END;
1182 return 0;
1183 default:
1184 return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
1185 }
1186 case NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN:
1187 if (event != NGHTTP3_HTTP_EVENT_HEADERS_END) {
1188 return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
1189 }
1190 stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_TRAILERS_END;
1191 return 0;
1192 case NGHTTP3_HTTP_STATE_RESP_TRAILERS_END:
1193 if (event != NGHTTP3_HTTP_EVENT_MSG_END) {
1194 return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
1195 }
1196 stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_END;
1197 return 0;
1198 case NGHTTP3_HTTP_STATE_RESP_END:
1199 return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
1200 default:
1201 assert(0);
1202 abort();
1203 }
1204 }
1205
nghttp3_stream_empty_headers_allowed(nghttp3_stream * stream)1206 int nghttp3_stream_empty_headers_allowed(nghttp3_stream *stream) {
1207 switch (stream->rx.hstate) {
1208 case NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN:
1209 case NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN:
1210 return 0;
1211 default:
1212 return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
1213 }
1214 }
1215
nghttp3_stream_uni(int64_t stream_id)1216 int nghttp3_stream_uni(int64_t stream_id) { return (stream_id & 0x2) != 0; }
1217
nghttp3_client_stream_bidi(int64_t stream_id)1218 int nghttp3_client_stream_bidi(int64_t stream_id) {
1219 return (stream_id & 0x3) == 0;
1220 }
1221
nghttp3_client_stream_uni(int64_t stream_id)1222 int nghttp3_client_stream_uni(int64_t stream_id) {
1223 return (stream_id & 0x3) == 0x2;
1224 }
1225
nghttp3_server_stream_uni(int64_t stream_id)1226 int nghttp3_server_stream_uni(int64_t stream_id) {
1227 return (stream_id & 0x3) == 0x3;
1228 }
1229