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