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