1 /** @file
2  *
3  *  Fundamental HTTP/2 protocol definitions and parsers.
4  *
5  *  @section license License
6  *
7  *  Licensed to the Apache Software Foundation (ASF) under one
8  *  or more contributor license agreements.  See the NOTICE file
9  *  distributed with this work for additional information
10  *  regarding copyright ownership.  The ASF licenses this file
11  *  to you under the Apache License, Version 2.0 (the
12  *  "License"); you may not use this file except in compliance
13  *  with the License.  You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  *  Unless required by applicable law or agreed to in writing, software
18  *  distributed under the License is distributed on an "AS IS" BASIS,
19  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  *  See the License for the specific language governing permissions and
21  *  limitations under the License.
22  */
23 
24 #pragma once
25 
26 #include "tscore/ink_defs.h"
27 #include "tscore/ink_memory.h"
28 #include "HPACK.h"
29 #include "MIME.h"
30 #include "records/P_RecDefs.h"
31 
32 class HTTPHdr;
33 
34 typedef unsigned Http2StreamId;
35 
36 constexpr Http2StreamId HTTP2_CONNECTION_CONTROL_STRTEAM = 0;
37 constexpr uint8_t HTTP2_FRAME_NO_FLAG                    = 0;
38 
39 // [RFC 7540] 6.9.2. Initial Flow Control Window Size
40 // the flow control window can be come negative so we need to track it with a signed type.
41 typedef int32_t Http2WindowSize;
42 
43 extern const char *const HTTP2_CONNECTION_PREFACE;
44 const size_t HTTP2_CONNECTION_PREFACE_LEN = 24;
45 
46 extern const char *HTTP2_VALUE_SCHEME;
47 extern const char *HTTP2_VALUE_METHOD;
48 extern const char *HTTP2_VALUE_AUTHORITY;
49 extern const char *HTTP2_VALUE_PATH;
50 extern const char *HTTP2_VALUE_STATUS;
51 
52 extern const unsigned HTTP2_LEN_SCHEME;
53 extern const unsigned HTTP2_LEN_METHOD;
54 extern const unsigned HTTP2_LEN_AUTHORITY;
55 extern const unsigned HTTP2_LEN_PATH;
56 extern const unsigned HTTP2_LEN_STATUS;
57 
58 const size_t HTTP2_FRAME_HEADER_LEN       = 9;
59 const size_t HTTP2_DATA_PADLEN_LEN        = 1;
60 const size_t HTTP2_HEADERS_PADLEN_LEN     = 1;
61 const size_t HTTP2_PRIORITY_LEN           = 5;
62 const size_t HTTP2_RST_STREAM_LEN         = 4;
63 const size_t HTTP2_PING_LEN               = 8;
64 const size_t HTTP2_GOAWAY_LEN             = 8;
65 const size_t HTTP2_WINDOW_UPDATE_LEN      = 4;
66 const size_t HTTP2_SETTINGS_PARAMETER_LEN = 6;
67 
68 // SETTINGS initial values. NOTE: These should not be modified
69 // unless the protocol changes! Do not change this thinking you
70 // are changing server defaults. that is done via RecordsConfig.cc
71 const uint32_t HTTP2_ENABLE_PUSH            = 1;
72 const uint32_t HTTP2_MAX_CONCURRENT_STREAMS = UINT_MAX;
73 const uint32_t HTTP2_INITIAL_WINDOW_SIZE    = 65535;
74 const uint32_t HTTP2_MAX_FRAME_SIZE         = 16384;
75 const uint32_t HTTP2_HEADER_TABLE_SIZE      = 4096;
76 const uint32_t HTTP2_MAX_HEADER_LIST_SIZE   = UINT_MAX;
77 const uint32_t HTTP2_MAX_BUFFER_USAGE       = 524288;
78 
79 // [RFC 7540] 5.3.5 Default Priorities
80 // The RFC says weight value is 1 to 256, but the value in TS is between 0 to 255
81 // to use uint8_t. So the default weight is 16 minus 1.
82 const uint32_t HTTP2_PRIORITY_DEFAULT_STREAM_DEPENDENCY = 0;
83 const uint8_t HTTP2_PRIORITY_DEFAULT_WEIGHT             = 15;
84 
85 // Statistics
86 enum {
87   HTTP2_STAT_CURRENT_CLIENT_SESSION_COUNT,           // Current # of HTTP2 connections
88   HTTP2_STAT_CURRENT_ACTIVE_CLIENT_CONNECTION_COUNT, // Current # of active HTTP2 connections
89   HTTP2_STAT_CURRENT_CLIENT_STREAM_COUNT,            // Current # of active HTTP2 streams
90   HTTP2_STAT_TOTAL_CLIENT_STREAM_COUNT,
91   HTTP2_STAT_TOTAL_TRANSACTIONS_TIME,       // Total stream time and streams
92   HTTP2_STAT_TOTAL_CLIENT_CONNECTION_COUNT, // Total connections running http2
93   HTTP2_STAT_STREAM_ERRORS_COUNT,
94   HTTP2_STAT_CONNECTION_ERRORS_COUNT,
95   HTTP2_STAT_SESSION_DIE_DEFAULT,
96   HTTP2_STAT_SESSION_DIE_OTHER,
97   HTTP2_STAT_SESSION_DIE_ACTIVE,
98   HTTP2_STAT_SESSION_DIE_INACTIVE,
99   HTTP2_STAT_SESSION_DIE_EOS,
100   HTTP2_STAT_SESSION_DIE_ERROR,
101   HTTP2_STAT_SESSION_DIE_HIGH_ERROR_RATE,
102   HTTP2_STAT_MAX_SETTINGS_PER_FRAME_EXCEEDED,
103   HTTP2_STAT_MAX_SETTINGS_PER_MINUTE_EXCEEDED,
104   HTTP2_STAT_MAX_SETTINGS_FRAMES_PER_MINUTE_EXCEEDED,
105   HTTP2_STAT_MAX_PING_FRAMES_PER_MINUTE_EXCEEDED,
106   HTTP2_STAT_MAX_PRIORITY_FRAMES_PER_MINUTE_EXCEEDED,
107   HTTP2_STAT_INSUFFICIENT_AVG_WINDOW_UPDATE,
108 
109   HTTP2_N_STATS // Terminal counter, NOT A STAT INDEX.
110 };
111 
112 #define HTTP2_INCREMENT_THREAD_DYN_STAT(_s, _t) RecIncrRawStat(http2_rsb, _t, (int)_s, 1);
113 #define HTTP2_DECREMENT_THREAD_DYN_STAT(_s, _t) RecIncrRawStat(http2_rsb, _t, (int)_s, -1);
114 #define HTTP2_SUM_THREAD_DYN_STAT(_s, _t, _v) RecIncrRawStat(http2_rsb, _t, (int)_s, _v);
115 extern RecRawStatBlock *http2_rsb; // Container for statistics.
116 
117 // [RFC 7540] 6.9.1. The Flow Control Window
118 static const Http2WindowSize HTTP2_MAX_WINDOW_SIZE = 0x7FFFFFFF;
119 
120 // [RFC 7540] 5.4. Error Handling
121 enum class Http2ErrorClass {
122   HTTP2_ERROR_CLASS_NONE,
123   HTTP2_ERROR_CLASS_CONNECTION,
124   HTTP2_ERROR_CLASS_STREAM,
125 };
126 
127 // [RFC 7540] 7. Error Codes
128 enum class Http2ErrorCode {
129   HTTP2_ERROR_NO_ERROR            = 0,
130   HTTP2_ERROR_PROTOCOL_ERROR      = 1,
131   HTTP2_ERROR_INTERNAL_ERROR      = 2,
132   HTTP2_ERROR_FLOW_CONTROL_ERROR  = 3,
133   HTTP2_ERROR_SETTINGS_TIMEOUT    = 4,
134   HTTP2_ERROR_STREAM_CLOSED       = 5,
135   HTTP2_ERROR_FRAME_SIZE_ERROR    = 6,
136   HTTP2_ERROR_REFUSED_STREAM      = 7,
137   HTTP2_ERROR_CANCEL              = 8,
138   HTTP2_ERROR_COMPRESSION_ERROR   = 9,
139   HTTP2_ERROR_CONNECT_ERROR       = 10,
140   HTTP2_ERROR_ENHANCE_YOUR_CALM   = 11,
141   HTTP2_ERROR_INADEQUATE_SECURITY = 12,
142   HTTP2_ERROR_HTTP_1_1_REQUIRED   = 13,
143 
144   HTTP2_ERROR_MAX,
145 };
146 
147 // [RFC 7540] 5.1. Stream States
148 enum class Http2StreamState {
149   HTTP2_STREAM_STATE_IDLE,
150   HTTP2_STREAM_STATE_RESERVED_LOCAL,
151   HTTP2_STREAM_STATE_RESERVED_REMOTE,
152   HTTP2_STREAM_STATE_OPEN,
153   HTTP2_STREAM_STATE_HALF_CLOSED_LOCAL,
154   HTTP2_STREAM_STATE_HALF_CLOSED_REMOTE,
155   HTTP2_STREAM_STATE_CLOSED
156 };
157 
158 enum Http2FrameType {
159   HTTP2_FRAME_TYPE_DATA          = 0,
160   HTTP2_FRAME_TYPE_HEADERS       = 1,
161   HTTP2_FRAME_TYPE_PRIORITY      = 2,
162   HTTP2_FRAME_TYPE_RST_STREAM    = 3,
163   HTTP2_FRAME_TYPE_SETTINGS      = 4,
164   HTTP2_FRAME_TYPE_PUSH_PROMISE  = 5,
165   HTTP2_FRAME_TYPE_PING          = 6,
166   HTTP2_FRAME_TYPE_GOAWAY        = 7,
167   HTTP2_FRAME_TYPE_WINDOW_UPDATE = 8,
168   HTTP2_FRAME_TYPE_CONTINUATION  = 9,
169 
170   HTTP2_FRAME_TYPE_MAX,
171 };
172 
173 // [RFC 7540] 6.1. Data
174 enum Http2FrameFlagsData {
175   HTTP2_FLAGS_DATA_END_STREAM = 0x01,
176   HTTP2_FLAGS_DATA_PADDED     = 0x08,
177 
178   HTTP2_FLAGS_DATA_MASK = 0x09,
179 };
180 
181 // [RFC 7540] 6.2. Headers
182 enum Http2FrameFlagsHeaders {
183   HTTP2_FLAGS_HEADERS_END_STREAM  = 0x01,
184   HTTP2_FLAGS_HEADERS_END_HEADERS = 0x04,
185   HTTP2_FLAGS_HEADERS_PADDED      = 0x08,
186   HTTP2_FLAGS_HEADERS_PRIORITY    = 0x20,
187 
188   HTTP2_FLAGS_HEADERS_MASK = 0x2D,
189 };
190 
191 // [RFC 7540] 6.3. Priority
192 enum Http2FrameFlagsPriority {
193   HTTP2_FLAGS_PRIORITY_MASK = 0x00,
194 };
195 
196 // [RFC 7540] 6.4. Rst Stream
197 enum Http2FrameFlagsRstStream {
198   HTTP2_FLAGS_RST_STREAM_MASK = 0x00,
199 };
200 
201 // [RFC 7540] 6.5. Settings
202 enum Http2FrameFlagsSettings {
203   HTTP2_FLAGS_SETTINGS_ACK = 0x01,
204 
205   HTTP2_FLAGS_SETTINGS_MASK = 0x01
206 };
207 
208 // [RFC 7540] 6.6. Push Promise
209 enum Http2FrameFlagsPushPromise {
210   HTTP2_FLAGS_PUSH_PROMISE_END_HEADERS = 0x04,
211   HTTP2_FLAGS_PUSH_PROMISE_PADDED      = 0x08,
212 
213   HTTP2_FLAGS_PUSH_PROMISE_MASK = 0x0C,
214 };
215 
216 // [RFC 7540] 6.7. Ping
217 enum Http2FrameFlagsPing {
218   HTTP2_FLAGS_PING_ACK = 0x01,
219 
220   HTTP2_FLAGS_PING_MASK = 0x01
221 };
222 
223 // [RFC 7540] 6.8. Goaway
224 enum Http2FrameFlagsGoaway {
225   HTTP2_FLAGS_GOAWAY_MASK = 0x00,
226 };
227 
228 // [RFC 7540] 6.9. Window Update
229 enum Http2FrameFlagsWindowUpdate {
230   HTTP2_FLAGS_WINDOW_UPDATE_MASK = 0x00,
231 };
232 
233 // [RFC 7540] 6.10. Continuation
234 enum Http2FrameFlagsContinuation {
235   HTTP2_FLAGS_CONTINUATION_END_HEADERS = 0x04,
236 
237   HTTP2_FLAGS_CONTINUATION_MASK = 0x04,
238 };
239 
240 // [RFC 7540] 6.5.2. Defined SETTINGS Parameters
241 enum Http2SettingsIdentifier {
242   HTTP2_SETTINGS_HEADER_TABLE_SIZE      = 1,
243   HTTP2_SETTINGS_ENABLE_PUSH            = 2,
244   HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 3,
245   HTTP2_SETTINGS_INITIAL_WINDOW_SIZE    = 4,
246   HTTP2_SETTINGS_MAX_FRAME_SIZE         = 5,
247   HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE   = 6,
248 
249   HTTP2_SETTINGS_MAX
250 };
251 
252 // [RFC 7540] 4.1. Frame Format
253 struct Http2FrameHeader {
254   uint32_t length;
255   uint8_t type;
256   uint8_t flags;
257   Http2StreamId streamid;
258 };
259 
260 // [RFC 7540] 5.4. Error Handling
261 struct Http2Error {
262   Http2Error(const Http2ErrorClass error_class = Http2ErrorClass::HTTP2_ERROR_CLASS_NONE,
263              const Http2ErrorCode error_code = Http2ErrorCode::HTTP2_ERROR_NO_ERROR, const char *err_msg = "")
264   {
265     cls  = error_class;
266     code = error_code;
267     msg  = err_msg;
268   };
269 
270   Http2ErrorClass cls;
271   Http2ErrorCode code;
272   const char *msg;
273 };
274 
275 // [RFC 7540] 6.5.1. SETTINGS Format
276 struct Http2SettingsParameter {
277   uint16_t id;
278   uint32_t value;
279 };
280 
281 // [RFC 7540] 6.3 PRIORITY Format
282 struct Http2Priority {
Http2PriorityHttp2Priority283   Http2Priority() : weight(HTTP2_PRIORITY_DEFAULT_WEIGHT), stream_dependency(HTTP2_PRIORITY_DEFAULT_STREAM_DEPENDENCY) {}
284 
285   bool exclusive_flag = false;
286   uint8_t weight;
287   uint32_t stream_dependency;
288 };
289 
290 // [RFC 7540] 6.2 HEADERS Format
291 struct Http2HeadersParameter {
Http2HeadersParameterHttp2HeadersParameter292   Http2HeadersParameter() {}
293   uint8_t pad_length = 0;
294   Http2Priority priority;
295 };
296 
297 // [RFC 7540] 6.8 GOAWAY Format
298 struct Http2Goaway {
Http2GoawayHttp2Goaway299   Http2Goaway() {}
300   Http2StreamId last_streamid = 0;
301   Http2ErrorCode error_code   = Http2ErrorCode::HTTP2_ERROR_NO_ERROR;
302 
303   // NOTE: we don't (de)serialize the variable length debug data at this layer
304   // because there's
305   // really nothing we can do with it without some out of band agreement. Trying
306   // to deal with it
307   // just complicates memory management.
308 };
309 
310 // [RFC 7540] 6.4 RST_STREAM Format
311 struct Http2RstStream {
312   uint32_t error_code;
313 };
314 
315 // [RFC 7540] 6.6 PUSH_PROMISE Format
316 struct Http2PushPromise {
317   uint8_t pad_length              = 0;
318   Http2StreamId promised_streamid = 0;
319 };
320 
321 static inline bool
http2_is_client_streamid(Http2StreamId streamid)322 http2_is_client_streamid(Http2StreamId streamid)
323 {
324   return (streamid & 0x1u) == 0x1u;
325 }
326 
327 static inline bool
http2_is_server_streamid(Http2StreamId streamid)328 http2_is_server_streamid(Http2StreamId streamid)
329 {
330   return (streamid & 0x1u) == 0x0u && streamid != 0x0u;
331 }
332 
333 bool http2_parse_frame_header(IOVec, Http2FrameHeader &);
334 
335 bool http2_write_frame_header(const Http2FrameHeader &, IOVec);
336 
337 bool http2_write_rst_stream(uint32_t, IOVec);
338 
339 bool http2_write_settings(const Http2SettingsParameter &, const IOVec &);
340 
341 bool http2_write_ping(const uint8_t *, IOVec);
342 
343 bool http2_write_goaway(const Http2Goaway &, IOVec);
344 
345 bool http2_write_window_update(const uint32_t new_size, const IOVec &);
346 
347 bool http2_write_push_promise(const Http2PushPromise &push_promise, const uint8_t *src, size_t length, const IOVec &iov);
348 
349 bool http2_frame_header_is_valid(const Http2FrameHeader &, unsigned);
350 
351 bool http2_settings_parameter_is_valid(const Http2SettingsParameter &);
352 
353 bool http2_parse_headers_parameter(IOVec, Http2HeadersParameter &);
354 
355 bool http2_parse_priority_parameter(IOVec, Http2Priority &);
356 
357 bool http2_parse_rst_stream(IOVec, Http2RstStream &);
358 
359 bool http2_parse_settings_parameter(IOVec, Http2SettingsParameter &);
360 
361 bool http2_parse_goaway(IOVec, Http2Goaway &);
362 
363 bool http2_parse_window_update(IOVec, uint32_t &);
364 
365 Http2ErrorCode http2_decode_header_blocks(HTTPHdr *, const uint8_t *, const uint32_t, uint32_t *, HpackHandle &, bool &, uint32_t);
366 
367 Http2ErrorCode http2_encode_header_blocks(HTTPHdr *, uint8_t *, uint32_t, uint32_t *, HpackHandle &, int32_t);
368 
369 ParseResult http2_convert_header_from_2_to_1_1(HTTPHdr *);
370 ParseResult http2_convert_header_from_1_1_to_2(HTTPHdr *);
371 void http2_init_pseudo_headers(HTTPHdr &);
372 void http2_init();
373 
374 // Not sure where else to put this, but figure this is as good of a start as
375 // anything else.
376 // Right now, only the static init() is available, which sets up some basic
377 // librecords
378 // dependencies.
379 class Http2
380 {
381 public:
382   static uint32_t max_concurrent_streams_in;
383   static uint32_t min_concurrent_streams_in;
384   static uint32_t max_active_streams_in;
385   static bool throttling;
386   static uint32_t stream_priority_enabled;
387   static uint32_t initial_window_size;
388   static uint32_t max_frame_size;
389   static uint32_t header_table_size;
390   static uint32_t max_header_list_size;
391   static uint32_t accept_no_activity_timeout;
392   static uint32_t no_activity_timeout_in;
393   static uint32_t active_timeout_in;
394   static uint32_t push_diary_size;
395   static uint32_t zombie_timeout_in;
396   static float stream_error_rate_threshold;
397   static uint32_t max_settings_per_frame;
398   static uint32_t max_settings_per_minute;
399   static uint32_t max_settings_frames_per_minute;
400   static uint32_t max_ping_frames_per_minute;
401   static uint32_t max_priority_frames_per_minute;
402   static float min_avg_window_update;
403   static uint32_t con_slow_log_threshold;
404   static uint32_t stream_slow_log_threshold;
405   static uint32_t header_table_size_limit;
406   static uint32_t write_buffer_block_size;
407   static float write_size_threshold;
408   static uint32_t write_time_threshold;
409 
410   static void init();
411 };
412