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