• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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