/src/haproxy/include/haproxy/h1.h
Line | Count | Source |
1 | | /* |
2 | | * include/haproxy/h1.h |
3 | | * This file contains HTTP/1 protocol definitions. |
4 | | * |
5 | | * Copyright (C) 2000-2020 Willy Tarreau - w@1wt.eu |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation, version 2.1 |
10 | | * exclusively. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with this library; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #ifndef _HAPROXY_H1_H |
23 | | #define _HAPROXY_H1_H |
24 | | |
25 | | #include <import/ist.h> |
26 | | #include <haproxy/api.h> |
27 | | #include <haproxy/buf.h> |
28 | | #include <haproxy/http.h> |
29 | | #include <haproxy/http-hdr-t.h> |
30 | | #include <haproxy/intops.h> |
31 | | |
32 | | |
33 | | /* Possible states while parsing HTTP/1 messages (request|response) */ |
34 | | enum h1m_state { |
35 | | H1_MSG_RQBEFORE = 0, // request: leading LF, before start line |
36 | | H1_MSG_RQBEFORE_CR = 1, // request: leading CRLF, before start line |
37 | | /* these ones define a request start line */ |
38 | | H1_MSG_RQMETH = 2, // parsing the Method |
39 | | H1_MSG_RQMETH_SP = 3, // space(s) after the Method |
40 | | H1_MSG_RQURI = 4, // parsing the Request URI |
41 | | H1_MSG_RQURI_SP = 5, // space(s) after the Request URI |
42 | | H1_MSG_RQVER = 6, // parsing the Request Version |
43 | | H1_MSG_RQLINE_END = 7, // end of request line (CR or LF) |
44 | | |
45 | | H1_MSG_RPBEFORE = 8, // response: leading LF, before start line |
46 | | H1_MSG_RPBEFORE_CR = 9, // response: leading CRLF, before start line |
47 | | |
48 | | /* these ones define a response start line */ |
49 | | H1_MSG_RPVER = 10, // parsing the Response Version |
50 | | H1_MSG_RPVER_SP = 11, // space(s) after the Response Version |
51 | | H1_MSG_RPCODE = 12, // response code |
52 | | H1_MSG_RPCODE_SP = 13, // space(s) after the response code |
53 | | H1_MSG_RPREASON = 14, // response reason |
54 | | H1_MSG_RPLINE_END = 15, // end of response line (CR or LF) |
55 | | |
56 | | /* common header processing */ |
57 | | H1_MSG_HDR_FIRST = 16, // waiting for first header or last CRLF (no LWS possible) |
58 | | H1_MSG_HDR_NAME = 17, // parsing header name |
59 | | H1_MSG_HDR_COL = 18, // parsing header colon |
60 | | H1_MSG_HDR_L1_SP = 19, // parsing header LWS (SP|HT) before value |
61 | | H1_MSG_HDR_L1_LF = 20, // parsing header LWS (LF) before value |
62 | | H1_MSG_HDR_L1_LWS = 21, // checking whether it's a new header or an LWS |
63 | | H1_MSG_HDR_VAL = 22, // parsing header value |
64 | | H1_MSG_HDR_L2_LF = 23, // parsing header LWS (LF) inside/after value |
65 | | H1_MSG_HDR_L2_LWS = 24, // checking whether it's a new header or an LWS |
66 | | |
67 | | H1_MSG_LAST_LF = 25, // parsing last LF, last state for headers |
68 | | |
69 | | /* Body processing. */ |
70 | | |
71 | | H1_MSG_CHUNK_SIZE = 26, // parsing the chunk size (RFC7230 #4.1) |
72 | | H1_MSG_DATA = 27, // skipping data chunk / content-length data |
73 | | H1_MSG_CHUNK_CRLF = 28, // skipping CRLF after data chunk |
74 | | H1_MSG_TRAILERS = 29, // trailers (post-data entity headers) |
75 | | /* we enter this state when we've received the end of the current message */ |
76 | | H1_MSG_DONE = 30, // message end received, waiting for resync or close |
77 | | H1_MSG_TUNNEL = 31, // tunneled data after DONE |
78 | | } __attribute__((packed)); |
79 | | |
80 | | |
81 | | /* HTTP/1 message flags (32 bit), for use in h1m->flags only */ |
82 | 0 | #define H1_MF_NONE 0x00000000 |
83 | 0 | #define H1_MF_CLEN 0x00000001 // content-length present |
84 | 0 | #define H1_MF_CHNK 0x00000002 // chunk present (as last encoding), exclusive with c-l |
85 | 0 | #define H1_MF_RESP 0x00000004 // this message is the response message |
86 | 0 | #define H1_MF_TOLOWER 0x00000008 // turn the header names to lower case |
87 | 0 | #define H1_MF_VER_11 0x00000010 // message indicates version 1.1 or above |
88 | 0 | #define H1_MF_CONN_CLO 0x00000020 // message contains "connection: close" |
89 | 0 | #define H1_MF_CONN_KAL 0x00000040 // message contains "connection: keep-alive" |
90 | 0 | #define H1_MF_CONN_UPG 0x00000080 // message contains "connection: upgrade" |
91 | 0 | #define H1_MF_XFER_LEN 0x00000100 // message xfer size can be determined |
92 | 0 | #define H1_MF_XFER_ENC 0x00000200 // transfer-encoding is present |
93 | 0 | #define H1_MF_NO_PHDR 0x00000400 // don't add pseudo-headers in the header list |
94 | 0 | #define H1_MF_HDRS_ONLY 0x00000800 // parse headers only |
95 | 0 | #define H1_MF_CLEAN_CONN_HDR 0x00001000 // skip close/keep-alive values of connection headers during parsing |
96 | 0 | #define H1_MF_METH_CONNECT 0x00002000 // Set for a response to a CONNECT request |
97 | 0 | #define H1_MF_METH_HEAD 0x00004000 // Set for a response to a HEAD request |
98 | 0 | #define H1_MF_UPG_WEBSOCKET 0x00008000 // Set for a Websocket upgrade handshake |
99 | 0 | #define H1_MF_TE_CHUNKED 0x00010000 // T-E "chunked" |
100 | 0 | #define H1_MF_TE_OTHER 0x00020000 // T-E other than supported ones found (only "chunked" is supported for now) |
101 | 0 | #define H1_MF_UPG_H2C 0x00040000 // "h2c" or "h2" used as upgrade token |
102 | | |
103 | | /* Mask to use to reset H1M flags when we restart headers parsing. |
104 | | * |
105 | | * WARNING: Don't forget to update it if a new flag must be preserved when |
106 | | * headers parsing is restarted. |
107 | | */ |
108 | 0 | #define H1_MF_RESTART_MASK (H1_MF_RESP|H1_MF_TOLOWER|H1_MF_NO_PHDR|H1_MF_HDRS_ONLY| \ |
109 | 0 | H1_MF_CLEAN_CONN_HDR|H1_MF_METH_CONNECT|H1_MF_METH_HEAD) |
110 | | |
111 | | /* Note: for a connection to be persistent, we need this for the request : |
112 | | * - one of CLEN or CHNK |
113 | | * - version 1.0 and KAL and not CLO |
114 | | * - or version 1.1 and not CLO |
115 | | * For the response it's the same except that UPG must not appear either. |
116 | | * So in short, for a request it's (CLEN|CHNK) > 0 && !CLO && (VER_11 || KAL) |
117 | | * and for a response it's (CLEN|CHNK) > 0 && !(CLO|UPG) && (VER_11 || KAL) |
118 | | */ |
119 | | |
120 | | |
121 | | /* basic HTTP/1 message state for use in parsers. The err_pos field is special, |
122 | | * it is pre-set to a negative value (-1 or -2), and once non-negative it contains |
123 | | * the relative position in the message of the first parse error. -2 is used to tell |
124 | | * the parser that we want to block the invalid message. -1 is used to only perform |
125 | | * a silent capture. |
126 | | */ |
127 | | struct h1m { |
128 | | enum h1m_state state; // H1 message state (H1_MSG_*) |
129 | | /* 24 bits available here */ |
130 | | uint32_t flags; // H1 message flags (H1_MF_*) |
131 | | uint64_t curr_len; // content-length or last chunk length |
132 | | uint64_t body_len; // total known size of the body length |
133 | | uint32_t next; // next byte to parse, relative to buffer's head |
134 | | unsigned int err_code; // the HTTP status code corresponding to the error, if it can be specified (0: unset) |
135 | | int err_pos; // position in the byte stream of the first error (H1 or H2) |
136 | | int err_state; // state where the first error was met (H1 or H2) |
137 | | }; |
138 | | |
139 | | /* basic H1 start line, describes either the request and the response */ |
140 | | union h1_sl { /* useful start line pointers, relative to ->sol */ |
141 | | struct { |
142 | | struct ist m; /* METHOD */ |
143 | | struct ist u; /* URI */ |
144 | | struct ist v; /* VERSION */ |
145 | | enum http_meth_t meth; /* method */ |
146 | | } rq; /* request line : field, length */ |
147 | | struct { |
148 | | struct ist v; /* VERSION */ |
149 | | struct ist c; /* CODE */ |
150 | | struct ist r; /* REASON */ |
151 | | uint16_t status; /* status code */ |
152 | | } st; /* status line : field, length */ |
153 | | }; |
154 | | |
155 | | extern int h1_do_not_close_on_insecure_t_e; |
156 | | |
157 | | int h1_headers_to_hdr_list(char *start, const char *stop, |
158 | | struct http_hdr *hdr, unsigned int hdr_num, |
159 | | struct h1m *h1m, union h1_sl *slp); |
160 | | |
161 | | int h1_parse_xfer_enc_header(struct h1m *h1m, struct ist value); |
162 | | void h1_parse_connection_header(struct h1m *h1m, struct ist *value); |
163 | | void h1_parse_upgrade_header(struct h1m *h1m, struct ist value); |
164 | | |
165 | | void h1_generate_random_ws_input_key(char key_out[25]); |
166 | | void h1_calculate_ws_output_key(const char *key, char *result); |
167 | | |
168 | | /* for debugging, reports the HTTP/1 message state name */ |
169 | | static inline const char *h1m_state_str(enum h1m_state msg_state) |
170 | 0 | { |
171 | 0 | switch (msg_state) { |
172 | 0 | case H1_MSG_RQBEFORE: return "MSG_RQBEFORE"; |
173 | 0 | case H1_MSG_RQBEFORE_CR: return "MSG_RQBEFORE_CR"; |
174 | 0 | case H1_MSG_RQMETH: return "MSG_RQMETH"; |
175 | 0 | case H1_MSG_RQMETH_SP: return "MSG_RQMETH_SP"; |
176 | 0 | case H1_MSG_RQURI: return "MSG_RQURI"; |
177 | 0 | case H1_MSG_RQURI_SP: return "MSG_RQURI_SP"; |
178 | 0 | case H1_MSG_RQVER: return "MSG_RQVER"; |
179 | 0 | case H1_MSG_RQLINE_END: return "MSG_RQLINE_END"; |
180 | 0 | case H1_MSG_RPBEFORE: return "MSG_RPBEFORE"; |
181 | 0 | case H1_MSG_RPBEFORE_CR: return "MSG_RPBEFORE_CR"; |
182 | 0 | case H1_MSG_RPVER: return "MSG_RPVER"; |
183 | 0 | case H1_MSG_RPVER_SP: return "MSG_RPVER_SP"; |
184 | 0 | case H1_MSG_RPCODE: return "MSG_RPCODE"; |
185 | 0 | case H1_MSG_RPCODE_SP: return "MSG_RPCODE_SP"; |
186 | 0 | case H1_MSG_RPREASON: return "MSG_RPREASON"; |
187 | 0 | case H1_MSG_RPLINE_END: return "MSG_RPLINE_END"; |
188 | 0 | case H1_MSG_HDR_FIRST: return "MSG_HDR_FIRST"; |
189 | 0 | case H1_MSG_HDR_NAME: return "MSG_HDR_NAME"; |
190 | 0 | case H1_MSG_HDR_COL: return "MSG_HDR_COL"; |
191 | 0 | case H1_MSG_HDR_L1_SP: return "MSG_HDR_L1_SP"; |
192 | 0 | case H1_MSG_HDR_L1_LF: return "MSG_HDR_L1_LF"; |
193 | 0 | case H1_MSG_HDR_L1_LWS: return "MSG_HDR_L1_LWS"; |
194 | 0 | case H1_MSG_HDR_VAL: return "MSG_HDR_VAL"; |
195 | 0 | case H1_MSG_HDR_L2_LF: return "MSG_HDR_L2_LF"; |
196 | 0 | case H1_MSG_HDR_L2_LWS: return "MSG_HDR_L2_LWS"; |
197 | 0 | case H1_MSG_LAST_LF: return "MSG_LAST_LF"; |
198 | 0 | case H1_MSG_CHUNK_SIZE: return "MSG_CHUNK_SIZE"; |
199 | 0 | case H1_MSG_DATA: return "MSG_DATA"; |
200 | 0 | case H1_MSG_CHUNK_CRLF: return "MSG_CHUNK_CRLF"; |
201 | 0 | case H1_MSG_TRAILERS: return "MSG_TRAILERS"; |
202 | 0 | case H1_MSG_DONE: return "MSG_DONE"; |
203 | 0 | case H1_MSG_TUNNEL: return "MSG_TUNNEL"; |
204 | 0 | default: return "MSG_??????"; |
205 | 0 | } |
206 | 0 | } Unexecuted instantiation: http_htx.c:h1m_state_str Unexecuted instantiation: tcpcheck.c:h1m_state_str Unexecuted instantiation: check.c:h1m_state_str Unexecuted instantiation: h1.c:h1m_state_str Unexecuted instantiation: http_fetch.c:h1m_state_str Unexecuted instantiation: h1_htx.c:h1m_state_str |
207 | | |
208 | | /* This function may be called only in HTTP_MSG_CHUNK_CRLF. It reads the CRLF |
209 | | * at the end of a chunk. The caller should adjust msg->next |
210 | | * in order to include this part into the next forwarding phase. Note that the |
211 | | * caller must ensure that head+start points to the first byte to parse. It |
212 | | * returns the number of bytes parsed on success, so the caller can set msg_state |
213 | | * to HTTP_MSG_CHUNK_SIZE. If not enough data are available, the function does not |
214 | | * change anything and returns zero. Otherwise it returns a negative value |
215 | | * indicating the error position relative to <stop>. Note: this function is |
216 | | * designed to parse wrapped CRLF at the end of the buffer. |
217 | | */ |
218 | | static inline int h1_skip_chunk_crlf(const struct buffer *buf, int start, int stop) |
219 | 0 | { |
220 | 0 | const char *ptr = b_peek(buf, start); |
221 | 0 | int bytes = 1; |
222 | |
|
223 | 0 | if (stop <= start) |
224 | 0 | return 0; |
225 | | |
226 | 0 | if (unlikely(*ptr != '\r')) // negative position to stop |
227 | 0 | return ptr - __b_peek(buf, stop); |
228 | | |
229 | | /* NB: we'll check data availability at the end. It's not a |
230 | | * problem because whatever we match first will be checked |
231 | | * against the correct length. |
232 | | */ |
233 | 0 | bytes++; |
234 | 0 | ptr++; |
235 | 0 | if (ptr >= b_wrap(buf)) |
236 | 0 | ptr = b_orig(buf); |
237 | |
|
238 | 0 | if (bytes > stop - start) |
239 | 0 | return 0; |
240 | | |
241 | 0 | if (*ptr != '\n') // negative position to stop |
242 | 0 | return ptr - __b_peek(buf, stop); |
243 | | |
244 | 0 | return bytes; |
245 | 0 | } Unexecuted instantiation: http_htx.c:h1_skip_chunk_crlf Unexecuted instantiation: tcpcheck.c:h1_skip_chunk_crlf Unexecuted instantiation: check.c:h1_skip_chunk_crlf Unexecuted instantiation: h1.c:h1_skip_chunk_crlf Unexecuted instantiation: http_fetch.c:h1_skip_chunk_crlf Unexecuted instantiation: h1_htx.c:h1_skip_chunk_crlf |
246 | | |
247 | | /* Parse the chunk size start at buf + start and stops before buf + stop. The |
248 | | * positions are relative to the buffer's head. |
249 | | * It returns the chunk size in <res> and the amount of bytes read this way : |
250 | | * < 0 : error at this position relative to <stop> |
251 | | * = 0 : not enough bytes to read a complete chunk size |
252 | | * > 0 : number of bytes successfully read that the caller can skip |
253 | | * On success, the caller should adjust its msg->next to point to the first |
254 | | * byte of data after the chunk size, so that we know we can forward exactly |
255 | | * msg->next bytes, and msg->sol to contain the exact number of bytes forming |
256 | | * the chunk size. That way it is always possible to differentiate between the |
257 | | * start of the body and the start of the data. Note: this function is designed |
258 | | * to parse wrapped CRLF at the end of the buffer. |
259 | | */ |
260 | | static inline int h1_parse_chunk_size(const struct buffer *buf, int start, int stop, uint64_t *res) |
261 | 0 | { |
262 | 0 | const char *ptr = b_peek(buf, start); |
263 | 0 | const char *ptr_old = ptr; |
264 | 0 | const char *end = b_wrap(buf); |
265 | 0 | uint64_t chunk = 0; |
266 | |
|
267 | 0 | stop -= start; // bytes left |
268 | 0 | start = stop; // bytes to transfer |
269 | | |
270 | | /* The chunk size is in the following form, though we are only |
271 | | * interested in the size and CRLF : |
272 | | * 1*HEXDIGIT *WSP *[ ';' extensions ] CRLF |
273 | | */ |
274 | 0 | while (1) { |
275 | 0 | int c; |
276 | 0 | if (!stop) |
277 | 0 | return 0; |
278 | 0 | c = hex2i(*ptr); |
279 | 0 | if (c < 0) /* not a hex digit anymore */ |
280 | 0 | break; |
281 | 0 | if (unlikely(++ptr >= end)) |
282 | 0 | ptr = b_orig(buf); |
283 | 0 | chunk = (chunk << 4) + c; |
284 | 0 | if (unlikely(chunk & 0xF0000000000000ULL)) { |
285 | | /* Don't get more than 13 hexa-digit (2^52 - 1) to never fed possibly |
286 | | * bogus values from languages that use floats for their integers |
287 | | */ |
288 | 0 | goto error; |
289 | 0 | } |
290 | 0 | stop--; |
291 | 0 | } |
292 | | |
293 | | /* empty size not allowed */ |
294 | 0 | if (unlikely(ptr == ptr_old)) |
295 | 0 | goto error; |
296 | | |
297 | 0 | while (HTTP_IS_SPHT(*ptr)) { |
298 | 0 | if (++ptr >= end) |
299 | 0 | ptr = b_orig(buf); |
300 | 0 | if (--stop == 0) |
301 | 0 | return 0; |
302 | 0 | } |
303 | | |
304 | | /* Up to there, we know that at least one byte is present at *ptr. Check |
305 | | * for the end of chunk size. |
306 | | */ |
307 | 0 | while (1) { |
308 | 0 | if (likely(*ptr == '\r')) { |
309 | | /* we now have a CR, it must be followed by a LF */ |
310 | 0 | if (++ptr >= end) |
311 | 0 | ptr = b_orig(buf); |
312 | 0 | if (--stop == 0) |
313 | 0 | return 0; |
314 | | |
315 | 0 | if (*ptr != '\n') |
316 | 0 | goto error; |
317 | 0 | if (++ptr >= end) |
318 | 0 | ptr = b_orig(buf); |
319 | 0 | --stop; |
320 | | /* done */ |
321 | 0 | break; |
322 | 0 | } |
323 | 0 | else if (likely(*ptr == ';')) { |
324 | | /* chunk extension, ends at next CRLF */ |
325 | 0 | if (++ptr >= end) |
326 | 0 | ptr = b_orig(buf); |
327 | 0 | if (--stop == 0) |
328 | 0 | return 0; |
329 | | |
330 | 0 | while (!HTTP_IS_CRLF(*ptr)) { |
331 | 0 | if (++ptr >= end) |
332 | 0 | ptr = b_orig(buf); |
333 | 0 | if (--stop == 0) |
334 | 0 | return 0; |
335 | 0 | } |
336 | | /* we have a CRLF now, loop above */ |
337 | 0 | continue; |
338 | 0 | } |
339 | 0 | else |
340 | 0 | goto error; |
341 | 0 | } |
342 | | |
343 | | /* OK we found our CRLF and now <ptr> points to the next byte, which may |
344 | | * or may not be present. Let's return the number of bytes parsed. |
345 | | */ |
346 | 0 | *res = chunk; |
347 | 0 | return start - stop; |
348 | 0 | error: |
349 | 0 | *res = 0; // just to stop gcc's -Wuninitialized warning :-( |
350 | 0 | return -stop; |
351 | 0 | } Unexecuted instantiation: http_htx.c:h1_parse_chunk_size Unexecuted instantiation: tcpcheck.c:h1_parse_chunk_size Unexecuted instantiation: check.c:h1_parse_chunk_size Unexecuted instantiation: h1.c:h1_parse_chunk_size Unexecuted instantiation: http_fetch.c:h1_parse_chunk_size Unexecuted instantiation: h1_htx.c:h1_parse_chunk_size |
352 | | |
353 | | /* initializes an H1 message for a request */ |
354 | | static inline struct h1m *h1m_init_req(struct h1m *h1m) |
355 | 0 | { |
356 | 0 | h1m->state = H1_MSG_RQBEFORE; |
357 | 0 | h1m->next = 0; |
358 | 0 | h1m->flags = H1_MF_NONE; |
359 | 0 | h1m->curr_len = 0; |
360 | 0 | h1m->body_len = 0; |
361 | 0 | h1m->err_code = 0; |
362 | 0 | h1m->err_pos = -2; |
363 | 0 | h1m->err_state = 0; |
364 | 0 | return h1m; |
365 | 0 | } Unexecuted instantiation: http_htx.c:h1m_init_req Unexecuted instantiation: tcpcheck.c:h1m_init_req Unexecuted instantiation: check.c:h1m_init_req Unexecuted instantiation: h1.c:h1m_init_req Unexecuted instantiation: http_fetch.c:h1m_init_req Unexecuted instantiation: h1_htx.c:h1m_init_req |
366 | | |
367 | | /* initializes an H1 message for a response */ |
368 | | static inline struct h1m *h1m_init_res(struct h1m *h1m) |
369 | 0 | { |
370 | 0 | h1m->state = H1_MSG_RPBEFORE; |
371 | 0 | h1m->next = 0; |
372 | 0 | h1m->flags = H1_MF_RESP; |
373 | 0 | h1m->curr_len = 0; |
374 | 0 | h1m->body_len = 0; |
375 | 0 | h1m->err_code = 0; |
376 | 0 | h1m->err_pos = -2; |
377 | 0 | h1m->err_state = 0; |
378 | 0 | return h1m; |
379 | 0 | } Unexecuted instantiation: http_htx.c:h1m_init_res Unexecuted instantiation: tcpcheck.c:h1m_init_res Unexecuted instantiation: check.c:h1m_init_res Unexecuted instantiation: h1.c:h1m_init_res Unexecuted instantiation: http_fetch.c:h1m_init_res Unexecuted instantiation: h1_htx.c:h1m_init_res |
380 | | |
381 | | #endif /* _HAPROXY_H1_H */ |