Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, Google Inc.
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are
8 : * met:
9 : *
10 : * * Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * * Redistributions in binary form must reproduce the above
13 : * copyright notice, this list of conditions and the following disclaimer
14 : * in the documentation and/or other materials provided with the
15 : * distribution.
16 : * * Neither the name of Google Inc. nor the names of its
17 : * contributors may be used to endorse or promote products derived from
18 : * this software without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : */
33 :
34 : #include "src/core/transport/chttp2/frame_settings.h"
35 : #include "src/core/transport/chttp2/internal.h"
36 :
37 : #include <string.h>
38 :
39 : #include <grpc/support/log.h>
40 : #include <grpc/support/useful.h>
41 :
42 : #include "src/core/debug/trace.h"
43 : #include "src/core/transport/chttp2/frame.h"
44 : #include "src/core/transport/chttp2/http2_errors.h"
45 : #include "src/core/transport/chttp2_transport.h"
46 :
47 : #define MAX_MAX_HEADER_LIST_SIZE (1024*1024*1024)
48 :
49 : /* HTTP/2 mandated initial connection settings */
50 : const grpc_chttp2_setting_parameters
51 : grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
52 : {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
53 : GRPC_CHTTP2_PROTOCOL_ERROR},
54 : {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff,
55 : GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
56 : {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
57 : GRPC_CHTTP2_PROTOCOL_ERROR},
58 : {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu,
59 : GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
60 : {"INITIAL_WINDOW_SIZE", 65535, 0, 0x7fffffffu,
61 : GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE,
62 : GRPC_CHTTP2_FLOW_CONTROL_ERROR},
63 : {"MAX_FRAME_SIZE", 16384, 16384, 16777215,
64 : GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
65 : {"MAX_HEADER_LIST_SIZE", MAX_MAX_HEADER_LIST_SIZE, 0, MAX_MAX_HEADER_LIST_SIZE,
66 : GRPC_CHTTP2_CLAMP_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR},
67 : };
68 :
69 11428 : static gpr_uint8 *fill_header(gpr_uint8 *out, gpr_uint32 length,
70 : gpr_uint8 flags) {
71 11592 : *out++ = (gpr_uint8)(length >> 16);
72 11592 : *out++ = (gpr_uint8)(length >> 8);
73 11592 : *out++ = (gpr_uint8)(length);
74 11592 : *out++ = GRPC_CHTTP2_FRAME_SETTINGS;
75 11592 : *out++ = flags;
76 11592 : *out++ = 0;
77 11592 : *out++ = 0;
78 11592 : *out++ = 0;
79 11592 : *out++ = 0;
80 11428 : return out;
81 : }
82 :
83 6039 : gpr_slice grpc_chttp2_settings_create(gpr_uint32 *old, const gpr_uint32 *new,
84 : gpr_uint32 force_mask, size_t count) {
85 : size_t i;
86 5957 : gpr_uint32 n = 0;
87 : gpr_slice output;
88 : gpr_uint8 *p;
89 :
90 48285 : for (i = 0; i < count; i++) {
91 42246 : n += (new[i] != old[i] || (force_mask & (1u << i)) != 0);
92 : }
93 :
94 6039 : output = gpr_slice_malloc(9 + 6 * n);
95 6039 : p = fill_header(GPR_SLICE_START_PTR(output), 6 * n, 0);
96 :
97 48279 : for (i = 0; i < count; i++) {
98 42240 : if (new[i] != old[i] || (force_mask & (1u << i)) != 0) {
99 12622 : GPR_ASSERT(i);
100 12626 : *p++ = (gpr_uint8)(i >> 8);
101 12626 : *p++ = (gpr_uint8)(i);
102 12626 : *p++ = (gpr_uint8)(new[i] >> 24);
103 12626 : *p++ = (gpr_uint8)(new[i] >> 16);
104 12626 : *p++ = (gpr_uint8)(new[i] >> 8);
105 12626 : *p++ = (gpr_uint8)(new[i]);
106 12626 : old[i] = new[i];
107 : }
108 : }
109 :
110 6039 : GPR_ASSERT(p == GPR_SLICE_END_PTR(output));
111 :
112 6039 : return output;
113 : }
114 :
115 5553 : gpr_slice grpc_chttp2_settings_ack_create(void) {
116 5553 : gpr_slice output = gpr_slice_malloc(9);
117 5554 : fill_header(GPR_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
118 5554 : return output;
119 : }
120 :
121 10934 : grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
122 : grpc_chttp2_settings_parser *parser, gpr_uint32 length, gpr_uint8 flags,
123 : gpr_uint32 *settings) {
124 10934 : parser->target_settings = settings;
125 10934 : memcpy(parser->incoming_settings, settings,
126 : GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
127 10934 : parser->is_ack = 0;
128 10934 : parser->state = GRPC_CHTTP2_SPS_ID0;
129 10934 : if (flags == GRPC_CHTTP2_FLAG_ACK) {
130 5373 : parser->is_ack = 1;
131 5373 : if (length != 0) {
132 1 : gpr_log(GPR_ERROR, "non-empty settings ack frame received");
133 1 : return GRPC_CHTTP2_CONNECTION_ERROR;
134 : }
135 5290 : return GRPC_CHTTP2_PARSE_OK;
136 5561 : } else if (flags != 0) {
137 1 : gpr_log(GPR_ERROR, "invalid flags on settings frame");
138 1 : return GRPC_CHTTP2_CONNECTION_ERROR;
139 5560 : } else if (length % 6 != 0) {
140 5 : gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes");
141 5 : return GRPC_CHTTP2_CONNECTION_ERROR;
142 : } else {
143 5473 : return GRPC_CHTTP2_PARSE_OK;
144 : }
145 : }
146 :
147 15264 : grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
148 : grpc_exec_ctx *exec_ctx, void *p,
149 : grpc_chttp2_transport_parsing *transport_parsing,
150 : grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
151 15100 : grpc_chttp2_settings_parser *parser = p;
152 15264 : const gpr_uint8 *cur = GPR_SLICE_START_PTR(slice);
153 15264 : const gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
154 :
155 15264 : if (parser->is_ack) {
156 5290 : return GRPC_CHTTP2_PARSE_OK;
157 : }
158 :
159 : for (;;) {
160 21464 : switch (parser->state) {
161 : case GRPC_CHTTP2_SPS_ID0:
162 17557 : if (cur == end) {
163 5975 : parser->state = GRPC_CHTTP2_SPS_ID0;
164 5975 : if (is_last) {
165 5553 : transport_parsing->settings_updated = 1;
166 5553 : memcpy(parser->target_settings, parser->incoming_settings,
167 : GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
168 5553 : gpr_slice_buffer_add(&transport_parsing->qbuf,
169 : grpc_chttp2_settings_ack_create());
170 : }
171 5894 : return GRPC_CHTTP2_PARSE_OK;
172 : }
173 11582 : parser->id = (gpr_uint16)(((gpr_uint16)*cur) << 8);
174 11582 : cur++;
175 : /* fallthrough */
176 : case GRPC_CHTTP2_SPS_ID1:
177 12363 : if (cur == end) {
178 782 : parser->state = GRPC_CHTTP2_SPS_ID1;
179 782 : return GRPC_CHTTP2_PARSE_OK;
180 : }
181 11581 : parser->id = (gpr_uint16)(parser->id | (*cur));
182 11581 : cur++;
183 : /* fallthrough */
184 : case GRPC_CHTTP2_SPS_VAL0:
185 12359 : if (cur == end) {
186 782 : parser->state = GRPC_CHTTP2_SPS_VAL0;
187 782 : return GRPC_CHTTP2_PARSE_OK;
188 : }
189 11577 : parser->value = ((gpr_uint32)*cur) << 24;
190 11577 : cur++;
191 : /* fallthrough */
192 : case GRPC_CHTTP2_SPS_VAL1:
193 12361 : if (cur == end) {
194 782 : parser->state = GRPC_CHTTP2_SPS_VAL1;
195 782 : return GRPC_CHTTP2_PARSE_OK;
196 : }
197 11579 : parser->value |= ((gpr_uint32)*cur) << 16;
198 11579 : cur++;
199 : /* fallthrough */
200 : case GRPC_CHTTP2_SPS_VAL2:
201 12360 : if (cur == end) {
202 782 : parser->state = GRPC_CHTTP2_SPS_VAL2;
203 782 : return GRPC_CHTTP2_PARSE_OK;
204 : }
205 11578 : parser->value |= ((gpr_uint32)*cur) << 8;
206 11578 : cur++;
207 : /* fallthrough */
208 : case GRPC_CHTTP2_SPS_VAL3:
209 12360 : if (cur == end) {
210 782 : parser->state = GRPC_CHTTP2_SPS_VAL3;
211 782 : return GRPC_CHTTP2_PARSE_OK;
212 : } else {
213 11578 : parser->state = GRPC_CHTTP2_SPS_ID0;
214 : }
215 11578 : parser->value |= *cur;
216 11578 : cur++;
217 :
218 22980 : if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) {
219 11410 : const grpc_chttp2_setting_parameters *sp =
220 11574 : &grpc_chttp2_settings_parameters[parser->id];
221 11574 : if (parser->value < sp->min_value || parser->value > sp->max_value) {
222 2 : switch (sp->invalid_value_behavior) {
223 : case GRPC_CHTTP2_CLAMP_INVALID_VALUE:
224 1 : parser->value =
225 1 : GPR_CLAMP(parser->value, sp->min_value, sp->max_value);
226 1 : break;
227 : case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE:
228 1 : grpc_chttp2_goaway_append(
229 : transport_parsing->last_incoming_stream_id, sp->error_value,
230 : gpr_slice_from_static_string("HTTP2 settings error"),
231 : &transport_parsing->qbuf);
232 1 : gpr_log(GPR_ERROR, "invalid value %u passed for %s",
233 : parser->value, sp->name);
234 1 : return GRPC_CHTTP2_CONNECTION_ERROR;
235 : }
236 : }
237 17060 : if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
238 5487 : parser->incoming_settings[parser->id] != parser->value) {
239 1 : transport_parsing->initial_window_update =
240 2 : (gpr_int64)parser->value -
241 1 : parser->incoming_settings[parser->id];
242 1 : gpr_log(GPR_DEBUG, "adding %d for initial_window change",
243 1 : (int)transport_parsing->initial_window_update);
244 : }
245 11566 : parser->incoming_settings[parser->id] = parser->value;
246 11566 : if (grpc_http_trace) {
247 1302 : gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d",
248 868 : transport_parsing->is_client ? "CLI" : "SVR", parser->id,
249 : parser->value);
250 : }
251 : } else {
252 8 : gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
253 4 : parser->id, parser->value);
254 : }
255 11407 : break;
256 : }
257 11408 : }
258 : }
|