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 "src/core/debug/trace.h"
40 : #include "src/core/transport/chttp2/frame.h"
41 : #include "src/core/transport/chttp2_transport.h"
42 : #include <grpc/support/log.h>
43 : #include <grpc/support/useful.h>
44 :
45 : /* HTTP/2 mandated initial connection settings */
46 : const grpc_chttp2_setting_parameters
47 : grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = {
48 : {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
49 : {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff,
50 : GRPC_CHTTP2_CLAMP_INVALID_VALUE},
51 : {"ENABLE_PUSH", 1, 0, 1, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
52 : {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu,
53 : GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
54 : {"INITIAL_WINDOW_SIZE", 65535, 0, 0xffffffffu,
55 : GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
56 : {"MAX_FRAME_SIZE", 16384, 16384, 16777215,
57 : GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE},
58 : {"MAX_HEADER_LIST_SIZE", 0xffffffffu, 0, 0xffffffffu,
59 : GRPC_CHTTP2_CLAMP_INVALID_VALUE},
60 : };
61 :
62 7694 : static gpr_uint8 *fill_header(gpr_uint8 *out, gpr_uint32 length,
63 : gpr_uint8 flags) {
64 7694 : *out++ = (gpr_uint8)(length >> 16);
65 7694 : *out++ = (gpr_uint8)(length >> 8);
66 7694 : *out++ = (gpr_uint8)(length);
67 7694 : *out++ = GRPC_CHTTP2_FRAME_SETTINGS;
68 7694 : *out++ = flags;
69 7694 : *out++ = 0;
70 7694 : *out++ = 0;
71 7694 : *out++ = 0;
72 7694 : *out++ = 0;
73 7694 : return out;
74 : }
75 :
76 4010 : gpr_slice grpc_chttp2_settings_create(gpr_uint32 *old, const gpr_uint32 *new,
77 : gpr_uint32 force_mask, size_t count) {
78 : size_t i;
79 4010 : gpr_uint32 n = 0;
80 : gpr_slice output;
81 : gpr_uint8 *p;
82 :
83 32061 : for (i = 0; i < count; i++) {
84 28051 : n += (new[i] != old[i] || (force_mask & (1u << i)) != 0);
85 : }
86 :
87 4010 : output = gpr_slice_malloc(9 + 6 * n);
88 4013 : p = fill_header(GPR_SLICE_START_PTR(output), 6 * n, 0);
89 :
90 32056 : for (i = 0; i < count; i++) {
91 28045 : if (new[i] != old[i] || (force_mask & (1u << i)) != 0) {
92 8007 : GPR_ASSERT(i);
93 8009 : *p++ = (gpr_uint8)(i >> 8);
94 8009 : *p++ = (gpr_uint8)(i);
95 8009 : *p++ = (gpr_uint8)(new[i] >> 24);
96 8009 : *p++ = (gpr_uint8)(new[i] >> 16);
97 8009 : *p++ = (gpr_uint8)(new[i] >> 8);
98 8009 : *p++ = (gpr_uint8)(new[i]);
99 8009 : old[i] = new[i];
100 : }
101 : }
102 :
103 4011 : GPR_ASSERT(p == GPR_SLICE_END_PTR(output));
104 :
105 4011 : return output;
106 : }
107 :
108 3680 : gpr_slice grpc_chttp2_settings_ack_create(void) {
109 3680 : gpr_slice output = gpr_slice_malloc(9);
110 3681 : fill_header(GPR_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
111 3681 : return output;
112 : }
113 :
114 7263 : grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
115 : grpc_chttp2_settings_parser *parser, gpr_uint32 length, gpr_uint8 flags,
116 : gpr_uint32 *settings) {
117 7263 : parser->target_settings = settings;
118 7263 : memcpy(parser->incoming_settings, settings,
119 : GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
120 7263 : parser->is_ack = 0;
121 7263 : parser->state = GRPC_CHTTP2_SPS_ID0;
122 7263 : if (flags == GRPC_CHTTP2_FLAG_ACK) {
123 3578 : parser->is_ack = 1;
124 3578 : if (length != 0) {
125 0 : gpr_log(GPR_ERROR, "non-empty settings ack frame received");
126 0 : return GRPC_CHTTP2_CONNECTION_ERROR;
127 : }
128 3578 : return GRPC_CHTTP2_PARSE_OK;
129 3685 : } else if (flags != 0) {
130 0 : gpr_log(GPR_ERROR, "invalid flags on settings frame");
131 0 : return GRPC_CHTTP2_CONNECTION_ERROR;
132 3685 : } else if (length % 6 != 0) {
133 5 : gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes");
134 5 : return GRPC_CHTTP2_CONNECTION_ERROR;
135 : } else {
136 3680 : return GRPC_CHTTP2_PARSE_OK;
137 : }
138 : }
139 :
140 9646 : grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
141 : grpc_exec_ctx *exec_ctx, void *p,
142 : grpc_chttp2_transport_parsing *transport_parsing,
143 : grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
144 9646 : grpc_chttp2_settings_parser *parser = p;
145 9646 : const gpr_uint8 *cur = GPR_SLICE_START_PTR(slice);
146 9646 : const gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
147 :
148 9646 : if (parser->is_ack) {
149 3578 : return GRPC_CHTTP2_PARSE_OK;
150 : }
151 :
152 : for (;;) {
153 13436 : switch (parser->state) {
154 : case GRPC_CHTTP2_SPS_ID0:
155 11269 : if (cur == end) {
156 3899 : parser->state = GRPC_CHTTP2_SPS_ID0;
157 3899 : if (is_last) {
158 3681 : transport_parsing->settings_updated = 1;
159 3681 : memcpy(parser->target_settings, parser->incoming_settings,
160 : GRPC_CHTTP2_NUM_SETTINGS * sizeof(gpr_uint32));
161 3681 : gpr_slice_buffer_add(&transport_parsing->qbuf,
162 : grpc_chttp2_settings_ack_create());
163 : }
164 3899 : return GRPC_CHTTP2_PARSE_OK;
165 : }
166 7370 : parser->id = (gpr_uint16)(((gpr_uint16)*cur) << 8);
167 7370 : cur++;
168 : /* fallthrough */
169 : case GRPC_CHTTP2_SPS_ID1:
170 7803 : if (cur == end) {
171 434 : parser->state = GRPC_CHTTP2_SPS_ID1;
172 434 : return GRPC_CHTTP2_PARSE_OK;
173 : }
174 7369 : parser->id = (gpr_uint16)(parser->id | (*cur));
175 7369 : cur++;
176 : /* fallthrough */
177 : case GRPC_CHTTP2_SPS_VAL0:
178 7802 : if (cur == end) {
179 434 : parser->state = GRPC_CHTTP2_SPS_VAL0;
180 434 : return GRPC_CHTTP2_PARSE_OK;
181 : }
182 7368 : parser->value = ((gpr_uint32)*cur) << 24;
183 7368 : cur++;
184 : /* fallthrough */
185 : case GRPC_CHTTP2_SPS_VAL1:
186 7803 : if (cur == end) {
187 434 : parser->state = GRPC_CHTTP2_SPS_VAL1;
188 434 : return GRPC_CHTTP2_PARSE_OK;
189 : }
190 7369 : parser->value |= ((gpr_uint32)*cur) << 16;
191 7369 : cur++;
192 : /* fallthrough */
193 : case GRPC_CHTTP2_SPS_VAL2:
194 7801 : if (cur == end) {
195 434 : parser->state = GRPC_CHTTP2_SPS_VAL2;
196 434 : return GRPC_CHTTP2_PARSE_OK;
197 : }
198 7367 : parser->value |= ((gpr_uint32)*cur) << 8;
199 7367 : cur++;
200 : /* fallthrough */
201 : case GRPC_CHTTP2_SPS_VAL3:
202 7801 : if (cur == end) {
203 434 : parser->state = GRPC_CHTTP2_SPS_VAL3;
204 434 : return GRPC_CHTTP2_PARSE_OK;
205 : } else {
206 7367 : parser->state = GRPC_CHTTP2_SPS_ID0;
207 : }
208 7367 : parser->value |= *cur;
209 7367 : cur++;
210 :
211 14733 : if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) {
212 7365 : const grpc_chttp2_setting_parameters *sp =
213 7365 : &grpc_chttp2_settings_parameters[parser->id];
214 7365 : if (parser->value < sp->min_value || parser->value > sp->max_value) {
215 0 : switch (sp->invalid_value_behavior) {
216 : case GRPC_CHTTP2_CLAMP_INVALID_VALUE:
217 0 : parser->value =
218 0 : GPR_CLAMP(parser->value, sp->min_value, sp->max_value);
219 0 : break;
220 : case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE:
221 0 : gpr_log(GPR_ERROR, "invalid value %u passed for %s",
222 : parser->value, sp->name);
223 0 : return GRPC_CHTTP2_CONNECTION_ERROR;
224 : }
225 : }
226 11046 : if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE &&
227 3681 : parser->incoming_settings[parser->id] != parser->value) {
228 0 : transport_parsing->initial_window_update =
229 0 : (gpr_int64)parser->value -
230 0 : parser->incoming_settings[parser->id];
231 0 : gpr_log(GPR_DEBUG, "adding %d for initial_window change",
232 0 : (int)transport_parsing->initial_window_update);
233 : }
234 7366 : parser->incoming_settings[parser->id] = parser->value;
235 7366 : if (grpc_http_trace) {
236 1302 : gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d",
237 868 : transport_parsing->is_client ? "CLI" : "SVR", parser->id,
238 : parser->value);
239 : }
240 : } else {
241 4 : gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)",
242 2 : parser->id, parser->value);
243 : }
244 7368 : break;
245 : }
246 7368 : }
247 : }
|