1 /*
2 * Copyright (c) 2019 Fastly, Kazuho Oku
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22 #include "h2o/absprio.h"
23 #include "h2o/http3_common.h"
24
h2o_http3_encode_priority_update_frame(uint8_t * dst,const h2o_http3_priority_update_frame_t * frame)25 uint8_t *h2o_http3_encode_priority_update_frame(uint8_t *dst, const h2o_http3_priority_update_frame_t *frame)
26 {
27 *dst++ = H2O_HTTP3_FRAME_TYPE_PRIORITY_UPDATE;
28 *dst++ = frame->element_is_push ? 0x80 : 0;
29 dst = quicly_encodev(dst, frame->element);
30 *dst++ = 'u';
31 *dst++ = '=';
32 *dst++ = '0' + frame->priority.urgency;
33 if (!frame->priority.incremental) {
34 static const h2o_iovec_t s = {H2O_STRLIT(",i=1")};
35 memcpy(dst, s.base, s.len);
36 dst += s.len;
37 }
38 return dst;
39 }
40
h2o_http3_decode_priority_update_frame(h2o_http3_priority_update_frame_t * frame,const uint8_t * payload,size_t len,const char ** err_desc)41 int h2o_http3_decode_priority_update_frame(h2o_http3_priority_update_frame_t *frame, const uint8_t *payload, size_t len,
42 const char **err_desc)
43 {
44 const uint8_t *src = payload, *end = src + len;
45
46 if (src == end)
47 return H2O_HTTP3_ERROR_FRAME;
48 frame->element_is_push = (*src++ & 0x80) != 0;
49 if ((frame->element = quicly_decodev(&src, end)) == UINT64_MAX) {
50 *err_desc = "invalid PRIORITY frame";
51 return H2O_HTTP3_ERROR_FRAME;
52 }
53 if (frame->element_is_push) {
54 if (!(!quicly_stream_is_client_initiated(frame->element) && quicly_stream_is_unidirectional(frame->element)))
55 return H2O_HTTP3_ERROR_FRAME;
56 } else {
57 if (!(quicly_stream_is_client_initiated(frame->element) && !quicly_stream_is_unidirectional(frame->element)))
58 return H2O_HTTP3_ERROR_FRAME;
59 }
60 frame->priority = h2o_absprio_default;
61 h2o_absprio_parse_priority((const char *)src, end - src, &frame->priority);
62
63 return 0;
64 }
65
h2o_http3_goaway_frame_capacity(quicly_stream_id_t stream_or_push_id)66 size_t h2o_http3_goaway_frame_capacity(quicly_stream_id_t stream_or_push_id)
67 {
68 return 1 /* type */
69 + 1 /* length field. length should be less than 64, so 1 byte should be enough to represent it */
70 + quicly_encodev_capacity(stream_or_push_id);
71 }
72
h2o_http3_encode_goaway_frame(uint8_t * dst,quicly_stream_id_t stream_or_push_id)73 uint8_t *h2o_http3_encode_goaway_frame(uint8_t *dst, quicly_stream_id_t stream_or_push_id)
74 {
75 *dst++ = H2O_HTTP3_FRAME_TYPE_GOAWAY; /* type */
76 *dst++ = quicly_encodev_capacity(stream_or_push_id); /* payload length */
77 dst = quicly_encodev(dst, stream_or_push_id);
78
79 return dst;
80 }
81
h2o_http3_decode_goaway_frame(h2o_http3_goaway_frame_t * frame,const uint8_t * payload,size_t len,const char ** err_desc)82 int h2o_http3_decode_goaway_frame(h2o_http3_goaway_frame_t *frame, const uint8_t *payload, size_t len, const char **err_desc)
83 {
84 const uint8_t *src = payload, *end = src + len;
85
86 if ((frame->stream_or_push_id = quicly_decodev(&src, end)) == UINT64_MAX)
87 goto Fail;
88
89 if (src != end) {
90 /* there was an extra byte(s) after a valid QUIC variable-length integer */
91 goto Fail;
92 }
93
94 return 0;
95
96 Fail:
97 *err_desc = "Invalid GOAWAY frame";
98 return H2O_HTTP3_ERROR_FRAME;
99 }
100