1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include "src/core/ext/transport/chttp2/transport/frame_settings.h"
20
21 #include <grpc/slice_buffer.h>
22 #include <grpc/support/port_platform.h>
23 #include <string.h>
24
25 #include <string>
26
27 #include "absl/base/attributes.h"
28 #include "absl/log/log.h"
29 #include "absl/status/status.h"
30 #include "absl/strings/str_format.h"
31 #include "src/core/ext/transport/chttp2/transport/flow_control.h"
32 #include "src/core/ext/transport/chttp2/transport/frame_goaway.h"
33 #include "src/core/ext/transport/chttp2/transport/http2_settings.h"
34 #include "src/core/ext/transport/chttp2/transport/internal.h"
35 #include "src/core/ext/transport/chttp2/transport/legacy_frame.h"
36 #include "src/core/lib/debug/trace.h"
37 #include "src/core/lib/iomgr/exec_ctx.h"
38 #include "src/core/lib/slice/slice.h"
39 #include "src/core/telemetry/stats.h"
40 #include "src/core/util/debug_location.h"
41 #include "src/core/util/useful.h"
42
fill_header(uint8_t * out,uint32_t length,uint8_t flags)43 static uint8_t* fill_header(uint8_t* out, uint32_t length, uint8_t flags) {
44 *out++ = static_cast<uint8_t>(length >> 16);
45 *out++ = static_cast<uint8_t>(length >> 8);
46 *out++ = static_cast<uint8_t>(length);
47 *out++ = GRPC_CHTTP2_FRAME_SETTINGS;
48 *out++ = flags;
49 *out++ = 0;
50 *out++ = 0;
51 *out++ = 0;
52 *out++ = 0;
53 return out;
54 }
55
grpc_chttp2_settings_ack_create(void)56 grpc_slice grpc_chttp2_settings_ack_create(void) {
57 grpc_slice output = GRPC_SLICE_MALLOC(9);
58 fill_header(GRPC_SLICE_START_PTR(output), 0, GRPC_CHTTP2_FLAG_ACK);
59 return output;
60 }
61
grpc_chttp2_settings_parser_begin_frame(grpc_chttp2_settings_parser * parser,uint32_t length,uint8_t flags,grpc_core::Http2Settings & settings)62 grpc_error_handle grpc_chttp2_settings_parser_begin_frame(
63 grpc_chttp2_settings_parser* parser, uint32_t length, uint8_t flags,
64 grpc_core::Http2Settings& settings) {
65 parser->target_settings = &settings;
66 parser->incoming_settings.Init(settings);
67 parser->is_ack = 0;
68 parser->state = GRPC_CHTTP2_SPS_ID0;
69 if (flags == GRPC_CHTTP2_FLAG_ACK) {
70 parser->is_ack = 1;
71 if (length != 0) {
72 return GRPC_ERROR_CREATE("non-empty settings ack frame received");
73 }
74 return absl::OkStatus();
75 } else if (flags != 0) {
76 return GRPC_ERROR_CREATE("invalid flags on settings frame");
77 } else if (length % 6 != 0) {
78 return GRPC_ERROR_CREATE("settings frames must be a multiple of six bytes");
79 } else {
80 return absl::OkStatus();
81 }
82 }
83
grpc_chttp2_settings_parser_parse(void * p,grpc_chttp2_transport * t,grpc_chttp2_stream *,const grpc_slice & slice,int is_last)84 grpc_error_handle grpc_chttp2_settings_parser_parse(void* p,
85 grpc_chttp2_transport* t,
86 grpc_chttp2_stream* /*s*/,
87 const grpc_slice& slice,
88 int is_last) {
89 grpc_chttp2_settings_parser* parser =
90 static_cast<grpc_chttp2_settings_parser*>(p);
91 const uint8_t* cur = GRPC_SLICE_START_PTR(slice);
92 const uint8_t* end = GRPC_SLICE_END_PTR(slice);
93
94 if (parser->is_ack) {
95 return absl::OkStatus();
96 }
97
98 for (;;) {
99 switch (parser->state) {
100 case GRPC_CHTTP2_SPS_ID0:
101 if (cur == end) {
102 parser->state = GRPC_CHTTP2_SPS_ID0;
103 if (is_last) {
104 grpc_core::Http2Settings* target_settings =
105 parser->incoming_settings.get();
106 grpc_core::global_stats().IncrementHttp2HeaderTableSize(
107 target_settings->header_table_size());
108 grpc_core::global_stats().IncrementHttp2InitialWindowSize(
109 target_settings->initial_window_size());
110 grpc_core::global_stats().IncrementHttp2MaxConcurrentStreams(
111 target_settings->max_concurrent_streams());
112 grpc_core::global_stats().IncrementHttp2MaxFrameSize(
113 target_settings->max_frame_size());
114 grpc_core::global_stats().IncrementHttp2MaxHeaderListSize(
115 target_settings->max_header_list_size());
116 grpc_core::global_stats()
117 .IncrementHttp2PreferredReceiveCryptoMessageSize(
118 target_settings->preferred_receive_crypto_message_size());
119 *parser->target_settings = *parser->incoming_settings;
120 t->num_pending_induced_frames++;
121 grpc_slice_buffer_add(&t->qbuf, grpc_chttp2_settings_ack_create());
122 grpc_chttp2_initiate_write(t,
123 GRPC_CHTTP2_INITIATE_WRITE_SETTINGS_ACK);
124 if (t->notify_on_receive_settings != nullptr) {
125 if (t->interested_parties_until_recv_settings != nullptr) {
126 grpc_endpoint_delete_from_pollset_set(
127 t->ep.get(), t->interested_parties_until_recv_settings);
128 t->interested_parties_until_recv_settings = nullptr;
129 }
130 grpc_core::ExecCtx::Run(DEBUG_LOCATION,
131 t->notify_on_receive_settings,
132 absl::OkStatus());
133 t->notify_on_receive_settings = nullptr;
134 }
135 }
136 return absl::OkStatus();
137 }
138 parser->id = static_cast<uint16_t>((static_cast<uint16_t>(*cur)) << 8);
139 cur++;
140 ABSL_FALLTHROUGH_INTENDED;
141 case GRPC_CHTTP2_SPS_ID1:
142 if (cur == end) {
143 parser->state = GRPC_CHTTP2_SPS_ID1;
144 return absl::OkStatus();
145 }
146 parser->id = static_cast<uint16_t>(parser->id | (*cur));
147 cur++;
148 ABSL_FALLTHROUGH_INTENDED;
149 case GRPC_CHTTP2_SPS_VAL0:
150 if (cur == end) {
151 parser->state = GRPC_CHTTP2_SPS_VAL0;
152 return absl::OkStatus();
153 }
154 parser->value = (static_cast<uint32_t>(*cur)) << 24;
155 cur++;
156 ABSL_FALLTHROUGH_INTENDED;
157 case GRPC_CHTTP2_SPS_VAL1:
158 if (cur == end) {
159 parser->state = GRPC_CHTTP2_SPS_VAL1;
160 return absl::OkStatus();
161 }
162 parser->value |= (static_cast<uint32_t>(*cur)) << 16;
163 cur++;
164 ABSL_FALLTHROUGH_INTENDED;
165 case GRPC_CHTTP2_SPS_VAL2:
166 if (cur == end) {
167 parser->state = GRPC_CHTTP2_SPS_VAL2;
168 return absl::OkStatus();
169 }
170 parser->value |= (static_cast<uint32_t>(*cur)) << 8;
171 cur++;
172 ABSL_FALLTHROUGH_INTENDED;
173 case GRPC_CHTTP2_SPS_VAL3: {
174 if (cur == end) {
175 parser->state = GRPC_CHTTP2_SPS_VAL3;
176 return absl::OkStatus();
177 } else {
178 parser->state = GRPC_CHTTP2_SPS_ID0;
179 }
180 parser->value |= *cur;
181 cur++;
182
183 if (parser->id == grpc_core::Http2Settings::kInitialWindowSizeWireId) {
184 t->initial_window_update +=
185 static_cast<int64_t>(parser->value) -
186 parser->incoming_settings->initial_window_size();
187 if (GRPC_TRACE_FLAG_ENABLED(http) ||
188 GRPC_TRACE_FLAG_ENABLED(flowctl)) {
189 LOG(INFO) << t << "[" << (t->is_client ? "cli" : "svr")
190 << "] adding " << t->initial_window_update
191 << " for initial_window change";
192 }
193 }
194 auto error =
195 parser->incoming_settings->Apply(parser->id, parser->value);
196 if (error != GRPC_HTTP2_NO_ERROR) {
197 grpc_chttp2_goaway_append(
198 t->last_new_stream_id, error,
199 grpc_slice_from_static_string("HTTP2 settings error"), &t->qbuf);
200 return GRPC_ERROR_CREATE(absl::StrFormat(
201 "invalid value %u passed for %s", parser->value,
202 grpc_core::Http2Settings::WireIdToName(parser->id).c_str()));
203 }
204 GRPC_TRACE_LOG(http, INFO)
205 << "CHTTP2:" << (t->is_client ? "CLI" : "SVR") << ":"
206 << t->peer_string.as_string_view() << ": got setting "
207 << grpc_core::Http2Settings::WireIdToName(parser->id) << " = "
208 << parser->value;
209 } break;
210 }
211 }
212 }
213