Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 1 | /* |
| 2 | * |
Craig Tiller | 8a9fd52 | 2016-03-25 17:09:29 -0700 | [diff] [blame] | 3 | * Copyright 2015-2016, Google Inc. |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 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 | |
Craig Tiller | 9533d04 | 2016-03-25 17:11:06 -0700 | [diff] [blame] | 34 | #include "src/core/lib/transport/chttp2/frame_settings.h" |
| 35 | #include "src/core/lib/transport/chttp2/internal.h" |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 36 | |
| 37 | #include <string.h> |
| 38 | |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 39 | #include <grpc/support/log.h> |
| 40 | #include <grpc/support/useful.h> |
| 41 | |
Craig Tiller | 9533d04 | 2016-03-25 17:11:06 -0700 | [diff] [blame] | 42 | #include "src/core/lib/debug/trace.h" |
| 43 | #include "src/core/lib/transport/chttp2/frame.h" |
| 44 | #include "src/core/lib/transport/chttp2/http2_errors.h" |
| 45 | #include "src/core/lib/transport/chttp2_transport.h" |
Craig Tiller | 5c3a110 | 2015-12-02 16:13:24 -0800 | [diff] [blame] | 46 | |
Craig Tiller | 620e965 | 2015-12-14 12:02:50 -0800 | [diff] [blame] | 47 | #define MAX_MAX_HEADER_LIST_SIZE (1024 * 1024 * 1024) |
Craig Tiller | 9ee2eec | 2015-12-08 10:28:33 -0800 | [diff] [blame] | 48 | |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 49 | /* HTTP/2 mandated initial connection settings */ |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 50 | const grpc_chttp2_setting_parameters |
| 51 | grpc_chttp2_settings_parameters[GRPC_CHTTP2_NUM_SETTINGS] = { |
Craig Tiller | 5c3a110 | 2015-12-02 16:13:24 -0800 | [diff] [blame] | 52 | {NULL, 0, 0, 0, GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, |
| 53 | GRPC_CHTTP2_PROTOCOL_ERROR}, |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 54 | {"HEADER_TABLE_SIZE", 4096, 0, 0xffffffff, |
Craig Tiller | 5c3a110 | 2015-12-02 16:13:24 -0800 | [diff] [blame] | 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}, |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 58 | {"MAX_CONCURRENT_STREAMS", 0xffffffffu, 0, 0xffffffffu, |
Craig Tiller | 5c3a110 | 2015-12-02 16:13:24 -0800 | [diff] [blame] | 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}, |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 63 | {"MAX_FRAME_SIZE", 16384, 16384, 16777215, |
Craig Tiller | 5c3a110 | 2015-12-02 16:13:24 -0800 | [diff] [blame] | 64 | GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE, GRPC_CHTTP2_PROTOCOL_ERROR}, |
Craig Tiller | 620e965 | 2015-12-14 12:02:50 -0800 | [diff] [blame] | 65 | {"MAX_HEADER_LIST_SIZE", MAX_MAX_HEADER_LIST_SIZE, 0, |
| 66 | MAX_MAX_HEADER_LIST_SIZE, GRPC_CHTTP2_CLAMP_INVALID_VALUE, |
| 67 | GRPC_CHTTP2_PROTOCOL_ERROR}, |
Craig Tiller | 5c6f21e | 2015-02-24 17:16:14 -0800 | [diff] [blame] | 68 | }; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 69 | |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 70 | static uint8_t *fill_header(uint8_t *out, uint32_t length, uint8_t flags) { |
| 71 | *out++ = (uint8_t)(length >> 16); |
| 72 | *out++ = (uint8_t)(length >> 8); |
| 73 | *out++ = (uint8_t)(length); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 74 | *out++ = GRPC_CHTTP2_FRAME_SETTINGS; |
| 75 | *out++ = flags; |
| 76 | *out++ = 0; |
| 77 | *out++ = 0; |
| 78 | *out++ = 0; |
| 79 | *out++ = 0; |
| 80 | return out; |
| 81 | } |
| 82 | |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 83 | gpr_slice grpc_chttp2_settings_create(uint32_t *old, const uint32_t *new, |
| 84 | uint32_t force_mask, size_t count) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 85 | size_t i; |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 86 | uint32_t n = 0; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 87 | gpr_slice output; |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 88 | uint8_t *p; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 89 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 90 | for (i = 0; i < count; i++) { |
| 91 | n += (new[i] != old[i] || (force_mask & (1u << i)) != 0); |
| 92 | } |
| 93 | |
| 94 | output = gpr_slice_malloc(9 + 6 * n); |
| 95 | p = fill_header(GPR_SLICE_START_PTR(output), 6 * n, 0); |
| 96 | |
| 97 | for (i = 0; i < count; i++) { |
| 98 | if (new[i] != old[i] || (force_mask & (1u << i)) != 0) { |
| 99 | GPR_ASSERT(i); |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 100 | *p++ = (uint8_t)(i >> 8); |
| 101 | *p++ = (uint8_t)(i); |
| 102 | *p++ = (uint8_t)(new[i] >> 24); |
| 103 | *p++ = (uint8_t)(new[i] >> 16); |
| 104 | *p++ = (uint8_t)(new[i] >> 8); |
| 105 | *p++ = (uint8_t)(new[i]); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 106 | old[i] = new[i]; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 107 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 108 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 109 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 110 | GPR_ASSERT(p == GPR_SLICE_END_PTR(output)); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 111 | |
| 112 | return output; |
| 113 | } |
| 114 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 115 | gpr_slice grpc_chttp2_settings_ack_create(void) { |
| 116 | gpr_slice output = gpr_slice_malloc(9); |
| 117 | fill_header(GPR_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 118 | return output; |
| 119 | } |
| 120 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 121 | grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame( |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 122 | grpc_chttp2_settings_parser *parser, uint32_t length, uint8_t flags, |
| 123 | uint32_t *settings) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 124 | parser->target_settings = settings; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 125 | memcpy(parser->incoming_settings, settings, |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 126 | GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 127 | parser->is_ack = 0; |
| 128 | parser->state = GRPC_CHTTP2_SPS_ID0; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 129 | if (flags == GRPC_CHTTP2_FLAG_ACK) { |
| 130 | parser->is_ack = 1; |
| 131 | if (length != 0) { |
| 132 | gpr_log(GPR_ERROR, "non-empty settings ack frame received"); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 133 | return GRPC_CHTTP2_CONNECTION_ERROR; |
| 134 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 135 | return GRPC_CHTTP2_PARSE_OK; |
| 136 | } else if (flags != 0) { |
| 137 | gpr_log(GPR_ERROR, "invalid flags on settings frame"); |
| 138 | return GRPC_CHTTP2_CONNECTION_ERROR; |
| 139 | } else if (length % 6 != 0) { |
| 140 | gpr_log(GPR_ERROR, "settings frames must be a multiple of six bytes"); |
| 141 | return GRPC_CHTTP2_CONNECTION_ERROR; |
| 142 | } else { |
| 143 | return GRPC_CHTTP2_PARSE_OK; |
| 144 | } |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 145 | } |
| 146 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 147 | 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) { |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 151 | grpc_chttp2_settings_parser *parser = p; |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 152 | const uint8_t *cur = GPR_SLICE_START_PTR(slice); |
| 153 | const uint8_t *end = GPR_SLICE_END_PTR(slice); |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 154 | |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 155 | if (parser->is_ack) { |
| 156 | return GRPC_CHTTP2_PARSE_OK; |
| 157 | } |
| 158 | |
| 159 | for (;;) { |
| 160 | switch (parser->state) { |
| 161 | case GRPC_CHTTP2_SPS_ID0: |
| 162 | if (cur == end) { |
| 163 | parser->state = GRPC_CHTTP2_SPS_ID0; |
| 164 | if (is_last) { |
| 165 | transport_parsing->settings_updated = 1; |
| 166 | memcpy(parser->target_settings, parser->incoming_settings, |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 167 | GRPC_CHTTP2_NUM_SETTINGS * sizeof(uint32_t)); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 168 | gpr_slice_buffer_add(&transport_parsing->qbuf, |
| 169 | grpc_chttp2_settings_ack_create()); |
| 170 | } |
| 171 | return GRPC_CHTTP2_PARSE_OK; |
| 172 | } |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 173 | parser->id = (uint16_t)(((uint16_t)*cur) << 8); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 174 | cur++; |
| 175 | /* fallthrough */ |
| 176 | case GRPC_CHTTP2_SPS_ID1: |
| 177 | if (cur == end) { |
| 178 | parser->state = GRPC_CHTTP2_SPS_ID1; |
| 179 | return GRPC_CHTTP2_PARSE_OK; |
| 180 | } |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 181 | parser->id = (uint16_t)(parser->id | (*cur)); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 182 | cur++; |
| 183 | /* fallthrough */ |
| 184 | case GRPC_CHTTP2_SPS_VAL0: |
| 185 | if (cur == end) { |
| 186 | parser->state = GRPC_CHTTP2_SPS_VAL0; |
| 187 | return GRPC_CHTTP2_PARSE_OK; |
| 188 | } |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 189 | parser->value = ((uint32_t)*cur) << 24; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 190 | cur++; |
| 191 | /* fallthrough */ |
| 192 | case GRPC_CHTTP2_SPS_VAL1: |
| 193 | if (cur == end) { |
| 194 | parser->state = GRPC_CHTTP2_SPS_VAL1; |
| 195 | return GRPC_CHTTP2_PARSE_OK; |
| 196 | } |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 197 | parser->value |= ((uint32_t)*cur) << 16; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 198 | cur++; |
| 199 | /* fallthrough */ |
| 200 | case GRPC_CHTTP2_SPS_VAL2: |
| 201 | if (cur == end) { |
| 202 | parser->state = GRPC_CHTTP2_SPS_VAL2; |
| 203 | return GRPC_CHTTP2_PARSE_OK; |
| 204 | } |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 205 | parser->value |= ((uint32_t)*cur) << 8; |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 206 | cur++; |
| 207 | /* fallthrough */ |
| 208 | case GRPC_CHTTP2_SPS_VAL3: |
| 209 | if (cur == end) { |
| 210 | parser->state = GRPC_CHTTP2_SPS_VAL3; |
| 211 | return GRPC_CHTTP2_PARSE_OK; |
| 212 | } else { |
| 213 | parser->state = GRPC_CHTTP2_SPS_ID0; |
| 214 | } |
| 215 | parser->value |= *cur; |
| 216 | cur++; |
| 217 | |
| 218 | if (parser->id > 0 && parser->id < GRPC_CHTTP2_NUM_SETTINGS) { |
| 219 | const grpc_chttp2_setting_parameters *sp = |
| 220 | &grpc_chttp2_settings_parameters[parser->id]; |
| 221 | if (parser->value < sp->min_value || parser->value > sp->max_value) { |
| 222 | switch (sp->invalid_value_behavior) { |
| 223 | case GRPC_CHTTP2_CLAMP_INVALID_VALUE: |
| 224 | parser->value = |
| 225 | GPR_CLAMP(parser->value, sp->min_value, sp->max_value); |
| 226 | break; |
| 227 | case GRPC_CHTTP2_DISCONNECT_ON_INVALID_VALUE: |
Craig Tiller | 5c3a110 | 2015-12-02 16:13:24 -0800 | [diff] [blame] | 228 | 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); |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 232 | gpr_log(GPR_ERROR, "invalid value %u passed for %s", |
| 233 | parser->value, sp->name); |
| 234 | return GRPC_CHTTP2_CONNECTION_ERROR; |
| 235 | } |
| 236 | } |
| 237 | if (parser->id == GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE && |
| 238 | parser->incoming_settings[parser->id] != parser->value) { |
| 239 | transport_parsing->initial_window_update = |
Craig Tiller | 7536af0 | 2015-12-22 13:49:30 -0800 | [diff] [blame] | 240 | (int64_t)parser->value - parser->incoming_settings[parser->id]; |
yang-g | 575625c | 2015-12-17 13:58:24 -0800 | [diff] [blame] | 241 | if (grpc_http_trace) { |
| 242 | gpr_log(GPR_DEBUG, "adding %d for initial_window change", |
| 243 | (int)transport_parsing->initial_window_update); |
| 244 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 245 | } |
| 246 | parser->incoming_settings[parser->id] = parser->value; |
| 247 | if (grpc_http_trace) { |
| 248 | gpr_log(GPR_DEBUG, "CHTTP2:%s: got setting %d = %d", |
| 249 | transport_parsing->is_client ? "CLI" : "SVR", parser->id, |
| 250 | parser->value); |
| 251 | } |
| 252 | } else { |
| 253 | gpr_log(GPR_ERROR, "CHTTP2: Ignoring unknown setting %d (value %d)", |
| 254 | parser->id, parser->value); |
| 255 | } |
| 256 | break; |
Nicolas Noble | b7ebd3b | 2014-11-26 16:33:03 -0800 | [diff] [blame] | 257 | } |
Craig Tiller | a82950e | 2015-09-22 12:33:20 -0700 | [diff] [blame] | 258 | } |
Craig Tiller | 190d360 | 2015-02-18 09:23:38 -0800 | [diff] [blame] | 259 | } |