blob: 7825d5c62458e7c1f302a9db4d9829ff8e168e29 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * HTTP protocol analyzer
3 *
Willy Tarreauf68a15a2011-01-06 16:53:21 +01004 * Copyright 2000-2011 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <syslog.h>
Willy Tarreau42250582007-04-01 01:30:43 +020020#include <time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020021
22#include <sys/socket.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25
Willy Tarreaub05405a2012-01-23 15:35:52 +010026#include <netinet/tcp.h>
27
Willy Tarreau2dd0d472006-06-29 17:53:05 +020028#include <common/appsession.h>
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +010029#include <common/base64.h>
Willy Tarreauc7e42382012-08-24 19:22:53 +020030#include <common/chunk.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020031#include <common/compat.h>
32#include <common/config.h>
Willy Tarreaua4cd1f52006-12-16 19:57:26 +010033#include <common/debug.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020034#include <common/memory.h>
35#include <common/mini-clist.h>
36#include <common/standard.h>
Willy Tarreau0c303ee2008-07-07 00:09:58 +020037#include <common/ticks.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020038#include <common/time.h>
39#include <common/uri_auth.h>
40#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020041
42#include <types/capture.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020043#include <types/global.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020044
Willy Tarreau8797c062007-05-07 00:55:35 +020045#include <proto/acl.h>
Willy Tarreau61612d42012-04-19 18:42:05 +020046#include <proto/arg.h>
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +010047#include <proto/auth.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020048#include <proto/backend.h>
Willy Tarreauc7e42382012-08-24 19:22:53 +020049#include <proto/channel.h>
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +010050#include <proto/checks.h>
William Lallemand82fe75c2012-10-23 10:25:10 +020051#include <proto/compression.h>
Willy Tarreau91861262007-10-17 17:06:05 +020052#include <proto/dumpstats.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020053#include <proto/fd.h>
Willy Tarreau03fa5df2010-05-24 21:02:37 +020054#include <proto/frontend.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020055#include <proto/log.h>
Willy Tarreau58f10d72006-12-04 02:26:12 +010056#include <proto/hdr_idx.h>
Thierry FOURNIERed66c292013-11-28 11:05:19 +010057#include <proto/pattern.h>
Willy Tarreaub6866442008-07-14 23:54:42 +020058#include <proto/proto_tcp.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020059#include <proto/proto_http.h>
Willy Tarreau7f062c42009-03-05 18:43:00 +010060#include <proto/proxy.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020061#include <proto/queue.h>
Willy Tarreaucd3b0942012-04-27 21:52:18 +020062#include <proto/sample.h>
Willy Tarreau7f062c42009-03-05 18:43:00 +010063#include <proto/server.h>
Willy Tarreau87b09662015-04-03 00:22:06 +020064#include <proto/stream.h>
Willy Tarreaucff64112008-11-03 06:26:53 +010065#include <proto/stream_interface.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020066#include <proto/task.h>
Baptiste Assmannfabcbe02014-04-24 22:16:59 +020067#include <proto/pattern.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020068
Willy Tarreau522d6c02009-12-06 18:49:18 +010069const char HTTP_100[] =
70 "HTTP/1.1 100 Continue\r\n\r\n";
71
72const struct chunk http_100_chunk = {
73 .str = (char *)&HTTP_100,
74 .len = sizeof(HTTP_100)-1
75};
76
Willy Tarreaua9679ac2010-01-03 17:32:57 +010077/* Warning: no "connection" header is provided with the 3xx messages below */
Willy Tarreaub463dfb2008-06-07 23:08:56 +020078const char *HTTP_301 =
Willy Tarreaubc5aa192010-01-03 15:09:36 +010079 "HTTP/1.1 301 Moved Permanently\r\n"
Willy Tarreaubc5aa192010-01-03 15:09:36 +010080 "Content-length: 0\r\n"
Willy Tarreaub463dfb2008-06-07 23:08:56 +020081 "Location: "; /* not terminated since it will be concatenated with the URL */
82
Willy Tarreau0f772532006-12-23 20:51:41 +010083const char *HTTP_302 =
Willy Tarreaubc5aa192010-01-03 15:09:36 +010084 "HTTP/1.1 302 Found\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +010085 "Cache-Control: no-cache\r\n"
Willy Tarreaubc5aa192010-01-03 15:09:36 +010086 "Content-length: 0\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +010087 "Location: "; /* not terminated since it will be concatenated with the URL */
88
89/* same as 302 except that the browser MUST retry with the GET method */
90const char *HTTP_303 =
Willy Tarreaubc5aa192010-01-03 15:09:36 +010091 "HTTP/1.1 303 See Other\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +010092 "Cache-Control: no-cache\r\n"
Willy Tarreaubc5aa192010-01-03 15:09:36 +010093 "Content-length: 0\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +010094 "Location: "; /* not terminated since it will be concatenated with the URL */
95
Yves Lafon3e8d1ae2013-03-11 11:06:05 -040096
97/* same as 302 except that the browser MUST retry with the same method */
98const char *HTTP_307 =
99 "HTTP/1.1 307 Temporary Redirect\r\n"
100 "Cache-Control: no-cache\r\n"
101 "Content-length: 0\r\n"
102 "Location: "; /* not terminated since it will be concatenated with the URL */
103
104/* same as 301 except that the browser MUST retry with the same method */
105const char *HTTP_308 =
106 "HTTP/1.1 308 Permanent Redirect\r\n"
107 "Content-length: 0\r\n"
108 "Location: "; /* not terminated since it will be concatenated with the URL */
109
Willy Tarreaubaaee002006-06-26 02:48:02 +0200110/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
111const char *HTTP_401_fmt =
112 "HTTP/1.0 401 Unauthorized\r\n"
113 "Cache-Control: no-cache\r\n"
114 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +0200115 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200116 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
117 "\r\n"
118 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
119
Willy Tarreau844a7e72010-01-31 21:46:18 +0100120const char *HTTP_407_fmt =
121 "HTTP/1.0 407 Unauthorized\r\n"
122 "Cache-Control: no-cache\r\n"
123 "Connection: close\r\n"
124 "Content-Type: text/html\r\n"
125 "Proxy-Authenticate: Basic realm=\"%s\"\r\n"
126 "\r\n"
Godbach1f1fae62014-12-17 16:32:05 +0800127 "<html><body><h1>407 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
Willy Tarreau844a7e72010-01-31 21:46:18 +0100128
Willy Tarreau0f772532006-12-23 20:51:41 +0100129
130const int http_err_codes[HTTP_ERR_SIZE] = {
Willy Tarreauae94d4d2011-05-11 16:28:49 +0200131 [HTTP_ERR_200] = 200, /* used by "monitor-uri" */
Willy Tarreau0f772532006-12-23 20:51:41 +0100132 [HTTP_ERR_400] = 400,
133 [HTTP_ERR_403] = 403,
134 [HTTP_ERR_408] = 408,
135 [HTTP_ERR_500] = 500,
136 [HTTP_ERR_502] = 502,
137 [HTTP_ERR_503] = 503,
138 [HTTP_ERR_504] = 504,
139};
140
Willy Tarreau80587432006-12-24 17:47:20 +0100141static const char *http_err_msgs[HTTP_ERR_SIZE] = {
Willy Tarreauae94d4d2011-05-11 16:28:49 +0200142 [HTTP_ERR_200] =
143 "HTTP/1.0 200 OK\r\n"
144 "Cache-Control: no-cache\r\n"
145 "Connection: close\r\n"
146 "Content-Type: text/html\r\n"
147 "\r\n"
148 "<html><body><h1>200 OK</h1>\nService ready.\n</body></html>\n",
149
Willy Tarreau0f772532006-12-23 20:51:41 +0100150 [HTTP_ERR_400] =
Willy Tarreau80587432006-12-24 17:47:20 +0100151 "HTTP/1.0 400 Bad request\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +0100152 "Cache-Control: no-cache\r\n"
153 "Connection: close\r\n"
154 "Content-Type: text/html\r\n"
155 "\r\n"
156 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
157
158 [HTTP_ERR_403] =
159 "HTTP/1.0 403 Forbidden\r\n"
160 "Cache-Control: no-cache\r\n"
161 "Connection: close\r\n"
162 "Content-Type: text/html\r\n"
163 "\r\n"
164 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
165
166 [HTTP_ERR_408] =
167 "HTTP/1.0 408 Request Time-out\r\n"
168 "Cache-Control: no-cache\r\n"
169 "Connection: close\r\n"
170 "Content-Type: text/html\r\n"
171 "\r\n"
172 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
173
174 [HTTP_ERR_500] =
175 "HTTP/1.0 500 Server Error\r\n"
176 "Cache-Control: no-cache\r\n"
177 "Connection: close\r\n"
178 "Content-Type: text/html\r\n"
179 "\r\n"
180 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n",
181
182 [HTTP_ERR_502] =
183 "HTTP/1.0 502 Bad Gateway\r\n"
184 "Cache-Control: no-cache\r\n"
185 "Connection: close\r\n"
186 "Content-Type: text/html\r\n"
187 "\r\n"
188 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n",
189
190 [HTTP_ERR_503] =
191 "HTTP/1.0 503 Service Unavailable\r\n"
192 "Cache-Control: no-cache\r\n"
193 "Connection: close\r\n"
194 "Content-Type: text/html\r\n"
195 "\r\n"
196 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n",
197
198 [HTTP_ERR_504] =
199 "HTTP/1.0 504 Gateway Time-out\r\n"
200 "Cache-Control: no-cache\r\n"
201 "Connection: close\r\n"
202 "Content-Type: text/html\r\n"
203 "\r\n"
204 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n",
205
206};
207
Cyril Bonté19979e12012-04-04 12:57:21 +0200208/* status codes available for the stats admin page (strictly 4 chars length) */
209const char *stat_status_codes[STAT_STATUS_SIZE] = {
210 [STAT_STATUS_DENY] = "DENY",
211 [STAT_STATUS_DONE] = "DONE",
212 [STAT_STATUS_ERRP] = "ERRP",
213 [STAT_STATUS_EXCD] = "EXCD",
214 [STAT_STATUS_NONE] = "NONE",
215 [STAT_STATUS_PART] = "PART",
216 [STAT_STATUS_UNKN] = "UNKN",
217};
218
219
William Lallemand73025dd2014-04-24 14:38:37 +0200220/* List head of all known action keywords for "http-request" */
221struct http_req_action_kw_list http_req_keywords = {
222 .list = LIST_HEAD_INIT(http_req_keywords.list)
223};
224
225/* List head of all known action keywords for "http-response" */
226struct http_res_action_kw_list http_res_keywords = {
227 .list = LIST_HEAD_INIT(http_res_keywords.list)
228};
229
Willy Tarreau80587432006-12-24 17:47:20 +0100230/* We must put the messages here since GCC cannot initialize consts depending
231 * on strlen().
232 */
233struct chunk http_err_chunks[HTTP_ERR_SIZE];
234
Willy Tarreaua890d072013-04-02 12:01:06 +0200235/* this struct is used between calls to smp_fetch_hdr() or smp_fetch_cookie() */
236static struct hdr_ctx static_hdr_ctx;
237
Willy Tarreau42250582007-04-01 01:30:43 +0200238#define FD_SETS_ARE_BITFIELDS
239#ifdef FD_SETS_ARE_BITFIELDS
240/*
241 * This map is used with all the FD_* macros to check whether a particular bit
242 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
243 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
244 * byte should be encoded. Be careful to always pass bytes from 0 to 255
245 * exclusively to the macros.
246 */
247fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
248fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +0100249fd_set http_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
Willy Tarreau42250582007-04-01 01:30:43 +0200250
251#else
252#error "Check if your OS uses bitfields for fd_sets"
253#endif
254
Willy Tarreau87b09662015-04-03 00:22:06 +0200255static int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struct http_txn *txn);
Willy Tarreau0b748332014-04-29 00:13:29 +0200256
Willy Tarreau80587432006-12-24 17:47:20 +0100257void init_proto_http()
258{
Willy Tarreau42250582007-04-01 01:30:43 +0200259 int i;
260 char *tmp;
Willy Tarreau80587432006-12-24 17:47:20 +0100261 int msg;
Willy Tarreau42250582007-04-01 01:30:43 +0200262
Willy Tarreau80587432006-12-24 17:47:20 +0100263 for (msg = 0; msg < HTTP_ERR_SIZE; msg++) {
264 if (!http_err_msgs[msg]) {
265 Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n", msg);
266 abort();
267 }
268
269 http_err_chunks[msg].str = (char *)http_err_msgs[msg];
270 http_err_chunks[msg].len = strlen(http_err_msgs[msg]);
271 }
Willy Tarreau42250582007-04-01 01:30:43 +0200272
273 /* initialize the log header encoding map : '{|}"#' should be encoded with
274 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
275 * URL encoding only requires '"', '#' to be encoded as well as non-
276 * printable characters above.
277 */
278 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
279 memset(url_encode_map, 0, sizeof(url_encode_map));
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +0100280 memset(http_encode_map, 0, sizeof(url_encode_map));
Willy Tarreau42250582007-04-01 01:30:43 +0200281 for (i = 0; i < 32; i++) {
282 FD_SET(i, hdr_encode_map);
283 FD_SET(i, url_encode_map);
284 }
285 for (i = 127; i < 256; i++) {
286 FD_SET(i, hdr_encode_map);
287 FD_SET(i, url_encode_map);
288 }
289
290 tmp = "\"#{|}";
291 while (*tmp) {
292 FD_SET(*tmp, hdr_encode_map);
293 tmp++;
294 }
295
296 tmp = "\"#";
297 while (*tmp) {
298 FD_SET(*tmp, url_encode_map);
299 tmp++;
300 }
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200301
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +0100302 /* initialize the http header encoding map. The draft httpbis define the
303 * header content as:
304 *
305 * HTTP-message = start-line
306 * *( header-field CRLF )
307 * CRLF
308 * [ message-body ]
309 * header-field = field-name ":" OWS field-value OWS
310 * field-value = *( field-content / obs-fold )
311 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
312 * obs-fold = CRLF 1*( SP / HTAB )
313 * field-vchar = VCHAR / obs-text
314 * VCHAR = %x21-7E
315 * obs-text = %x80-FF
316 *
317 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
318 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
319 * "obs-fold" is volontary forgotten because haproxy remove this.
320 */
321 memset(http_encode_map, 0, sizeof(http_encode_map));
322 for (i = 0x00; i <= 0x08; i++)
323 FD_SET(i, http_encode_map);
324 for (i = 0x0a; i <= 0x1f; i++)
325 FD_SET(i, http_encode_map);
326 FD_SET(0x7f, http_encode_map);
327
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200328 /* memory allocations */
Willy Tarreau63986c72015-04-03 22:55:33 +0200329 pool2_http_txn = create_pool("http_txn", sizeof(struct http_txn), MEM_F_SHARED);
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200330 pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED);
William Lallemanda73203e2012-03-12 12:48:57 +0100331 pool2_uniqueid = create_pool("uniqueid", UNIQUEID_LEN, MEM_F_SHARED);
Willy Tarreau80587432006-12-24 17:47:20 +0100332}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200333
Willy Tarreau53b6c742006-12-17 13:37:46 +0100334/*
335 * We have 26 list of methods (1 per first letter), each of which can have
336 * up to 3 entries (2 valid, 1 null).
337 */
338struct http_method_desc {
Willy Tarreauc8987b32013-12-06 23:43:17 +0100339 enum http_meth_t meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100340 int len;
341 const char text[8];
342};
343
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100344const struct http_method_desc http_methods[26][3] = {
Willy Tarreau53b6c742006-12-17 13:37:46 +0100345 ['C' - 'A'] = {
346 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
347 },
348 ['D' - 'A'] = {
349 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
350 },
351 ['G' - 'A'] = {
352 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
353 },
354 ['H' - 'A'] = {
355 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
356 },
357 ['P' - 'A'] = {
358 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
359 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
360 },
361 ['T' - 'A'] = {
362 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
363 },
364 /* rest is empty like this :
365 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
366 */
367};
368
Thierry FOURNIERd4373142013-12-17 01:10:10 +0100369const struct http_method_name http_known_methods[HTTP_METH_OTHER] = {
370 [HTTP_METH_NONE] = { "", 0 },
371 [HTTP_METH_OPTIONS] = { "OPTIONS", 7 },
372 [HTTP_METH_GET] = { "GET", 3 },
373 [HTTP_METH_HEAD] = { "HEAD", 4 },
374 [HTTP_METH_POST] = { "POST", 4 },
375 [HTTP_METH_PUT] = { "PUT", 3 },
376 [HTTP_METH_DELETE] = { "DELETE", 6 },
377 [HTTP_METH_TRACE] = { "TRACE", 5 },
378 [HTTP_METH_CONNECT] = { "CONNECT", 7 },
379};
380
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100381/* It is about twice as fast on recent architectures to lookup a byte in a
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +0200382 * table than to perform a boolean AND or OR between two tests. Refer to
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100383 * RFC2616 for those chars.
384 */
385
386const char http_is_spht[256] = {
387 [' '] = 1, ['\t'] = 1,
388};
389
390const char http_is_crlf[256] = {
391 ['\r'] = 1, ['\n'] = 1,
392};
393
394const char http_is_lws[256] = {
395 [' '] = 1, ['\t'] = 1,
396 ['\r'] = 1, ['\n'] = 1,
397};
398
399const char http_is_sep[256] = {
400 ['('] = 1, [')'] = 1, ['<'] = 1, ['>'] = 1,
401 ['@'] = 1, [','] = 1, [';'] = 1, [':'] = 1,
402 ['"'] = 1, ['/'] = 1, ['['] = 1, [']'] = 1,
403 ['{'] = 1, ['}'] = 1, ['?'] = 1, ['='] = 1,
404 [' '] = 1, ['\t'] = 1, ['\\'] = 1,
405};
406
407const char http_is_ctl[256] = {
408 [0 ... 31] = 1,
409 [127] = 1,
410};
411
412/*
413 * A token is any ASCII char that is neither a separator nor a CTL char.
414 * Do not overwrite values in assignment since gcc-2.95 will not handle
415 * them correctly. Instead, define every non-CTL char's status.
416 */
417const char http_is_token[256] = {
418 [' '] = 0, ['!'] = 1, ['"'] = 0, ['#'] = 1,
419 ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1,
420 ['('] = 0, [')'] = 0, ['*'] = 1, ['+'] = 1,
421 [','] = 0, ['-'] = 1, ['.'] = 1, ['/'] = 0,
422 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1,
423 ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1,
424 ['8'] = 1, ['9'] = 1, [':'] = 0, [';'] = 0,
425 ['<'] = 0, ['='] = 0, ['>'] = 0, ['?'] = 0,
426 ['@'] = 0, ['A'] = 1, ['B'] = 1, ['C'] = 1,
427 ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1,
428 ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1,
429 ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1,
430 ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1,
431 ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1,
432 ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 0,
433 ['\\'] = 0, [']'] = 0, ['^'] = 1, ['_'] = 1,
434 ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1,
435 ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1,
436 ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1,
437 ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1,
438 ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1,
439 ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1,
440 ['x'] = 1, ['y'] = 1, ['z'] = 1, ['{'] = 0,
441 ['|'] = 1, ['}'] = 0, ['~'] = 1,
442};
443
444
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100445/*
446 * An http ver_token is any ASCII which can be found in an HTTP version,
447 * which includes 'H', 'T', 'P', '/', '.' and any digit.
448 */
449const char http_is_ver_token[256] = {
450 ['.'] = 1, ['/'] = 1,
451 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1,
452 ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1,
Thierry FOURNIER63d692c2015-02-28 19:03:56 +0100453 ['H'] = 1, ['P'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1,
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100454};
455
456
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100457/*
Willy Tarreau6acf7c92012-03-09 13:30:45 +0100458 * Adds a header and its CRLF at the tail of the message's buffer, just before
459 * the last CRLF. Text length is measured first, so it cannot be NULL.
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100460 * The header is also automatically added to the index <hdr_idx>, and the end
461 * of headers is automatically adjusted. The number of bytes added is returned
462 * on success, otherwise <0 is returned indicating an error.
463 */
Willy Tarreau6acf7c92012-03-09 13:30:45 +0100464int http_header_add_tail(struct http_msg *msg, struct hdr_idx *hdr_idx, const char *text)
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100465{
466 int bytes, len;
467
468 len = strlen(text);
Willy Tarreau9b28e032012-10-12 23:49:43 +0200469 bytes = buffer_insert_line2(msg->chn->buf, msg->chn->buf->p + msg->eoh, text, len);
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100470 if (!bytes)
471 return -1;
Willy Tarreaufa355d42009-11-29 18:12:29 +0100472 http_msg_move_end(msg, bytes);
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100473 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
474}
475
476/*
Willy Tarreau6acf7c92012-03-09 13:30:45 +0100477 * Adds a header and its CRLF at the tail of the message's buffer, just before
478 * the last CRLF. <len> bytes are copied, not counting the CRLF. If <text> is NULL, then
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100479 * the buffer is only opened and the space reserved, but nothing is copied.
480 * The header is also automatically added to the index <hdr_idx>, and the end
481 * of headers is automatically adjusted. The number of bytes added is returned
482 * on success, otherwise <0 is returned indicating an error.
483 */
Willy Tarreau6acf7c92012-03-09 13:30:45 +0100484int http_header_add_tail2(struct http_msg *msg,
485 struct hdr_idx *hdr_idx, const char *text, int len)
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100486{
487 int bytes;
488
Willy Tarreau9b28e032012-10-12 23:49:43 +0200489 bytes = buffer_insert_line2(msg->chn->buf, msg->chn->buf->p + msg->eoh, text, len);
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100490 if (!bytes)
491 return -1;
Willy Tarreaufa355d42009-11-29 18:12:29 +0100492 http_msg_move_end(msg, bytes);
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100493 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
494}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200495
496/*
Willy Tarreauaa9dce32007-03-18 23:50:16 +0100497 * Checks if <hdr> is exactly <name> for <len> chars, and ends with a colon.
498 * If so, returns the position of the first non-space character relative to
499 * <hdr>, or <end>-<hdr> if not found before. If no value is found, it tries
500 * to return a pointer to the place after the first space. Returns 0 if the
501 * header name does not match. Checks are case-insensitive.
502 */
503int http_header_match2(const char *hdr, const char *end,
504 const char *name, int len)
505{
506 const char *val;
507
508 if (hdr + len >= end)
509 return 0;
510 if (hdr[len] != ':')
511 return 0;
512 if (strncasecmp(hdr, name, len) != 0)
513 return 0;
514 val = hdr + len + 1;
515 while (val < end && HTTP_IS_SPHT(*val))
516 val++;
517 if ((val >= end) && (len + 2 <= end - hdr))
518 return len + 2; /* we may replace starting from second space */
519 return val - hdr;
520}
521
Willy Tarreau04ff9f12013-06-10 18:39:42 +0200522/* Find the first or next occurrence of header <name> in message buffer <sol>
523 * using headers index <idx>, and return it in the <ctx> structure. This
524 * structure holds everything necessary to use the header and find next
525 * occurrence. If its <idx> member is 0, the header is searched from the
526 * beginning. Otherwise, the next occurrence is returned. The function returns
527 * 1 when it finds a value, and 0 when there is no more. It is very similar to
528 * http_find_header2() except that it is designed to work with full-line headers
529 * whose comma is not a delimiter but is part of the syntax. As a special case,
530 * if ctx->val is NULL when searching for a new values of a header, the current
531 * header is rescanned. This allows rescanning after a header deletion.
532 */
533int http_find_full_header2(const char *name, int len,
534 char *sol, struct hdr_idx *idx,
535 struct hdr_ctx *ctx)
536{
537 char *eol, *sov;
538 int cur_idx, old_idx;
539
540 cur_idx = ctx->idx;
541 if (cur_idx) {
542 /* We have previously returned a header, let's search another one */
543 sol = ctx->line;
544 eol = sol + idx->v[cur_idx].len;
545 goto next_hdr;
546 }
547
548 /* first request for this header */
549 sol += hdr_idx_first_pos(idx);
550 old_idx = 0;
551 cur_idx = hdr_idx_first_idx(idx);
552 while (cur_idx) {
553 eol = sol + idx->v[cur_idx].len;
554
555 if (len == 0) {
556 /* No argument was passed, we want any header.
557 * To achieve this, we simply build a fake request. */
558 while (sol + len < eol && sol[len] != ':')
559 len++;
560 name = sol;
561 }
562
563 if ((len < eol - sol) &&
564 (sol[len] == ':') &&
565 (strncasecmp(sol, name, len) == 0)) {
566 ctx->del = len;
567 sov = sol + len + 1;
568 while (sov < eol && http_is_lws[(unsigned char)*sov])
569 sov++;
570
571 ctx->line = sol;
572 ctx->prev = old_idx;
573 ctx->idx = cur_idx;
574 ctx->val = sov - sol;
575 ctx->tws = 0;
576 while (eol > sov && http_is_lws[(unsigned char)*(eol - 1)]) {
577 eol--;
578 ctx->tws++;
579 }
580 ctx->vlen = eol - sov;
581 return 1;
582 }
583 next_hdr:
584 sol = eol + idx->v[cur_idx].cr + 1;
585 old_idx = cur_idx;
586 cur_idx = idx->v[cur_idx].next;
587 }
588 return 0;
589}
590
Willy Tarreauc90dc232015-02-20 13:51:36 +0100591/* Find the first or next header field in message buffer <sol> using headers
592 * index <idx>, and return it in the <ctx> structure. This structure holds
593 * everything necessary to use the header and find next occurrence. If its
594 * <idx> member is 0, the first header is retrieved. Otherwise, the next
595 * occurrence is returned. The function returns 1 when it finds a value, and
596 * 0 when there is no more. It is equivalent to http_find_full_header2() with
597 * no header name.
598 */
599int http_find_next_header(char *sol, struct hdr_idx *idx, struct hdr_ctx *ctx)
600{
601 char *eol, *sov;
602 int cur_idx, old_idx;
603 int len;
604
605 cur_idx = ctx->idx;
606 if (cur_idx) {
607 /* We have previously returned a header, let's search another one */
608 sol = ctx->line;
609 eol = sol + idx->v[cur_idx].len;
610 goto next_hdr;
611 }
612
613 /* first request for this header */
614 sol += hdr_idx_first_pos(idx);
615 old_idx = 0;
616 cur_idx = hdr_idx_first_idx(idx);
617 while (cur_idx) {
618 eol = sol + idx->v[cur_idx].len;
619
620 len = 0;
621 while (1) {
622 if (len >= eol - sol)
623 goto next_hdr;
624 if (sol[len] == ':')
625 break;
626 len++;
627 }
628
629 ctx->del = len;
630 sov = sol + len + 1;
631 while (sov < eol && http_is_lws[(unsigned char)*sov])
632 sov++;
633
634 ctx->line = sol;
635 ctx->prev = old_idx;
636 ctx->idx = cur_idx;
637 ctx->val = sov - sol;
638 ctx->tws = 0;
639
640 while (eol > sov && http_is_lws[(unsigned char)*(eol - 1)]) {
641 eol--;
642 ctx->tws++;
643 }
644 ctx->vlen = eol - sov;
645 return 1;
646
647 next_hdr:
648 sol = eol + idx->v[cur_idx].cr + 1;
649 old_idx = cur_idx;
650 cur_idx = idx->v[cur_idx].next;
651 }
652 return 0;
653}
654
Willy Tarreau68085d82010-01-18 14:54:04 +0100655/* Find the end of the header value contained between <s> and <e>. See RFC2616,
656 * par 2.2 for more information. Note that it requires a valid header to return
657 * a valid result. This works for headers defined as comma-separated lists.
Willy Tarreau33a7e692007-06-10 19:45:56 +0200658 */
Willy Tarreau68085d82010-01-18 14:54:04 +0100659char *find_hdr_value_end(char *s, const char *e)
Willy Tarreau33a7e692007-06-10 19:45:56 +0200660{
661 int quoted, qdpair;
662
663 quoted = qdpair = 0;
664 for (; s < e; s++) {
665 if (qdpair) qdpair = 0;
Willy Tarreau0f7f51f2010-08-30 11:06:34 +0200666 else if (quoted) {
667 if (*s == '\\') qdpair = 1;
668 else if (*s == '"') quoted = 0;
669 }
Willy Tarreau33a7e692007-06-10 19:45:56 +0200670 else if (*s == '"') quoted = 1;
671 else if (*s == ',') return s;
672 }
673 return s;
674}
675
676/* Find the first or next occurrence of header <name> in message buffer <sol>
677 * using headers index <idx>, and return it in the <ctx> structure. This
678 * structure holds everything necessary to use the header and find next
679 * occurrence. If its <idx> member is 0, the header is searched from the
680 * beginning. Otherwise, the next occurrence is returned. The function returns
Willy Tarreau68085d82010-01-18 14:54:04 +0100681 * 1 when it finds a value, and 0 when there is no more. It is designed to work
682 * with headers defined as comma-separated lists. As a special case, if ctx->val
683 * is NULL when searching for a new values of a header, the current header is
684 * rescanned. This allows rescanning after a header deletion.
Willy Tarreau33a7e692007-06-10 19:45:56 +0200685 */
686int http_find_header2(const char *name, int len,
Willy Tarreau68085d82010-01-18 14:54:04 +0100687 char *sol, struct hdr_idx *idx,
Willy Tarreau33a7e692007-06-10 19:45:56 +0200688 struct hdr_ctx *ctx)
689{
Willy Tarreau68085d82010-01-18 14:54:04 +0100690 char *eol, *sov;
691 int cur_idx, old_idx;
Willy Tarreau33a7e692007-06-10 19:45:56 +0200692
Willy Tarreau68085d82010-01-18 14:54:04 +0100693 cur_idx = ctx->idx;
694 if (cur_idx) {
Willy Tarreau33a7e692007-06-10 19:45:56 +0200695 /* We have previously returned a value, let's search
696 * another one on the same line.
697 */
Willy Tarreau33a7e692007-06-10 19:45:56 +0200698 sol = ctx->line;
Willy Tarreau588bd4f2011-09-01 22:22:28 +0200699 ctx->del = ctx->val + ctx->vlen + ctx->tws;
Willy Tarreau68085d82010-01-18 14:54:04 +0100700 sov = sol + ctx->del;
Willy Tarreau33a7e692007-06-10 19:45:56 +0200701 eol = sol + idx->v[cur_idx].len;
702
703 if (sov >= eol)
704 /* no more values in this header */
705 goto next_hdr;
706
Willy Tarreau68085d82010-01-18 14:54:04 +0100707 /* values remaining for this header, skip the comma but save it
708 * for later use (eg: for header deletion).
709 */
Willy Tarreau33a7e692007-06-10 19:45:56 +0200710 sov++;
711 while (sov < eol && http_is_lws[(unsigned char)*sov])
712 sov++;
713
714 goto return_hdr;
715 }
716
717 /* first request for this header */
718 sol += hdr_idx_first_pos(idx);
Willy Tarreau68085d82010-01-18 14:54:04 +0100719 old_idx = 0;
Willy Tarreau33a7e692007-06-10 19:45:56 +0200720 cur_idx = hdr_idx_first_idx(idx);
Willy Tarreau33a7e692007-06-10 19:45:56 +0200721 while (cur_idx) {
722 eol = sol + idx->v[cur_idx].len;
723
Willy Tarreau1ad7c6d2007-06-10 21:42:55 +0200724 if (len == 0) {
725 /* No argument was passed, we want any header.
726 * To achieve this, we simply build a fake request. */
727 while (sol + len < eol && sol[len] != ':')
728 len++;
729 name = sol;
730 }
731
Willy Tarreau33a7e692007-06-10 19:45:56 +0200732 if ((len < eol - sol) &&
733 (sol[len] == ':') &&
734 (strncasecmp(sol, name, len) == 0)) {
Willy Tarreau68085d82010-01-18 14:54:04 +0100735 ctx->del = len;
Willy Tarreau33a7e692007-06-10 19:45:56 +0200736 sov = sol + len + 1;
737 while (sov < eol && http_is_lws[(unsigned char)*sov])
738 sov++;
Willy Tarreau68085d82010-01-18 14:54:04 +0100739
Willy Tarreau33a7e692007-06-10 19:45:56 +0200740 ctx->line = sol;
Willy Tarreau68085d82010-01-18 14:54:04 +0100741 ctx->prev = old_idx;
742 return_hdr:
Willy Tarreau33a7e692007-06-10 19:45:56 +0200743 ctx->idx = cur_idx;
744 ctx->val = sov - sol;
745
746 eol = find_hdr_value_end(sov, eol);
Willy Tarreau588bd4f2011-09-01 22:22:28 +0200747 ctx->tws = 0;
Willy Tarreau275600b2011-09-16 08:11:26 +0200748 while (eol > sov && http_is_lws[(unsigned char)*(eol - 1)]) {
Willy Tarreau588bd4f2011-09-01 22:22:28 +0200749 eol--;
750 ctx->tws++;
751 }
Willy Tarreau33a7e692007-06-10 19:45:56 +0200752 ctx->vlen = eol - sov;
753 return 1;
754 }
755 next_hdr:
756 sol = eol + idx->v[cur_idx].cr + 1;
Willy Tarreau68085d82010-01-18 14:54:04 +0100757 old_idx = cur_idx;
Willy Tarreau33a7e692007-06-10 19:45:56 +0200758 cur_idx = idx->v[cur_idx].next;
759 }
760 return 0;
761}
762
763int http_find_header(const char *name,
Willy Tarreau68085d82010-01-18 14:54:04 +0100764 char *sol, struct hdr_idx *idx,
Willy Tarreau33a7e692007-06-10 19:45:56 +0200765 struct hdr_ctx *ctx)
766{
767 return http_find_header2(name, strlen(name), sol, idx, ctx);
768}
769
Willy Tarreau68085d82010-01-18 14:54:04 +0100770/* Remove one value of a header. This only works on a <ctx> returned by one of
771 * the http_find_header functions. The value is removed, as well as surrounding
772 * commas if any. If the removed value was alone, the whole header is removed.
Willy Tarreau6acf7c92012-03-09 13:30:45 +0100773 * The ctx is always updated accordingly, as well as the buffer and HTTP
Willy Tarreau68085d82010-01-18 14:54:04 +0100774 * message <msg>. The new index is returned. If it is zero, it means there is
775 * no more header, so any processing may stop. The ctx is always left in a form
776 * that can be handled by http_find_header2() to find next occurrence.
777 */
Willy Tarreau6acf7c92012-03-09 13:30:45 +0100778int http_remove_header2(struct http_msg *msg, struct hdr_idx *idx, struct hdr_ctx *ctx)
Willy Tarreau68085d82010-01-18 14:54:04 +0100779{
780 int cur_idx = ctx->idx;
781 char *sol = ctx->line;
782 struct hdr_idx_elem *hdr;
783 int delta, skip_comma;
784
785 if (!cur_idx)
786 return 0;
787
788 hdr = &idx->v[cur_idx];
Willy Tarreau588bd4f2011-09-01 22:22:28 +0200789 if (sol[ctx->del] == ':' && ctx->val + ctx->vlen + ctx->tws == hdr->len) {
Willy Tarreau68085d82010-01-18 14:54:04 +0100790 /* This was the only value of the header, we must now remove it entirely. */
Willy Tarreau9b28e032012-10-12 23:49:43 +0200791 delta = buffer_replace2(msg->chn->buf, sol, sol + hdr->len + hdr->cr + 1, NULL, 0);
Willy Tarreau68085d82010-01-18 14:54:04 +0100792 http_msg_move_end(msg, delta);
793 idx->used--;
794 hdr->len = 0; /* unused entry */
795 idx->v[ctx->prev].next = idx->v[ctx->idx].next;
Willy Tarreau5c4784f2011-02-12 13:07:35 +0100796 if (idx->tail == ctx->idx)
797 idx->tail = ctx->prev;
Willy Tarreau68085d82010-01-18 14:54:04 +0100798 ctx->idx = ctx->prev; /* walk back to the end of previous header */
Willy Tarreau7c1c2172015-01-07 17:23:50 +0100799 ctx->line -= idx->v[ctx->idx].len + idx->v[ctx->idx].cr + 1;
Willy Tarreau68085d82010-01-18 14:54:04 +0100800 ctx->val = idx->v[ctx->idx].len; /* point to end of previous header */
Willy Tarreau588bd4f2011-09-01 22:22:28 +0200801 ctx->tws = ctx->vlen = 0;
Willy Tarreau68085d82010-01-18 14:54:04 +0100802 return ctx->idx;
803 }
804
805 /* This was not the only value of this header. We have to remove between
Willy Tarreau588bd4f2011-09-01 22:22:28 +0200806 * ctx->del+1 and ctx->val+ctx->vlen+ctx->tws+1 included. If it is the
807 * last entry of the list, we remove the last separator.
Willy Tarreau68085d82010-01-18 14:54:04 +0100808 */
809
Willy Tarreau588bd4f2011-09-01 22:22:28 +0200810 skip_comma = (ctx->val + ctx->vlen + ctx->tws == hdr->len) ? 0 : 1;
Willy Tarreau9b28e032012-10-12 23:49:43 +0200811 delta = buffer_replace2(msg->chn->buf, sol + ctx->del + skip_comma,
Willy Tarreau588bd4f2011-09-01 22:22:28 +0200812 sol + ctx->val + ctx->vlen + ctx->tws + skip_comma,
Willy Tarreau68085d82010-01-18 14:54:04 +0100813 NULL, 0);
814 hdr->len += delta;
815 http_msg_move_end(msg, delta);
816 ctx->val = ctx->del;
Willy Tarreau588bd4f2011-09-01 22:22:28 +0200817 ctx->tws = ctx->vlen = 0;
Willy Tarreau68085d82010-01-18 14:54:04 +0100818 return ctx->idx;
819}
820
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100821/* This function handles a server error at the stream interface level. The
822 * stream interface is assumed to be already in a closed state. An optional
823 * message is copied into the input buffer, and an HTTP status code stored.
824 * The error flags are set to the values in arguments. Any pending request
Willy Tarreau6f0aa472009-03-08 20:33:29 +0100825 * in this buffer will be lost.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200826 */
Willy Tarreau87b09662015-04-03 00:22:06 +0200827static void http_server_error(struct stream *s, struct stream_interface *si,
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100828 int err, int finst, int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200829{
Willy Tarreau2bb4a962014-11-28 11:11:05 +0100830 channel_auto_read(si_oc(si));
831 channel_abort(si_oc(si));
832 channel_auto_close(si_oc(si));
833 channel_erase(si_oc(si));
834 channel_auto_close(si_ic(si));
835 channel_auto_read(si_ic(si));
Willy Tarreau0f772532006-12-23 20:51:41 +0100836 if (status > 0 && msg) {
Willy Tarreaueee5b512015-04-03 23:46:31 +0200837 s->txn->status = status;
Willy Tarreau2bb4a962014-11-28 11:11:05 +0100838 bo_inject(si_ic(si), msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200839 }
Willy Tarreaue7dff022015-04-03 01:14:29 +0200840 if (!(s->flags & SF_ERR_MASK))
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +0200841 s->flags |= err;
Willy Tarreaue7dff022015-04-03 01:14:29 +0200842 if (!(s->flags & SF_FINST_MASK))
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +0200843 s->flags |= finst;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200844}
845
Willy Tarreau87b09662015-04-03 00:22:06 +0200846/* This function returns the appropriate error location for the given stream
Willy Tarreau80587432006-12-24 17:47:20 +0100847 * and message.
848 */
849
Willy Tarreau87b09662015-04-03 00:22:06 +0200850struct chunk *http_error_message(struct stream *s, int msgnum)
Willy Tarreau80587432006-12-24 17:47:20 +0100851{
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200852 if (s->be->errmsg[msgnum].str)
853 return &s->be->errmsg[msgnum];
Willy Tarreaue36cbcb2015-04-03 15:40:56 +0200854 else if (strm_sess(s)->fe->errmsg[msgnum].str)
855 return &strm_sess(s)->fe->errmsg[msgnum];
Willy Tarreau80587432006-12-24 17:47:20 +0100856 else
857 return &http_err_chunks[msgnum];
858}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200859
Willy Tarreau53b6c742006-12-17 13:37:46 +0100860/*
861 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
862 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
863 */
Thierry FOURNIERd4373142013-12-17 01:10:10 +0100864enum http_meth_t find_http_meth(const char *str, const int len)
Willy Tarreau53b6c742006-12-17 13:37:46 +0100865{
866 unsigned char m;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100867 const struct http_method_desc *h;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100868
869 m = ((unsigned)*str - 'A');
870
871 if (m < 26) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100872 for (h = http_methods[m]; h->len > 0; h++) {
873 if (unlikely(h->len != len))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100874 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100875 if (likely(memcmp(str, h->text, h->len) == 0))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100876 return h->meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100877 };
878 return HTTP_METH_OTHER;
879 }
880 return HTTP_METH_NONE;
881
882}
883
Willy Tarreau21d2af32008-02-14 20:25:24 +0100884/* Parse the URI from the given transaction (which is assumed to be in request
885 * phase) and look for the "/" beginning the PATH. If not found, return NULL.
886 * It is returned otherwise.
887 */
888static char *
889http_get_path(struct http_txn *txn)
890{
891 char *ptr, *end;
892
Willy Tarreau9b28e032012-10-12 23:49:43 +0200893 ptr = txn->req.chn->buf->p + txn->req.sl.rq.u;
Willy Tarreau21d2af32008-02-14 20:25:24 +0100894 end = ptr + txn->req.sl.rq.u_l;
895
896 if (ptr >= end)
897 return NULL;
898
899 /* RFC2616, par. 5.1.2 :
900 * Request-URI = "*" | absuri | abspath | authority
901 */
902
903 if (*ptr == '*')
904 return NULL;
905
906 if (isalpha((unsigned char)*ptr)) {
907 /* this is a scheme as described by RFC3986, par. 3.1 */
908 ptr++;
909 while (ptr < end &&
910 (isalnum((unsigned char)*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.'))
911 ptr++;
912 /* skip '://' */
913 if (ptr == end || *ptr++ != ':')
914 return NULL;
915 if (ptr == end || *ptr++ != '/')
916 return NULL;
917 if (ptr == end || *ptr++ != '/')
918 return NULL;
919 }
920 /* skip [user[:passwd]@]host[:[port]] */
921
922 while (ptr < end && *ptr != '/')
923 ptr++;
924
925 if (ptr == end)
926 return NULL;
927
928 /* OK, we got the '/' ! */
929 return ptr;
930}
931
William Lallemand65ad6e12014-01-31 15:08:02 +0100932/* Parse the URI from the given string and look for the "/" beginning the PATH.
933 * If not found, return NULL. It is returned otherwise.
934 */
935static char *
936http_get_path_from_string(char *str)
937{
938 char *ptr = str;
939
940 /* RFC2616, par. 5.1.2 :
941 * Request-URI = "*" | absuri | abspath | authority
942 */
943
944 if (*ptr == '*')
945 return NULL;
946
947 if (isalpha((unsigned char)*ptr)) {
948 /* this is a scheme as described by RFC3986, par. 3.1 */
949 ptr++;
950 while (isalnum((unsigned char)*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.')
951 ptr++;
952 /* skip '://' */
953 if (*ptr == '\0' || *ptr++ != ':')
954 return NULL;
955 if (*ptr == '\0' || *ptr++ != '/')
956 return NULL;
957 if (*ptr == '\0' || *ptr++ != '/')
958 return NULL;
959 }
960 /* skip [user[:passwd]@]host[:[port]] */
961
962 while (*ptr != '\0' && *ptr != ' ' && *ptr != '/')
963 ptr++;
964
965 if (*ptr == '\0' || *ptr == ' ')
966 return NULL;
967
968 /* OK, we got the '/' ! */
969 return ptr;
970}
971
Willy Tarreau71241ab2012-12-27 11:30:54 +0100972/* Returns a 302 for a redirectable request that reaches a server working in
973 * in redirect mode. This may only be called just after the stream interface
974 * has moved to SI_ST_ASS. Unprocessable requests are left unchanged and will
975 * follow normal proxy processing. NOTE: this function is designed to support
976 * being called once data are scheduled for forwarding.
Willy Tarreauefb453c2008-10-26 20:49:47 +0100977 */
Willy Tarreau87b09662015-04-03 00:22:06 +0200978void http_perform_server_redirect(struct stream *s, struct stream_interface *si)
Willy Tarreauefb453c2008-10-26 20:49:47 +0100979{
980 struct http_txn *txn;
Willy Tarreau827aee92011-03-10 16:55:02 +0100981 struct server *srv;
Willy Tarreauefb453c2008-10-26 20:49:47 +0100982 char *path;
Willy Tarreaucde18fc2012-05-30 07:59:54 +0200983 int len, rewind;
Willy Tarreauefb453c2008-10-26 20:49:47 +0100984
985 /* 1: create the response header */
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100986 trash.len = strlen(HTTP_302);
987 memcpy(trash.str, HTTP_302, trash.len);
Willy Tarreauefb453c2008-10-26 20:49:47 +0100988
Willy Tarreau3fdb3662012-11-12 00:42:33 +0100989 srv = objt_server(s->target);
Willy Tarreau827aee92011-03-10 16:55:02 +0100990
Willy Tarreauefb453c2008-10-26 20:49:47 +0100991 /* 2: add the server's prefix */
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100992 if (trash.len + srv->rdr_len > trash.size)
Willy Tarreauefb453c2008-10-26 20:49:47 +0100993 return;
994
Willy Tarreaudcb75c42010-01-10 00:24:22 +0100995 /* special prefix "/" means don't change URL */
Willy Tarreau827aee92011-03-10 16:55:02 +0100996 if (srv->rdr_len != 1 || *srv->rdr_pfx != '/') {
Willy Tarreau19d14ef2012-10-29 16:51:55 +0100997 memcpy(trash.str + trash.len, srv->rdr_pfx, srv->rdr_len);
998 trash.len += srv->rdr_len;
Willy Tarreaudcb75c42010-01-10 00:24:22 +0100999 }
Willy Tarreauefb453c2008-10-26 20:49:47 +01001000
Willy Tarreaucde18fc2012-05-30 07:59:54 +02001001 /* 3: add the request URI. Since it was already forwarded, we need
1002 * to temporarily rewind the buffer.
1003 */
Willy Tarreaueee5b512015-04-03 23:46:31 +02001004 txn = s->txn;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01001005 b_rew(s->req.buf, rewind = http_hdr_rewind(&txn->req));
Willy Tarreaucde18fc2012-05-30 07:59:54 +02001006
Willy Tarreauefb453c2008-10-26 20:49:47 +01001007 path = http_get_path(txn);
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01001008 len = buffer_count(s->req.buf, path, b_ptr(s->req.buf, txn->req.sl.rq.u + txn->req.sl.rq.u_l));
Willy Tarreaucde18fc2012-05-30 07:59:54 +02001009
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01001010 b_adv(s->req.buf, rewind);
Willy Tarreaucde18fc2012-05-30 07:59:54 +02001011
Willy Tarreauefb453c2008-10-26 20:49:47 +01001012 if (!path)
1013 return;
1014
Willy Tarreau19d14ef2012-10-29 16:51:55 +01001015 if (trash.len + len > trash.size - 4) /* 4 for CRLF-CRLF */
Willy Tarreauefb453c2008-10-26 20:49:47 +01001016 return;
1017
Willy Tarreau19d14ef2012-10-29 16:51:55 +01001018 memcpy(trash.str + trash.len, path, len);
1019 trash.len += len;
Willy Tarreau88d349d2010-01-25 12:15:43 +01001020
1021 if (unlikely(txn->flags & TX_USE_PX_CONN)) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +01001022 memcpy(trash.str + trash.len, "\r\nProxy-Connection: close\r\n\r\n", 29);
1023 trash.len += 29;
Willy Tarreau88d349d2010-01-25 12:15:43 +01001024 } else {
Willy Tarreau19d14ef2012-10-29 16:51:55 +01001025 memcpy(trash.str + trash.len, "\r\nConnection: close\r\n\r\n", 23);
1026 trash.len += 23;
Willy Tarreau88d349d2010-01-25 12:15:43 +01001027 }
Willy Tarreauefb453c2008-10-26 20:49:47 +01001028
1029 /* prepare to return without error. */
Willy Tarreau73b013b2012-05-21 16:31:45 +02001030 si_shutr(si);
1031 si_shutw(si);
Willy Tarreauefb453c2008-10-26 20:49:47 +01001032 si->err_type = SI_ET_NONE;
Willy Tarreauefb453c2008-10-26 20:49:47 +01001033 si->state = SI_ST_CLO;
1034
1035 /* send the message */
Willy Tarreaue7dff022015-04-03 01:14:29 +02001036 http_server_error(s, si, SF_ERR_LOCAL, SF_FINST_C, 302, &trash);
Willy Tarreauefb453c2008-10-26 20:49:47 +01001037
1038 /* FIXME: we should increase a counter of redirects per server and per backend. */
Willy Tarreau4521ba62013-01-24 01:25:25 +01001039 srv_inc_sess_ctr(srv);
Bhaskar Maddalaa20cb852014-02-03 16:26:46 -05001040 srv_set_sess_last(srv);
Willy Tarreauefb453c2008-10-26 20:49:47 +01001041}
1042
Willy Tarreau0cac36f2008-11-30 20:44:17 +01001043/* Return the error message corresponding to si->err_type. It is assumed
Willy Tarreauefb453c2008-10-26 20:49:47 +01001044 * that the server side is closed. Note that err_type is actually a
1045 * bitmask, where almost only aborts may be cumulated with other
1046 * values. We consider that aborted operations are more important
1047 * than timeouts or errors due to the fact that nobody else in the
1048 * logs might explain incomplete retries. All others should avoid
1049 * being cumulated. It should normally not be possible to have multiple
1050 * aborts at once, but just in case, the first one in sequence is reported.
Willy Tarreau6b726ad2013-12-15 19:31:37 +01001051 * Note that connection errors appearing on the second request of a keep-alive
1052 * connection are not reported since this allows the client to retry.
Willy Tarreauefb453c2008-10-26 20:49:47 +01001053 */
Willy Tarreau87b09662015-04-03 00:22:06 +02001054void http_return_srv_error(struct stream *s, struct stream_interface *si)
Willy Tarreauefb453c2008-10-26 20:49:47 +01001055{
Willy Tarreau0cac36f2008-11-30 20:44:17 +01001056 int err_type = si->err_type;
Willy Tarreauefb453c2008-10-26 20:49:47 +01001057
1058 if (err_type & SI_ET_QUEUE_ABRT)
Willy Tarreaue7dff022015-04-03 01:14:29 +02001059 http_server_error(s, si, SF_ERR_CLICL, SF_FINST_Q,
Willy Tarreau783f2582012-09-04 12:19:04 +02001060 503, http_error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +01001061 else if (err_type & SI_ET_CONN_ABRT)
Willy Tarreaue7dff022015-04-03 01:14:29 +02001062 http_server_error(s, si, SF_ERR_CLICL, SF_FINST_C,
Willy Tarreaueee5b512015-04-03 23:46:31 +02001063 503, (s->txn->flags & TX_NOT_FIRST) ? NULL :
Willy Tarreau6b726ad2013-12-15 19:31:37 +01001064 http_error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +01001065 else if (err_type & SI_ET_QUEUE_TO)
Willy Tarreaue7dff022015-04-03 01:14:29 +02001066 http_server_error(s, si, SF_ERR_SRVTO, SF_FINST_Q,
Willy Tarreau783f2582012-09-04 12:19:04 +02001067 503, http_error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +01001068 else if (err_type & SI_ET_QUEUE_ERR)
Willy Tarreaue7dff022015-04-03 01:14:29 +02001069 http_server_error(s, si, SF_ERR_SRVCL, SF_FINST_Q,
Willy Tarreau783f2582012-09-04 12:19:04 +02001070 503, http_error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +01001071 else if (err_type & SI_ET_CONN_TO)
Willy Tarreaue7dff022015-04-03 01:14:29 +02001072 http_server_error(s, si, SF_ERR_SRVTO, SF_FINST_C,
Willy Tarreaueee5b512015-04-03 23:46:31 +02001073 503, (s->txn->flags & TX_NOT_FIRST) ? NULL :
Willy Tarreau6b726ad2013-12-15 19:31:37 +01001074 http_error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +01001075 else if (err_type & SI_ET_CONN_ERR)
Willy Tarreaue7dff022015-04-03 01:14:29 +02001076 http_server_error(s, si, SF_ERR_SRVCL, SF_FINST_C,
1077 503, (s->flags & SF_SRV_REUSED) ? NULL :
Willy Tarreau6b726ad2013-12-15 19:31:37 +01001078 http_error_message(s, HTTP_ERR_503));
Willy Tarreau2d400bb2012-05-14 12:11:47 +02001079 else if (err_type & SI_ET_CONN_RES)
Willy Tarreaue7dff022015-04-03 01:14:29 +02001080 http_server_error(s, si, SF_ERR_RESOURCE, SF_FINST_C,
Willy Tarreaueee5b512015-04-03 23:46:31 +02001081 503, (s->txn->flags & TX_NOT_FIRST) ? NULL :
Willy Tarreau6b726ad2013-12-15 19:31:37 +01001082 http_error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +01001083 else /* SI_ET_CONN_OTHER and others */
Willy Tarreaue7dff022015-04-03 01:14:29 +02001084 http_server_error(s, si, SF_ERR_INTERNAL, SF_FINST_C,
Willy Tarreau783f2582012-09-04 12:19:04 +02001085 500, http_error_message(s, HTTP_ERR_500));
Willy Tarreauefb453c2008-10-26 20:49:47 +01001086}
1087
Willy Tarreau42250582007-04-01 01:30:43 +02001088extern const char sess_term_cond[8];
1089extern const char sess_fin_state[8];
1090extern const char *monthname[12];
Willy Tarreau63986c72015-04-03 22:55:33 +02001091struct pool_head *pool2_http_txn;
Willy Tarreau332f8bf2007-05-13 21:36:56 +02001092struct pool_head *pool2_requri;
Willy Tarreau193b8c62012-11-22 00:17:38 +01001093struct pool_head *pool2_capture = NULL;
William Lallemanda73203e2012-03-12 12:48:57 +01001094struct pool_head *pool2_uniqueid;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001095
Willy Tarreau117f59e2007-03-04 18:17:17 +01001096/*
1097 * Capture headers from message starting at <som> according to header list
Willy Tarreau54da8db2014-06-13 16:11:48 +02001098 * <cap_hdr>, and fill the <cap> pointers appropriately.
Willy Tarreau117f59e2007-03-04 18:17:17 +01001099 */
1100void capture_headers(char *som, struct hdr_idx *idx,
1101 char **cap, struct cap_hdr *cap_hdr)
1102{
1103 char *eol, *sol, *col, *sov;
1104 int cur_idx;
1105 struct cap_hdr *h;
1106 int len;
1107
1108 sol = som + hdr_idx_first_pos(idx);
1109 cur_idx = hdr_idx_first_idx(idx);
1110
1111 while (cur_idx) {
1112 eol = sol + idx->v[cur_idx].len;
1113
1114 col = sol;
1115 while (col < eol && *col != ':')
1116 col++;
1117
1118 sov = col + 1;
1119 while (sov < eol && http_is_lws[(unsigned char)*sov])
1120 sov++;
1121
1122 for (h = cap_hdr; h; h = h->next) {
Willy Tarreau54da8db2014-06-13 16:11:48 +02001123 if (h->namelen && (h->namelen == col - sol) &&
Willy Tarreau117f59e2007-03-04 18:17:17 +01001124 (strncasecmp(sol, h->name, h->namelen) == 0)) {
1125 if (cap[h->index] == NULL)
1126 cap[h->index] =
Willy Tarreaucf7f3202007-05-13 22:46:04 +02001127 pool_alloc2(h->pool);
Willy Tarreau117f59e2007-03-04 18:17:17 +01001128
1129 if (cap[h->index] == NULL) {
1130 Alert("HTTP capture : out of memory.\n");
1131 continue;
1132 }
1133
1134 len = eol - sov;
1135 if (len > h->len)
1136 len = h->len;
1137
1138 memcpy(cap[h->index], sov, len);
1139 cap[h->index][len]=0;
1140 }
1141 }
1142 sol = eol + idx->v[cur_idx].cr + 1;
1143 cur_idx = idx->v[cur_idx].next;
1144 }
1145}
1146
1147
Willy Tarreau42250582007-04-01 01:30:43 +02001148/* either we find an LF at <ptr> or we jump to <bad>.
1149 */
1150#define EXPECT_LF_HERE(ptr, bad) do { if (unlikely(*(ptr) != '\n')) goto bad; } while (0)
1151
1152/* plays with variables <ptr>, <end> and <state>. Jumps to <good> if OK,
1153 * otherwise to <http_msg_ood> with <state> set to <st>.
1154 */
1155#define EAT_AND_JUMP_OR_RETURN(good, st) do { \
1156 ptr++; \
1157 if (likely(ptr < end)) \
1158 goto good; \
1159 else { \
1160 state = (st); \
1161 goto http_msg_ood; \
1162 } \
1163 } while (0)
1164
1165
Willy Tarreaubaaee002006-06-26 02:48:02 +02001166/*
Willy Tarreaua15645d2007-03-18 16:22:39 +01001167 * This function parses a status line between <ptr> and <end>, starting with
Willy Tarreau8973c702007-01-21 23:58:29 +01001168 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
1169 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
1170 * will give undefined results.
1171 * Note that it is upon the caller's responsibility to ensure that ptr < end,
1172 * and that msg->sol points to the beginning of the response.
1173 * If a complete line is found (which implies that at least one CR or LF is
1174 * found before <end>, the updated <ptr> is returned, otherwise NULL is
1175 * returned indicating an incomplete line (which does not mean that parts have
1176 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
1177 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
1178 * upon next call.
1179 *
Willy Tarreau9cdde232007-05-02 20:58:19 +02001180 * This function was intentionally designed to be called from
Willy Tarreau8973c702007-01-21 23:58:29 +01001181 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
1182 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +02001183 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreau8973c702007-01-21 23:58:29 +01001184 */
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02001185const char *http_parse_stsline(struct http_msg *msg,
Willy Tarreau3770f232013-12-07 00:01:53 +01001186 enum ht_state state, const char *ptr, const char *end,
1187 unsigned int *ret_ptr, enum ht_state *ret_state)
Willy Tarreau8973c702007-01-21 23:58:29 +01001188{
Willy Tarreau9b28e032012-10-12 23:49:43 +02001189 const char *msg_start = msg->chn->buf->p;
Willy Tarreau62f791e2012-03-09 11:32:30 +01001190
Willy Tarreau8973c702007-01-21 23:58:29 +01001191 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +01001192 case HTTP_MSG_RPVER:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001193 http_msg_rpver:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001194 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8973c702007-01-21 23:58:29 +01001195 EAT_AND_JUMP_OR_RETURN(http_msg_rpver, HTTP_MSG_RPVER);
1196
1197 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreauea1175a2012-03-05 15:52:30 +01001198 msg->sl.st.v_l = ptr - msg_start;
Willy Tarreau8973c702007-01-21 23:58:29 +01001199 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
1200 }
Willy Tarreau7552c032009-03-01 11:10:40 +01001201 state = HTTP_MSG_ERROR;
1202 break;
1203
Willy Tarreau8973c702007-01-21 23:58:29 +01001204 case HTTP_MSG_RPVER_SP:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001205 http_msg_rpver_sp:
Willy Tarreau8973c702007-01-21 23:58:29 +01001206 if (likely(!HTTP_IS_LWS(*ptr))) {
Willy Tarreauea1175a2012-03-05 15:52:30 +01001207 msg->sl.st.c = ptr - msg_start;
Willy Tarreau8973c702007-01-21 23:58:29 +01001208 goto http_msg_rpcode;
1209 }
1210 if (likely(HTTP_IS_SPHT(*ptr)))
1211 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
1212 /* so it's a CR/LF, this is invalid */
Willy Tarreau7552c032009-03-01 11:10:40 +01001213 state = HTTP_MSG_ERROR;
1214 break;
Willy Tarreau8973c702007-01-21 23:58:29 +01001215
Willy Tarreau8973c702007-01-21 23:58:29 +01001216 case HTTP_MSG_RPCODE:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001217 http_msg_rpcode:
Willy Tarreau8973c702007-01-21 23:58:29 +01001218 if (likely(!HTTP_IS_LWS(*ptr)))
1219 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode, HTTP_MSG_RPCODE);
1220
1221 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreauea1175a2012-03-05 15:52:30 +01001222 msg->sl.st.c_l = ptr - msg_start - msg->sl.st.c;
Willy Tarreau8973c702007-01-21 23:58:29 +01001223 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1224 }
1225
1226 /* so it's a CR/LF, so there is no reason phrase */
Willy Tarreauea1175a2012-03-05 15:52:30 +01001227 msg->sl.st.c_l = ptr - msg_start - msg->sl.st.c;
Willy Tarreau8973c702007-01-21 23:58:29 +01001228 http_msg_rsp_reason:
1229 /* FIXME: should we support HTTP responses without any reason phrase ? */
Willy Tarreauea1175a2012-03-05 15:52:30 +01001230 msg->sl.st.r = ptr - msg_start;
Willy Tarreau8973c702007-01-21 23:58:29 +01001231 msg->sl.st.r_l = 0;
1232 goto http_msg_rpline_eol;
1233
Willy Tarreau8973c702007-01-21 23:58:29 +01001234 case HTTP_MSG_RPCODE_SP:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001235 http_msg_rpcode_sp:
Willy Tarreau8973c702007-01-21 23:58:29 +01001236 if (likely(!HTTP_IS_LWS(*ptr))) {
Willy Tarreauea1175a2012-03-05 15:52:30 +01001237 msg->sl.st.r = ptr - msg_start;
Willy Tarreau8973c702007-01-21 23:58:29 +01001238 goto http_msg_rpreason;
1239 }
1240 if (likely(HTTP_IS_SPHT(*ptr)))
1241 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1242 /* so it's a CR/LF, so there is no reason phrase */
1243 goto http_msg_rsp_reason;
1244
Willy Tarreau8973c702007-01-21 23:58:29 +01001245 case HTTP_MSG_RPREASON:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001246 http_msg_rpreason:
Willy Tarreau8973c702007-01-21 23:58:29 +01001247 if (likely(!HTTP_IS_CRLF(*ptr)))
1248 EAT_AND_JUMP_OR_RETURN(http_msg_rpreason, HTTP_MSG_RPREASON);
Willy Tarreauea1175a2012-03-05 15:52:30 +01001249 msg->sl.st.r_l = ptr - msg_start - msg->sl.st.r;
Willy Tarreau8973c702007-01-21 23:58:29 +01001250 http_msg_rpline_eol:
1251 /* We have seen the end of line. Note that we do not
1252 * necessarily have the \n yet, but at least we know that we
1253 * have EITHER \r OR \n, otherwise the response would not be
1254 * complete. We can then record the response length and return
1255 * to the caller which will be able to register it.
1256 */
Willy Tarreau3a215be2012-03-09 21:39:51 +01001257 msg->sl.st.l = ptr - msg_start - msg->sol;
Willy Tarreau8973c702007-01-21 23:58:29 +01001258 return ptr;
1259
Willy Tarreau8973c702007-01-21 23:58:29 +01001260 default:
Willy Tarreau3770f232013-12-07 00:01:53 +01001261#ifdef DEBUG_FULL
Willy Tarreau8973c702007-01-21 23:58:29 +01001262 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1263 exit(1);
1264#endif
Willy Tarreau3770f232013-12-07 00:01:53 +01001265 ;
Willy Tarreau8973c702007-01-21 23:58:29 +01001266 }
1267
1268 http_msg_ood:
Willy Tarreau7552c032009-03-01 11:10:40 +01001269 /* out of valid data */
Willy Tarreau8973c702007-01-21 23:58:29 +01001270 if (ret_state)
1271 *ret_state = state;
1272 if (ret_ptr)
Willy Tarreaua458b672012-03-05 11:17:50 +01001273 *ret_ptr = ptr - msg_start;
Willy Tarreau8973c702007-01-21 23:58:29 +01001274 return NULL;
Willy Tarreau8973c702007-01-21 23:58:29 +01001275}
1276
Willy Tarreau8973c702007-01-21 23:58:29 +01001277/*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001278 * This function parses a request line between <ptr> and <end>, starting with
1279 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
1280 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
1281 * will give undefined results.
1282 * Note that it is upon the caller's responsibility to ensure that ptr < end,
1283 * and that msg->sol points to the beginning of the request.
1284 * If a complete line is found (which implies that at least one CR or LF is
1285 * found before <end>, the updated <ptr> is returned, otherwise NULL is
1286 * returned indicating an incomplete line (which does not mean that parts have
1287 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
1288 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
1289 * upon next call.
1290 *
Willy Tarreau9cdde232007-05-02 20:58:19 +02001291 * This function was intentionally designed to be called from
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001292 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
1293 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +02001294 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001295 */
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02001296const char *http_parse_reqline(struct http_msg *msg,
Willy Tarreau3770f232013-12-07 00:01:53 +01001297 enum ht_state state, const char *ptr, const char *end,
1298 unsigned int *ret_ptr, enum ht_state *ret_state)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001299{
Willy Tarreau9b28e032012-10-12 23:49:43 +02001300 const char *msg_start = msg->chn->buf->p;
Willy Tarreau62f791e2012-03-09 11:32:30 +01001301
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001302 switch (state) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001303 case HTTP_MSG_RQMETH:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001304 http_msg_rqmeth:
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001305 if (likely(HTTP_IS_TOKEN(*ptr)))
1306 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth, HTTP_MSG_RQMETH);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001307
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001308 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreauea1175a2012-03-05 15:52:30 +01001309 msg->sl.rq.m_l = ptr - msg_start;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001310 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1311 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001312
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001313 if (likely(HTTP_IS_CRLF(*ptr))) {
1314 /* HTTP 0.9 request */
Willy Tarreauea1175a2012-03-05 15:52:30 +01001315 msg->sl.rq.m_l = ptr - msg_start;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001316 http_msg_req09_uri:
Willy Tarreauea1175a2012-03-05 15:52:30 +01001317 msg->sl.rq.u = ptr - msg_start;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001318 http_msg_req09_uri_e:
Willy Tarreauea1175a2012-03-05 15:52:30 +01001319 msg->sl.rq.u_l = ptr - msg_start - msg->sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001320 http_msg_req09_ver:
Willy Tarreauea1175a2012-03-05 15:52:30 +01001321 msg->sl.rq.v = ptr - msg_start;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001322 msg->sl.rq.v_l = 0;
1323 goto http_msg_rqline_eol;
1324 }
Willy Tarreau7552c032009-03-01 11:10:40 +01001325 state = HTTP_MSG_ERROR;
1326 break;
1327
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001328 case HTTP_MSG_RQMETH_SP:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001329 http_msg_rqmeth_sp:
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001330 if (likely(!HTTP_IS_LWS(*ptr))) {
Willy Tarreauea1175a2012-03-05 15:52:30 +01001331 msg->sl.rq.u = ptr - msg_start;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001332 goto http_msg_rquri;
1333 }
1334 if (likely(HTTP_IS_SPHT(*ptr)))
1335 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1336 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1337 goto http_msg_req09_uri;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001338
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001339 case HTTP_MSG_RQURI:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001340 http_msg_rquri:
Willy Tarreau2e9506d2012-01-07 23:22:31 +01001341 if (likely((unsigned char)(*ptr - 33) <= 93)) /* 33 to 126 included */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001342 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001343
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001344 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreauea1175a2012-03-05 15:52:30 +01001345 msg->sl.rq.u_l = ptr - msg_start - msg->sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001346 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1347 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001348
Willy Tarreau2e9506d2012-01-07 23:22:31 +01001349 if (likely((unsigned char)*ptr >= 128)) {
Willy Tarreau422246e2012-01-07 23:54:13 +01001350 /* non-ASCII chars are forbidden unless option
1351 * accept-invalid-http-request is enabled in the frontend.
1352 * In any case, we capture the faulty char.
Willy Tarreau2e9506d2012-01-07 23:22:31 +01001353 */
Willy Tarreau422246e2012-01-07 23:54:13 +01001354 if (msg->err_pos < -1)
1355 goto invalid_char;
1356 if (msg->err_pos == -1)
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02001357 msg->err_pos = ptr - msg_start;
Willy Tarreau2e9506d2012-01-07 23:22:31 +01001358 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
1359 }
1360
1361 if (likely(HTTP_IS_CRLF(*ptr))) {
1362 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1363 goto http_msg_req09_uri_e;
1364 }
1365
1366 /* OK forbidden chars, 0..31 or 127 */
Willy Tarreau422246e2012-01-07 23:54:13 +01001367 invalid_char:
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02001368 msg->err_pos = ptr - msg_start;
Willy Tarreau2e9506d2012-01-07 23:22:31 +01001369 state = HTTP_MSG_ERROR;
1370 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001371
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001372 case HTTP_MSG_RQURI_SP:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001373 http_msg_rquri_sp:
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001374 if (likely(!HTTP_IS_LWS(*ptr))) {
Willy Tarreauea1175a2012-03-05 15:52:30 +01001375 msg->sl.rq.v = ptr - msg_start;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001376 goto http_msg_rqver;
1377 }
1378 if (likely(HTTP_IS_SPHT(*ptr)))
1379 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1380 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1381 goto http_msg_req09_ver;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001382
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001383 case HTTP_MSG_RQVER:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001384 http_msg_rqver:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001385 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001386 EAT_AND_JUMP_OR_RETURN(http_msg_rqver, HTTP_MSG_RQVER);
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001387
1388 if (likely(HTTP_IS_CRLF(*ptr))) {
Willy Tarreauea1175a2012-03-05 15:52:30 +01001389 msg->sl.rq.v_l = ptr - msg_start - msg->sl.rq.v;
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001390 http_msg_rqline_eol:
1391 /* We have seen the end of line. Note that we do not
1392 * necessarily have the \n yet, but at least we know that we
1393 * have EITHER \r OR \n, otherwise the request would not be
1394 * complete. We can then record the request length and return
1395 * to the caller which will be able to register it.
1396 */
Willy Tarreau3a215be2012-03-09 21:39:51 +01001397 msg->sl.rq.l = ptr - msg_start - msg->sol;
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001398 return ptr;
1399 }
1400
1401 /* neither an HTTP_VER token nor a CRLF */
Willy Tarreau7552c032009-03-01 11:10:40 +01001402 state = HTTP_MSG_ERROR;
1403 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001404
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001405 default:
Willy Tarreau3770f232013-12-07 00:01:53 +01001406#ifdef DEBUG_FULL
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001407 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1408 exit(1);
1409#endif
Willy Tarreau3770f232013-12-07 00:01:53 +01001410 ;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001411 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001412
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001413 http_msg_ood:
Willy Tarreau7552c032009-03-01 11:10:40 +01001414 /* out of valid data */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001415 if (ret_state)
1416 *ret_state = state;
1417 if (ret_ptr)
Willy Tarreaua458b672012-03-05 11:17:50 +01001418 *ret_ptr = ptr - msg_start;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001419 return NULL;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001420}
Willy Tarreau58f10d72006-12-04 02:26:12 +01001421
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001422/*
1423 * Returns the data from Authorization header. Function may be called more
1424 * than once so data is stored in txn->auth_data. When no header is found
1425 * or auth method is unknown auth_method is set to HTTP_AUTH_WRONG to avoid
Thierry FOURNIER98d96952014-01-23 12:13:02 +01001426 * searching again for something we are unable to find anyway. However, if
1427 * the result if valid, the cache is not reused because we would risk to
Willy Tarreau87b09662015-04-03 00:22:06 +02001428 * have the credentials overwritten by another stream in parallel.
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001429 */
1430
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +01001431/* This bufffer is initialized in the file 'src/haproxy.c'. This length is
1432 * set according to global.tune.bufsize.
1433 */
Willy Tarreau7e2c6472012-10-29 20:44:36 +01001434char *get_http_auth_buff;
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001435
1436int
Willy Tarreau87b09662015-04-03 00:22:06 +02001437get_http_auth(struct stream *s)
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001438{
1439
Willy Tarreaueee5b512015-04-03 23:46:31 +02001440 struct http_txn *txn = s->txn;
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001441 struct chunk auth_method;
1442 struct hdr_ctx ctx;
1443 char *h, *p;
1444 int len;
1445
1446#ifdef DEBUG_AUTH
Willy Tarreau87b09662015-04-03 00:22:06 +02001447 printf("Auth for stream %p: %d\n", s, txn->auth.method);
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001448#endif
1449
1450 if (txn->auth.method == HTTP_AUTH_WRONG)
1451 return 0;
1452
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001453 txn->auth.method = HTTP_AUTH_WRONG;
1454
1455 ctx.idx = 0;
Willy Tarreau844a7e72010-01-31 21:46:18 +01001456
1457 if (txn->flags & TX_USE_PX_CONN) {
1458 h = "Proxy-Authorization";
1459 len = strlen(h);
1460 } else {
1461 h = "Authorization";
1462 len = strlen(h);
1463 }
1464
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01001465 if (!http_find_header2(h, len, s->req.buf->p, &txn->hdr_idx, &ctx))
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001466 return 0;
1467
1468 h = ctx.line + ctx.val;
1469
1470 p = memchr(h, ' ', ctx.vlen);
1471 if (!p || p == h)
1472 return 0;
1473
1474 chunk_initlen(&auth_method, h, 0, p-h);
1475 chunk_initlen(&txn->auth.method_data, p+1, 0, ctx.vlen-(p-h)-1);
1476
1477 if (!strncasecmp("Basic", auth_method.str, auth_method.len)) {
1478
1479 len = base64dec(txn->auth.method_data.str, txn->auth.method_data.len,
Willy Tarreau7e2c6472012-10-29 20:44:36 +01001480 get_http_auth_buff, global.tune.bufsize - 1);
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01001481
1482 if (len < 0)
1483 return 0;
1484
1485
1486 get_http_auth_buff[len] = '\0';
1487
1488 p = strchr(get_http_auth_buff, ':');
1489
1490 if (!p)
1491 return 0;
1492
1493 txn->auth.user = get_http_auth_buff;
1494 *p = '\0';
1495 txn->auth.pass = p+1;
1496
1497 txn->auth.method = HTTP_AUTH_BASIC;
1498 return 1;
1499 }
1500
1501 return 0;
1502}
1503
Willy Tarreau58f10d72006-12-04 02:26:12 +01001504
Willy Tarreau8973c702007-01-21 23:58:29 +01001505/*
1506 * This function parses an HTTP message, either a request or a response,
Willy Tarreau8b1323e2012-03-09 14:46:19 +01001507 * depending on the initial msg->msg_state. The caller is responsible for
1508 * ensuring that the message does not wrap. The function can be preempted
1509 * everywhere when data are missing and recalled at the exact same location
1510 * with no information loss. The message may even be realigned between two
1511 * calls. The header index is re-initialized when switching from
Willy Tarreau9cdde232007-05-02 20:58:19 +02001512 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH. It modifies msg->sol among other
Willy Tarreau26927362012-05-18 23:22:52 +02001513 * fields. Note that msg->sol will be initialized after completing the first
1514 * state, so that none of the msg pointers has to be initialized prior to the
1515 * first call.
Willy Tarreau8973c702007-01-21 23:58:29 +01001516 */
Willy Tarreaua560c212012-03-09 13:50:57 +01001517void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx)
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001518{
Willy Tarreau3770f232013-12-07 00:01:53 +01001519 enum ht_state state; /* updated only when leaving the FSM */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001520 register char *ptr, *end; /* request pointers, to avoid dereferences */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001521 struct buffer *buf;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001522
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001523 state = msg->msg_state;
Willy Tarreau9b28e032012-10-12 23:49:43 +02001524 buf = msg->chn->buf;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001525 ptr = buf->p + msg->next;
1526 end = buf->p + buf->i;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001527
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001528 if (unlikely(ptr >= end))
1529 goto http_msg_ood;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001530
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001531 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +01001532 /*
1533 * First, states that are specific to the response only.
1534 * We check them first so that request and headers are
1535 * closer to each other (accessed more often).
1536 */
Willy Tarreau8973c702007-01-21 23:58:29 +01001537 case HTTP_MSG_RPBEFORE:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001538 http_msg_rpbefore:
Willy Tarreau8973c702007-01-21 23:58:29 +01001539 if (likely(HTTP_IS_TOKEN(*ptr))) {
Willy Tarreau15de77e2010-01-02 21:59:16 +01001540 /* we have a start of message, but we have to check
1541 * first if we need to remove some CRLF. We can only
Willy Tarreau2e046c62012-03-01 16:08:30 +01001542 * do this when o=0.
Willy Tarreau15de77e2010-01-02 21:59:16 +01001543 */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001544 if (unlikely(ptr != buf->p)) {
1545 if (buf->o)
Willy Tarreau15de77e2010-01-02 21:59:16 +01001546 goto http_msg_ood;
Willy Tarreau1d3bcce2009-12-27 15:50:06 +01001547 /* Remove empty leading lines, as recommended by RFC2616. */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001548 bi_fast_delete(buf, ptr - buf->p);
Willy Tarreau8973c702007-01-21 23:58:29 +01001549 }
Willy Tarreau26927362012-05-18 23:22:52 +02001550 msg->sol = 0;
Willy Tarreaue92693a2012-09-24 21:13:39 +02001551 msg->sl.st.l = 0; /* used in debug mode */
Willy Tarreau8973c702007-01-21 23:58:29 +01001552 hdr_idx_init(idx);
1553 state = HTTP_MSG_RPVER;
1554 goto http_msg_rpver;
1555 }
1556
1557 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1558 goto http_msg_invalid;
1559
1560 if (unlikely(*ptr == '\n'))
1561 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1562 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore_cr, HTTP_MSG_RPBEFORE_CR);
1563 /* stop here */
1564
Willy Tarreau8973c702007-01-21 23:58:29 +01001565 case HTTP_MSG_RPBEFORE_CR:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001566 http_msg_rpbefore_cr:
Willy Tarreau8973c702007-01-21 23:58:29 +01001567 EXPECT_LF_HERE(ptr, http_msg_invalid);
1568 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1569 /* stop here */
1570
Willy Tarreau8973c702007-01-21 23:58:29 +01001571 case HTTP_MSG_RPVER:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001572 http_msg_rpver:
Willy Tarreau8973c702007-01-21 23:58:29 +01001573 case HTTP_MSG_RPVER_SP:
1574 case HTTP_MSG_RPCODE:
1575 case HTTP_MSG_RPCODE_SP:
1576 case HTTP_MSG_RPREASON:
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02001577 ptr = (char *)http_parse_stsline(msg,
Willy Tarreaua458b672012-03-05 11:17:50 +01001578 state, ptr, end,
1579 &msg->next, &msg->msg_state);
Willy Tarreau8973c702007-01-21 23:58:29 +01001580 if (unlikely(!ptr))
1581 return;
1582
1583 /* we have a full response and we know that we have either a CR
1584 * or an LF at <ptr>.
1585 */
Willy Tarreau8973c702007-01-21 23:58:29 +01001586 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
1587
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001588 msg->sol = ptr - buf->p;
Willy Tarreau8973c702007-01-21 23:58:29 +01001589 if (likely(*ptr == '\r'))
1590 EAT_AND_JUMP_OR_RETURN(http_msg_rpline_end, HTTP_MSG_RPLINE_END);
1591 goto http_msg_rpline_end;
1592
Willy Tarreau8973c702007-01-21 23:58:29 +01001593 case HTTP_MSG_RPLINE_END:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001594 http_msg_rpline_end:
Willy Tarreau8973c702007-01-21 23:58:29 +01001595 /* msg->sol must point to the first of CR or LF. */
1596 EXPECT_LF_HERE(ptr, http_msg_invalid);
1597 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
1598 /* stop here */
1599
1600 /*
1601 * Second, states that are specific to the request only
1602 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001603 case HTTP_MSG_RQBEFORE:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001604 http_msg_rqbefore:
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001605 if (likely(HTTP_IS_TOKEN(*ptr))) {
Willy Tarreau15de77e2010-01-02 21:59:16 +01001606 /* we have a start of message, but we have to check
1607 * first if we need to remove some CRLF. We can only
Willy Tarreau2e046c62012-03-01 16:08:30 +01001608 * do this when o=0.
Willy Tarreau15de77e2010-01-02 21:59:16 +01001609 */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001610 if (likely(ptr != buf->p)) {
1611 if (buf->o)
Willy Tarreau15de77e2010-01-02 21:59:16 +01001612 goto http_msg_ood;
Willy Tarreau1d3bcce2009-12-27 15:50:06 +01001613 /* Remove empty leading lines, as recommended by RFC2616. */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001614 bi_fast_delete(buf, ptr - buf->p);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001615 }
Willy Tarreau26927362012-05-18 23:22:52 +02001616 msg->sol = 0;
Willy Tarreaue92693a2012-09-24 21:13:39 +02001617 msg->sl.rq.l = 0; /* used in debug mode */
Willy Tarreau8973c702007-01-21 23:58:29 +01001618 state = HTTP_MSG_RQMETH;
1619 goto http_msg_rqmeth;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001620 }
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001621
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001622 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1623 goto http_msg_invalid;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001624
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001625 if (unlikely(*ptr == '\n'))
1626 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
1627 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore_cr, HTTP_MSG_RQBEFORE_CR);
Willy Tarreau8973c702007-01-21 23:58:29 +01001628 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001629
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001630 case HTTP_MSG_RQBEFORE_CR:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001631 http_msg_rqbefore_cr:
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001632 EXPECT_LF_HERE(ptr, http_msg_invalid);
1633 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
Willy Tarreau8973c702007-01-21 23:58:29 +01001634 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001635
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001636 case HTTP_MSG_RQMETH:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001637 http_msg_rqmeth:
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001638 case HTTP_MSG_RQMETH_SP:
1639 case HTTP_MSG_RQURI:
1640 case HTTP_MSG_RQURI_SP:
1641 case HTTP_MSG_RQVER:
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02001642 ptr = (char *)http_parse_reqline(msg,
Willy Tarreaua458b672012-03-05 11:17:50 +01001643 state, ptr, end,
1644 &msg->next, &msg->msg_state);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001645 if (unlikely(!ptr))
1646 return;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001647
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001648 /* we have a full request and we know that we have either a CR
1649 * or an LF at <ptr>.
1650 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001651 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001652
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001653 msg->sol = ptr - buf->p;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001654 if (likely(*ptr == '\r'))
1655 EAT_AND_JUMP_OR_RETURN(http_msg_rqline_end, HTTP_MSG_RQLINE_END);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001656 goto http_msg_rqline_end;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001657
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001658 case HTTP_MSG_RQLINE_END:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001659 http_msg_rqline_end:
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001660 /* check for HTTP/0.9 request : no version information available.
1661 * msg->sol must point to the first of CR or LF.
1662 */
1663 if (unlikely(msg->sl.rq.v_l == 0))
1664 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001665
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001666 EXPECT_LF_HERE(ptr, http_msg_invalid);
1667 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
Willy Tarreau8973c702007-01-21 23:58:29 +01001668 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001669
Willy Tarreau8973c702007-01-21 23:58:29 +01001670 /*
1671 * Common states below
1672 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001673 case HTTP_MSG_HDR_FIRST:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001674 http_msg_hdr_first:
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001675 msg->sol = ptr - buf->p;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001676 if (likely(!HTTP_IS_CRLF(*ptr))) {
1677 goto http_msg_hdr_name;
1678 }
1679
1680 if (likely(*ptr == '\r'))
1681 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1682 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001683
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001684 case HTTP_MSG_HDR_NAME:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001685 http_msg_hdr_name:
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001686 /* assumes msg->sol points to the first char */
1687 if (likely(HTTP_IS_TOKEN(*ptr)))
1688 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001689
Willy Tarreaufa4a03c2012-03-09 21:28:54 +01001690 if (likely(*ptr == ':'))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001691 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001692
Willy Tarreau32a4ec02009-04-02 11:35:18 +02001693 if (likely(msg->err_pos < -1) || *ptr == '\n')
1694 goto http_msg_invalid;
1695
1696 if (msg->err_pos == -1) /* capture error pointer */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001697 msg->err_pos = ptr - buf->p; /* >= 0 now */
Willy Tarreau32a4ec02009-04-02 11:35:18 +02001698
1699 /* and we still accept this non-token character */
1700 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001701
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001702 case HTTP_MSG_HDR_L1_SP:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001703 http_msg_hdr_l1_sp:
Willy Tarreaufa4a03c2012-03-09 21:28:54 +01001704 /* assumes msg->sol points to the first char */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001705 if (likely(HTTP_IS_SPHT(*ptr)))
1706 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001707
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001708 /* header value can be basically anything except CR/LF */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001709 msg->sov = ptr - buf->p;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001710
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001711 if (likely(!HTTP_IS_CRLF(*ptr))) {
1712 goto http_msg_hdr_val;
1713 }
1714
1715 if (likely(*ptr == '\r'))
1716 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lf, HTTP_MSG_HDR_L1_LF);
1717 goto http_msg_hdr_l1_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001718
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001719 case HTTP_MSG_HDR_L1_LF:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001720 http_msg_hdr_l1_lf:
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001721 EXPECT_LF_HERE(ptr, http_msg_invalid);
1722 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lws, HTTP_MSG_HDR_L1_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001723
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001724 case HTTP_MSG_HDR_L1_LWS:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001725 http_msg_hdr_l1_lws:
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001726 if (likely(HTTP_IS_SPHT(*ptr))) {
1727 /* replace HT,CR,LF with spaces */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001728 for (; buf->p + msg->sov < ptr; msg->sov++)
1729 buf->p[msg->sov] = ' ';
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001730 goto http_msg_hdr_l1_sp;
1731 }
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001732 /* we had a header consisting only in spaces ! */
Willy Tarreau12e48b32012-03-05 16:57:34 +01001733 msg->eol = msg->sov;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001734 goto http_msg_complete_header;
1735
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001736 case HTTP_MSG_HDR_VAL:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001737 http_msg_hdr_val:
Willy Tarreaufa4a03c2012-03-09 21:28:54 +01001738 /* assumes msg->sol points to the first char, and msg->sov
1739 * points to the first character of the value.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001740 */
1741 if (likely(!HTTP_IS_CRLF(*ptr)))
1742 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001743
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001744 msg->eol = ptr - buf->p;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001745 /* Note: we could also copy eol into ->eoh so that we have the
1746 * real header end in case it ends with lots of LWS, but is this
1747 * really needed ?
1748 */
1749 if (likely(*ptr == '\r'))
1750 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1751 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001752
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001753 case HTTP_MSG_HDR_L2_LF:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001754 http_msg_hdr_l2_lf:
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001755 EXPECT_LF_HERE(ptr, http_msg_invalid);
1756 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001757
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001758 case HTTP_MSG_HDR_L2_LWS:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001759 http_msg_hdr_l2_lws:
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001760 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1761 /* LWS: replace HT,CR,LF with spaces */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001762 for (; buf->p + msg->eol < ptr; msg->eol++)
1763 buf->p[msg->eol] = ' ';
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001764 goto http_msg_hdr_val;
1765 }
1766 http_msg_complete_header:
1767 /*
1768 * It was a new header, so the last one is finished.
Willy Tarreaufa4a03c2012-03-09 21:28:54 +01001769 * Assumes msg->sol points to the first char, msg->sov points
1770 * to the first character of the value and msg->eol to the
1771 * first CR or LF so we know how the line ends. We insert last
1772 * header into the index.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001773 */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001774 if (unlikely(hdr_idx_add(msg->eol - msg->sol, buf->p[msg->eol] == '\r',
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001775 idx, idx->tail) < 0))
1776 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001777
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001778 msg->sol = ptr - buf->p;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001779 if (likely(!HTTP_IS_CRLF(*ptr))) {
1780 goto http_msg_hdr_name;
1781 }
1782
1783 if (likely(*ptr == '\r'))
1784 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1785 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001786
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001787 case HTTP_MSG_LAST_LF:
Willy Tarreaue3f284a2010-09-28 19:42:42 +02001788 http_msg_last_lf:
Willy Tarreau0558a022014-03-13 15:48:45 +01001789 /* Assumes msg->sol points to the first of either CR or LF.
1790 * Sets ->sov and ->next to the total header length, ->eoh to
1791 * the last CRLF, and ->eol to the last CRLF length (1 or 2).
1792 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001793 EXPECT_LF_HERE(ptr, http_msg_invalid);
1794 ptr++;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001795 msg->sov = msg->next = ptr - buf->p;
Willy Tarreau3a215be2012-03-09 21:39:51 +01001796 msg->eoh = msg->sol;
1797 msg->sol = 0;
Willy Tarreau0558a022014-03-13 15:48:45 +01001798 msg->eol = msg->sov - msg->eoh;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001799 msg->msg_state = HTTP_MSG_BODY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001800 return;
Willy Tarreaub56928a2012-04-16 14:51:55 +02001801
1802 case HTTP_MSG_ERROR:
1803 /* this may only happen if we call http_msg_analyser() twice with an error */
1804 break;
1805
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001806 default:
Willy Tarreau3770f232013-12-07 00:01:53 +01001807#ifdef DEBUG_FULL
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001808 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1809 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001810#endif
Willy Tarreau3770f232013-12-07 00:01:53 +01001811 ;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001812 }
1813 http_msg_ood:
1814 /* out of data */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001815 msg->msg_state = state;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001816 msg->next = ptr - buf->p;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001817 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001818
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001819 http_msg_invalid:
1820 /* invalid message */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001821 msg->msg_state = HTTP_MSG_ERROR;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001822 msg->next = ptr - buf->p;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001823 return;
1824}
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001825
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001826/* convert an HTTP/0.9 request into an HTTP/1.0 request. Returns 1 if the
1827 * conversion succeeded, 0 in case of error. If the request was already 1.X,
1828 * nothing is done and 1 is returned.
1829 */
Willy Tarreau418bfcc2012-03-09 13:56:20 +01001830static int http_upgrade_v09_to_v10(struct http_txn *txn)
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001831{
1832 int delta;
1833 char *cur_end;
Willy Tarreau418bfcc2012-03-09 13:56:20 +01001834 struct http_msg *msg = &txn->req;
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001835
1836 if (msg->sl.rq.v_l != 0)
1837 return 1;
1838
Apollon Oikonomopoulos25a15222014-04-06 02:46:00 +03001839 /* RFC 1945 allows only GET for HTTP/0.9 requests */
1840 if (txn->meth != HTTP_METH_GET)
1841 return 0;
1842
Willy Tarreau9b28e032012-10-12 23:49:43 +02001843 cur_end = msg->chn->buf->p + msg->sl.rq.l;
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001844 delta = 0;
1845
1846 if (msg->sl.rq.u_l == 0) {
Apollon Oikonomopoulos25a15222014-04-06 02:46:00 +03001847 /* HTTP/0.9 requests *must* have a request URI, per RFC 1945 */
1848 return 0;
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001849 }
1850 /* add HTTP version */
Willy Tarreau9b28e032012-10-12 23:49:43 +02001851 delta = buffer_replace2(msg->chn->buf, cur_end, cur_end, " HTTP/1.0\r\n", 11);
Willy Tarreaufa355d42009-11-29 18:12:29 +01001852 http_msg_move_end(msg, delta);
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001853 cur_end += delta;
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02001854 cur_end = (char *)http_parse_reqline(msg,
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001855 HTTP_MSG_RQMETH,
Willy Tarreau9b28e032012-10-12 23:49:43 +02001856 msg->chn->buf->p, cur_end + 1,
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001857 NULL, NULL);
1858 if (unlikely(!cur_end))
1859 return 0;
1860
1861 /* we have a full HTTP/1.0 request now and we know that
1862 * we have either a CR or an LF at <ptr>.
1863 */
1864 hdr_idx_set_start(&txn->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
1865 return 1;
1866}
1867
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001868/* Parse the Connection: header of an HTTP request, looking for both "close"
Willy Tarreau6acf7c92012-03-09 13:30:45 +01001869 * and "keep-alive" values. If we already know that some headers may safely
1870 * be removed, we remove them now. The <to_del> flags are used for that :
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001871 * - bit 0 means remove "close" headers (in HTTP/1.0 requests/responses)
1872 * - bit 1 means remove "keep-alive" headers (in HTTP/1.1 reqs/resp to 1.1).
Willy Tarreau50fc7772012-11-11 22:19:57 +01001873 * Presence of the "Upgrade" token is also checked and reported.
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001874 * The TX_HDR_CONN_* flags are adjusted in txn->flags depending on what was
1875 * found, and TX_CON_*_SET is adjusted depending on what is left so only
1876 * harmless combinations may be removed. Do not call that after changes have
Willy Tarreau6acf7c92012-03-09 13:30:45 +01001877 * been processed.
Willy Tarreau5b154472009-12-21 20:11:07 +01001878 */
Willy Tarreau6acf7c92012-03-09 13:30:45 +01001879void http_parse_connection_header(struct http_txn *txn, struct http_msg *msg, int to_del)
Willy Tarreau5b154472009-12-21 20:11:07 +01001880{
Willy Tarreau5b154472009-12-21 20:11:07 +01001881 struct hdr_ctx ctx;
Willy Tarreau88d349d2010-01-25 12:15:43 +01001882 const char *hdr_val = "Connection";
1883 int hdr_len = 10;
Willy Tarreau5b154472009-12-21 20:11:07 +01001884
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001885 if (txn->flags & TX_HDR_CONN_PRS)
Willy Tarreau5b154472009-12-21 20:11:07 +01001886 return;
1887
Willy Tarreau88d349d2010-01-25 12:15:43 +01001888 if (unlikely(txn->flags & TX_USE_PX_CONN)) {
1889 hdr_val = "Proxy-Connection";
1890 hdr_len = 16;
1891 }
1892
Willy Tarreau5b154472009-12-21 20:11:07 +01001893 ctx.idx = 0;
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001894 txn->flags &= ~(TX_CON_KAL_SET|TX_CON_CLO_SET);
Willy Tarreau9b28e032012-10-12 23:49:43 +02001895 while (http_find_header2(hdr_val, hdr_len, msg->chn->buf->p, &txn->hdr_idx, &ctx)) {
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001896 if (ctx.vlen >= 10 && word_match(ctx.line + ctx.val, ctx.vlen, "keep-alive", 10)) {
1897 txn->flags |= TX_HDR_CONN_KAL;
Willy Tarreau6acf7c92012-03-09 13:30:45 +01001898 if (to_del & 2)
1899 http_remove_header2(msg, &txn->hdr_idx, &ctx);
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001900 else
1901 txn->flags |= TX_CON_KAL_SET;
1902 }
1903 else if (ctx.vlen >= 5 && word_match(ctx.line + ctx.val, ctx.vlen, "close", 5)) {
1904 txn->flags |= TX_HDR_CONN_CLO;
Willy Tarreau6acf7c92012-03-09 13:30:45 +01001905 if (to_del & 1)
1906 http_remove_header2(msg, &txn->hdr_idx, &ctx);
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001907 else
1908 txn->flags |= TX_CON_CLO_SET;
1909 }
Willy Tarreau50fc7772012-11-11 22:19:57 +01001910 else if (ctx.vlen >= 7 && word_match(ctx.line + ctx.val, ctx.vlen, "upgrade", 7)) {
1911 txn->flags |= TX_HDR_CONN_UPG;
1912 }
Willy Tarreau5b154472009-12-21 20:11:07 +01001913 }
1914
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001915 txn->flags |= TX_HDR_CONN_PRS;
1916 return;
1917}
Willy Tarreau5b154472009-12-21 20:11:07 +01001918
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001919/* Apply desired changes on the Connection: header. Values may be removed and/or
1920 * added depending on the <wanted> flags, which are exclusively composed of
1921 * TX_CON_CLO_SET and TX_CON_KAL_SET, depending on what flags are desired. The
1922 * TX_CON_*_SET flags are adjusted in txn->flags depending on what is left.
1923 */
Willy Tarreau6acf7c92012-03-09 13:30:45 +01001924void http_change_connection_header(struct http_txn *txn, struct http_msg *msg, int wanted)
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001925{
1926 struct hdr_ctx ctx;
Willy Tarreau88d349d2010-01-25 12:15:43 +01001927 const char *hdr_val = "Connection";
1928 int hdr_len = 10;
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001929
1930 ctx.idx = 0;
1931
Willy Tarreau88d349d2010-01-25 12:15:43 +01001932
1933 if (unlikely(txn->flags & TX_USE_PX_CONN)) {
1934 hdr_val = "Proxy-Connection";
1935 hdr_len = 16;
1936 }
1937
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001938 txn->flags &= ~(TX_CON_CLO_SET | TX_CON_KAL_SET);
Willy Tarreau9b28e032012-10-12 23:49:43 +02001939 while (http_find_header2(hdr_val, hdr_len, msg->chn->buf->p, &txn->hdr_idx, &ctx)) {
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001940 if (ctx.vlen >= 10 && word_match(ctx.line + ctx.val, ctx.vlen, "keep-alive", 10)) {
1941 if (wanted & TX_CON_KAL_SET)
1942 txn->flags |= TX_CON_KAL_SET;
1943 else
Willy Tarreau6acf7c92012-03-09 13:30:45 +01001944 http_remove_header2(msg, &txn->hdr_idx, &ctx);
Willy Tarreau5b154472009-12-21 20:11:07 +01001945 }
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001946 else if (ctx.vlen >= 5 && word_match(ctx.line + ctx.val, ctx.vlen, "close", 5)) {
1947 if (wanted & TX_CON_CLO_SET)
1948 txn->flags |= TX_CON_CLO_SET;
1949 else
Willy Tarreau6acf7c92012-03-09 13:30:45 +01001950 http_remove_header2(msg, &txn->hdr_idx, &ctx);
Willy Tarreau0dfdf192010-01-05 11:33:11 +01001951 }
Willy Tarreau5b154472009-12-21 20:11:07 +01001952 }
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001953
1954 if (wanted == (txn->flags & (TX_CON_CLO_SET|TX_CON_KAL_SET)))
1955 return;
1956
1957 if ((wanted & TX_CON_CLO_SET) && !(txn->flags & TX_CON_CLO_SET)) {
1958 txn->flags |= TX_CON_CLO_SET;
Willy Tarreau88d349d2010-01-25 12:15:43 +01001959 hdr_val = "Connection: close";
1960 hdr_len = 17;
1961 if (unlikely(txn->flags & TX_USE_PX_CONN)) {
1962 hdr_val = "Proxy-Connection: close";
1963 hdr_len = 23;
1964 }
Willy Tarreau6acf7c92012-03-09 13:30:45 +01001965 http_header_add_tail2(msg, &txn->hdr_idx, hdr_val, hdr_len);
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001966 }
1967
1968 if ((wanted & TX_CON_KAL_SET) && !(txn->flags & TX_CON_KAL_SET)) {
1969 txn->flags |= TX_CON_KAL_SET;
Willy Tarreau88d349d2010-01-25 12:15:43 +01001970 hdr_val = "Connection: keep-alive";
1971 hdr_len = 22;
1972 if (unlikely(txn->flags & TX_USE_PX_CONN)) {
1973 hdr_val = "Proxy-Connection: keep-alive";
1974 hdr_len = 28;
1975 }
Willy Tarreau6acf7c92012-03-09 13:30:45 +01001976 http_header_add_tail2(msg, &txn->hdr_idx, hdr_val, hdr_len);
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001977 }
1978 return;
Willy Tarreau5b154472009-12-21 20:11:07 +01001979}
1980
Willy Tarreauc24715e2014-04-17 15:21:20 +02001981/* Parse the chunk size at msg->next. Once done, it adjusts ->next to point to
1982 * the first byte of data after the chunk size, so that we know we can forward
1983 * exactly msg->next bytes. msg->sol contains the exact number of bytes forming
1984 * the chunk size. That way it is always possible to differentiate between the
1985 * start of the body and the start of the data.
Willy Tarreau115acb92009-12-26 13:56:06 +01001986 * Return >0 on success, 0 when some data is missing, <0 on error.
Willy Tarreaud98cf932009-12-27 22:54:55 +01001987 * Note: this function is designed to parse wrapped CRLF at the end of the buffer.
Willy Tarreau115acb92009-12-26 13:56:06 +01001988 */
Willy Tarreau24e6d972012-10-26 00:49:52 +02001989static inline int http_parse_chunk_size(struct http_msg *msg)
Willy Tarreau115acb92009-12-26 13:56:06 +01001990{
Willy Tarreau9b28e032012-10-12 23:49:43 +02001991 const struct buffer *buf = msg->chn->buf;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001992 const char *ptr = b_ptr(buf, msg->next);
Willy Tarreau4baf44b2012-03-09 14:10:20 +01001993 const char *ptr_old = ptr;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02001994 const char *end = buf->data + buf->size;
1995 const char *stop = bi_end(buf);
Willy Tarreau115acb92009-12-26 13:56:06 +01001996 unsigned int chunk = 0;
1997
1998 /* The chunk size is in the following form, though we are only
1999 * interested in the size and CRLF :
2000 * 1*HEXDIGIT *WSP *[ ';' extensions ] CRLF
2001 */
2002 while (1) {
2003 int c;
Willy Tarreau363a5bb2012-03-02 20:14:45 +01002004 if (ptr == stop)
Willy Tarreau115acb92009-12-26 13:56:06 +01002005 return 0;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002006 c = hex2i(*ptr);
Willy Tarreau115acb92009-12-26 13:56:06 +01002007 if (c < 0) /* not a hex digit anymore */
2008 break;
Willy Tarreau0161d622013-04-02 01:26:55 +02002009 if (unlikely(++ptr >= end))
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002010 ptr = buf->data;
Willy Tarreau431946e2012-02-24 19:20:12 +01002011 if (chunk & 0xF8000000) /* integer overflow will occur if result >= 2GB */
Willy Tarreaue1582eb2010-12-12 13:10:11 +01002012 goto error;
Willy Tarreau115acb92009-12-26 13:56:06 +01002013 chunk = (chunk << 4) + c;
2014 }
2015
Willy Tarreaud98cf932009-12-27 22:54:55 +01002016 /* empty size not allowed */
Willy Tarreau0161d622013-04-02 01:26:55 +02002017 if (unlikely(ptr == ptr_old))
Willy Tarreaue1582eb2010-12-12 13:10:11 +01002018 goto error;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002019
2020 while (http_is_spht[(unsigned char)*ptr]) {
2021 if (++ptr >= end)
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002022 ptr = buf->data;
Willy Tarreau0161d622013-04-02 01:26:55 +02002023 if (unlikely(ptr == stop))
Willy Tarreau115acb92009-12-26 13:56:06 +01002024 return 0;
Willy Tarreau115acb92009-12-26 13:56:06 +01002025 }
2026
Willy Tarreaud98cf932009-12-27 22:54:55 +01002027 /* Up to there, we know that at least one byte is present at *ptr. Check
2028 * for the end of chunk size.
2029 */
2030 while (1) {
2031 if (likely(HTTP_IS_CRLF(*ptr))) {
2032 /* we now have a CR or an LF at ptr */
2033 if (likely(*ptr == '\r')) {
2034 if (++ptr >= end)
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002035 ptr = buf->data;
Willy Tarreau363a5bb2012-03-02 20:14:45 +01002036 if (ptr == stop)
Willy Tarreaud98cf932009-12-27 22:54:55 +01002037 return 0;
2038 }
Willy Tarreau115acb92009-12-26 13:56:06 +01002039
Willy Tarreaud98cf932009-12-27 22:54:55 +01002040 if (*ptr != '\n')
Willy Tarreaue1582eb2010-12-12 13:10:11 +01002041 goto error;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002042 if (++ptr >= end)
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002043 ptr = buf->data;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002044 /* done */
2045 break;
2046 }
2047 else if (*ptr == ';') {
2048 /* chunk extension, ends at next CRLF */
2049 if (++ptr >= end)
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002050 ptr = buf->data;
Willy Tarreau363a5bb2012-03-02 20:14:45 +01002051 if (ptr == stop)
Willy Tarreau115acb92009-12-26 13:56:06 +01002052 return 0;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002053
2054 while (!HTTP_IS_CRLF(*ptr)) {
2055 if (++ptr >= end)
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002056 ptr = buf->data;
Willy Tarreau363a5bb2012-03-02 20:14:45 +01002057 if (ptr == stop)
Willy Tarreaud98cf932009-12-27 22:54:55 +01002058 return 0;
2059 }
2060 /* we have a CRLF now, loop above */
2061 continue;
Willy Tarreau115acb92009-12-26 13:56:06 +01002062 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01002063 else
Willy Tarreaue1582eb2010-12-12 13:10:11 +01002064 goto error;
Willy Tarreau115acb92009-12-26 13:56:06 +01002065 }
2066
Willy Tarreaud98cf932009-12-27 22:54:55 +01002067 /* OK we found our CRLF and now <ptr> points to the next byte,
Willy Tarreauc24715e2014-04-17 15:21:20 +02002068 * which may or may not be present. We save that into ->next,
2069 * and the number of bytes parsed into msg->sol.
Willy Tarreau115acb92009-12-26 13:56:06 +01002070 */
Willy Tarreauc24715e2014-04-17 15:21:20 +02002071 msg->sol = ptr - ptr_old;
Willy Tarreau0161d622013-04-02 01:26:55 +02002072 if (unlikely(ptr < ptr_old))
Willy Tarreauc24715e2014-04-17 15:21:20 +02002073 msg->sol += buf->size;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002074 msg->next = buffer_count(buf, buf->p, ptr);
Willy Tarreau124d9912011-03-01 20:30:48 +01002075 msg->chunk_len = chunk;
2076 msg->body_len += chunk;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002077 msg->msg_state = chunk ? HTTP_MSG_DATA : HTTP_MSG_TRAILERS;
Willy Tarreau115acb92009-12-26 13:56:06 +01002078 return 1;
Willy Tarreaue1582eb2010-12-12 13:10:11 +01002079 error:
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002080 msg->err_pos = buffer_count(buf, buf->p, ptr);
Willy Tarreaue1582eb2010-12-12 13:10:11 +01002081 return -1;
Willy Tarreau115acb92009-12-26 13:56:06 +01002082}
2083
Willy Tarreau4baf44b2012-03-09 14:10:20 +01002084/* This function skips trailers in the buffer associated with HTTP
Willy Tarreaua458b672012-03-05 11:17:50 +01002085 * message <msg>. The first visited position is msg->next. If the end of
Willy Tarreaud98cf932009-12-27 22:54:55 +01002086 * the trailers is found, it is automatically scheduled to be forwarded,
2087 * msg->msg_state switches to HTTP_MSG_DONE, and the function returns >0.
2088 * If not enough data are available, the function does not change anything
Willy Tarreauc24715e2014-04-17 15:21:20 +02002089 * except maybe msg->next if it could parse some lines, and returns zero.
2090 * If a parse error is encountered, the function returns < 0 and does not
2091 * change anything except maybe msg->next. Note that the message must
2092 * already be in HTTP_MSG_TRAILERS state before calling this function,
Willy Tarreau638cd022010-01-03 07:42:04 +01002093 * which implies that all non-trailers data have already been scheduled for
Willy Tarreauc24715e2014-04-17 15:21:20 +02002094 * forwarding, and that msg->next exactly matches the length of trailers
2095 * already parsed and not forwarded. It is also important to note that this
2096 * function is designed to be able to parse wrapped headers at end of buffer.
Willy Tarreaud98cf932009-12-27 22:54:55 +01002097 */
Willy Tarreau24e6d972012-10-26 00:49:52 +02002098static int http_forward_trailers(struct http_msg *msg)
Willy Tarreaud98cf932009-12-27 22:54:55 +01002099{
Willy Tarreau9b28e032012-10-12 23:49:43 +02002100 const struct buffer *buf = msg->chn->buf;
Willy Tarreau4baf44b2012-03-09 14:10:20 +01002101
Willy Tarreaua458b672012-03-05 11:17:50 +01002102 /* we have msg->next which points to next line. Look for CRLF. */
Willy Tarreaud98cf932009-12-27 22:54:55 +01002103 while (1) {
Willy Tarreau4baf44b2012-03-09 14:10:20 +01002104 const char *p1 = NULL, *p2 = NULL;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002105 const char *ptr = b_ptr(buf, msg->next);
2106 const char *stop = bi_end(buf);
Willy Tarreau638cd022010-01-03 07:42:04 +01002107 int bytes;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002108
2109 /* scan current line and stop at LF or CRLF */
2110 while (1) {
Willy Tarreau363a5bb2012-03-02 20:14:45 +01002111 if (ptr == stop)
Willy Tarreaud98cf932009-12-27 22:54:55 +01002112 return 0;
2113
2114 if (*ptr == '\n') {
2115 if (!p1)
2116 p1 = ptr;
2117 p2 = ptr;
2118 break;
2119 }
2120
2121 if (*ptr == '\r') {
Willy Tarreaue1582eb2010-12-12 13:10:11 +01002122 if (p1) {
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002123 msg->err_pos = buffer_count(buf, buf->p, ptr);
Willy Tarreaud98cf932009-12-27 22:54:55 +01002124 return -1;
Willy Tarreaue1582eb2010-12-12 13:10:11 +01002125 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01002126 p1 = ptr;
2127 }
2128
2129 ptr++;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002130 if (ptr >= buf->data + buf->size)
2131 ptr = buf->data;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002132 }
2133
2134 /* after LF; point to beginning of next line */
2135 p2++;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002136 if (p2 >= buf->data + buf->size)
2137 p2 = buf->data;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002138
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002139 bytes = p2 - b_ptr(buf, msg->next);
Willy Tarreau638cd022010-01-03 07:42:04 +01002140 if (bytes < 0)
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002141 bytes += buf->size;
Willy Tarreau638cd022010-01-03 07:42:04 +01002142
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002143 if (p1 == b_ptr(buf, msg->next)) {
Willy Tarreau638cd022010-01-03 07:42:04 +01002144 /* LF/CRLF at beginning of line => end of trailers at p2.
2145 * Everything was scheduled for forwarding, there's nothing
2146 * left from this message.
Willy Tarreau5523b322009-12-29 12:05:52 +01002147 */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002148 msg->next = buffer_count(buf, buf->p, p2);
Willy Tarreaud98cf932009-12-27 22:54:55 +01002149 msg->msg_state = HTTP_MSG_DONE;
2150 return 1;
2151 }
2152 /* OK, next line then */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002153 msg->next = buffer_count(buf, buf->p, p2);
Willy Tarreaud98cf932009-12-27 22:54:55 +01002154 }
2155}
2156
Willy Tarreauc24715e2014-04-17 15:21:20 +02002157/* This function may be called only in HTTP_MSG_CHUNK_CRLF. It reads the CRLF
2158 * or a possible LF alone at the end of a chunk. It automatically adjusts
2159 * msg->next in order to include this part into the next forwarding phase.
Willy Tarreaua458b672012-03-05 11:17:50 +01002160 * Note that the caller must ensure that ->p points to the first byte to parse.
Willy Tarreaud98cf932009-12-27 22:54:55 +01002161 * It also sets msg_state to HTTP_MSG_CHUNK_SIZE and returns >0 on success. If
2162 * not enough data are available, the function does not change anything and
2163 * returns zero. If a parse error is encountered, the function returns < 0 and
2164 * does not change anything. Note: this function is designed to parse wrapped
2165 * CRLF at the end of the buffer.
2166 */
Willy Tarreau24e6d972012-10-26 00:49:52 +02002167static inline int http_skip_chunk_crlf(struct http_msg *msg)
Willy Tarreaud98cf932009-12-27 22:54:55 +01002168{
Willy Tarreau9b28e032012-10-12 23:49:43 +02002169 const struct buffer *buf = msg->chn->buf;
Willy Tarreau4baf44b2012-03-09 14:10:20 +01002170 const char *ptr;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002171 int bytes;
2172
2173 /* NB: we'll check data availabilty at the end. It's not a
2174 * problem because whatever we match first will be checked
2175 * against the correct length.
2176 */
2177 bytes = 1;
Willy Tarreau0669d7d2014-04-17 11:40:10 +02002178 ptr = b_ptr(buf, msg->next);
Willy Tarreaud98cf932009-12-27 22:54:55 +01002179 if (*ptr == '\r') {
2180 bytes++;
2181 ptr++;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002182 if (ptr >= buf->data + buf->size)
2183 ptr = buf->data;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002184 }
2185
Willy Tarreau0669d7d2014-04-17 11:40:10 +02002186 if (msg->next + bytes > buf->i)
Willy Tarreaud98cf932009-12-27 22:54:55 +01002187 return 0;
2188
Willy Tarreaue1582eb2010-12-12 13:10:11 +01002189 if (*ptr != '\n') {
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002190 msg->err_pos = buffer_count(buf, buf->p, ptr);
Willy Tarreaud98cf932009-12-27 22:54:55 +01002191 return -1;
Willy Tarreaue1582eb2010-12-12 13:10:11 +01002192 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01002193
2194 ptr++;
Willy Tarreau0161d622013-04-02 01:26:55 +02002195 if (unlikely(ptr >= buf->data + buf->size))
Willy Tarreaucdbdd522012-10-12 22:51:15 +02002196 ptr = buf->data;
Willy Tarreauc24715e2014-04-17 15:21:20 +02002197 /* Advance ->next to allow the CRLF to be forwarded */
Willy Tarreau0669d7d2014-04-17 11:40:10 +02002198 msg->next += bytes;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002199 msg->msg_state = HTTP_MSG_CHUNK_SIZE;
2200 return 1;
2201}
Willy Tarreau5b154472009-12-21 20:11:07 +01002202
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002203/* Parses a qvalue and returns it multipled by 1000, from 0 to 1000. If the
2204 * value is larger than 1000, it is bound to 1000. The parser consumes up to
2205 * 1 digit, one dot and 3 digits and stops on the first invalid character.
2206 * Unparsable qvalues return 1000 as "q=1.000".
2207 */
Thierry FOURNIERad903512014-04-11 17:51:01 +02002208int parse_qvalue(const char *qvalue, const char **end)
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002209{
2210 int q = 1000;
2211
Willy Tarreau506c69a2014-07-08 00:59:48 +02002212 if (!isdigit((unsigned char)*qvalue))
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002213 goto out;
2214 q = (*qvalue++ - '0') * 1000;
2215
2216 if (*qvalue++ != '.')
2217 goto out;
2218
Willy Tarreau506c69a2014-07-08 00:59:48 +02002219 if (!isdigit((unsigned char)*qvalue))
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002220 goto out;
2221 q += (*qvalue++ - '0') * 100;
2222
Willy Tarreau506c69a2014-07-08 00:59:48 +02002223 if (!isdigit((unsigned char)*qvalue))
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002224 goto out;
2225 q += (*qvalue++ - '0') * 10;
2226
Willy Tarreau506c69a2014-07-08 00:59:48 +02002227 if (!isdigit((unsigned char)*qvalue))
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002228 goto out;
2229 q += (*qvalue++ - '0') * 1;
2230 out:
2231 if (q > 1000)
2232 q = 1000;
Willy Tarreau38b3aa52014-04-22 23:32:05 +02002233 if (end)
Thierry FOURNIERad903512014-04-11 17:51:01 +02002234 *end = qvalue;
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002235 return q;
2236}
William Lallemand82fe75c2012-10-23 10:25:10 +02002237
2238/*
2239 * Selects a compression algorithm depending on the client request.
Willy Tarreau05d84602012-10-26 02:11:25 +02002240 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002241int select_compression_request_header(struct stream *s, struct buffer *req)
William Lallemand82fe75c2012-10-23 10:25:10 +02002242{
Willy Tarreaueee5b512015-04-03 23:46:31 +02002243 struct http_txn *txn = s->txn;
Willy Tarreau70737d12012-10-27 00:34:28 +02002244 struct http_msg *msg = &txn->req;
William Lallemand82fe75c2012-10-23 10:25:10 +02002245 struct hdr_ctx ctx;
2246 struct comp_algo *comp_algo = NULL;
Willy Tarreau3c7b97b2012-10-26 14:50:26 +02002247 struct comp_algo *comp_algo_back = NULL;
William Lallemand82fe75c2012-10-23 10:25:10 +02002248
Finn Arne Gangstadcbb9a4b2012-10-29 21:43:01 +01002249 /* Disable compression for older user agents announcing themselves as "Mozilla/4"
2250 * unless they are known good (MSIE 6 with XP SP2, or MSIE 7 and later).
Willy Tarreau05d84602012-10-26 02:11:25 +02002251 * See http://zoompf.com/2012/02/lose-the-wait-http-compression for more details.
2252 */
2253 ctx.idx = 0;
2254 if (http_find_header2("User-Agent", 10, req->p, &txn->hdr_idx, &ctx) &&
2255 ctx.vlen >= 9 &&
Finn Arne Gangstadcbb9a4b2012-10-29 21:43:01 +01002256 memcmp(ctx.line + ctx.val, "Mozilla/4", 9) == 0 &&
2257 (ctx.vlen < 31 ||
2258 memcmp(ctx.line + ctx.val + 25, "MSIE ", 5) != 0 ||
2259 ctx.line[ctx.val + 30] < '6' ||
2260 (ctx.line[ctx.val + 30] == '6' &&
2261 (ctx.vlen < 54 || memcmp(ctx.line + 51, "SV1", 3) != 0)))) {
2262 s->comp_algo = NULL;
2263 return 0;
Willy Tarreau05d84602012-10-26 02:11:25 +02002264 }
2265
William Lallemand82fe75c2012-10-23 10:25:10 +02002266 /* search for the algo in the backend in priority or the frontend */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002267 if ((s->be->comp && (comp_algo_back = s->be->comp->algos)) || (strm_sess(s)->fe->comp && (comp_algo_back = strm_sess(s)->fe->comp->algos))) {
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002268 int best_q = 0;
2269
William Lallemand82fe75c2012-10-23 10:25:10 +02002270 ctx.idx = 0;
2271 while (http_find_header2("Accept-Encoding", 15, req->p, &txn->hdr_idx, &ctx)) {
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002272 const char *qval;
2273 int q;
2274 int toklen;
2275
2276 /* try to isolate the token from the optional q-value */
2277 toklen = 0;
2278 while (toklen < ctx.vlen && http_is_token[(unsigned char)*(ctx.line + ctx.val + toklen)])
2279 toklen++;
2280
2281 qval = ctx.line + ctx.val + toklen;
2282 while (1) {
2283 while (qval < ctx.line + ctx.val + ctx.vlen && http_is_lws[(unsigned char)*qval])
2284 qval++;
2285
2286 if (qval >= ctx.line + ctx.val + ctx.vlen || *qval != ';') {
2287 qval = NULL;
2288 break;
2289 }
2290 qval++;
Willy Tarreau70737d12012-10-27 00:34:28 +02002291
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002292 while (qval < ctx.line + ctx.val + ctx.vlen && http_is_lws[(unsigned char)*qval])
2293 qval++;
Willy Tarreau70737d12012-10-27 00:34:28 +02002294
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002295 if (qval >= ctx.line + ctx.val + ctx.vlen) {
2296 qval = NULL;
2297 break;
William Lallemand82fe75c2012-10-23 10:25:10 +02002298 }
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002299 if (strncmp(qval, "q=", MIN(ctx.line + ctx.val + ctx.vlen - qval, 2)) == 0)
2300 break;
2301
2302 while (qval < ctx.line + ctx.val + ctx.vlen && *qval != ';')
2303 qval++;
2304 }
2305
2306 /* here we have qval pointing to the first "q=" attribute or NULL if not found */
Thierry FOURNIERad903512014-04-11 17:51:01 +02002307 q = qval ? parse_qvalue(qval + 2, NULL) : 1000;
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002308
2309 if (q <= best_q)
2310 continue;
2311
2312 for (comp_algo = comp_algo_back; comp_algo; comp_algo = comp_algo->next) {
2313 if (*(ctx.line + ctx.val) == '*' ||
Willy Tarreau615105e2015-03-28 16:40:46 +01002314 word_match(ctx.line + ctx.val, toklen, comp_algo->ua_name, comp_algo->ua_name_len)) {
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002315 s->comp_algo = comp_algo;
2316 best_q = q;
2317 break;
2318 }
2319 }
2320 }
2321 }
2322
2323 /* remove all occurrences of the header when "compression offload" is set */
2324 if (s->comp_algo) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002325 if ((s->be->comp && s->be->comp->offload) || (strm_sess(s)->fe->comp && strm_sess(s)->fe->comp->offload)) {
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002326 http_remove_header2(msg, &txn->hdr_idx, &ctx);
2327 ctx.idx = 0;
2328 while (http_find_header2("Accept-Encoding", 15, req->p, &txn->hdr_idx, &ctx)) {
2329 http_remove_header2(msg, &txn->hdr_idx, &ctx);
William Lallemand82fe75c2012-10-23 10:25:10 +02002330 }
2331 }
Willy Tarreau0e9b1b42014-03-19 12:07:52 +01002332 return 1;
William Lallemand82fe75c2012-10-23 10:25:10 +02002333 }
2334
2335 /* identity is implicit does not require headers */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002336 if ((s->be->comp && (comp_algo_back = s->be->comp->algos)) || (strm_sess(s)->fe->comp && (comp_algo_back = strm_sess(s)->fe->comp->algos))) {
Willy Tarreau3c7b97b2012-10-26 14:50:26 +02002337 for (comp_algo = comp_algo_back; comp_algo; comp_algo = comp_algo->next) {
Willy Tarreau615105e2015-03-28 16:40:46 +01002338 if (comp_algo->cfg_name_len == 8 && memcmp(comp_algo->cfg_name, "identity", 8) == 0) {
William Lallemand82fe75c2012-10-23 10:25:10 +02002339 s->comp_algo = comp_algo;
2340 return 1;
2341 }
2342 }
2343 }
2344
2345 s->comp_algo = NULL;
William Lallemand82fe75c2012-10-23 10:25:10 +02002346 return 0;
2347}
2348
2349/*
2350 * Selects a comression algorithm depending of the server response.
2351 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002352int select_compression_response_header(struct stream *s, struct buffer *res)
William Lallemand82fe75c2012-10-23 10:25:10 +02002353{
Willy Tarreaueee5b512015-04-03 23:46:31 +02002354 struct http_txn *txn = s->txn;
William Lallemand82fe75c2012-10-23 10:25:10 +02002355 struct http_msg *msg = &txn->rsp;
2356 struct hdr_ctx ctx;
2357 struct comp_type *comp_type;
William Lallemand82fe75c2012-10-23 10:25:10 +02002358
2359 /* no common compression algorithm was found in request header */
2360 if (s->comp_algo == NULL)
2361 goto fail;
2362
2363 /* HTTP < 1.1 should not be compressed */
Willy Tarreau72575502013-12-24 14:41:35 +01002364 if (!(msg->flags & HTTP_MSGF_VER_11) || !(txn->req.flags & HTTP_MSGF_VER_11))
William Lallemand82fe75c2012-10-23 10:25:10 +02002365 goto fail;
2366
Jesse Hathaway2468d4e2015-03-06 20:16:15 +00002367 /* compress 200,201,202,203 responses only */
2368 if ((txn->status != 200) &&
2369 (txn->status != 201) &&
2370 (txn->status != 202) &&
2371 (txn->status != 203))
William Lallemandd3002612012-11-26 14:34:47 +01002372 goto fail;
2373
William Lallemand82fe75c2012-10-23 10:25:10 +02002374 /* Content-Length is null */
2375 if (!(msg->flags & HTTP_MSGF_TE_CHNK) && msg->body_len == 0)
2376 goto fail;
2377
2378 /* content is already compressed */
Willy Tarreau0a80a8d2012-11-26 16:33:37 +01002379 ctx.idx = 0;
William Lallemand82fe75c2012-10-23 10:25:10 +02002380 if (http_find_header2("Content-Encoding", 16, res->p, &txn->hdr_idx, &ctx))
2381 goto fail;
2382
Willy Tarreau56e9ffa2013-01-05 16:20:35 +01002383 /* no compression when Cache-Control: no-transform is present in the message */
2384 ctx.idx = 0;
2385 while (http_find_header2("Cache-Control", 13, res->p, &txn->hdr_idx, &ctx)) {
2386 if (word_match(ctx.line + ctx.val, ctx.vlen, "no-transform", 12))
2387 goto fail;
2388 }
2389
William Lallemand82fe75c2012-10-23 10:25:10 +02002390 comp_type = NULL;
2391
Willy Tarreau0a80a8d2012-11-26 16:33:37 +01002392 /* we don't want to compress multipart content-types, nor content-types that are
2393 * not listed in the "compression type" directive if any. If no content-type was
2394 * found but configuration requires one, we don't compress either. Backend has
2395 * the priority.
William Lallemand82fe75c2012-10-23 10:25:10 +02002396 */
Willy Tarreau0a80a8d2012-11-26 16:33:37 +01002397 ctx.idx = 0;
2398 if (http_find_header2("Content-Type", 12, res->p, &txn->hdr_idx, &ctx)) {
2399 if (ctx.vlen >= 9 && strncasecmp("multipart", ctx.line+ctx.val, 9) == 0)
2400 goto fail;
2401
2402 if ((s->be->comp && (comp_type = s->be->comp->types)) ||
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002403 (strm_sess(s)->fe->comp && (comp_type = strm_sess(s)->fe->comp->types))) {
William Lallemand82fe75c2012-10-23 10:25:10 +02002404 for (; comp_type; comp_type = comp_type->next) {
Willy Tarreau0a80a8d2012-11-26 16:33:37 +01002405 if (ctx.vlen >= comp_type->name_len &&
2406 strncasecmp(ctx.line+ctx.val, comp_type->name, comp_type->name_len) == 0)
William Lallemand82fe75c2012-10-23 10:25:10 +02002407 /* this Content-Type should be compressed */
2408 break;
2409 }
Willy Tarreau0a80a8d2012-11-26 16:33:37 +01002410 /* this Content-Type should not be compressed */
2411 if (comp_type == NULL)
2412 goto fail;
William Lallemand82fe75c2012-10-23 10:25:10 +02002413 }
William Lallemand82fe75c2012-10-23 10:25:10 +02002414 }
Willy Tarreau0a80a8d2012-11-26 16:33:37 +01002415 else { /* no content-type header */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002416 if ((s->be->comp && s->be->comp->types) || (strm_sess(s)->fe->comp && strm_sess(s)->fe->comp->types))
Willy Tarreau0a80a8d2012-11-26 16:33:37 +01002417 goto fail; /* a content-type was required */
William Lallemandd3002612012-11-26 14:34:47 +01002418 }
2419
William Lallemandd85f9172012-11-09 17:05:39 +01002420 /* limit compression rate */
2421 if (global.comp_rate_lim > 0)
2422 if (read_freq_ctr(&global.comp_bps_in) > global.comp_rate_lim)
2423 goto fail;
2424
William Lallemand072a2bf2012-11-20 17:01:01 +01002425 /* limit cpu usage */
2426 if (idle_pct < compress_min_idle)
2427 goto fail;
2428
William Lallemand4c49fae2012-11-07 15:00:23 +01002429 /* initialize compression */
William Lallemandf3747832012-11-09 12:33:10 +01002430 if (s->comp_algo->init(&s->comp_ctx, global.tune.comp_maxlevel) < 0)
William Lallemand4c49fae2012-11-07 15:00:23 +01002431 goto fail;
2432
Willy Tarreaue7dff022015-04-03 01:14:29 +02002433 s->flags |= SF_COMP_READY;
William Lallemandec3e3892012-11-12 17:02:18 +01002434
William Lallemand82fe75c2012-10-23 10:25:10 +02002435 /* remove Content-Length header */
Willy Tarreau0a80a8d2012-11-26 16:33:37 +01002436 ctx.idx = 0;
William Lallemand82fe75c2012-10-23 10:25:10 +02002437 if ((msg->flags & HTTP_MSGF_CNT_LEN) && http_find_header2("Content-Length", 14, res->p, &txn->hdr_idx, &ctx))
2438 http_remove_header2(msg, &txn->hdr_idx, &ctx);
2439
2440 /* add Transfer-Encoding header */
2441 if (!(msg->flags & HTTP_MSGF_TE_CHNK))
2442 http_header_add_tail2(&txn->rsp, &txn->hdr_idx, "Transfer-Encoding: chunked", 26);
2443
2444 /*
2445 * Add Content-Encoding header when it's not identity encoding.
2446 * RFC 2616 : Identity encoding: This content-coding is used only in the
2447 * Accept-Encoding header, and SHOULD NOT be used in the Content-Encoding
2448 * header.
2449 */
Willy Tarreau615105e2015-03-28 16:40:46 +01002450 if (s->comp_algo->cfg_name_len != 8 || memcmp(s->comp_algo->cfg_name, "identity", 8) != 0) {
Willy Tarreau19d14ef2012-10-29 16:51:55 +01002451 trash.len = 18;
2452 memcpy(trash.str, "Content-Encoding: ", trash.len);
Willy Tarreau615105e2015-03-28 16:40:46 +01002453 memcpy(trash.str + trash.len, s->comp_algo->ua_name, s->comp_algo->ua_name_len);
2454 trash.len += s->comp_algo->ua_name_len;
Willy Tarreau19d14ef2012-10-29 16:51:55 +01002455 trash.str[trash.len] = '\0';
2456 http_header_add_tail2(&txn->rsp, &txn->hdr_idx, trash.str, trash.len);
William Lallemand82fe75c2012-10-23 10:25:10 +02002457 }
William Lallemand82fe75c2012-10-23 10:25:10 +02002458 return 1;
2459
2460fail:
Willy Tarreaub97b6192012-11-19 14:55:02 +01002461 s->comp_algo = NULL;
William Lallemand82fe75c2012-10-23 10:25:10 +02002462 return 0;
2463}
2464
Willy Tarreau87b09662015-04-03 00:22:06 +02002465void http_adjust_conn_mode(struct stream *s, struct http_txn *txn, struct http_msg *msg)
Willy Tarreau4e21ff92014-09-30 18:44:22 +02002466{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002467 struct proxy *fe = strm_sess(s)->fe;
Willy Tarreau4e21ff92014-09-30 18:44:22 +02002468 int tmp = TX_CON_WANT_KAL;
2469
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002470 if (!((fe->options2|s->be->options2) & PR_O2_FAKE_KA)) {
2471 if ((fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN ||
Willy Tarreau4e21ff92014-09-30 18:44:22 +02002472 (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_TUN)
2473 tmp = TX_CON_WANT_TUN;
2474
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002475 if ((fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
Willy Tarreau4e21ff92014-09-30 18:44:22 +02002476 (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL)
2477 tmp = TX_CON_WANT_TUN;
2478 }
2479
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002480 if ((fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL ||
Willy Tarreau4e21ff92014-09-30 18:44:22 +02002481 (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_SCL) {
2482 /* option httpclose + server_close => forceclose */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002483 if ((fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
Willy Tarreau4e21ff92014-09-30 18:44:22 +02002484 (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL)
2485 tmp = TX_CON_WANT_CLO;
2486 else
2487 tmp = TX_CON_WANT_SCL;
2488 }
2489
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002490 if ((fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL ||
Willy Tarreau4e21ff92014-09-30 18:44:22 +02002491 (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_FCL)
2492 tmp = TX_CON_WANT_CLO;
2493
2494 if ((txn->flags & TX_CON_WANT_MSK) < tmp)
2495 txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp;
2496
2497 if (!(txn->flags & TX_HDR_CONN_PRS) &&
2498 (txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) {
2499 /* parse the Connection header and possibly clean it */
2500 int to_del = 0;
2501 if ((msg->flags & HTTP_MSGF_VER_11) ||
2502 ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL &&
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002503 !((fe->options2|s->be->options2) & PR_O2_FAKE_KA)))
Willy Tarreau4e21ff92014-09-30 18:44:22 +02002504 to_del |= 2; /* remove "keep-alive" */
2505 if (!(msg->flags & HTTP_MSGF_VER_11))
2506 to_del |= 1; /* remove "close" */
2507 http_parse_connection_header(txn, msg, to_del);
2508 }
2509
2510 /* check if client or config asks for explicit close in KAL/SCL */
2511 if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
2512 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) &&
2513 ((txn->flags & TX_HDR_CONN_CLO) || /* "connection: close" */
2514 (!(msg->flags & HTTP_MSGF_VER_11) && !(txn->flags & TX_HDR_CONN_KAL)) || /* no "connection: k-a" in 1.0 */
2515 !(msg->flags & HTTP_MSGF_XFER_LEN) || /* no length known => close */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002516 fe->state == PR_STSTOPPED)) /* frontend is stopping */
Willy Tarreau4e21ff92014-09-30 18:44:22 +02002517 txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
2518}
William Lallemand82fe75c2012-10-23 10:25:10 +02002519
Willy Tarreaud787e662009-07-07 10:14:51 +02002520/* This stream analyser waits for a complete HTTP request. It returns 1 if the
2521 * processing can continue on next analysers, or zero if it either needs more
2522 * data or wants to immediately abort the request (eg: timeout, error, ...). It
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01002523 * is tied to AN_REQ_WAIT_HTTP and may may remove itself from s->req.analysers
Willy Tarreaud787e662009-07-07 10:14:51 +02002524 * when it has nothing left to do, and may remove any analyser when it wants to
2525 * abort.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002526 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002527int http_wait_for_request(struct stream *s, struct channel *req, int an_bit)
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002528{
Willy Tarreau59234e92008-11-30 23:51:27 +01002529 /*
2530 * We will parse the partial (or complete) lines.
2531 * We will check the request syntax, and also join multi-line
2532 * headers. An index of all the lines will be elaborated while
2533 * parsing.
2534 *
2535 * For the parsing, we use a 28 states FSM.
2536 *
2537 * Here is the information we currently have :
Willy Tarreau9b28e032012-10-12 23:49:43 +02002538 * req->buf->p = beginning of request
2539 * req->buf->p + msg->eoh = end of processed headers / start of current one
2540 * req->buf->p + req->buf->i = end of input data
Willy Tarreau26927362012-05-18 23:22:52 +02002541 * msg->eol = end of current header or line (LF or CRLF)
2542 * msg->next = first non-visited byte
Willy Tarreaud787e662009-07-07 10:14:51 +02002543 *
2544 * At end of parsing, we may perform a capture of the error (if any), and
Willy Tarreaue7dff022015-04-03 01:14:29 +02002545 * we will set a few fields (txn->meth, sn->flags/SF_REDIRECTABLE).
Willy Tarreaud787e662009-07-07 10:14:51 +02002546 * We also check for monitor-uri, logging, HTTP/0.9 to 1.0 conversion, and
2547 * finally headers capture.
Willy Tarreau59234e92008-11-30 23:51:27 +01002548 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01002549
Willy Tarreau59234e92008-11-30 23:51:27 +01002550 int cur_idx;
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002551 int use_close_only;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002552 struct session *sess = s->sess;
Willy Tarreaueee5b512015-04-03 23:46:31 +02002553 struct http_txn *txn = s->txn;
Willy Tarreau59234e92008-11-30 23:51:27 +01002554 struct http_msg *msg = &txn->req;
Willy Tarreau32b47f42009-10-18 20:55:02 +02002555 struct hdr_ctx ctx;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01002556
Willy Tarreau87b09662015-04-03 00:22:06 +02002557 DPRINTF(stderr,"[%u] %s: stream=%p b=%p, exp(r,w)=%u,%u bf=%08x bh=%d analysers=%02x\n",
Willy Tarreau6bf17362009-02-24 10:48:35 +01002558 now_ms, __FUNCTION__,
2559 s,
2560 req,
2561 req->rex, req->wex,
2562 req->flags,
Willy Tarreau9b28e032012-10-12 23:49:43 +02002563 req->buf->i,
Willy Tarreau6bf17362009-02-24 10:48:35 +01002564 req->analysers);
2565
Willy Tarreau52a0c602009-08-16 22:45:38 +02002566 /* we're speaking HTTP here, so let's speak HTTP to the client */
2567 s->srv_error = http_return_srv_error;
2568
Willy Tarreau83e3af02009-12-28 17:39:57 +01002569 /* There's a protected area at the end of the buffer for rewriting
2570 * purposes. We don't want to start to parse the request if the
2571 * protected area is affected, because we may have to move processed
2572 * data later, which is much more complicated.
2573 */
Willy Tarreau9b28e032012-10-12 23:49:43 +02002574 if (buffer_not_empty(req->buf) && msg->msg_state < HTTP_MSG_ERROR) {
Willy Tarreau379357a2013-06-08 12:55:46 +02002575 if (txn->flags & TX_NOT_FIRST) {
Willy Tarreauba0902e2015-01-13 14:39:16 +01002576 if (unlikely(!channel_is_rewritable(req))) {
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02002577 if (req->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_WRITE_ERROR|CF_WRITE_TIMEOUT))
Willy Tarreau64648412010-03-05 10:41:54 +01002578 goto failed_keep_alive;
Willy Tarreau2ab6eb12010-01-02 22:04:45 +01002579 /* some data has still not left the buffer, wake us once that's done */
Willy Tarreau8263d2b2012-08-28 00:06:31 +02002580 channel_dont_connect(req);
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02002581 req->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */
Willy Tarreaud7ad9f52013-12-31 17:26:25 +01002582 req->flags |= CF_WAKE_WRITE;
Willy Tarreau2ab6eb12010-01-02 22:04:45 +01002583 return 0;
2584 }
Willy Tarreau379357a2013-06-08 12:55:46 +02002585 if (unlikely(bi_end(req->buf) < b_ptr(req->buf, msg->next) ||
2586 bi_end(req->buf) > req->buf->data + req->buf->size - global.tune.maxrewrite))
2587 buffer_slow_realign(req->buf);
Willy Tarreau83e3af02009-12-28 17:39:57 +01002588 }
2589
Willy Tarreau065e8332010-01-08 00:30:20 +01002590 /* Note that we have the same problem with the response ; we
2591 * may want to send a redirect, error or anything which requires
2592 * some spare space. So we'll ensure that we have at least
2593 * maxrewrite bytes available in the response buffer before
2594 * processing that one. This will only affect pipelined
2595 * keep-alive requests.
2596 */
2597 if ((txn->flags & TX_NOT_FIRST) &&
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01002598 unlikely(!channel_is_rewritable(&s->res) ||
2599 bi_end(s->res.buf) < b_ptr(s->res.buf, txn->rsp.next) ||
2600 bi_end(s->res.buf) > s->res.buf->data + s->res.buf->size - global.tune.maxrewrite)) {
2601 if (s->res.buf->o) {
2602 if (s->res.flags & (CF_SHUTW|CF_SHUTW_NOW|CF_WRITE_ERROR|CF_WRITE_TIMEOUT))
Willy Tarreau64648412010-03-05 10:41:54 +01002603 goto failed_keep_alive;
Willy Tarreau065e8332010-01-08 00:30:20 +01002604 /* don't let a connection request be initiated */
Willy Tarreau8263d2b2012-08-28 00:06:31 +02002605 channel_dont_connect(req);
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01002606 s->res.flags &= ~CF_EXPECT_MORE; /* speed up sending a previous response */
2607 s->res.flags |= CF_WAKE_WRITE;
2608 s->res.analysers |= an_bit; /* wake us up once it changes */
Willy Tarreau065e8332010-01-08 00:30:20 +01002609 return 0;
2610 }
2611 }
2612
Willy Tarreau9b28e032012-10-12 23:49:43 +02002613 if (likely(msg->next < req->buf->i)) /* some unparsed data are available */
Willy Tarreaua560c212012-03-09 13:50:57 +01002614 http_msg_analyzer(msg, &txn->hdr_idx);
Willy Tarreau83e3af02009-12-28 17:39:57 +01002615 }
2616
Willy Tarreau59234e92008-11-30 23:51:27 +01002617 /* 1: we might have to print this header in debug mode */
2618 if (unlikely((global.mode & MODE_DEBUG) &&
2619 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
Willy Tarreau7d59e902014-10-21 19:36:09 +02002620 msg->msg_state >= HTTP_MSG_BODY)) {
Willy Tarreau59234e92008-11-30 23:51:27 +01002621 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01002622
Willy Tarreau9b28e032012-10-12 23:49:43 +02002623 sol = req->buf->p;
Willy Tarreaue92693a2012-09-24 21:13:39 +02002624 /* this is a bit complex : in case of error on the request line,
2625 * we know that rq.l is still zero, so we display only the part
2626 * up to the end of the line (truncated by debug_hdr).
2627 */
Willy Tarreau9b28e032012-10-12 23:49:43 +02002628 eol = sol + (msg->sl.rq.l ? msg->sl.rq.l : req->buf->i);
Willy Tarreau59234e92008-11-30 23:51:27 +01002629 debug_hdr("clireq", s, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01002630
Willy Tarreau59234e92008-11-30 23:51:27 +01002631 sol += hdr_idx_first_pos(&txn->hdr_idx);
2632 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01002633
Willy Tarreau59234e92008-11-30 23:51:27 +01002634 while (cur_idx) {
2635 eol = sol + txn->hdr_idx.v[cur_idx].len;
2636 debug_hdr("clihdr", s, sol, eol);
2637 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
2638 cur_idx = txn->hdr_idx.v[cur_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002639 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002640 }
2641
Willy Tarreau58f10d72006-12-04 02:26:12 +01002642
Willy Tarreau59234e92008-11-30 23:51:27 +01002643 /*
2644 * Now we quickly check if we have found a full valid request.
2645 * If not so, we check the FD and buffer states before leaving.
2646 * A full request is indicated by the fact that we have seen
Willy Tarreau655dce92009-11-08 13:10:58 +01002647 * the double LF/CRLF, so the state is >= HTTP_MSG_BODY. Invalid
Willy Tarreaud3c343f2010-01-16 10:26:19 +01002648 * requests are checked first. When waiting for a second request
Willy Tarreau87b09662015-04-03 00:22:06 +02002649 * on a keep-alive stream, if we encounter and error, close, t/o,
2650 * we note the error in the stream flags but don't set any state.
Willy Tarreaud3c343f2010-01-16 10:26:19 +01002651 * Since the error will be noted there, it will not be counted by
Willy Tarreau87b09662015-04-03 00:22:06 +02002652 * process_stream() as a frontend error.
Willy Tarreauda7ff642010-06-23 11:44:09 +02002653 * Last, we may increase some tracked counters' http request errors on
2654 * the cases that are deliberately the client's fault. For instance,
2655 * a timeout or connection reset is not counted as an error. However
2656 * a bad request is.
Willy Tarreau59234e92008-11-30 23:51:27 +01002657 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01002658
Willy Tarreau655dce92009-11-08 13:10:58 +01002659 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01002660 /*
Willy Tarreau59234e92008-11-30 23:51:27 +01002661 * First, let's catch bad requests.
Willy Tarreau58f10d72006-12-04 02:26:12 +01002662 */
Willy Tarreau3e1b6d12010-03-04 23:02:38 +01002663 if (unlikely(msg->msg_state == HTTP_MSG_ERROR)) {
Willy Tarreau87b09662015-04-03 00:22:06 +02002664 stream_inc_http_req_ctr(s);
2665 stream_inc_http_err_ctr(s);
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002666 proxy_inc_fe_req_ctr(sess->fe);
Willy Tarreau59234e92008-11-30 23:51:27 +01002667 goto return_bad_req;
Willy Tarreau3e1b6d12010-03-04 23:02:38 +01002668 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002669
Willy Tarreau59234e92008-11-30 23:51:27 +01002670 /* 1: Since we are in header mode, if there's no space
2671 * left for headers, we won't be able to free more
Willy Tarreau87b09662015-04-03 00:22:06 +02002672 * later, so the stream will never terminate. We
Willy Tarreau59234e92008-11-30 23:51:27 +01002673 * must terminate it now.
2674 */
Willy Tarreau9b28e032012-10-12 23:49:43 +02002675 if (unlikely(buffer_full(req->buf, global.tune.maxrewrite))) {
Willy Tarreau59234e92008-11-30 23:51:27 +01002676 /* FIXME: check if URI is set and return Status
2677 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01002678 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002679 stream_inc_http_req_ctr(s);
2680 stream_inc_http_err_ctr(s);
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002681 proxy_inc_fe_req_ctr(sess->fe);
Willy Tarreaufec4d892011-09-02 20:04:57 +02002682 if (msg->err_pos < 0)
Willy Tarreau9b28e032012-10-12 23:49:43 +02002683 msg->err_pos = req->buf->i;
Willy Tarreau59234e92008-11-30 23:51:27 +01002684 goto return_bad_req;
2685 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002686
Willy Tarreau59234e92008-11-30 23:51:27 +01002687 /* 2: have we encountered a read error ? */
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02002688 else if (req->flags & CF_READ_ERROR) {
Willy Tarreaue7dff022015-04-03 01:14:29 +02002689 if (!(s->flags & SF_ERR_MASK))
2690 s->flags |= SF_ERR_CLICL;
Willy Tarreaud3c343f2010-01-16 10:26:19 +01002691
Willy Tarreaufcffa692010-01-10 14:21:19 +01002692 if (txn->flags & TX_WAIT_NEXT_RQ)
Willy Tarreaub608feb2010-01-02 22:47:18 +01002693 goto failed_keep_alive;
2694
Willy Tarreau59234e92008-11-30 23:51:27 +01002695 /* we cannot return any message on error */
Willy Tarreauda7ff642010-06-23 11:44:09 +02002696 if (msg->err_pos >= 0) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002697 http_capture_bad_message(&sess->fe->invalid_req, s, msg, msg->msg_state, sess->fe);
Willy Tarreau87b09662015-04-03 00:22:06 +02002698 stream_inc_http_err_ctr(s);
Willy Tarreauda7ff642010-06-23 11:44:09 +02002699 }
2700
Willy Tarreaudc979f22012-12-04 10:39:01 +01002701 txn->status = 400;
Willy Tarreau350f4872014-11-28 14:42:25 +01002702 stream_int_retnclose(&s->si[0], NULL);
Willy Tarreau59234e92008-11-30 23:51:27 +01002703 msg->msg_state = HTTP_MSG_ERROR;
2704 req->analysers = 0;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002705
Willy Tarreau87b09662015-04-03 00:22:06 +02002706 stream_inc_http_req_ctr(s);
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002707 proxy_inc_fe_req_ctr(sess->fe);
2708 sess->fe->fe_counters.failed_req++;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002709 if (sess->listener->counters)
2710 sess->listener->counters->failed_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002711
Willy Tarreaue7dff022015-04-03 01:14:29 +02002712 if (!(s->flags & SF_FINST_MASK))
2713 s->flags |= SF_FINST_R;
Willy Tarreau59234e92008-11-30 23:51:27 +01002714 return 0;
2715 }
Willy Tarreauf9839bd2008-08-27 23:57:16 +02002716
Willy Tarreau59234e92008-11-30 23:51:27 +01002717 /* 3: has the read timeout expired ? */
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02002718 else if (req->flags & CF_READ_TIMEOUT || tick_is_expired(req->analyse_exp, now_ms)) {
Willy Tarreaue7dff022015-04-03 01:14:29 +02002719 if (!(s->flags & SF_ERR_MASK))
2720 s->flags |= SF_ERR_CLITO;
Willy Tarreaud3c343f2010-01-16 10:26:19 +01002721
Willy Tarreaufcffa692010-01-10 14:21:19 +01002722 if (txn->flags & TX_WAIT_NEXT_RQ)
Willy Tarreaub608feb2010-01-02 22:47:18 +01002723 goto failed_keep_alive;
2724
Willy Tarreau59234e92008-11-30 23:51:27 +01002725 /* read timeout : give up with an error message. */
Willy Tarreauda7ff642010-06-23 11:44:09 +02002726 if (msg->err_pos >= 0) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002727 http_capture_bad_message(&sess->fe->invalid_req, s, msg, msg->msg_state, sess->fe);
Willy Tarreau87b09662015-04-03 00:22:06 +02002728 stream_inc_http_err_ctr(s);
Willy Tarreauda7ff642010-06-23 11:44:09 +02002729 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002730 txn->status = 408;
Willy Tarreau350f4872014-11-28 14:42:25 +01002731 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_408));
Willy Tarreau59234e92008-11-30 23:51:27 +01002732 msg->msg_state = HTTP_MSG_ERROR;
2733 req->analysers = 0;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002734
Willy Tarreau87b09662015-04-03 00:22:06 +02002735 stream_inc_http_req_ctr(s);
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002736 proxy_inc_fe_req_ctr(sess->fe);
2737 sess->fe->fe_counters.failed_req++;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002738 if (sess->listener->counters)
2739 sess->listener->counters->failed_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002740
Willy Tarreaue7dff022015-04-03 01:14:29 +02002741 if (!(s->flags & SF_FINST_MASK))
2742 s->flags |= SF_FINST_R;
Willy Tarreau59234e92008-11-30 23:51:27 +01002743 return 0;
2744 }
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02002745
Willy Tarreau59234e92008-11-30 23:51:27 +01002746 /* 4: have we encountered a close ? */
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02002747 else if (req->flags & CF_SHUTR) {
Willy Tarreaue7dff022015-04-03 01:14:29 +02002748 if (!(s->flags & SF_ERR_MASK))
2749 s->flags |= SF_ERR_CLICL;
Willy Tarreaud3c343f2010-01-16 10:26:19 +01002750
Willy Tarreaufcffa692010-01-10 14:21:19 +01002751 if (txn->flags & TX_WAIT_NEXT_RQ)
Willy Tarreaub608feb2010-01-02 22:47:18 +01002752 goto failed_keep_alive;
2753
Willy Tarreau4076a152009-04-02 15:18:36 +02002754 if (msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002755 http_capture_bad_message(&sess->fe->invalid_req, s, msg, msg->msg_state, sess->fe);
Willy Tarreau59234e92008-11-30 23:51:27 +01002756 txn->status = 400;
Willy Tarreau350f4872014-11-28 14:42:25 +01002757 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_400));
Willy Tarreau59234e92008-11-30 23:51:27 +01002758 msg->msg_state = HTTP_MSG_ERROR;
2759 req->analysers = 0;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002760
Willy Tarreau87b09662015-04-03 00:22:06 +02002761 stream_inc_http_err_ctr(s);
2762 stream_inc_http_req_ctr(s);
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002763 proxy_inc_fe_req_ctr(sess->fe);
2764 sess->fe->fe_counters.failed_req++;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002765 if (sess->listener->counters)
2766 sess->listener->counters->failed_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002767
Willy Tarreaue7dff022015-04-03 01:14:29 +02002768 if (!(s->flags & SF_FINST_MASK))
2769 s->flags |= SF_FINST_R;
Willy Tarreaudafde432008-08-17 01:00:46 +02002770 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01002771 }
2772
Willy Tarreau8263d2b2012-08-28 00:06:31 +02002773 channel_dont_connect(req);
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02002774 req->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01002775 s->res.flags &= ~CF_EXPECT_MORE; /* speed up sending a previous response */
Willy Tarreau5e205522011-12-17 16:34:27 +01002776#ifdef TCP_QUICKACK
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002777 if (sess->listener->options & LI_O_NOQUICKACK && req->buf->i &&
2778 objt_conn(sess->origin) && conn_ctrl_ready(__objt_conn(sess->origin))) {
Willy Tarreau5e205522011-12-17 16:34:27 +01002779 /* We need more data, we have to re-enable quick-ack in case we
2780 * previously disabled it, otherwise we might cause the client
2781 * to delay next data.
2782 */
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002783 setsockopt(__objt_conn(sess->origin)->t.sock.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
Willy Tarreau5e205522011-12-17 16:34:27 +01002784 }
2785#endif
Willy Tarreau1b194fe2009-03-21 21:10:04 +01002786
Willy Tarreaufcffa692010-01-10 14:21:19 +01002787 if ((msg->msg_state != HTTP_MSG_RQBEFORE) && (txn->flags & TX_WAIT_NEXT_RQ)) {
2788 /* If the client starts to talk, let's fall back to
2789 * request timeout processing.
2790 */
2791 txn->flags &= ~TX_WAIT_NEXT_RQ;
Willy Tarreaub16a5742010-01-10 14:46:16 +01002792 req->analyse_exp = TICK_ETERNITY;
Willy Tarreaufcffa692010-01-10 14:21:19 +01002793 }
2794
Willy Tarreau59234e92008-11-30 23:51:27 +01002795 /* just set the request timeout once at the beginning of the request */
Willy Tarreaub16a5742010-01-10 14:46:16 +01002796 if (!tick_isset(req->analyse_exp)) {
2797 if ((msg->msg_state == HTTP_MSG_RQBEFORE) &&
2798 (txn->flags & TX_WAIT_NEXT_RQ) &&
2799 tick_isset(s->be->timeout.httpka))
2800 req->analyse_exp = tick_add(now_ms, s->be->timeout.httpka);
2801 else
2802 req->analyse_exp = tick_add_ifset(now_ms, s->be->timeout.httpreq);
2803 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002804
Willy Tarreau59234e92008-11-30 23:51:27 +01002805 /* we're not ready yet */
2806 return 0;
Willy Tarreaub608feb2010-01-02 22:47:18 +01002807
2808 failed_keep_alive:
2809 /* Here we process low-level errors for keep-alive requests. In
2810 * short, if the request is not the first one and it experiences
2811 * a timeout, read error or shutdown, we just silently close so
2812 * that the client can try again.
2813 */
2814 txn->status = 0;
2815 msg->msg_state = HTTP_MSG_RQBEFORE;
2816 req->analysers = 0;
2817 s->logs.logwait = 0;
Willy Tarreauabcd5142013-06-11 17:18:02 +02002818 s->logs.level = 0;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01002819 s->res.flags &= ~CF_EXPECT_MORE; /* speed up sending a previous response */
Willy Tarreau350f4872014-11-28 14:42:25 +01002820 stream_int_retnclose(&s->si[0], NULL);
Willy Tarreaub608feb2010-01-02 22:47:18 +01002821 return 0;
Willy Tarreau59234e92008-11-30 23:51:27 +01002822 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002823
Willy Tarreaud787e662009-07-07 10:14:51 +02002824 /* OK now we have a complete HTTP request with indexed headers. Let's
2825 * complete the request parsing by setting a few fields we will need
Willy Tarreau9b28e032012-10-12 23:49:43 +02002826 * later. At this point, we have the last CRLF at req->buf->data + msg->eoh.
Willy Tarreaufa355d42009-11-29 18:12:29 +01002827 * If the request is in HTTP/0.9 form, the rule is still true, and eoh
Willy Tarreaua458b672012-03-05 11:17:50 +01002828 * points to the CRLF of the request line. msg->next points to the first
Willy Tarreaufa4a03c2012-03-09 21:28:54 +01002829 * byte after the last LF. msg->sov points to the first byte of data.
2830 * msg->eol cannot be trusted because it may have been left uninitialized
2831 * (for instance in the absence of headers).
Willy Tarreaud787e662009-07-07 10:14:51 +02002832 */
Willy Tarreau9cdde232007-05-02 20:58:19 +02002833
Willy Tarreau87b09662015-04-03 00:22:06 +02002834 stream_inc_http_req_ctr(s);
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002835 proxy_inc_fe_req_ctr(sess->fe); /* one more valid request for this FE */
Willy Tarreaud9b587f2010-02-26 10:05:55 +01002836
Willy Tarreaub16a5742010-01-10 14:46:16 +01002837 if (txn->flags & TX_WAIT_NEXT_RQ) {
2838 /* kill the pending keep-alive timeout */
2839 txn->flags &= ~TX_WAIT_NEXT_RQ;
2840 req->analyse_exp = TICK_ETERNITY;
2841 }
2842
2843
Willy Tarreaud787e662009-07-07 10:14:51 +02002844 /* Maybe we found in invalid header name while we were configured not
2845 * to block on that, so we have to capture it now.
2846 */
2847 if (unlikely(msg->err_pos >= 0))
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002848 http_capture_bad_message(&sess->fe->invalid_req, s, msg, msg->msg_state, sess->fe);
Willy Tarreau4076a152009-04-02 15:18:36 +02002849
Willy Tarreau59234e92008-11-30 23:51:27 +01002850 /*
2851 * 1: identify the method
2852 */
Willy Tarreau9b28e032012-10-12 23:49:43 +02002853 txn->meth = find_http_meth(req->buf->p, msg->sl.rq.m_l);
Willy Tarreau59234e92008-11-30 23:51:27 +01002854
2855 /* we can make use of server redirect on GET and HEAD */
2856 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
Willy Tarreaue7dff022015-04-03 01:14:29 +02002857 s->flags |= SF_REDIRECTABLE;
Willy Tarreaufa7e1022008-10-19 07:30:41 +02002858
Willy Tarreau59234e92008-11-30 23:51:27 +01002859 /*
2860 * 2: check if the URI matches the monitor_uri.
2861 * We have to do this for every request which gets in, because
2862 * the monitor-uri is defined by the frontend.
2863 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002864 if (unlikely((sess->fe->monitor_uri_len != 0) &&
2865 (sess->fe->monitor_uri_len == msg->sl.rq.u_l) &&
Willy Tarreau9b28e032012-10-12 23:49:43 +02002866 !memcmp(req->buf->p + msg->sl.rq.u,
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002867 sess->fe->monitor_uri,
2868 sess->fe->monitor_uri_len))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01002869 /*
Willy Tarreau59234e92008-11-30 23:51:27 +01002870 * We have found the monitor URI
Willy Tarreau58f10d72006-12-04 02:26:12 +01002871 */
Willy Tarreau59234e92008-11-30 23:51:27 +01002872 struct acl_cond *cond;
Willy Tarreaub80c2302007-11-30 20:51:32 +01002873
Willy Tarreaue7dff022015-04-03 01:14:29 +02002874 s->flags |= SF_MONITOR;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002875 sess->fe->fe_counters.intercepted_req++;
Willy Tarreaub80c2302007-11-30 20:51:32 +01002876
Willy Tarreau59234e92008-11-30 23:51:27 +01002877 /* Check if we want to fail this monitor request or not */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002878 list_for_each_entry(cond, &sess->fe->mon_fail_cond, list) {
Willy Tarreau15e91e12015-04-04 00:52:09 +02002879 int ret = acl_exec_cond(cond, sess->fe, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
Willy Tarreau11382812008-07-09 16:18:21 +02002880
Willy Tarreau59234e92008-11-30 23:51:27 +01002881 ret = acl_pass(ret);
2882 if (cond->pol == ACL_COND_UNLESS)
2883 ret = !ret;
Willy Tarreaub80c2302007-11-30 20:51:32 +01002884
Willy Tarreau59234e92008-11-30 23:51:27 +01002885 if (ret) {
2886 /* we fail this request, let's return 503 service unavail */
2887 txn->status = 503;
Willy Tarreau350f4872014-11-28 14:42:25 +01002888 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_503));
Willy Tarreaue7dff022015-04-03 01:14:29 +02002889 if (!(s->flags & SF_ERR_MASK))
2890 s->flags |= SF_ERR_LOCAL; /* we don't want a real error here */
Willy Tarreau59234e92008-11-30 23:51:27 +01002891 goto return_prx_cond;
Willy Tarreaub80c2302007-11-30 20:51:32 +01002892 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002893 }
Willy Tarreaua5555ec2008-11-30 19:02:32 +01002894
Willy Tarreau59234e92008-11-30 23:51:27 +01002895 /* nothing to fail, let's reply normaly */
2896 txn->status = 200;
Willy Tarreau350f4872014-11-28 14:42:25 +01002897 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_200));
Willy Tarreaue7dff022015-04-03 01:14:29 +02002898 if (!(s->flags & SF_ERR_MASK))
2899 s->flags |= SF_ERR_LOCAL; /* we don't want a real error here */
Willy Tarreau59234e92008-11-30 23:51:27 +01002900 goto return_prx_cond;
2901 }
2902
2903 /*
2904 * 3: Maybe we have to copy the original REQURI for the logs ?
2905 * Note: we cannot log anymore if the request has been
2906 * classified as invalid.
2907 */
2908 if (unlikely(s->logs.logwait & LW_REQ)) {
2909 /* we have a complete HTTP request that we must log */
2910 if ((txn->uri = pool_alloc2(pool2_requri)) != NULL) {
2911 int urilen = msg->sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002912
Willy Tarreau59234e92008-11-30 23:51:27 +01002913 if (urilen >= REQURI_LEN)
2914 urilen = REQURI_LEN - 1;
Willy Tarreau9b28e032012-10-12 23:49:43 +02002915 memcpy(txn->uri, req->buf->p, urilen);
Willy Tarreau59234e92008-11-30 23:51:27 +01002916 txn->uri[urilen] = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002917
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002918 if (!(s->logs.logwait &= ~(LW_REQ|LW_INIT)))
Willy Tarreau59234e92008-11-30 23:51:27 +01002919 s->do_log(s);
2920 } else {
2921 Alert("HTTP logging : out of memory.\n");
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002922 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002923 }
Willy Tarreau06619262006-12-17 08:37:22 +01002924
Willy Tarreau59234e92008-11-30 23:51:27 +01002925 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
Willy Tarreau418bfcc2012-03-09 13:56:20 +01002926 if (unlikely(msg->sl.rq.v_l == 0) && !http_upgrade_v09_to_v10(txn))
Willy Tarreau2492d5b2009-07-11 00:06:00 +02002927 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01002928
Willy Tarreau5b154472009-12-21 20:11:07 +01002929 /* ... and check if the request is HTTP/1.1 or above */
2930 if ((msg->sl.rq.v_l == 8) &&
Willy Tarreau9b28e032012-10-12 23:49:43 +02002931 ((req->buf->p[msg->sl.rq.v + 5] > '1') ||
2932 ((req->buf->p[msg->sl.rq.v + 5] == '1') &&
2933 (req->buf->p[msg->sl.rq.v + 7] >= '1'))))
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01002934 msg->flags |= HTTP_MSGF_VER_11;
Willy Tarreau5b154472009-12-21 20:11:07 +01002935
2936 /* "connection" has not been parsed yet */
Willy Tarreau50fc7772012-11-11 22:19:57 +01002937 txn->flags &= ~(TX_HDR_CONN_PRS | TX_HDR_CONN_CLO | TX_HDR_CONN_KAL | TX_HDR_CONN_UPG);
Willy Tarreau5b154472009-12-21 20:11:07 +01002938
Willy Tarreau88d349d2010-01-25 12:15:43 +01002939 /* if the frontend has "option http-use-proxy-header", we'll check if
2940 * we have what looks like a proxied connection instead of a connection,
2941 * and in this case set the TX_USE_PX_CONN flag to use Proxy-connection.
2942 * Note that this is *not* RFC-compliant, however browsers and proxies
2943 * happen to do that despite being non-standard :-(
2944 * We consider that a request not beginning with either '/' or '*' is
2945 * a proxied connection, which covers both "scheme://location" and
2946 * CONNECT ip:port.
2947 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002948 if ((sess->fe->options2 & PR_O2_USE_PXHDR) &&
Willy Tarreau9b28e032012-10-12 23:49:43 +02002949 req->buf->p[msg->sl.rq.u] != '/' && req->buf->p[msg->sl.rq.u] != '*')
Willy Tarreau88d349d2010-01-25 12:15:43 +01002950 txn->flags |= TX_USE_PX_CONN;
2951
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002952 /* transfer length unknown*/
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01002953 msg->flags &= ~HTTP_MSGF_XFER_LEN;
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002954
Willy Tarreau59234e92008-11-30 23:51:27 +01002955 /* 5: we may need to capture headers */
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002956 if (unlikely((s->logs.logwait & LW_REQHDR) && s->req_cap))
Willy Tarreau9b28e032012-10-12 23:49:43 +02002957 capture_headers(req->buf->p, &txn->hdr_idx,
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002958 s->req_cap, sess->fe->req_cap);
Willy Tarreau11382812008-07-09 16:18:21 +02002959
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002960 /* 6: determine the transfer-length.
2961 * According to RFC2616 #4.4, amended by the HTTPbis working group,
2962 * the presence of a message-body in a REQUEST and its transfer length
2963 * must be determined that way (in order of precedence) :
2964 * 1. The presence of a message-body in a request is signaled by the
2965 * inclusion of a Content-Length or Transfer-Encoding header field
2966 * in the request's header fields. When a request message contains
2967 * both a message-body of non-zero length and a method that does
2968 * not define any semantics for that request message-body, then an
2969 * origin server SHOULD either ignore the message-body or respond
2970 * with an appropriate error message (e.g., 413). A proxy or
2971 * gateway, when presented the same request, SHOULD either forward
2972 * the request inbound with the message- body or ignore the
2973 * message-body when determining a response.
2974 *
2975 * 2. If a Transfer-Encoding header field (Section 9.7) is present
2976 * and the "chunked" transfer-coding (Section 6.2) is used, the
2977 * transfer-length is defined by the use of this transfer-coding.
2978 * If a Transfer-Encoding header field is present and the "chunked"
2979 * transfer-coding is not present, the transfer-length is defined
2980 * by the sender closing the connection.
Willy Tarreau32b47f42009-10-18 20:55:02 +02002981 *
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002982 * 3. If a Content-Length header field is present, its decimal value in
2983 * OCTETs represents both the entity-length and the transfer-length.
2984 * If a message is received with both a Transfer-Encoding header
2985 * field and a Content-Length header field, the latter MUST be ignored.
Willy Tarreau32b47f42009-10-18 20:55:02 +02002986 *
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002987 * 4. By the server closing the connection. (Closing the connection
2988 * cannot be used to indicate the end of a request body, since that
2989 * would leave no possibility for the server to send back a response.)
2990 *
2991 * Whenever a transfer-coding is applied to a message-body, the set of
2992 * transfer-codings MUST include "chunked", unless the message indicates
2993 * it is terminated by closing the connection. When the "chunked"
2994 * transfer-coding is used, it MUST be the last transfer-coding applied
2995 * to the message-body.
Willy Tarreau32b47f42009-10-18 20:55:02 +02002996 */
2997
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002998 use_close_only = 0;
Willy Tarreau32b47f42009-10-18 20:55:02 +02002999 ctx.idx = 0;
Willy Tarreaue8e785b2009-12-26 15:34:26 +01003000 /* set TE_CHNK and XFER_LEN only if "chunked" is seen last */
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01003001 while ((msg->flags & HTTP_MSGF_VER_11) &&
Willy Tarreau9b28e032012-10-12 23:49:43 +02003002 http_find_header2("Transfer-Encoding", 17, req->buf->p, &txn->hdr_idx, &ctx)) {
Willy Tarreaue8e785b2009-12-26 15:34:26 +01003003 if (ctx.vlen == 7 && strncasecmp(ctx.line + ctx.val, "chunked", 7) == 0)
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01003004 msg->flags |= (HTTP_MSGF_TE_CHNK | HTTP_MSGF_XFER_LEN);
3005 else if (msg->flags & HTTP_MSGF_TE_CHNK) {
Willy Tarreaue8e785b2009-12-26 15:34:26 +01003006 /* bad transfer-encoding (chunked followed by something else) */
3007 use_close_only = 1;
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01003008 msg->flags &= ~(HTTP_MSGF_TE_CHNK | HTTP_MSGF_XFER_LEN);
Willy Tarreaue8e785b2009-12-26 15:34:26 +01003009 break;
3010 }
Willy Tarreau32b47f42009-10-18 20:55:02 +02003011 }
3012
Willy Tarreau32b47f42009-10-18 20:55:02 +02003013 ctx.idx = 0;
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01003014 while (!(msg->flags & HTTP_MSGF_TE_CHNK) && !use_close_only &&
Willy Tarreau9b28e032012-10-12 23:49:43 +02003015 http_find_header2("Content-Length", 14, req->buf->p, &txn->hdr_idx, &ctx)) {
Willy Tarreau32b47f42009-10-18 20:55:02 +02003016 signed long long cl;
3017
Willy Tarreauad14f752011-09-02 20:33:27 +02003018 if (!ctx.vlen) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02003019 msg->err_pos = ctx.line + ctx.val - req->buf->p;
Willy Tarreau32b47f42009-10-18 20:55:02 +02003020 goto return_bad_req;
Willy Tarreauad14f752011-09-02 20:33:27 +02003021 }
Willy Tarreau32b47f42009-10-18 20:55:02 +02003022
Willy Tarreauad14f752011-09-02 20:33:27 +02003023 if (strl2llrc(ctx.line + ctx.val, ctx.vlen, &cl)) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02003024 msg->err_pos = ctx.line + ctx.val - req->buf->p;
Willy Tarreau32b47f42009-10-18 20:55:02 +02003025 goto return_bad_req; /* parse failure */
Willy Tarreauad14f752011-09-02 20:33:27 +02003026 }
Willy Tarreau32b47f42009-10-18 20:55:02 +02003027
Willy Tarreauad14f752011-09-02 20:33:27 +02003028 if (cl < 0) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02003029 msg->err_pos = ctx.line + ctx.val - req->buf->p;
Willy Tarreau32b47f42009-10-18 20:55:02 +02003030 goto return_bad_req;
Willy Tarreauad14f752011-09-02 20:33:27 +02003031 }
Willy Tarreau32b47f42009-10-18 20:55:02 +02003032
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01003033 if ((msg->flags & HTTP_MSGF_CNT_LEN) && (msg->chunk_len != cl)) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02003034 msg->err_pos = ctx.line + ctx.val - req->buf->p;
Willy Tarreau32b47f42009-10-18 20:55:02 +02003035 goto return_bad_req; /* already specified, was different */
Willy Tarreauad14f752011-09-02 20:33:27 +02003036 }
Willy Tarreau32b47f42009-10-18 20:55:02 +02003037
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01003038 msg->flags |= HTTP_MSGF_CNT_LEN | HTTP_MSGF_XFER_LEN;
Willy Tarreau124d9912011-03-01 20:30:48 +01003039 msg->body_len = msg->chunk_len = cl;
Willy Tarreau32b47f42009-10-18 20:55:02 +02003040 }
3041
Willy Tarreaue8e785b2009-12-26 15:34:26 +01003042 /* bodyless requests have a known length */
3043 if (!use_close_only)
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01003044 msg->flags |= HTTP_MSGF_XFER_LEN;
Willy Tarreaue8e785b2009-12-26 15:34:26 +01003045
Willy Tarreau179085c2014-04-28 16:48:56 +02003046 /* Until set to anything else, the connection mode is set as Keep-Alive. It will
3047 * only change if both the request and the config reference something else.
3048 * Option httpclose by itself sets tunnel mode where headers are mangled.
3049 * However, if another mode is set, it will affect it (eg: server-close/
3050 * keep-alive + httpclose = close). Note that we avoid to redo the same work
3051 * if FE and BE have the same settings (common). The method consists in
3052 * checking if options changed between the two calls (implying that either
3053 * one is non-null, or one of them is non-null and we are there for the first
3054 * time.
3055 */
3056 if (!(txn->flags & TX_HDR_CONN_PRS) ||
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003057 ((sess->fe->options & PR_O_HTTP_MODE) != (s->be->options & PR_O_HTTP_MODE)))
Willy Tarreau4e21ff92014-09-30 18:44:22 +02003058 http_adjust_conn_mode(s, txn, msg);
Willy Tarreau179085c2014-04-28 16:48:56 +02003059
Willy Tarreaud787e662009-07-07 10:14:51 +02003060 /* end of job, return OK */
Willy Tarreau3a816292009-07-07 10:55:49 +02003061 req->analysers &= ~an_bit;
Willy Tarreaud787e662009-07-07 10:14:51 +02003062 req->analyse_exp = TICK_ETERNITY;
3063 return 1;
3064
3065 return_bad_req:
3066 /* We centralize bad requests processing here */
3067 if (unlikely(msg->msg_state == HTTP_MSG_ERROR) || msg->err_pos >= 0) {
3068 /* we detected a parsing error. We want to archive this request
3069 * in the dedicated proxy area for later troubleshooting.
3070 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003071 http_capture_bad_message(&sess->fe->invalid_req, s, msg, msg->msg_state, sess->fe);
Willy Tarreaud787e662009-07-07 10:14:51 +02003072 }
3073
3074 txn->req.msg_state = HTTP_MSG_ERROR;
3075 txn->status = 400;
Willy Tarreau350f4872014-11-28 14:42:25 +01003076 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_400));
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02003077
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003078 sess->fe->fe_counters.failed_req++;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02003079 if (sess->listener->counters)
3080 sess->listener->counters->failed_req++;
Willy Tarreaud787e662009-07-07 10:14:51 +02003081
3082 return_prx_cond:
Willy Tarreaue7dff022015-04-03 01:14:29 +02003083 if (!(s->flags & SF_ERR_MASK))
3084 s->flags |= SF_ERR_PRXCOND;
3085 if (!(s->flags & SF_FINST_MASK))
3086 s->flags |= SF_FINST_R;
Willy Tarreaud787e662009-07-07 10:14:51 +02003087
3088 req->analysers = 0;
3089 req->analyse_exp = TICK_ETERNITY;
3090 return 0;
3091}
3092
Willy Tarreau4f8a83c2012-06-04 00:26:23 +02003093
Willy Tarreau347a35d2013-11-22 17:51:09 +01003094/* This function prepares an applet to handle the stats. It can deal with the
3095 * "100-continue" expectation, check that admin rules are met for POST requests,
3096 * and program a response message if something was unexpected. It cannot fail
3097 * and always relies on the stats applet to complete the job. It does not touch
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003098 * analysers nor counters, which are left to the caller. It does not touch
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003099 * s->target which is supposed to already point to the stats applet. The caller
Willy Tarreau87b09662015-04-03 00:22:06 +02003100 * is expected to have already assigned an appctx to the stream.
Willy Tarreau1facd6d2012-12-22 22:03:39 +01003101 */
Willy Tarreau87b09662015-04-03 00:22:06 +02003102int http_handle_stats(struct stream *s, struct channel *req)
Willy Tarreau1facd6d2012-12-22 22:03:39 +01003103{
3104 struct stats_admin_rule *stats_admin_rule;
Willy Tarreau350f4872014-11-28 14:42:25 +01003105 struct stream_interface *si = &s->si[1];
Willy Tarreaueee5b512015-04-03 23:46:31 +02003106 struct http_txn *txn = s->txn;
Willy Tarreau1facd6d2012-12-22 22:03:39 +01003107 struct http_msg *msg = &txn->req;
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003108 struct uri_auth *uri_auth = s->be->uri_auth;
3109 const char *uri, *h, *lookup;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003110 struct appctx *appctx;
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003111
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003112 appctx = si_appctx(si);
3113 memset(&appctx->ctx.stats, 0, sizeof(appctx->ctx.stats));
3114 appctx->st1 = appctx->st2 = 0;
3115 appctx->ctx.stats.st_code = STAT_STATUS_INIT;
3116 appctx->ctx.stats.flags |= STAT_FMT_HTML; /* assume HTML mode by default */
Willy Tarreaueee5b512015-04-03 23:46:31 +02003117 if ((msg->flags & HTTP_MSGF_VER_11) && (s->txn->meth != HTTP_METH_HEAD))
Willy Tarreauaf3cf702014-04-22 22:19:53 +02003118 appctx->ctx.stats.flags |= STAT_CHUNKED;
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003119
3120 uri = msg->chn->buf->p + msg->sl.rq.u;
3121 lookup = uri + uri_auth->uri_len;
3122
3123 for (h = lookup; h <= uri + msg->sl.rq.u_l - 3; h++) {
3124 if (memcmp(h, ";up", 3) == 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003125 appctx->ctx.stats.flags |= STAT_HIDE_DOWN;
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003126 break;
3127 }
3128 }
3129
3130 if (uri_auth->refresh) {
3131 for (h = lookup; h <= uri + msg->sl.rq.u_l - 10; h++) {
3132 if (memcmp(h, ";norefresh", 10) == 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003133 appctx->ctx.stats.flags |= STAT_NO_REFRESH;
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003134 break;
3135 }
3136 }
3137 }
3138
3139 for (h = lookup; h <= uri + msg->sl.rq.u_l - 4; h++) {
3140 if (memcmp(h, ";csv", 4) == 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003141 appctx->ctx.stats.flags &= ~STAT_FMT_HTML;
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003142 break;
3143 }
3144 }
3145
3146 for (h = lookup; h <= uri + msg->sl.rq.u_l - 8; h++) {
3147 if (memcmp(h, ";st=", 4) == 0) {
3148 int i;
3149 h += 4;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003150 appctx->ctx.stats.st_code = STAT_STATUS_UNKN;
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003151 for (i = STAT_STATUS_INIT + 1; i < STAT_STATUS_SIZE; i++) {
3152 if (strncmp(stat_status_codes[i], h, 4) == 0) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003153 appctx->ctx.stats.st_code = i;
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003154 break;
3155 }
3156 }
3157 break;
3158 }
3159 }
3160
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003161 appctx->ctx.stats.scope_str = 0;
3162 appctx->ctx.stats.scope_len = 0;
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003163 for (h = lookup; h <= uri + msg->sl.rq.u_l - 8; h++) {
3164 if (memcmp(h, STAT_SCOPE_INPUT_NAME "=", strlen(STAT_SCOPE_INPUT_NAME) + 1) == 0) {
3165 int itx = 0;
3166 const char *h2;
3167 char scope_txt[STAT_SCOPE_TXT_MAXLEN + 1];
3168 const char *err;
3169
3170 h += strlen(STAT_SCOPE_INPUT_NAME) + 1;
3171 h2 = h;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003172 appctx->ctx.stats.scope_str = h2 - msg->chn->buf->p;
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003173 while (*h != ';' && *h != '\0' && *h != '&' && *h != ' ' && *h != '\n') {
3174 itx++;
3175 h++;
3176 }
3177
3178 if (itx > STAT_SCOPE_TXT_MAXLEN)
3179 itx = STAT_SCOPE_TXT_MAXLEN;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003180 appctx->ctx.stats.scope_len = itx;
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003181
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003182 /* scope_txt = search query, appctx->ctx.stats.scope_len is always <= STAT_SCOPE_TXT_MAXLEN */
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003183 memcpy(scope_txt, h2, itx);
3184 scope_txt[itx] = '\0';
3185 err = invalid_char(scope_txt);
3186 if (err) {
3187 /* bad char in search text => clear scope */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003188 appctx->ctx.stats.scope_str = 0;
3189 appctx->ctx.stats.scope_len = 0;
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003190 }
3191 break;
3192 }
3193 }
Willy Tarreau1facd6d2012-12-22 22:03:39 +01003194
3195 /* now check whether we have some admin rules for this request */
Willy Tarreau414e9bb2013-11-23 00:30:38 +01003196 list_for_each_entry(stats_admin_rule, &uri_auth->admin_rules, list) {
Willy Tarreau1facd6d2012-12-22 22:03:39 +01003197 int ret = 1;
3198
3199 if (stats_admin_rule->cond) {
Willy Tarreau15e91e12015-04-04 00:52:09 +02003200 ret = acl_exec_cond(stats_admin_rule->cond, s->be, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
Willy Tarreau1facd6d2012-12-22 22:03:39 +01003201 ret = acl_pass(ret);
3202 if (stats_admin_rule->cond->pol == ACL_COND_UNLESS)
3203 ret = !ret;
3204 }
3205
3206 if (ret) {
3207 /* no rule, or the rule matches */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003208 appctx->ctx.stats.flags |= STAT_ADMIN;
Willy Tarreau1facd6d2012-12-22 22:03:39 +01003209 break;
3210 }
3211 }
3212
3213 /* Was the status page requested with a POST ? */
Willy Tarreau347a35d2013-11-22 17:51:09 +01003214 if (unlikely(txn->meth == HTTP_METH_POST && txn->req.body_len > 0)) {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003215 if (appctx->ctx.stats.flags & STAT_ADMIN) {
Willy Tarreaucfe7fdd2014-04-26 22:08:32 +02003216 /* we'll need the request body, possibly after sending 100-continue */
3217 req->analysers |= AN_REQ_HTTP_BODY;
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003218 appctx->st0 = STAT_HTTP_POST;
Willy Tarreau1facd6d2012-12-22 22:03:39 +01003219 }
Willy Tarreau347a35d2013-11-22 17:51:09 +01003220 else {
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003221 appctx->ctx.stats.st_code = STAT_STATUS_DENY;
3222 appctx->st0 = STAT_HTTP_LAST;
de Lafond Guillaume88c278f2013-04-15 19:27:10 +02003223 }
Willy Tarreau1facd6d2012-12-22 22:03:39 +01003224 }
Willy Tarreau347a35d2013-11-22 17:51:09 +01003225 else {
3226 /* So it was another method (GET/HEAD) */
Willy Tarreau7b4b4992013-12-01 09:15:12 +01003227 appctx->st0 = STAT_HTTP_HEAD;
Willy Tarreau1facd6d2012-12-22 22:03:39 +01003228 }
3229
Willy Tarreau1facd6d2012-12-22 22:03:39 +01003230 s->task->nice = -32; /* small boost for HTTP statistics */
Willy Tarreau1facd6d2012-12-22 22:03:39 +01003231 return 1;
3232}
3233
Lukas Tribus67db8df2013-06-23 17:37:13 +02003234/* Sets the TOS header in IPv4 and the traffic class header in IPv6 packets
3235 * (as per RFC3260 #4 and BCP37 #4.2 and #5.2).
3236 */
Thierry FOURNIER7fe75e02015-03-16 12:03:44 +01003237void inet_set_tos(int fd, struct sockaddr_storage from, int tos)
Lukas Tribus67db8df2013-06-23 17:37:13 +02003238{
3239#ifdef IP_TOS
3240 if (from.ss_family == AF_INET)
3241 setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
3242#endif
3243#ifdef IPV6_TCLASS
3244 if (from.ss_family == AF_INET6) {
3245 if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr))
3246 /* v4-mapped addresses need IP_TOS */
3247 setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
3248 else
3249 setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof(tos));
3250 }
3251#endif
3252}
3253
Willy Tarreau87b09662015-04-03 00:22:06 +02003254int http_transform_header_str(struct stream* s, struct http_msg *msg,
Thierry FOURNIER5531f872015-03-16 11:15:50 +01003255 const char* name, unsigned int name_len,
3256 const char *str, struct my_regex *re,
3257 int action)
Sasha Pachev218f0642014-06-16 12:05:59 -06003258{
Thierry FOURNIER5a33ac72015-03-16 23:54:35 +01003259 struct hdr_ctx ctx;
3260 char *buf = msg->chn->buf->p;
Willy Tarreaueee5b512015-04-03 23:46:31 +02003261 struct hdr_idx *idx = &s->txn->hdr_idx;
Thierry FOURNIER5531f872015-03-16 11:15:50 +01003262 int (*http_find_hdr_func)(const char *name, int len, char *sol,
3263 struct hdr_idx *idx, struct hdr_ctx *ctx);
Thierry FOURNIER191f9ef2015-03-16 23:23:53 +01003264 struct chunk *output = get_trash_chunk();
3265
Thierry FOURNIER5a33ac72015-03-16 23:54:35 +01003266 ctx.idx = 0;
Sasha Pachev218f0642014-06-16 12:05:59 -06003267
Thierry FOURNIER191f9ef2015-03-16 23:23:53 +01003268 /* Choose the header browsing function. */
3269 switch (action) {
3270 case HTTP_REQ_ACT_REPLACE_VAL:
3271 case HTTP_RES_ACT_REPLACE_VAL:
3272 http_find_hdr_func = http_find_header2;
3273 break;
3274 case HTTP_REQ_ACT_REPLACE_HDR:
3275 case HTTP_RES_ACT_REPLACE_HDR:
3276 http_find_hdr_func = http_find_full_header2;
3277 break;
3278 default: /* impossible */
3279 return -1;
3280 }
3281
Thierry FOURNIER5a33ac72015-03-16 23:54:35 +01003282 while (http_find_hdr_func(name, name_len, buf, idx, &ctx)) {
3283 struct hdr_idx_elem *hdr = idx->v + ctx.idx;
Sasha Pachev218f0642014-06-16 12:05:59 -06003284 int delta;
Thierry FOURNIER5a33ac72015-03-16 23:54:35 +01003285 char *val = ctx.line + ctx.val;
3286 char* val_end = val + ctx.vlen;
Sasha Pachev218f0642014-06-16 12:05:59 -06003287
Thierry FOURNIER191f9ef2015-03-16 23:23:53 +01003288 if (!regex_exec_match2(re, val, val_end-val, MAX_MATCH, pmatch, 0))
3289 continue;
Sasha Pachev218f0642014-06-16 12:05:59 -06003290
Thierry FOURNIER5531f872015-03-16 11:15:50 +01003291 output->len = exp_replace(output->str, output->size, val, str, pmatch);
Thierry FOURNIER191f9ef2015-03-16 23:23:53 +01003292 if (output->len == -1)
Sasha Pachev218f0642014-06-16 12:05:59 -06003293 return -1;
Sasha Pachev218f0642014-06-16 12:05:59 -06003294
Thierry FOURNIER191f9ef2015-03-16 23:23:53 +01003295 delta = buffer_replace2(msg->chn->buf, val, val_end, output->str, output->len);
Sasha Pachev218f0642014-06-16 12:05:59 -06003296
3297 hdr->len += delta;
3298 http_msg_move_end(msg, delta);
Thierry FOURNIER191f9ef2015-03-16 23:23:53 +01003299
3300 /* Adjust the length of the current value of the index. */
Thierry FOURNIER5a33ac72015-03-16 23:54:35 +01003301 ctx.vlen += delta;
Sasha Pachev218f0642014-06-16 12:05:59 -06003302 }
3303
3304 return 0;
3305}
3306
Willy Tarreau87b09662015-04-03 00:22:06 +02003307static int http_transform_header(struct stream* s, struct http_msg *msg,
Thierry FOURNIER5531f872015-03-16 11:15:50 +01003308 const char* name, unsigned int name_len,
3309 struct list *fmt, struct my_regex *re,
3310 int action)
3311{
3312 struct chunk *replace = get_trash_chunk();
3313
3314 replace->len = build_logline(s, replace->str, replace->size, fmt);
3315 if (replace->len >= replace->size - 1)
3316 return -1;
3317
3318 return http_transform_header_str(s, msg, name, name_len, replace->str, re, action);
3319}
3320
Willy Tarreau87b09662015-04-03 00:22:06 +02003321/* Executes the http-request rules <rules> for stream <s>, proxy <px> and
Willy Tarreau0b748332014-04-29 00:13:29 +02003322 * transaction <txn>. Returns the verdict of the first rule that prevents
3323 * further processing of the request (auth, deny, ...), and defaults to
3324 * HTTP_RULE_RES_STOP if it executed all rules or stopped on an allow, or
3325 * HTTP_RULE_RES_CONT if the last rule was reached. It may set the TX_CLTARPIT
3326 * on txn->flags if it encounters a tarpit rule.
Willy Tarreauf68a15a2011-01-06 16:53:21 +01003327 */
Willy Tarreau0b748332014-04-29 00:13:29 +02003328enum rule_result
Willy Tarreau987e3fb2015-04-04 01:09:08 +02003329http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct stream *s)
Willy Tarreauf68a15a2011-01-06 16:53:21 +01003330{
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02003331 struct session *sess = strm_sess(s);
Willy Tarreau987e3fb2015-04-04 01:09:08 +02003332 struct http_txn *txn = s->txn;
Willy Tarreaub363a1f2013-10-01 10:45:07 +02003333 struct connection *cli_conn;
Willy Tarreauff011f22011-01-06 17:51:27 +01003334 struct http_req_rule *rule;
Willy Tarreau20b0de52012-12-24 15:45:22 +01003335 struct hdr_ctx ctx;
Willy Tarreauae3c0102014-04-28 23:22:08 +02003336 const char *auth_realm;
Willy Tarreauf68a15a2011-01-06 16:53:21 +01003337
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01003338 /* If "the current_rule_list" match the executed rule list, we are in
3339 * resume condition. If a resume is needed it is always in the action
3340 * and never in the ACL or converters. In this case, we initialise the
3341 * current rule, and go to the action execution point.
3342 */
3343 if (s->current_rule_list == rules) {
3344 rule = LIST_ELEM(s->current_rule, typeof(rule), list);
3345 goto resume_execution;
3346 }
3347 s->current_rule_list = rules;
Willy Tarreauff011f22011-01-06 17:51:27 +01003348 list_for_each_entry(rule, rules, list) {
Willy Tarreauff011f22011-01-06 17:51:27 +01003349 if (rule->action >= HTTP_REQ_ACT_MAX)
Willy Tarreauf68a15a2011-01-06 16:53:21 +01003350 continue;
3351
Willy Tarreau96257ec2012-12-27 10:46:37 +01003352 /* check optional condition */
Willy Tarreauff011f22011-01-06 17:51:27 +01003353 if (rule->cond) {
Willy Tarreau96257ec2012-12-27 10:46:37 +01003354 int ret;
3355
Willy Tarreau15e91e12015-04-04 00:52:09 +02003356 ret = acl_exec_cond(rule->cond, px, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
Willy Tarreauf68a15a2011-01-06 16:53:21 +01003357 ret = acl_pass(ret);
3358
Willy Tarreauff011f22011-01-06 17:51:27 +01003359 if (rule->cond->pol == ACL_COND_UNLESS)
Willy Tarreauf68a15a2011-01-06 16:53:21 +01003360 ret = !ret;
Willy Tarreau96257ec2012-12-27 10:46:37 +01003361
3362 if (!ret) /* condition not matched */
3363 continue;
Willy Tarreauf68a15a2011-01-06 16:53:21 +01003364 }
3365
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01003366resume_execution:
Willy Tarreau20b0de52012-12-24 15:45:22 +01003367
Willy Tarreau96257ec2012-12-27 10:46:37 +01003368 switch (rule->action) {
3369 case HTTP_REQ_ACT_ALLOW:
Willy Tarreau0b748332014-04-29 00:13:29 +02003370 return HTTP_RULE_RES_STOP;
Willy Tarreau96257ec2012-12-27 10:46:37 +01003371
3372 case HTTP_REQ_ACT_DENY:
Willy Tarreau0b748332014-04-29 00:13:29 +02003373 return HTTP_RULE_RES_DENY;
Willy Tarreau96257ec2012-12-27 10:46:37 +01003374
Willy Tarreauccbcc372012-12-27 12:37:57 +01003375 case HTTP_REQ_ACT_TARPIT:
3376 txn->flags |= TX_CLTARPIT;
Willy Tarreau0b748332014-04-29 00:13:29 +02003377 return HTTP_RULE_RES_DENY;
Willy Tarreauccbcc372012-12-27 12:37:57 +01003378
Willy Tarreau96257ec2012-12-27 10:46:37 +01003379 case HTTP_REQ_ACT_AUTH:
Willy Tarreauae3c0102014-04-28 23:22:08 +02003380 /* Auth might be performed on regular http-req rules as well as on stats */
3381 auth_realm = rule->arg.auth.realm;
3382 if (!auth_realm) {
3383 if (px->uri_auth && rules == &px->uri_auth->http_req_rules)
3384 auth_realm = STATS_DEFAULT_REALM;
3385 else
3386 auth_realm = px->id;
3387 }
3388 /* send 401/407 depending on whether we use a proxy or not. We still
3389 * count one error, because normal browsing won't significantly
3390 * increase the counter but brute force attempts will.
3391 */
3392 chunk_printf(&trash, (txn->flags & TX_USE_PX_CONN) ? HTTP_407_fmt : HTTP_401_fmt, auth_realm);
3393 txn->status = (txn->flags & TX_USE_PX_CONN) ? 407 : 401;
3394 stream_int_retnclose(&s->si[0], &trash);
Willy Tarreau87b09662015-04-03 00:22:06 +02003395 stream_inc_http_err_ctr(s);
Willy Tarreau0b748332014-04-29 00:13:29 +02003396 return HTTP_RULE_RES_ABRT;
Willy Tarreau96257ec2012-12-27 10:46:37 +01003397
Willy Tarreau81499eb2012-12-27 12:19:02 +01003398 case HTTP_REQ_ACT_REDIR:
Willy Tarreau0b748332014-04-29 00:13:29 +02003399 if (!http_apply_redirect_rule(rule->arg.redir, s, txn))
3400 return HTTP_RULE_RES_BADREQ;
3401 return HTTP_RULE_RES_DONE;
Willy Tarreau81499eb2012-12-27 12:19:02 +01003402
Willy Tarreauf4c43c12013-06-11 17:01:13 +02003403 case HTTP_REQ_ACT_SET_NICE:
3404 s->task->nice = rule->arg.nice;
3405 break;
3406
Willy Tarreau42cf39e2013-06-11 18:51:32 +02003407 case HTTP_REQ_ACT_SET_TOS:
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02003408 if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn))
Willy Tarreaub363a1f2013-10-01 10:45:07 +02003409 inet_set_tos(cli_conn->t.sock.fd, cli_conn->addr.from, rule->arg.tos);
Willy Tarreau42cf39e2013-06-11 18:51:32 +02003410 break;
3411
Willy Tarreau51347ed2013-06-11 19:34:13 +02003412 case HTTP_REQ_ACT_SET_MARK:
3413#ifdef SO_MARK
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02003414 if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn))
Willy Tarreaub363a1f2013-10-01 10:45:07 +02003415 setsockopt(cli_conn->t.sock.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark));
Willy Tarreau51347ed2013-06-11 19:34:13 +02003416#endif
3417 break;
3418
Willy Tarreau9a355ec2013-06-11 17:45:46 +02003419 case HTTP_REQ_ACT_SET_LOGL:
3420 s->logs.level = rule->arg.loglevel;
3421 break;
3422
Sasha Pachev218f0642014-06-16 12:05:59 -06003423 case HTTP_REQ_ACT_REPLACE_HDR:
3424 case HTTP_REQ_ACT_REPLACE_VAL:
Thierry FOURNIER5a33ac72015-03-16 23:54:35 +01003425 if (http_transform_header(s, &txn->req, rule->arg.hdr_add.name,
3426 rule->arg.hdr_add.name_len,
3427 &rule->arg.hdr_add.fmt,
3428 &rule->arg.hdr_add.re, rule->action))
Sasha Pachev218f0642014-06-16 12:05:59 -06003429 return HTTP_RULE_RES_BADREQ;
3430 break;
3431
Thierry FOURNIERdad3d1d2014-04-22 18:07:25 +02003432 case HTTP_REQ_ACT_DEL_HDR:
Willy Tarreau96257ec2012-12-27 10:46:37 +01003433 ctx.idx = 0;
3434 /* remove all occurrences of the header */
3435 while (http_find_header2(rule->arg.hdr_add.name, rule->arg.hdr_add.name_len,
3436 txn->req.chn->buf->p, &txn->hdr_idx, &ctx)) {
3437 http_remove_header2(&txn->req, &txn->hdr_idx, &ctx);
Willy Tarreau20b0de52012-12-24 15:45:22 +01003438 }
Willy Tarreau85603282015-01-21 20:39:27 +01003439 break;
Willy Tarreau96257ec2012-12-27 10:46:37 +01003440
Willy Tarreau85603282015-01-21 20:39:27 +01003441 case HTTP_REQ_ACT_SET_HDR:
Willy Tarreau96257ec2012-12-27 10:46:37 +01003442 case HTTP_REQ_ACT_ADD_HDR:
3443 chunk_printf(&trash, "%s: ", rule->arg.hdr_add.name);
3444 memcpy(trash.str, rule->arg.hdr_add.name, rule->arg.hdr_add.name_len);
3445 trash.len = rule->arg.hdr_add.name_len;
3446 trash.str[trash.len++] = ':';
3447 trash.str[trash.len++] = ' ';
3448 trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, &rule->arg.hdr_add.fmt);
Willy Tarreau85603282015-01-21 20:39:27 +01003449
3450 if (rule->action == HTTP_REQ_ACT_SET_HDR) {
3451 /* remove all occurrences of the header */
3452 ctx.idx = 0;
3453 while (http_find_header2(rule->arg.hdr_add.name, rule->arg.hdr_add.name_len,
3454 txn->req.chn->buf->p, &txn->hdr_idx, &ctx)) {
3455 http_remove_header2(&txn->req, &txn->hdr_idx, &ctx);
3456 }
3457 }
3458
Willy Tarreau96257ec2012-12-27 10:46:37 +01003459 http_header_add_tail2(&txn->req, &txn->hdr_idx, trash.str, trash.len);
3460 break;
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02003461
3462 case HTTP_REQ_ACT_DEL_ACL:
3463 case HTTP_REQ_ACT_DEL_MAP: {
3464 struct pat_ref *ref;
3465 char *key;
3466 int len;
3467
3468 /* collect reference */
3469 ref = pat_ref_lookup(rule->arg.map.ref);
3470 if (!ref)
3471 continue;
3472
3473 /* collect key */
3474 len = build_logline(s, trash.str, trash.size, &rule->arg.map.key);
3475 key = trash.str;
3476 key[len] = '\0';
3477
3478 /* perform update */
3479 /* returned code: 1=ok, 0=ko */
3480 pat_ref_delete(ref, key);
3481
3482 break;
3483 }
3484
3485 case HTTP_REQ_ACT_ADD_ACL: {
3486 struct pat_ref *ref;
3487 char *key;
3488 struct chunk *trash_key;
3489 int len;
3490
3491 trash_key = get_trash_chunk();
3492
3493 /* collect reference */
3494 ref = pat_ref_lookup(rule->arg.map.ref);
3495 if (!ref)
3496 continue;
3497
3498 /* collect key */
3499 len = build_logline(s, trash_key->str, trash_key->size, &rule->arg.map.key);
3500 key = trash_key->str;
3501 key[len] = '\0';
3502
3503 /* perform update */
3504 /* add entry only if it does not already exist */
3505 if (pat_ref_find_elt(ref, key) == NULL)
Thierry FOURNIERe47e4e22014-04-28 11:18:57 +02003506 pat_ref_add(ref, key, NULL, NULL);
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02003507
3508 break;
3509 }
3510
3511 case HTTP_REQ_ACT_SET_MAP: {
3512 struct pat_ref *ref;
3513 char *key, *value;
3514 struct chunk *trash_key, *trash_value;
3515 int len;
3516
3517 trash_key = get_trash_chunk();
3518 trash_value = get_trash_chunk();
3519
3520 /* collect reference */
3521 ref = pat_ref_lookup(rule->arg.map.ref);
3522 if (!ref)
3523 continue;
3524
3525 /* collect key */
3526 len = build_logline(s, trash_key->str, trash_key->size, &rule->arg.map.key);
3527 key = trash_key->str;
3528 key[len] = '\0';
3529
3530 /* collect value */
3531 len = build_logline(s, trash_value->str, trash_value->size, &rule->arg.map.value);
3532 value = trash_value->str;
3533 value[len] = '\0';
3534
3535 /* perform update */
3536 if (pat_ref_find_elt(ref, key) != NULL)
3537 /* update entry if it exists */
3538 pat_ref_set(ref, key, value, NULL);
3539 else
3540 /* insert a new entry */
Thierry FOURNIERe47e4e22014-04-28 11:18:57 +02003541 pat_ref_add(ref, key, value, NULL);
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02003542
3543 break;
3544 }
William Lallemand73025dd2014-04-24 14:38:37 +02003545
3546 case HTTP_REQ_ACT_CUSTOM_CONT:
Willy Tarreau987e3fb2015-04-04 01:09:08 +02003547 if (!rule->action_ptr(rule, px, s)) {
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01003548 s->current_rule = &rule->list;
3549 return HTTP_RULE_RES_YIELD;
3550 }
William Lallemand73025dd2014-04-24 14:38:37 +02003551 break;
3552
3553 case HTTP_REQ_ACT_CUSTOM_STOP:
Willy Tarreau987e3fb2015-04-04 01:09:08 +02003554 rule->action_ptr(rule, px, s);
Willy Tarreau0b748332014-04-29 00:13:29 +02003555 return HTTP_RULE_RES_DONE;
Willy Tarreau09448f72014-06-25 18:12:15 +02003556
3557 case HTTP_REQ_ACT_TRK_SC0 ... HTTP_REQ_ACT_TRK_SCMAX:
3558 /* Note: only the first valid tracking parameter of each
3559 * applies.
3560 */
3561
3562 if (stkctr_entry(&s->stkctr[http_req_trk_idx(rule->action)]) == NULL) {
3563 struct stktable *t;
3564 struct stksess *ts;
3565 struct stktable_key *key;
3566 void *ptr;
3567
3568 t = rule->act_prm.trk_ctr.table.t;
Willy Tarreau15e91e12015-04-04 00:52:09 +02003569 key = stktable_fetch_key(t, s->be, s, SMP_OPT_DIR_REQ | SMP_OPT_FINAL, rule->act_prm.trk_ctr.expr, NULL);
Willy Tarreau09448f72014-06-25 18:12:15 +02003570
3571 if (key && (ts = stktable_get_entry(t, key))) {
Willy Tarreau87b09662015-04-03 00:22:06 +02003572 stream_track_stkctr(&s->stkctr[http_req_trk_idx(rule->action)], t, ts);
Willy Tarreau09448f72014-06-25 18:12:15 +02003573
3574 /* let's count a new HTTP request as it's the first time we do it */
3575 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_CNT);
3576 if (ptr)
3577 stktable_data_cast(ptr, http_req_cnt)++;
3578
3579 ptr = stktable_data_ptr(t, ts, STKTABLE_DT_HTTP_REQ_RATE);
3580 if (ptr)
3581 update_freq_ctr_period(&stktable_data_cast(ptr, http_req_rate),
3582 t->data_arg[STKTABLE_DT_HTTP_REQ_RATE].u, 1);
3583
3584 stkctr_set_flags(&s->stkctr[http_req_trk_idx(rule->action)], STKCTR_TRACK_CONTENT);
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02003585 if (sess->fe != s->be)
Willy Tarreau09448f72014-06-25 18:12:15 +02003586 stkctr_set_flags(&s->stkctr[http_req_trk_idx(rule->action)], STKCTR_TRACK_BACKEND);
3587 }
3588 }
Willy Tarreauf68a15a2011-01-06 16:53:21 +01003589 }
3590 }
Willy Tarreau96257ec2012-12-27 10:46:37 +01003591
3592 /* we reached the end of the rules, nothing to report */
Willy Tarreau0b748332014-04-29 00:13:29 +02003593 return HTTP_RULE_RES_CONT;
Willy Tarreauf68a15a2011-01-06 16:53:21 +01003594}
3595
Willy Tarreau71241ab2012-12-27 11:30:54 +01003596
Willy Tarreau87b09662015-04-03 00:22:06 +02003597/* Executes the http-response rules <rules> for stream <s>, proxy <px> and
Thierry FOURNIER9e2ef992015-02-25 13:51:19 +01003598 * transaction <txn>. Returns 3 states: HTTP_RULE_RES_CONT, HTTP_RULE_RES_YIELD
3599 * or HTTP_RULE_RES_STOP. If *CONT is returned, the process can continue the
3600 * evaluation of next rule list. If *STOP is returned, the process must stop
3601 * the evaluation. It may set the TX_SVDENY on txn->flags if it encounters a deny
3602 * rule. If *YIELD is returned, the czller must call again the function with
3603 * the same context.
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003604 */
Thierry FOURNIER9e2ef992015-02-25 13:51:19 +01003605static enum rule_result
Willy Tarreau987e3fb2015-04-04 01:09:08 +02003606http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct stream *s)
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003607{
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02003608 struct session *sess = strm_sess(s);
Willy Tarreau987e3fb2015-04-04 01:09:08 +02003609 struct http_txn *txn = s->txn;
Willy Tarreaub363a1f2013-10-01 10:45:07 +02003610 struct connection *cli_conn;
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003611 struct http_res_rule *rule;
3612 struct hdr_ctx ctx;
3613
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01003614 /* If "the current_rule_list" match the executed rule list, we are in
3615 * resume condition. If a resume is needed it is always in the action
3616 * and never in the ACL or converters. In this case, we initialise the
3617 * current rule, and go to the action execution point.
3618 */
3619 if (s->current_rule_list == rules) {
3620 rule = LIST_ELEM(s->current_rule, typeof(rule), list);
3621 goto resume_execution;
3622 }
3623 s->current_rule_list = rules;
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003624 list_for_each_entry(rule, rules, list) {
3625 if (rule->action >= HTTP_RES_ACT_MAX)
3626 continue;
3627
3628 /* check optional condition */
3629 if (rule->cond) {
3630 int ret;
3631
Willy Tarreau15e91e12015-04-04 00:52:09 +02003632 ret = acl_exec_cond(rule->cond, px, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL);
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003633 ret = acl_pass(ret);
3634
3635 if (rule->cond->pol == ACL_COND_UNLESS)
3636 ret = !ret;
3637
3638 if (!ret) /* condition not matched */
3639 continue;
3640 }
3641
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01003642resume_execution:
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003643
3644 switch (rule->action) {
3645 case HTTP_RES_ACT_ALLOW:
Thierry FOURNIER9e2ef992015-02-25 13:51:19 +01003646 return HTTP_RULE_RES_STOP; /* "allow" rules are OK */
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003647
3648 case HTTP_RES_ACT_DENY:
3649 txn->flags |= TX_SVDENY;
Thierry FOURNIER9e2ef992015-02-25 13:51:19 +01003650 return HTTP_RULE_RES_STOP;
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003651
Willy Tarreauf4c43c12013-06-11 17:01:13 +02003652 case HTTP_RES_ACT_SET_NICE:
3653 s->task->nice = rule->arg.nice;
3654 break;
3655
Willy Tarreau42cf39e2013-06-11 18:51:32 +02003656 case HTTP_RES_ACT_SET_TOS:
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02003657 if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn))
Willy Tarreaub363a1f2013-10-01 10:45:07 +02003658 inet_set_tos(cli_conn->t.sock.fd, cli_conn->addr.from, rule->arg.tos);
Willy Tarreau42cf39e2013-06-11 18:51:32 +02003659 break;
3660
Willy Tarreau51347ed2013-06-11 19:34:13 +02003661 case HTTP_RES_ACT_SET_MARK:
3662#ifdef SO_MARK
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02003663 if ((cli_conn = objt_conn(sess->origin)) && conn_ctrl_ready(cli_conn))
Willy Tarreaub363a1f2013-10-01 10:45:07 +02003664 setsockopt(cli_conn->t.sock.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark));
Willy Tarreau51347ed2013-06-11 19:34:13 +02003665#endif
3666 break;
3667
Willy Tarreau9a355ec2013-06-11 17:45:46 +02003668 case HTTP_RES_ACT_SET_LOGL:
3669 s->logs.level = rule->arg.loglevel;
3670 break;
3671
Sasha Pachev218f0642014-06-16 12:05:59 -06003672 case HTTP_RES_ACT_REPLACE_HDR:
3673 case HTTP_RES_ACT_REPLACE_VAL:
Thierry FOURNIER5a33ac72015-03-16 23:54:35 +01003674 if (http_transform_header(s, &txn->rsp, rule->arg.hdr_add.name,
3675 rule->arg.hdr_add.name_len,
3676 &rule->arg.hdr_add.fmt,
3677 &rule->arg.hdr_add.re, rule->action))
Thierry FOURNIER9e2ef992015-02-25 13:51:19 +01003678 return HTTP_RULE_RES_STOP; /* note: we should report an error here */
Sasha Pachev218f0642014-06-16 12:05:59 -06003679 break;
3680
Thierry FOURNIERdad3d1d2014-04-22 18:07:25 +02003681 case HTTP_RES_ACT_DEL_HDR:
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003682 ctx.idx = 0;
3683 /* remove all occurrences of the header */
3684 while (http_find_header2(rule->arg.hdr_add.name, rule->arg.hdr_add.name_len,
3685 txn->rsp.chn->buf->p, &txn->hdr_idx, &ctx)) {
3686 http_remove_header2(&txn->rsp, &txn->hdr_idx, &ctx);
3687 }
Willy Tarreau85603282015-01-21 20:39:27 +01003688 break;
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003689
Willy Tarreau85603282015-01-21 20:39:27 +01003690 case HTTP_RES_ACT_SET_HDR:
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003691 case HTTP_RES_ACT_ADD_HDR:
3692 chunk_printf(&trash, "%s: ", rule->arg.hdr_add.name);
3693 memcpy(trash.str, rule->arg.hdr_add.name, rule->arg.hdr_add.name_len);
3694 trash.len = rule->arg.hdr_add.name_len;
3695 trash.str[trash.len++] = ':';
3696 trash.str[trash.len++] = ' ';
3697 trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, &rule->arg.hdr_add.fmt);
Willy Tarreau85603282015-01-21 20:39:27 +01003698
3699 if (rule->action == HTTP_RES_ACT_SET_HDR) {
3700 /* remove all occurrences of the header */
3701 ctx.idx = 0;
3702 while (http_find_header2(rule->arg.hdr_add.name, rule->arg.hdr_add.name_len,
3703 txn->rsp.chn->buf->p, &txn->hdr_idx, &ctx)) {
3704 http_remove_header2(&txn->rsp, &txn->hdr_idx, &ctx);
3705 }
3706 }
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003707 http_header_add_tail2(&txn->rsp, &txn->hdr_idx, trash.str, trash.len);
3708 break;
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02003709
3710 case HTTP_RES_ACT_DEL_ACL:
3711 case HTTP_RES_ACT_DEL_MAP: {
3712 struct pat_ref *ref;
3713 char *key;
3714 int len;
3715
3716 /* collect reference */
3717 ref = pat_ref_lookup(rule->arg.map.ref);
3718 if (!ref)
3719 continue;
3720
3721 /* collect key */
3722 len = build_logline(s, trash.str, trash.size, &rule->arg.map.key);
3723 key = trash.str;
3724 key[len] = '\0';
3725
3726 /* perform update */
3727 /* returned code: 1=ok, 0=ko */
3728 pat_ref_delete(ref, key);
3729
3730 break;
3731 }
3732
3733 case HTTP_RES_ACT_ADD_ACL: {
3734 struct pat_ref *ref;
3735 char *key;
3736 struct chunk *trash_key;
3737 int len;
3738
3739 trash_key = get_trash_chunk();
3740
3741 /* collect reference */
3742 ref = pat_ref_lookup(rule->arg.map.ref);
3743 if (!ref)
3744 continue;
3745
3746 /* collect key */
3747 len = build_logline(s, trash_key->str, trash_key->size, &rule->arg.map.key);
3748 key = trash_key->str;
3749 key[len] = '\0';
3750
3751 /* perform update */
3752 /* check if the entry already exists */
3753 if (pat_ref_find_elt(ref, key) == NULL)
Thierry FOURNIERe47e4e22014-04-28 11:18:57 +02003754 pat_ref_add(ref, key, NULL, NULL);
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02003755
3756 break;
3757 }
3758
3759 case HTTP_RES_ACT_SET_MAP: {
3760 struct pat_ref *ref;
3761 char *key, *value;
3762 struct chunk *trash_key, *trash_value;
3763 int len;
3764
3765 trash_key = get_trash_chunk();
3766 trash_value = get_trash_chunk();
3767
3768 /* collect reference */
3769 ref = pat_ref_lookup(rule->arg.map.ref);
3770 if (!ref)
3771 continue;
3772
3773 /* collect key */
3774 len = build_logline(s, trash_key->str, trash_key->size, &rule->arg.map.key);
3775 key = trash_key->str;
3776 key[len] = '\0';
3777
3778 /* collect value */
3779 len = build_logline(s, trash_value->str, trash_value->size, &rule->arg.map.value);
3780 value = trash_value->str;
3781 value[len] = '\0';
3782
3783 /* perform update */
3784 if (pat_ref_find_elt(ref, key) != NULL)
3785 /* update entry if it exists */
3786 pat_ref_set(ref, key, value, NULL);
3787 else
3788 /* insert a new entry */
Thierry FOURNIERe47e4e22014-04-28 11:18:57 +02003789 pat_ref_add(ref, key, value, NULL);
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02003790
3791 break;
3792 }
William Lallemand73025dd2014-04-24 14:38:37 +02003793
3794 case HTTP_RES_ACT_CUSTOM_CONT:
Willy Tarreau987e3fb2015-04-04 01:09:08 +02003795 if (!rule->action_ptr(rule, px, s)) {
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01003796 s->current_rule = &rule->list;
3797 return HTTP_RULE_RES_YIELD;
3798 }
William Lallemand73025dd2014-04-24 14:38:37 +02003799 break;
3800
3801 case HTTP_RES_ACT_CUSTOM_STOP:
Willy Tarreau987e3fb2015-04-04 01:09:08 +02003802 rule->action_ptr(rule, px, s);
Thierry FOURNIER9e2ef992015-02-25 13:51:19 +01003803 return HTTP_RULE_RES_STOP;
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003804 }
3805 }
3806
3807 /* we reached the end of the rules, nothing to report */
Thierry FOURNIER9e2ef992015-02-25 13:51:19 +01003808 return HTTP_RULE_RES_CONT;
Willy Tarreaue365c0b2013-06-11 16:06:12 +02003809}
3810
3811
Willy Tarreau71241ab2012-12-27 11:30:54 +01003812/* Perform an HTTP redirect based on the information in <rule>. The function
3813 * returns non-zero on success, or zero in case of a, irrecoverable error such
3814 * as too large a request to build a valid response.
3815 */
Willy Tarreau87b09662015-04-03 00:22:06 +02003816static int http_apply_redirect_rule(struct redirect_rule *rule, struct stream *s, struct http_txn *txn)
Willy Tarreau71241ab2012-12-27 11:30:54 +01003817{
3818 struct http_msg *msg = &txn->req;
3819 const char *msg_fmt;
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01003820 const char *location;
Willy Tarreau71241ab2012-12-27 11:30:54 +01003821
3822 /* build redirect message */
3823 switch(rule->code) {
Yves Lafon3e8d1ae2013-03-11 11:06:05 -04003824 case 308:
3825 msg_fmt = HTTP_308;
3826 break;
3827 case 307:
3828 msg_fmt = HTTP_307;
3829 break;
Willy Tarreau71241ab2012-12-27 11:30:54 +01003830 case 303:
3831 msg_fmt = HTTP_303;
3832 break;
3833 case 301:
3834 msg_fmt = HTTP_301;
3835 break;
3836 case 302:
3837 default:
3838 msg_fmt = HTTP_302;
3839 break;
3840 }
3841
3842 if (unlikely(!chunk_strcpy(&trash, msg_fmt)))
3843 return 0;
3844
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01003845 location = trash.str + trash.len;
3846
Willy Tarreau71241ab2012-12-27 11:30:54 +01003847 switch(rule->type) {
3848 case REDIRECT_TYPE_SCHEME: {
3849 const char *path;
3850 const char *host;
3851 struct hdr_ctx ctx;
3852 int pathlen;
3853 int hostlen;
3854
3855 host = "";
3856 hostlen = 0;
3857 ctx.idx = 0;
Willy Tarreau877e78d2013-04-07 18:48:08 +02003858 if (http_find_header2("Host", 4, txn->req.chn->buf->p, &txn->hdr_idx, &ctx)) {
Willy Tarreau71241ab2012-12-27 11:30:54 +01003859 host = ctx.line + ctx.val;
3860 hostlen = ctx.vlen;
3861 }
3862
3863 path = http_get_path(txn);
3864 /* build message using path */
3865 if (path) {
3866 pathlen = txn->req.sl.rq.u_l + (txn->req.chn->buf->p + txn->req.sl.rq.u) - path;
3867 if (rule->flags & REDIRECT_FLAG_DROP_QS) {
3868 int qs = 0;
3869 while (qs < pathlen) {
3870 if (path[qs] == '?') {
3871 pathlen = qs;
3872 break;
3873 }
3874 qs++;
3875 }
3876 }
3877 } else {
3878 path = "/";
3879 pathlen = 1;
3880 }
3881
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01003882 if (rule->rdr_str) { /* this is an old "redirect" rule */
3883 /* check if we can add scheme + "://" + host + path */
3884 if (trash.len + rule->rdr_len + 3 + hostlen + pathlen > trash.size - 4)
3885 return 0;
Willy Tarreau71241ab2012-12-27 11:30:54 +01003886
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01003887 /* add scheme */
3888 memcpy(trash.str + trash.len, rule->rdr_str, rule->rdr_len);
3889 trash.len += rule->rdr_len;
3890 }
3891 else {
3892 /* add scheme with executing log format */
3893 trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, &rule->rdr_fmt);
Willy Tarreau71241ab2012-12-27 11:30:54 +01003894
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01003895 /* check if we can add scheme + "://" + host + path */
3896 if (trash.len + 3 + hostlen + pathlen > trash.size - 4)
3897 return 0;
3898 }
Willy Tarreau71241ab2012-12-27 11:30:54 +01003899 /* add "://" */
3900 memcpy(trash.str + trash.len, "://", 3);
3901 trash.len += 3;
3902
3903 /* add host */
3904 memcpy(trash.str + trash.len, host, hostlen);
3905 trash.len += hostlen;
3906
3907 /* add path */
3908 memcpy(trash.str + trash.len, path, pathlen);
3909 trash.len += pathlen;
3910
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01003911 /* append a slash at the end of the location if needed and missing */
Willy Tarreau71241ab2012-12-27 11:30:54 +01003912 if (trash.len && trash.str[trash.len - 1] != '/' &&
3913 (rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
3914 if (trash.len > trash.size - 5)
3915 return 0;
3916 trash.str[trash.len] = '/';
3917 trash.len++;
3918 }
3919
3920 break;
3921 }
3922 case REDIRECT_TYPE_PREFIX: {
3923 const char *path;
3924 int pathlen;
3925
3926 path = http_get_path(txn);
3927 /* build message using path */
3928 if (path) {
3929 pathlen = txn->req.sl.rq.u_l + (txn->req.chn->buf->p + txn->req.sl.rq.u) - path;
3930 if (rule->flags & REDIRECT_FLAG_DROP_QS) {
3931 int qs = 0;
3932 while (qs < pathlen) {
3933 if (path[qs] == '?') {
3934 pathlen = qs;
3935 break;
3936 }
3937 qs++;
3938 }
3939 }
3940 } else {
3941 path = "/";
3942 pathlen = 1;
3943 }
3944
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01003945 if (rule->rdr_str) { /* this is an old "redirect" rule */
3946 if (trash.len + rule->rdr_len + pathlen > trash.size - 4)
3947 return 0;
Willy Tarreau71241ab2012-12-27 11:30:54 +01003948
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01003949 /* add prefix. Note that if prefix == "/", we don't want to
3950 * add anything, otherwise it makes it hard for the user to
3951 * configure a self-redirection.
3952 */
3953 if (rule->rdr_len != 1 || *rule->rdr_str != '/') {
3954 memcpy(trash.str + trash.len, rule->rdr_str, rule->rdr_len);
3955 trash.len += rule->rdr_len;
3956 }
3957 }
3958 else {
3959 /* add prefix with executing log format */
3960 trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, &rule->rdr_fmt);
3961
3962 /* Check length */
3963 if (trash.len + pathlen > trash.size - 4)
3964 return 0;
Willy Tarreau71241ab2012-12-27 11:30:54 +01003965 }
3966
3967 /* add path */
3968 memcpy(trash.str + trash.len, path, pathlen);
3969 trash.len += pathlen;
3970
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01003971 /* append a slash at the end of the location if needed and missing */
Willy Tarreau71241ab2012-12-27 11:30:54 +01003972 if (trash.len && trash.str[trash.len - 1] != '/' &&
3973 (rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
3974 if (trash.len > trash.size - 5)
3975 return 0;
3976 trash.str[trash.len] = '/';
3977 trash.len++;
3978 }
3979
3980 break;
3981 }
3982 case REDIRECT_TYPE_LOCATION:
3983 default:
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01003984 if (rule->rdr_str) { /* this is an old "redirect" rule */
3985 if (trash.len + rule->rdr_len > trash.size - 4)
3986 return 0;
3987
3988 /* add location */
3989 memcpy(trash.str + trash.len, rule->rdr_str, rule->rdr_len);
3990 trash.len += rule->rdr_len;
3991 }
3992 else {
3993 /* add location with executing log format */
3994 trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, &rule->rdr_fmt);
Willy Tarreau71241ab2012-12-27 11:30:54 +01003995
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01003996 /* Check left length */
3997 if (trash.len > trash.size - 4)
3998 return 0;
3999 }
Willy Tarreau71241ab2012-12-27 11:30:54 +01004000 break;
4001 }
4002
4003 if (rule->cookie_len) {
4004 memcpy(trash.str + trash.len, "\r\nSet-Cookie: ", 14);
4005 trash.len += 14;
4006 memcpy(trash.str + trash.len, rule->cookie_str, rule->cookie_len);
4007 trash.len += rule->cookie_len;
4008 memcpy(trash.str + trash.len, "\r\n", 2);
4009 trash.len += 2;
4010 }
4011
4012 /* add end of headers and the keep-alive/close status.
4013 * We may choose to set keep-alive if the Location begins
4014 * with a slash, because the client will come back to the
4015 * same server.
4016 */
4017 txn->status = rule->code;
4018 /* let's log the request time */
4019 s->logs.tv_request = now;
4020
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01004021 if (*location == '/' &&
Willy Tarreau71241ab2012-12-27 11:30:54 +01004022 (msg->flags & HTTP_MSGF_XFER_LEN) &&
4023 !(msg->flags & HTTP_MSGF_TE_CHNK) && !txn->req.body_len &&
4024 ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL ||
4025 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL)) {
4026 /* keep-alive possible */
4027 if (!(msg->flags & HTTP_MSGF_VER_11)) {
4028 if (unlikely(txn->flags & TX_USE_PX_CONN)) {
4029 memcpy(trash.str + trash.len, "\r\nProxy-Connection: keep-alive", 30);
4030 trash.len += 30;
4031 } else {
4032 memcpy(trash.str + trash.len, "\r\nConnection: keep-alive", 24);
4033 trash.len += 24;
4034 }
4035 }
4036 memcpy(trash.str + trash.len, "\r\n\r\n", 4);
4037 trash.len += 4;
4038 bo_inject(txn->rsp.chn, trash.str, trash.len);
4039 /* "eat" the request */
4040 bi_fast_delete(txn->req.chn->buf, msg->sov);
Willy Tarreau6d8bac72014-04-25 12:19:32 +02004041 msg->next -= msg->sov;
Willy Tarreau71241ab2012-12-27 11:30:54 +01004042 msg->sov = 0;
4043 txn->req.chn->analysers = AN_REQ_HTTP_XFER_BODY;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01004044 s->res.analysers = AN_RES_HTTP_XFER_BODY;
Willy Tarreau71241ab2012-12-27 11:30:54 +01004045 txn->req.msg_state = HTTP_MSG_CLOSED;
4046 txn->rsp.msg_state = HTTP_MSG_DONE;
4047 } else {
4048 /* keep-alive not possible */
4049 if (unlikely(txn->flags & TX_USE_PX_CONN)) {
4050 memcpy(trash.str + trash.len, "\r\nProxy-Connection: close\r\n\r\n", 29);
4051 trash.len += 29;
4052 } else {
4053 memcpy(trash.str + trash.len, "\r\nConnection: close\r\n\r\n", 23);
4054 trash.len += 23;
4055 }
Willy Tarreau350f4872014-11-28 14:42:25 +01004056 stream_int_retnclose(&s->si[0], &trash);
Willy Tarreau71241ab2012-12-27 11:30:54 +01004057 txn->req.chn->analysers = 0;
4058 }
4059
Willy Tarreaue7dff022015-04-03 01:14:29 +02004060 if (!(s->flags & SF_ERR_MASK))
4061 s->flags |= SF_ERR_LOCAL;
4062 if (!(s->flags & SF_FINST_MASK))
4063 s->flags |= SF_FINST_R;
Willy Tarreau71241ab2012-12-27 11:30:54 +01004064
4065 return 1;
4066}
4067
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004068/* This stream analyser runs all HTTP request processing which is common to
4069 * frontends and backends, which means blocking ACLs, filters, connection-close,
4070 * reqadd, stats and redirects. This is performed for the designated proxy.
Willy Tarreaud787e662009-07-07 10:14:51 +02004071 * It returns 1 if the processing can continue on next analysers, or zero if it
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004072 * either needs more data or wants to immediately abort the request (eg: deny,
4073 * error, ...).
Willy Tarreaud787e662009-07-07 10:14:51 +02004074 */
Willy Tarreau87b09662015-04-03 00:22:06 +02004075int http_process_req_common(struct stream *s, struct channel *req, int an_bit, struct proxy *px)
Willy Tarreaud787e662009-07-07 10:14:51 +02004076{
Willy Tarreaufb0afa72015-04-03 14:46:27 +02004077 struct session *sess = s->sess;
Willy Tarreaueee5b512015-04-03 23:46:31 +02004078 struct http_txn *txn = s->txn;
Willy Tarreaud787e662009-07-07 10:14:51 +02004079 struct http_msg *msg = &txn->req;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004080 struct redirect_rule *rule;
Willy Tarreauf4f04122010-01-28 18:10:50 +01004081 struct cond_wordlist *wl;
Willy Tarreau0b748332014-04-29 00:13:29 +02004082 enum rule_result verdict;
Willy Tarreaud787e662009-07-07 10:14:51 +02004083
Willy Tarreau655dce92009-11-08 13:10:58 +01004084 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
Willy Tarreau51aecc72009-07-12 09:47:04 +02004085 /* we need more data */
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01004086 goto return_prx_yield;
Willy Tarreau51aecc72009-07-12 09:47:04 +02004087 }
4088
Willy Tarreau87b09662015-04-03 00:22:06 +02004089 DPRINTF(stderr,"[%u] %s: stream=%p b=%p, exp(r,w)=%u,%u bf=%08x bh=%d analysers=%02x\n",
Willy Tarreaud787e662009-07-07 10:14:51 +02004090 now_ms, __FUNCTION__,
4091 s,
4092 req,
4093 req->rex, req->wex,
4094 req->flags,
Willy Tarreau9b28e032012-10-12 23:49:43 +02004095 req->buf->i,
Willy Tarreaud787e662009-07-07 10:14:51 +02004096 req->analysers);
4097
Willy Tarreau65410832014-04-28 21:25:43 +02004098 /* just in case we have some per-backend tracking */
Willy Tarreau87b09662015-04-03 00:22:06 +02004099 stream_inc_be_http_req_ctr(s);
Willy Tarreau65410832014-04-28 21:25:43 +02004100
Willy Tarreauf68a15a2011-01-06 16:53:21 +01004101 /* evaluate http-request rules */
Willy Tarreau0b748332014-04-29 00:13:29 +02004102 if (!LIST_ISEMPTY(&px->http_req_rules)) {
Willy Tarreau987e3fb2015-04-04 01:09:08 +02004103 verdict = http_req_get_intercept_rule(px, &px->http_req_rules, s);
Willy Tarreau51425942010-02-01 10:40:19 +01004104
Willy Tarreau0b748332014-04-29 00:13:29 +02004105 switch (verdict) {
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01004106 case HTTP_RULE_RES_YIELD: /* some data miss, call the function later. */
4107 goto return_prx_yield;
4108
Willy Tarreau0b748332014-04-29 00:13:29 +02004109 case HTTP_RULE_RES_CONT:
4110 case HTTP_RULE_RES_STOP: /* nothing to do */
4111 break;
Willy Tarreau52542592014-04-28 18:33:26 +02004112
Willy Tarreau0b748332014-04-29 00:13:29 +02004113 case HTTP_RULE_RES_DENY: /* deny or tarpit */
4114 if (txn->flags & TX_CLTARPIT)
4115 goto tarpit;
4116 goto deny;
Willy Tarreau52542592014-04-28 18:33:26 +02004117
Willy Tarreau0b748332014-04-29 00:13:29 +02004118 case HTTP_RULE_RES_ABRT: /* abort request, response already sent. Eg: auth */
4119 goto return_prx_cond;
Willy Tarreau52542592014-04-28 18:33:26 +02004120
Willy Tarreau0b748332014-04-29 00:13:29 +02004121 case HTTP_RULE_RES_DONE: /* OK, but terminate request processing (eg: redirect) */
Willy Tarreau52542592014-04-28 18:33:26 +02004122 goto done;
4123
Willy Tarreau0b748332014-04-29 00:13:29 +02004124 case HTTP_RULE_RES_BADREQ: /* failed with a bad request */
4125 goto return_bad_req;
4126 }
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004127 }
4128
Willy Tarreau52542592014-04-28 18:33:26 +02004129 /* OK at this stage, we know that the request was accepted according to
4130 * the http-request rules, we can check for the stats. Note that the
4131 * URI is detected *before* the req* rules in order not to be affected
4132 * by a possible reqrep, while they are processed *after* so that a
4133 * reqdeny can still block them. This clearly needs to change in 1.6!
4134 */
Willy Tarreau350f4872014-11-28 14:42:25 +01004135 if (stats_check_uri(&s->si[1], txn, px)) {
Willy Tarreau52542592014-04-28 18:33:26 +02004136 s->target = &http_stats_applet.obj_type;
Willy Tarreau350f4872014-11-28 14:42:25 +01004137 if (unlikely(!stream_int_register_handler(&s->si[1], objt_applet(s->target)))) {
Willy Tarreau52542592014-04-28 18:33:26 +02004138 txn->status = 500;
4139 s->logs.tv_request = now;
Willy Tarreau350f4872014-11-28 14:42:25 +01004140 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_500));
Willy Tarreau7b4b4992013-12-01 09:15:12 +01004141
Willy Tarreaue7dff022015-04-03 01:14:29 +02004142 if (!(s->flags & SF_ERR_MASK))
4143 s->flags |= SF_ERR_RESOURCE;
Willy Tarreau52542592014-04-28 18:33:26 +02004144 goto return_prx_cond;
4145 }
4146
4147 /* parse the whole stats request and extract the relevant information */
4148 http_handle_stats(s, req);
Willy Tarreau987e3fb2015-04-04 01:09:08 +02004149 verdict = http_req_get_intercept_rule(px, &px->uri_auth->http_req_rules, s);
Willy Tarreau0b748332014-04-29 00:13:29 +02004150 /* not all actions implemented: deny, allow, auth */
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004151
Willy Tarreau0b748332014-04-29 00:13:29 +02004152 if (verdict == HTTP_RULE_RES_DENY) /* stats http-request deny */
4153 goto deny;
Willy Tarreau52542592014-04-28 18:33:26 +02004154
Willy Tarreau0b748332014-04-29 00:13:29 +02004155 if (verdict == HTTP_RULE_RES_ABRT) /* stats auth / stats http-request auth */
4156 goto return_prx_cond;
Krzysztof Piotr Oledzki59bb2182010-01-29 17:58:21 +01004157 }
4158
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004159 /* evaluate the req* rules except reqadd */
4160 if (px->req_exp != NULL) {
Willy Tarreau6c123b12010-01-28 20:22:06 +01004161 if (apply_filters_to_request(s, req, px) < 0)
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004162 goto return_bad_req;
Willy Tarreau06619262006-12-17 08:37:22 +01004163
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004164 if (txn->flags & TX_CLDENY)
4165 goto deny;
Willy Tarreauc465fd72009-08-31 00:17:18 +02004166
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004167 if (txn->flags & TX_CLTARPIT)
4168 goto tarpit;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004169 }
Willy Tarreau06619262006-12-17 08:37:22 +01004170
Willy Tarreauf68a15a2011-01-06 16:53:21 +01004171 /* add request headers from the rule sets in the same order */
4172 list_for_each_entry(wl, &px->req_add, list) {
4173 if (wl->cond) {
Willy Tarreau15e91e12015-04-04 00:52:09 +02004174 int ret = acl_exec_cond(wl->cond, px, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
Willy Tarreauf68a15a2011-01-06 16:53:21 +01004175 ret = acl_pass(ret);
4176 if (((struct acl_cond *)wl->cond)->pol == ACL_COND_UNLESS)
4177 ret = !ret;
4178 if (!ret)
4179 continue;
4180 }
4181
Willy Tarreau6acf7c92012-03-09 13:30:45 +01004182 if (unlikely(http_header_add_tail(&txn->req, &txn->hdr_idx, wl->s) < 0))
Willy Tarreauf68a15a2011-01-06 16:53:21 +01004183 goto return_bad_req;
Willy Tarreau81499eb2012-12-27 12:19:02 +01004184 }
4185
Willy Tarreau52542592014-04-28 18:33:26 +02004186
4187 /* Proceed with the stats now. */
Willy Tarreau414e9bb2013-11-23 00:30:38 +01004188 if (unlikely(objt_applet(s->target) == &http_stats_applet)) {
Willy Tarreau1facd6d2012-12-22 22:03:39 +01004189 /* process the stats request now */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004190 if (sess->fe == s->be) /* report it if the request was intercepted by the frontend */
4191 sess->fe->fe_counters.intercepted_req++;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004192
Willy Tarreaue7dff022015-04-03 01:14:29 +02004193 if (!(s->flags & SF_ERR_MASK)) // this is not really an error but it is
4194 s->flags |= SF_ERR_LOCAL; // to mark that it comes from the proxy
4195 if (!(s->flags & SF_FINST_MASK))
4196 s->flags |= SF_FINST_R;
Willy Tarreau347a35d2013-11-22 17:51:09 +01004197
Willy Tarreau70730dd2014-04-24 18:06:27 +02004198 /* we may want to compress the stats page */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004199 if (sess->fe->comp || s->be->comp)
Willy Tarreau70730dd2014-04-24 18:06:27 +02004200 select_compression_request_header(s, req->buf);
4201
4202 /* enable the minimally required analyzers to handle keep-alive and compression on the HTTP response */
Willy Tarreau5506e3f2014-11-20 22:23:10 +01004203 req->analysers = (req->analysers & AN_REQ_HTTP_BODY) | AN_REQ_HTTP_XFER_BODY;
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004204 goto done;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004205 }
Willy Tarreaub2513902006-12-17 14:52:38 +01004206
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004207 /* check whether we have some ACLs set to redirect this request */
4208 list_for_each_entry(rule, &px->redirect_rules, list) {
Willy Tarreauf285f542010-01-03 20:03:03 +01004209 if (rule->cond) {
Willy Tarreau71241ab2012-12-27 11:30:54 +01004210 int ret;
4211
Willy Tarreau15e91e12015-04-04 00:52:09 +02004212 ret = acl_exec_cond(rule->cond, px, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
Willy Tarreauf285f542010-01-03 20:03:03 +01004213 ret = acl_pass(ret);
4214 if (rule->cond->pol == ACL_COND_UNLESS)
4215 ret = !ret;
Willy Tarreau71241ab2012-12-27 11:30:54 +01004216 if (!ret)
4217 continue;
Willy Tarreauf285f542010-01-03 20:03:03 +01004218 }
Willy Tarreau71241ab2012-12-27 11:30:54 +01004219 if (!http_apply_redirect_rule(rule, s, txn))
4220 goto return_bad_req;
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004221 goto done;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004222 }
Willy Tarreau55ea7572007-06-17 19:56:27 +02004223
Willy Tarreau2be39392010-01-03 17:24:51 +01004224 /* POST requests may be accompanied with an "Expect: 100-Continue" header.
4225 * If this happens, then the data will not come immediately, so we must
4226 * send all what we have without waiting. Note that due to the small gain
4227 * in waiting for the body of the request, it's easier to simply put the
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02004228 * CF_SEND_DONTWAIT flag any time. It's a one-shot flag so it will remove
Willy Tarreau2be39392010-01-03 17:24:51 +01004229 * itself once used.
4230 */
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02004231 req->flags |= CF_SEND_DONTWAIT;
Willy Tarreau2be39392010-01-03 17:24:51 +01004232
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004233 done: /* done with this analyser, continue with next ones that the calling
4234 * points will have set, if any.
4235 */
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004236 req->analyse_exp = TICK_ETERNITY;
Thierry FOURNIER7566e302014-08-22 06:55:26 +02004237 done_without_exp: /* done with this analyser, but dont reset the analyse_exp. */
4238 req->analysers &= ~an_bit;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004239 return 1;
Willy Tarreau11382812008-07-09 16:18:21 +02004240
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004241 tarpit:
4242 /* When a connection is tarpitted, we use the tarpit timeout,
4243 * which may be the same as the connect timeout if unspecified.
4244 * If unset, then set it to zero because we really want it to
4245 * eventually expire. We build the tarpit as an analyser.
4246 */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01004247 channel_erase(&s->req);
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004248
4249 /* wipe the request out so that we can drop the connection early
4250 * if the client closes first.
4251 */
4252 channel_dont_connect(req);
4253 req->analysers = 0; /* remove switching rules etc... */
4254 req->analysers |= AN_REQ_HTTP_TARPIT;
4255 req->analyse_exp = tick_add_ifset(now_ms, s->be->timeout.tarpit);
4256 if (!req->analyse_exp)
4257 req->analyse_exp = tick_add(now_ms, 0);
Willy Tarreau87b09662015-04-03 00:22:06 +02004258 stream_inc_http_err_ctr(s);
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004259 sess->fe->fe_counters.denied_req++;
4260 if (sess->fe != s->be)
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004261 s->be->be_counters.denied_req++;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02004262 if (sess->listener->counters)
4263 sess->listener->counters->denied_req++;
Thierry FOURNIER7566e302014-08-22 06:55:26 +02004264 goto done_without_exp;
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004265
4266 deny: /* this request was blocked (denied) */
Willy Tarreau0b748332014-04-29 00:13:29 +02004267 txn->flags |= TX_CLDENY;
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004268 txn->status = 403;
4269 s->logs.tv_request = now;
Willy Tarreau350f4872014-11-28 14:42:25 +01004270 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_403));
Willy Tarreau87b09662015-04-03 00:22:06 +02004271 stream_inc_http_err_ctr(s);
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004272 sess->fe->fe_counters.denied_req++;
4273 if (sess->fe != s->be)
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004274 s->be->be_counters.denied_req++;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02004275 if (sess->listener->counters)
4276 sess->listener->counters->denied_req++;
Willy Tarreaubbba2a82014-04-28 13:57:26 +02004277 goto return_prx_cond;
4278
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004279 return_bad_req:
4280 /* We centralize bad requests processing here */
4281 if (unlikely(msg->msg_state == HTTP_MSG_ERROR) || msg->err_pos >= 0) {
4282 /* we detected a parsing error. We want to archive this request
4283 * in the dedicated proxy area for later troubleshooting.
4284 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004285 http_capture_bad_message(&sess->fe->invalid_req, s, msg, msg->msg_state, sess->fe);
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004286 }
Willy Tarreau55ea7572007-06-17 19:56:27 +02004287
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004288 txn->req.msg_state = HTTP_MSG_ERROR;
4289 txn->status = 400;
Willy Tarreau350f4872014-11-28 14:42:25 +01004290 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_400));
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02004291
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004292 sess->fe->fe_counters.failed_req++;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02004293 if (sess->listener->counters)
4294 sess->listener->counters->failed_req++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02004295
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004296 return_prx_cond:
Willy Tarreaue7dff022015-04-03 01:14:29 +02004297 if (!(s->flags & SF_ERR_MASK))
4298 s->flags |= SF_ERR_PRXCOND;
4299 if (!(s->flags & SF_FINST_MASK))
4300 s->flags |= SF_FINST_R;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01004301
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004302 req->analysers = 0;
4303 req->analyse_exp = TICK_ETERNITY;
4304 return 0;
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01004305
4306 return_prx_yield:
4307 channel_dont_connect(req);
4308 return 0;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004309}
Willy Tarreau58f10d72006-12-04 02:26:12 +01004310
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004311/* This function performs all the processing enabled for the current request.
4312 * It returns 1 if the processing can continue on next analysers, or zero if it
4313 * needs more data, encounters an error, or wants to immediately abort the
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01004314 * request. It relies on buffers flags, and updates s->req.analysers.
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004315 */
Willy Tarreau87b09662015-04-03 00:22:06 +02004316int http_process_request(struct stream *s, struct channel *req, int an_bit)
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004317{
Willy Tarreaufb0afa72015-04-03 14:46:27 +02004318 struct session *sess = s->sess;
Willy Tarreaueee5b512015-04-03 23:46:31 +02004319 struct http_txn *txn = s->txn;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004320 struct http_msg *msg = &txn->req;
Willy Tarreau350f4872014-11-28 14:42:25 +01004321 struct connection *cli_conn = objt_conn(s->si[1].end);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004322
Willy Tarreau655dce92009-11-08 13:10:58 +01004323 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
Willy Tarreau51aecc72009-07-12 09:47:04 +02004324 /* we need more data */
Willy Tarreau8263d2b2012-08-28 00:06:31 +02004325 channel_dont_connect(req);
Willy Tarreau51aecc72009-07-12 09:47:04 +02004326 return 0;
4327 }
4328
Willy Tarreau87b09662015-04-03 00:22:06 +02004329 DPRINTF(stderr,"[%u] %s: stream=%p b=%p, exp(r,w)=%u,%u bf=%08x bh=%d analysers=%02x\n",
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004330 now_ms, __FUNCTION__,
4331 s,
4332 req,
4333 req->rex, req->wex,
4334 req->flags,
Willy Tarreau9b28e032012-10-12 23:49:43 +02004335 req->buf->i,
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02004336 req->analysers);
Willy Tarreau06619262006-12-17 08:37:22 +01004337
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004338 if (sess->fe->comp || s->be->comp)
William Lallemand82fe75c2012-10-23 10:25:10 +02004339 select_compression_request_header(s, req->buf);
4340
Willy Tarreau59234e92008-11-30 23:51:27 +01004341 /*
4342 * Right now, we know that we have processed the entire headers
4343 * and that unwanted requests have been filtered out. We can do
4344 * whatever we want with the remaining request. Also, now we
4345 * may have separate values for ->fe, ->be.
4346 */
Willy Tarreau06619262006-12-17 08:37:22 +01004347
Willy Tarreau59234e92008-11-30 23:51:27 +01004348 /*
Willy Tarreaub363a1f2013-10-01 10:45:07 +02004349 * If HTTP PROXY is set we simply get remote server address parsing
4350 * incoming request. Note that this requires that a connection is
4351 * allocated on the server side.
Willy Tarreau59234e92008-11-30 23:51:27 +01004352 */
Willy Tarreaue7dff022015-04-03 01:14:29 +02004353 if ((s->be->options & PR_O_HTTP_PROXY) && !(s->flags & SF_ADDR_SET)) {
Willy Tarreau32e3c6a2013-10-11 19:34:20 +02004354 struct connection *conn;
Willy Tarreaue8df1e12013-12-16 14:30:55 +01004355 char *path;
Willy Tarreau32e3c6a2013-10-11 19:34:20 +02004356
Willy Tarreau9471b8c2013-12-15 13:31:35 +01004357 /* Note that for now we don't reuse existing proxy connections */
Willy Tarreau350f4872014-11-28 14:42:25 +01004358 if (unlikely((conn = si_alloc_conn(&s->si[1], 0)) == NULL)) {
Willy Tarreau32e3c6a2013-10-11 19:34:20 +02004359 txn->req.msg_state = HTTP_MSG_ERROR;
4360 txn->status = 500;
4361 req->analysers = 0;
Willy Tarreau350f4872014-11-28 14:42:25 +01004362 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_500));
Willy Tarreau32e3c6a2013-10-11 19:34:20 +02004363
Willy Tarreaue7dff022015-04-03 01:14:29 +02004364 if (!(s->flags & SF_ERR_MASK))
4365 s->flags |= SF_ERR_RESOURCE;
4366 if (!(s->flags & SF_FINST_MASK))
4367 s->flags |= SF_FINST_R;
Willy Tarreau32e3c6a2013-10-11 19:34:20 +02004368
4369 return 0;
4370 }
Willy Tarreaue8df1e12013-12-16 14:30:55 +01004371
4372 path = http_get_path(txn);
4373 url2sa(req->buf->p + msg->sl.rq.u,
4374 path ? path - (req->buf->p + msg->sl.rq.u) : msg->sl.rq.u_l,
Thierry FOURNIER9f95e402014-03-21 14:51:46 +01004375 &conn->addr.to, NULL);
Willy Tarreaue8df1e12013-12-16 14:30:55 +01004376 /* if the path was found, we have to remove everything between
4377 * req->buf->p + msg->sl.rq.u and path (excluded). If it was not
4378 * found, we need to replace from req->buf->p + msg->sl.rq.u for
4379 * u_l characters by a single "/".
4380 */
4381 if (path) {
4382 char *cur_ptr = req->buf->p;
4383 char *cur_end = cur_ptr + txn->req.sl.rq.l;
4384 int delta;
4385
4386 delta = buffer_replace2(req->buf, req->buf->p + msg->sl.rq.u, path, NULL, 0);
4387 http_msg_move_end(&txn->req, delta);
4388 cur_end += delta;
4389 if (http_parse_reqline(&txn->req, HTTP_MSG_RQMETH, cur_ptr, cur_end + 1, NULL, NULL) == NULL)
4390 goto return_bad_req;
4391 }
4392 else {
4393 char *cur_ptr = req->buf->p;
4394 char *cur_end = cur_ptr + txn->req.sl.rq.l;
4395 int delta;
4396
4397 delta = buffer_replace2(req->buf, req->buf->p + msg->sl.rq.u,
4398 req->buf->p + msg->sl.rq.u + msg->sl.rq.u_l, "/", 1);
4399 http_msg_move_end(&txn->req, delta);
4400 cur_end += delta;
4401 if (http_parse_reqline(&txn->req, HTTP_MSG_RQMETH, cur_ptr, cur_end + 1, NULL, NULL) == NULL)
4402 goto return_bad_req;
4403 }
Willy Tarreau59234e92008-11-30 23:51:27 +01004404 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004405
Willy Tarreau59234e92008-11-30 23:51:27 +01004406 /*
Cyril Bontéb21570a2009-11-29 20:04:48 +01004407 * 7: Now we can work with the cookies.
Willy Tarreau59234e92008-11-30 23:51:27 +01004408 * Note that doing so might move headers in the request, but
4409 * the fields will stay coherent and the URI will not move.
4410 * This should only be performed in the backend.
4411 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004412 if ((s->be->cookie_name || s->be->appsession_name || sess->fe->capture_name)
Willy Tarreau59234e92008-11-30 23:51:27 +01004413 && !(txn->flags & (TX_CLDENY|TX_CLTARPIT)))
4414 manage_client_side_cookies(s, req);
Willy Tarreau7ac51f62007-03-25 16:00:04 +02004415
Willy Tarreau59234e92008-11-30 23:51:27 +01004416 /*
Cyril Bontéb21570a2009-11-29 20:04:48 +01004417 * 8: the appsession cookie was looked up very early in 1.2,
4418 * so let's do the same now.
4419 */
4420
Cyril Bonté47fdd8e2010-04-25 00:00:51 +02004421 /* It needs to look into the URI unless persistence must be ignored */
Willy Tarreaue7dff022015-04-03 01:14:29 +02004422 if ((txn->sessid == NULL) && s->be->appsession_name && !(s->flags & SF_IGNORE_PRST)) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02004423 get_srv_from_appsession(s, req->buf->p + msg->sl.rq.u, msg->sl.rq.u_l);
Cyril Bontéb21570a2009-11-29 20:04:48 +01004424 }
4425
William Lallemanda73203e2012-03-12 12:48:57 +01004426 /* add unique-id if "header-unique-id" is specified */
4427
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004428 if (!LIST_ISEMPTY(&sess->fe->format_unique_id)) {
William Lallemand5b7ea3a2013-08-28 15:44:19 +02004429 if ((s->unique_id = pool_alloc2(pool2_uniqueid)) == NULL)
4430 goto return_bad_req;
4431 s->unique_id[0] = '\0';
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004432 build_logline(s, s->unique_id, UNIQUEID_LEN, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02004433 }
William Lallemanda73203e2012-03-12 12:48:57 +01004434
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004435 if (sess->fe->header_unique_id && s->unique_id) {
4436 chunk_printf(&trash, "%s: %s", sess->fe->header_unique_id, s->unique_id);
Willy Tarreau19d14ef2012-10-29 16:51:55 +01004437 if (trash.len < 0)
William Lallemanda73203e2012-03-12 12:48:57 +01004438 goto return_bad_req;
Willy Tarreau19d14ef2012-10-29 16:51:55 +01004439 if (unlikely(http_header_add_tail2(&txn->req, &txn->hdr_idx, trash.str, trash.len) < 0))
William Lallemanda73203e2012-03-12 12:48:57 +01004440 goto return_bad_req;
4441 }
4442
Cyril Bontéb21570a2009-11-29 20:04:48 +01004443 /*
Willy Tarreau59234e92008-11-30 23:51:27 +01004444 * 9: add X-Forwarded-For if either the frontend or the backend
4445 * asks for it.
4446 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004447 if ((sess->fe->options | s->be->options) & PR_O_FWDFOR) {
Willy Tarreau87cf5142011-08-19 22:57:24 +02004448 struct hdr_ctx ctx = { .idx = 0 };
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004449 if (!((sess->fe->options | s->be->options) & PR_O_FF_ALWAYS) &&
4450 http_find_header2(s->be->fwdfor_hdr_len ? s->be->fwdfor_hdr_name : sess->fe->fwdfor_hdr_name,
4451 s->be->fwdfor_hdr_len ? s->be->fwdfor_hdr_len : sess->fe->fwdfor_hdr_len,
Willy Tarreau9b28e032012-10-12 23:49:43 +02004452 req->buf->p, &txn->hdr_idx, &ctx)) {
Willy Tarreau87cf5142011-08-19 22:57:24 +02004453 /* The header is set to be added only if none is present
4454 * and we found it, so don't do anything.
4455 */
4456 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02004457 else if (cli_conn && cli_conn->addr.from.ss_family == AF_INET) {
Willy Tarreau59234e92008-11-30 23:51:27 +01004458 /* Add an X-Forwarded-For header unless the source IP is
4459 * in the 'except' network range.
4460 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004461 if ((!sess->fe->except_mask.s_addr ||
4462 (((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr.s_addr & sess->fe->except_mask.s_addr)
4463 != sess->fe->except_net.s_addr) &&
Willy Tarreau59234e92008-11-30 23:51:27 +01004464 (!s->be->except_mask.s_addr ||
Willy Tarreaub363a1f2013-10-01 10:45:07 +02004465 (((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr.s_addr & s->be->except_mask.s_addr)
Willy Tarreau59234e92008-11-30 23:51:27 +01004466 != s->be->except_net.s_addr)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01004467 int len;
Willy Tarreau59234e92008-11-30 23:51:27 +01004468 unsigned char *pn;
Willy Tarreaub363a1f2013-10-01 10:45:07 +02004469 pn = (unsigned char *)&((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr;
Ross Westaf72a1d2008-08-03 10:51:45 +02004470
4471 /* Note: we rely on the backend to get the header name to be used for
4472 * x-forwarded-for, because the header is really meant for the backends.
4473 * However, if the backend did not specify any option, we have to rely
4474 * on the frontend's header name.
4475 */
Willy Tarreau59234e92008-11-30 23:51:27 +01004476 if (s->be->fwdfor_hdr_len) {
4477 len = s->be->fwdfor_hdr_len;
Willy Tarreau19d14ef2012-10-29 16:51:55 +01004478 memcpy(trash.str, s->be->fwdfor_hdr_name, len);
Ross Westaf72a1d2008-08-03 10:51:45 +02004479 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004480 len = sess->fe->fwdfor_hdr_len;
4481 memcpy(trash.str, sess->fe->fwdfor_hdr_name, len);
Willy Tarreaub86db342009-11-30 11:50:16 +01004482 }
Willy Tarreaue9187f82014-04-14 15:27:14 +02004483 len += snprintf(trash.str + len, trash.size - len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
Willy Tarreauedcf6682008-11-30 23:15:34 +01004484
Willy Tarreau19d14ef2012-10-29 16:51:55 +01004485 if (unlikely(http_header_add_tail2(&txn->req, &txn->hdr_idx, trash.str, len) < 0))
Willy Tarreau06619262006-12-17 08:37:22 +01004486 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01004487 }
4488 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02004489 else if (cli_conn && cli_conn->addr.from.ss_family == AF_INET6) {
Willy Tarreau59234e92008-11-30 23:51:27 +01004490 /* FIXME: for the sake of completeness, we should also support
4491 * 'except' here, although it is mostly useless in this case.
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02004492 */
Willy Tarreau59234e92008-11-30 23:51:27 +01004493 int len;
4494 char pn[INET6_ADDRSTRLEN];
4495 inet_ntop(AF_INET6,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02004496 (const void *)&((struct sockaddr_in6 *)(&cli_conn->addr.from))->sin6_addr,
Willy Tarreau59234e92008-11-30 23:51:27 +01004497 pn, sizeof(pn));
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02004498
Willy Tarreau59234e92008-11-30 23:51:27 +01004499 /* Note: we rely on the backend to get the header name to be used for
4500 * x-forwarded-for, because the header is really meant for the backends.
4501 * However, if the backend did not specify any option, we have to rely
4502 * on the frontend's header name.
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02004503 */
Willy Tarreau59234e92008-11-30 23:51:27 +01004504 if (s->be->fwdfor_hdr_len) {
4505 len = s->be->fwdfor_hdr_len;
Willy Tarreau19d14ef2012-10-29 16:51:55 +01004506 memcpy(trash.str, s->be->fwdfor_hdr_name, len);
Willy Tarreau59234e92008-11-30 23:51:27 +01004507 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004508 len = sess->fe->fwdfor_hdr_len;
4509 memcpy(trash.str, sess->fe->fwdfor_hdr_name, len);
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02004510 }
Willy Tarreaue9187f82014-04-14 15:27:14 +02004511 len += snprintf(trash.str + len, trash.size - len, ": %s", pn);
Willy Tarreauadfb8562008-08-11 15:24:42 +02004512
Willy Tarreau19d14ef2012-10-29 16:51:55 +01004513 if (unlikely(http_header_add_tail2(&txn->req, &txn->hdr_idx, trash.str, len) < 0))
Willy Tarreau59234e92008-11-30 23:51:27 +01004514 goto return_bad_req;
4515 }
4516 }
4517
4518 /*
Maik Broemme2850cb42009-04-17 18:53:21 +02004519 * 10: add X-Original-To if either the frontend or the backend
4520 * asks for it.
4521 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004522 if ((sess->fe->options | s->be->options) & PR_O_ORGTO) {
Maik Broemme2850cb42009-04-17 18:53:21 +02004523
4524 /* FIXME: don't know if IPv6 can handle that case too. */
Willy Tarreaub363a1f2013-10-01 10:45:07 +02004525 if (cli_conn && cli_conn->addr.from.ss_family == AF_INET) {
Maik Broemme2850cb42009-04-17 18:53:21 +02004526 /* Add an X-Original-To header unless the destination IP is
4527 * in the 'except' network range.
4528 */
Willy Tarreaub363a1f2013-10-01 10:45:07 +02004529 conn_get_to_addr(cli_conn);
Maik Broemme2850cb42009-04-17 18:53:21 +02004530
Willy Tarreaub363a1f2013-10-01 10:45:07 +02004531 if (cli_conn->addr.to.ss_family == AF_INET &&
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004532 ((!sess->fe->except_mask_to.s_addr ||
4533 (((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr.s_addr & sess->fe->except_mask_to.s_addr)
4534 != sess->fe->except_to.s_addr) &&
Emeric Brun5bd86a82010-10-22 17:23:04 +02004535 (!s->be->except_mask_to.s_addr ||
Willy Tarreaub363a1f2013-10-01 10:45:07 +02004536 (((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr.s_addr & s->be->except_mask_to.s_addr)
Emeric Brun5bd86a82010-10-22 17:23:04 +02004537 != s->be->except_to.s_addr))) {
Maik Broemme2850cb42009-04-17 18:53:21 +02004538 int len;
4539 unsigned char *pn;
Willy Tarreaub363a1f2013-10-01 10:45:07 +02004540 pn = (unsigned char *)&((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr;
Maik Broemme2850cb42009-04-17 18:53:21 +02004541
4542 /* Note: we rely on the backend to get the header name to be used for
4543 * x-original-to, because the header is really meant for the backends.
4544 * However, if the backend did not specify any option, we have to rely
4545 * on the frontend's header name.
4546 */
4547 if (s->be->orgto_hdr_len) {
4548 len = s->be->orgto_hdr_len;
Willy Tarreau19d14ef2012-10-29 16:51:55 +01004549 memcpy(trash.str, s->be->orgto_hdr_name, len);
Maik Broemme2850cb42009-04-17 18:53:21 +02004550 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004551 len = sess->fe->orgto_hdr_len;
4552 memcpy(trash.str, sess->fe->orgto_hdr_name, len);
Willy Tarreaub86db342009-11-30 11:50:16 +01004553 }
Willy Tarreaue9187f82014-04-14 15:27:14 +02004554 len += snprintf(trash.str + len, trash.size - len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
Maik Broemme2850cb42009-04-17 18:53:21 +02004555
Willy Tarreau19d14ef2012-10-29 16:51:55 +01004556 if (unlikely(http_header_add_tail2(&txn->req, &txn->hdr_idx, trash.str, len) < 0))
Maik Broemme2850cb42009-04-17 18:53:21 +02004557 goto return_bad_req;
4558 }
4559 }
4560 }
4561
Willy Tarreau50fc7772012-11-11 22:19:57 +01004562 /* 11: add "Connection: close" or "Connection: keep-alive" if needed and not yet set.
4563 * If an "Upgrade" token is found, the header is left untouched in order not to have
4564 * to deal with some servers bugs : some of them fail an Upgrade if anything but
4565 * "Upgrade" is present in the Connection header.
4566 */
4567 if (!(txn->flags & TX_HDR_CONN_UPG) &&
4568 (((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) ||
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004569 ((sess->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
Willy Tarreau02bce8b2014-01-30 00:15:28 +01004570 (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL))) {
Willy Tarreaubbf0b372010-01-18 16:54:40 +01004571 unsigned int want_flags = 0;
4572
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01004573 if (msg->flags & HTTP_MSGF_VER_11) {
Willy Tarreau22a95342010-09-29 14:31:41 +02004574 if (((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL ||
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004575 ((sess->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
Willy Tarreau02bce8b2014-01-30 00:15:28 +01004576 (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL)) &&
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004577 !((sess->fe->options2|s->be->options2) & PR_O2_FAKE_KA))
Willy Tarreaubbf0b372010-01-18 16:54:40 +01004578 want_flags |= TX_CON_CLO_SET;
4579 } else {
Willy Tarreau22a95342010-09-29 14:31:41 +02004580 if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL &&
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004581 ((sess->fe->options & PR_O_HTTP_MODE) != PR_O_HTTP_PCL &&
Willy Tarreau02bce8b2014-01-30 00:15:28 +01004582 (s->be->options & PR_O_HTTP_MODE) != PR_O_HTTP_PCL)) ||
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004583 ((sess->fe->options2|s->be->options2) & PR_O2_FAKE_KA))
Willy Tarreaubbf0b372010-01-18 16:54:40 +01004584 want_flags |= TX_CON_KAL_SET;
4585 }
4586
4587 if (want_flags != (txn->flags & (TX_CON_CLO_SET|TX_CON_KAL_SET)))
Willy Tarreau6acf7c92012-03-09 13:30:45 +01004588 http_change_connection_header(txn, msg, want_flags);
Willy Tarreau59234e92008-11-30 23:51:27 +01004589 }
Willy Tarreau522d6c02009-12-06 18:49:18 +01004590
Willy Tarreaubbf0b372010-01-18 16:54:40 +01004591
Willy Tarreau522d6c02009-12-06 18:49:18 +01004592 /* If we have no server assigned yet and we're balancing on url_param
4593 * with a POST request, we may be interested in checking the body for
4594 * that parameter. This will be done in another analyser.
Willy Tarreau59234e92008-11-30 23:51:27 +01004595 */
Willy Tarreaue7dff022015-04-03 01:14:29 +02004596 if (!(s->flags & (SF_ASSIGNED|SF_DIRECT)) &&
Willy Tarreaueee5b512015-04-03 23:46:31 +02004597 s->txn->meth == HTTP_METH_POST && s->be->url_param_name != NULL &&
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01004598 (msg->flags & (HTTP_MSGF_CNT_LEN|HTTP_MSGF_TE_CHNK))) {
Willy Tarreau8263d2b2012-08-28 00:06:31 +02004599 channel_dont_connect(req);
Willy Tarreau522d6c02009-12-06 18:49:18 +01004600 req->analysers |= AN_REQ_HTTP_BODY;
Willy Tarreau59234e92008-11-30 23:51:27 +01004601 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02004602
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01004603 if (msg->flags & HTTP_MSGF_XFER_LEN) {
Willy Tarreaud98cf932009-12-27 22:54:55 +01004604 req->analysers |= AN_REQ_HTTP_XFER_BODY;
Willy Tarreau5e205522011-12-17 16:34:27 +01004605#ifdef TCP_QUICKACK
4606 /* We expect some data from the client. Unless we know for sure
4607 * we already have a full request, we have to re-enable quick-ack
4608 * in case we previously disabled it, otherwise we might cause
4609 * the client to delay further data.
4610 */
Willy Tarreaufb0afa72015-04-03 14:46:27 +02004611 if ((sess->listener->options & LI_O_NOQUICKACK) &&
Willy Tarreau3c728722014-01-23 13:50:42 +01004612 cli_conn && conn_ctrl_ready(cli_conn) &&
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01004613 ((msg->flags & HTTP_MSGF_TE_CHNK) ||
Willy Tarreau9b28e032012-10-12 23:49:43 +02004614 (msg->body_len > req->buf->i - txn->req.eoh - 2)))
Willy Tarreaub363a1f2013-10-01 10:45:07 +02004615 setsockopt(cli_conn->t.sock.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
Willy Tarreau5e205522011-12-17 16:34:27 +01004616#endif
4617 }
Willy Tarreau03945942009-12-22 16:50:27 +01004618
Willy Tarreau59234e92008-11-30 23:51:27 +01004619 /*************************************************************
4620 * OK, that's finished for the headers. We have done what we *
4621 * could. Let's switch to the DATA state. *
4622 ************************************************************/
Willy Tarreau522d6c02009-12-06 18:49:18 +01004623 req->analyse_exp = TICK_ETERNITY;
4624 req->analysers &= ~an_bit;
Willy Tarreaubaaee002006-06-26 02:48:02 +02004625
Willy Tarreau7bb68ab2012-05-13 14:48:59 +02004626 /* if the server closes the connection, we want to immediately react
4627 * and close the socket to save packets and syscalls.
4628 */
Willy Tarreau40f151a2012-12-20 12:10:09 +01004629 if (!(req->analysers & AN_REQ_HTTP_XFER_BODY))
Willy Tarreau350f4872014-11-28 14:42:25 +01004630 s->si[1].flags |= SI_FL_NOHALF;
Willy Tarreau7bb68ab2012-05-13 14:48:59 +02004631
Willy Tarreau59234e92008-11-30 23:51:27 +01004632 s->logs.tv_request = now;
Willy Tarreau59234e92008-11-30 23:51:27 +01004633 /* OK let's go on with the BODY now */
4634 return 1;
Willy Tarreau06619262006-12-17 08:37:22 +01004635
Willy Tarreau59234e92008-11-30 23:51:27 +01004636 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau4076a152009-04-02 15:18:36 +02004637 if (unlikely(msg->msg_state == HTTP_MSG_ERROR) || msg->err_pos >= 0) {
Willy Tarreauf073a832009-03-01 23:21:47 +01004638 /* we detected a parsing error. We want to archive this request
4639 * in the dedicated proxy area for later troubleshooting.
4640 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004641 http_capture_bad_message(&sess->fe->invalid_req, s, msg, msg->msg_state, sess->fe);
Willy Tarreauf073a832009-03-01 23:21:47 +01004642 }
Willy Tarreau4076a152009-04-02 15:18:36 +02004643
Willy Tarreau59234e92008-11-30 23:51:27 +01004644 txn->req.msg_state = HTTP_MSG_ERROR;
4645 txn->status = 400;
4646 req->analysers = 0;
Willy Tarreau350f4872014-11-28 14:42:25 +01004647 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_400));
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02004648
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004649 sess->fe->fe_counters.failed_req++;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02004650 if (sess->listener->counters)
4651 sess->listener->counters->failed_req++;
Willy Tarreauadfb8562008-08-11 15:24:42 +02004652
Willy Tarreaue7dff022015-04-03 01:14:29 +02004653 if (!(s->flags & SF_ERR_MASK))
4654 s->flags |= SF_ERR_PRXCOND;
4655 if (!(s->flags & SF_FINST_MASK))
4656 s->flags |= SF_FINST_R;
Willy Tarreaudafde432008-08-17 01:00:46 +02004657 return 0;
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02004658}
Willy Tarreauadfb8562008-08-11 15:24:42 +02004659
Willy Tarreau60b85b02008-11-30 23:28:40 +01004660/* This function is an analyser which processes the HTTP tarpit. It always
4661 * returns zero, at the beginning because it prevents any other processing
4662 * from occurring, and at the end because it terminates the request.
4663 */
Willy Tarreau87b09662015-04-03 00:22:06 +02004664int http_process_tarpit(struct stream *s, struct channel *req, int an_bit)
Willy Tarreau60b85b02008-11-30 23:28:40 +01004665{
Willy Tarreaueee5b512015-04-03 23:46:31 +02004666 struct http_txn *txn = s->txn;
Willy Tarreau60b85b02008-11-30 23:28:40 +01004667
4668 /* This connection is being tarpitted. The CLIENT side has
4669 * already set the connect expiration date to the right
4670 * timeout. We just have to check that the client is still
4671 * there and that the timeout has not expired.
4672 */
Willy Tarreau8263d2b2012-08-28 00:06:31 +02004673 channel_dont_connect(req);
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02004674 if ((req->flags & (CF_SHUTR|CF_READ_ERROR)) == 0 &&
Willy Tarreau60b85b02008-11-30 23:28:40 +01004675 !tick_is_expired(req->analyse_exp, now_ms))
4676 return 0;
4677
4678 /* We will set the queue timer to the time spent, just for
4679 * logging purposes. We fake a 500 server error, so that the
4680 * attacker will not suspect his connection has been tarpitted.
4681 * It will not cause trouble to the logs because we can exclude
4682 * the tarpitted connections by filtering on the 'PT' status flags.
4683 */
Willy Tarreau60b85b02008-11-30 23:28:40 +01004684 s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
4685
4686 txn->status = 500;
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02004687 if (!(req->flags & CF_READ_ERROR))
Willy Tarreau350f4872014-11-28 14:42:25 +01004688 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_500));
Willy Tarreau60b85b02008-11-30 23:28:40 +01004689
4690 req->analysers = 0;
4691 req->analyse_exp = TICK_ETERNITY;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02004692
Willy Tarreaue7dff022015-04-03 01:14:29 +02004693 if (!(s->flags & SF_ERR_MASK))
4694 s->flags |= SF_ERR_PRXCOND;
4695 if (!(s->flags & SF_FINST_MASK))
4696 s->flags |= SF_FINST_T;
Willy Tarreau60b85b02008-11-30 23:28:40 +01004697 return 0;
4698}
4699
Willy Tarreau5a8f9472014-04-10 11:16:06 +02004700/* This function is an analyser which waits for the HTTP request body. It waits
4701 * for either the buffer to be full, or the full advertised contents to have
4702 * reached the buffer. It must only be called after the standard HTTP request
4703 * processing has occurred, because it expects the request to be parsed and will
4704 * look for the Expect header. It may send a 100-Continue interim response. It
4705 * takes in input any state starting from HTTP_MSG_BODY and leaves with one of
4706 * HTTP_MSG_CHK_SIZE, HTTP_MSG_DATA or HTTP_MSG_TRAILERS. It returns zero if it
4707 * needs to read more data, or 1 once it has completed its analysis.
Willy Tarreaud34af782008-11-30 23:36:37 +01004708 */
Willy Tarreau87b09662015-04-03 00:22:06 +02004709int http_wait_for_request_body(struct stream *s, struct channel *req, int an_bit)
Willy Tarreaud34af782008-11-30 23:36:37 +01004710{
Willy Tarreaufb0afa72015-04-03 14:46:27 +02004711 struct session *sess = s->sess;
Willy Tarreaueee5b512015-04-03 23:46:31 +02004712 struct http_txn *txn = s->txn;
4713 struct http_msg *msg = &s->txn->req;
Willy Tarreaud34af782008-11-30 23:36:37 +01004714
4715 /* We have to parse the HTTP request body to find any required data.
4716 * "balance url_param check_post" should have been the only way to get
4717 * into this. We were brought here after HTTP header analysis, so all
4718 * related structures are ready.
4719 */
4720
Willy Tarreau890988f2014-04-10 11:59:33 +02004721 if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) {
4722 /* This is the first call */
4723 if (msg->msg_state < HTTP_MSG_BODY)
4724 goto missing_data;
Willy Tarreau522d6c02009-12-06 18:49:18 +01004725
Willy Tarreau890988f2014-04-10 11:59:33 +02004726 if (msg->msg_state < HTTP_MSG_100_SENT) {
4727 /* If we have HTTP/1.1 and Expect: 100-continue, then we must
4728 * send an HTTP/1.1 100 Continue intermediate response.
4729 */
4730 if (msg->flags & HTTP_MSGF_VER_11) {
4731 struct hdr_ctx ctx;
4732 ctx.idx = 0;
4733 /* Expect is allowed in 1.1, look for it */
4734 if (http_find_header2("Expect", 6, req->buf->p, &txn->hdr_idx, &ctx) &&
4735 unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val, "100-continue", 12) == 0)) {
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01004736 bo_inject(&s->res, http_100_chunk.str, http_100_chunk.len);
Willy Tarreau890988f2014-04-10 11:59:33 +02004737 }
Willy Tarreau522d6c02009-12-06 18:49:18 +01004738 }
Willy Tarreau890988f2014-04-10 11:59:33 +02004739 msg->msg_state = HTTP_MSG_100_SENT;
Willy Tarreau522d6c02009-12-06 18:49:18 +01004740 }
Willy Tarreau522d6c02009-12-06 18:49:18 +01004741
Willy Tarreaufa4a03c2012-03-09 21:28:54 +01004742 /* we have msg->sov which points to the first byte of message body.
Willy Tarreau877e78d2013-04-07 18:48:08 +02004743 * req->buf->p still points to the beginning of the message. We
4744 * must save the body in msg->next because it survives buffer
4745 * re-alignments.
Willy Tarreaud98cf932009-12-27 22:54:55 +01004746 */
Willy Tarreauea1175a2012-03-05 15:52:30 +01004747 msg->next = msg->sov;
Willy Tarreaua458b672012-03-05 11:17:50 +01004748
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01004749 if (msg->flags & HTTP_MSGF_TE_CHNK)
Willy Tarreau522d6c02009-12-06 18:49:18 +01004750 msg->msg_state = HTTP_MSG_CHUNK_SIZE;
4751 else
4752 msg->msg_state = HTTP_MSG_DATA;
4753 }
4754
Willy Tarreau890988f2014-04-10 11:59:33 +02004755 if (!(msg->flags & HTTP_MSGF_TE_CHNK)) {
4756 /* We're in content-length mode, we just have to wait for enough data. */
4757 if (req->buf->i - msg->sov < msg->body_len)
4758 goto missing_data;
4759
4760 /* OK we have everything we need now */
4761 goto http_end;
4762 }
4763
4764 /* OK here we're parsing a chunked-encoded message */
4765
Willy Tarreau522d6c02009-12-06 18:49:18 +01004766 if (msg->msg_state == HTTP_MSG_CHUNK_SIZE) {
Willy Tarreau124d9912011-03-01 20:30:48 +01004767 /* read the chunk size and assign it to ->chunk_len, then
Willy Tarreaua458b672012-03-05 11:17:50 +01004768 * set ->sov and ->next to point to the body and switch to DATA or
Willy Tarreaud98cf932009-12-27 22:54:55 +01004769 * TRAILERS state.
Willy Tarreau115acb92009-12-26 13:56:06 +01004770 */
Willy Tarreau4baf44b2012-03-09 14:10:20 +01004771 int ret = http_parse_chunk_size(msg);
Willy Tarreaud34af782008-11-30 23:36:37 +01004772
Willy Tarreau115acb92009-12-26 13:56:06 +01004773 if (!ret)
4774 goto missing_data;
Willy Tarreauda7ff642010-06-23 11:44:09 +02004775 else if (ret < 0) {
Willy Tarreau87b09662015-04-03 00:22:06 +02004776 stream_inc_http_err_ctr(s);
Willy Tarreau522d6c02009-12-06 18:49:18 +01004777 goto return_bad_req;
Willy Tarreauda7ff642010-06-23 11:44:09 +02004778 }
Willy Tarreaud34af782008-11-30 23:36:37 +01004779 }
4780
Willy Tarreaud98cf932009-12-27 22:54:55 +01004781 /* Now we're in HTTP_MSG_DATA or HTTP_MSG_TRAILERS state.
Willy Tarreaufa4a03c2012-03-09 21:28:54 +01004782 * We have the first data byte is in msg->sov. We're waiting for at
Willy Tarreau226071e2014-04-10 11:55:45 +02004783 * least a whole chunk or the whole content length bytes after msg->sov.
Willy Tarreaud34af782008-11-30 23:36:37 +01004784 */
Willy Tarreau890988f2014-04-10 11:59:33 +02004785 if (msg->msg_state == HTTP_MSG_TRAILERS)
4786 goto http_end;
4787
Willy Tarreau226071e2014-04-10 11:55:45 +02004788 if (req->buf->i - msg->sov >= msg->body_len) /* we have enough bytes now */
Willy Tarreau522d6c02009-12-06 18:49:18 +01004789 goto http_end;
4790
4791 missing_data:
Willy Tarreau31a19952014-04-10 11:50:37 +02004792 /* we get here if we need to wait for more data. If the buffer is full,
4793 * we have the maximum we can expect.
4794 */
4795 if (buffer_full(req->buf, global.tune.maxrewrite))
4796 goto http_end;
Willy Tarreau115acb92009-12-26 13:56:06 +01004797
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02004798 if ((req->flags & CF_READ_TIMEOUT) || tick_is_expired(req->analyse_exp, now_ms)) {
Willy Tarreau522d6c02009-12-06 18:49:18 +01004799 txn->status = 408;
Willy Tarreau350f4872014-11-28 14:42:25 +01004800 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_408));
Willy Tarreau79ebac62010-06-07 13:47:49 +02004801
Willy Tarreaue7dff022015-04-03 01:14:29 +02004802 if (!(s->flags & SF_ERR_MASK))
4803 s->flags |= SF_ERR_CLITO;
4804 if (!(s->flags & SF_FINST_MASK))
4805 s->flags |= SF_FINST_D;
Willy Tarreau522d6c02009-12-06 18:49:18 +01004806 goto return_err_msg;
Willy Tarreaud34af782008-11-30 23:36:37 +01004807 }
Willy Tarreau522d6c02009-12-06 18:49:18 +01004808
4809 /* we get here if we need to wait for more data */
Willy Tarreau31a19952014-04-10 11:50:37 +02004810 if (!(req->flags & (CF_SHUTR | CF_READ_ERROR))) {
Willy Tarreaud34af782008-11-30 23:36:37 +01004811 /* Not enough data. We'll re-use the http-request
4812 * timeout here. Ideally, we should set the timeout
4813 * relative to the accept() date. We just set the
4814 * request timeout once at the beginning of the
4815 * request.
4816 */
Willy Tarreau8263d2b2012-08-28 00:06:31 +02004817 channel_dont_connect(req);
Willy Tarreaud34af782008-11-30 23:36:37 +01004818 if (!tick_isset(req->analyse_exp))
Willy Tarreaucd7afc02009-07-12 10:03:17 +02004819 req->analyse_exp = tick_add_ifset(now_ms, s->be->timeout.httpreq);
Willy Tarreaud34af782008-11-30 23:36:37 +01004820 return 0;
4821 }
Willy Tarreau522d6c02009-12-06 18:49:18 +01004822
4823 http_end:
4824 /* The situation will not evolve, so let's give up on the analysis. */
4825 s->logs.tv_request = now; /* update the request timer to reflect full request */
4826 req->analysers &= ~an_bit;
4827 req->analyse_exp = TICK_ETERNITY;
4828 return 1;
4829
4830 return_bad_req: /* let's centralize all bad requests */
4831 txn->req.msg_state = HTTP_MSG_ERROR;
4832 txn->status = 400;
Willy Tarreau350f4872014-11-28 14:42:25 +01004833 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_400));
Willy Tarreau522d6c02009-12-06 18:49:18 +01004834
Willy Tarreaue7dff022015-04-03 01:14:29 +02004835 if (!(s->flags & SF_ERR_MASK))
4836 s->flags |= SF_ERR_PRXCOND;
4837 if (!(s->flags & SF_FINST_MASK))
4838 s->flags |= SF_FINST_R;
Willy Tarreau79ebac62010-06-07 13:47:49 +02004839
Willy Tarreau522d6c02009-12-06 18:49:18 +01004840 return_err_msg:
4841 req->analysers = 0;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004842 sess->fe->fe_counters.failed_req++;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02004843 if (sess->listener->counters)
4844 sess->listener->counters->failed_req++;
Willy Tarreau522d6c02009-12-06 18:49:18 +01004845 return 0;
Willy Tarreaud34af782008-11-30 23:36:37 +01004846}
4847
Willy Tarreaud1de8af2012-05-18 22:12:14 +02004848/* send a server's name with an outgoing request over an established connection.
4849 * Note: this function is designed to be called once the request has been scheduled
4850 * for being forwarded. This is the reason why it rewinds the buffer before
4851 * proceeding.
4852 */
Willy Tarreau45c0d982012-03-09 12:11:57 +01004853int http_send_name_header(struct http_txn *txn, struct proxy* be, const char* srv_name) {
Mark Lamourinec2247f02012-01-04 13:02:01 -05004854
4855 struct hdr_ctx ctx;
4856
Mark Lamourinec2247f02012-01-04 13:02:01 -05004857 char *hdr_name = be->server_id_hdr_name;
4858 int hdr_name_len = be->server_id_hdr_len;
Willy Tarreau394db372012-10-12 22:40:39 +02004859 struct channel *chn = txn->req.chn;
Mark Lamourinec2247f02012-01-04 13:02:01 -05004860 char *hdr_val;
Willy Tarreaud1de8af2012-05-18 22:12:14 +02004861 unsigned int old_o, old_i;
Mark Lamourinec2247f02012-01-04 13:02:01 -05004862
William Lallemandd9e90662012-01-30 17:27:17 +01004863 ctx.idx = 0;
4864
Willy Tarreau211cdec2014-04-17 20:18:08 +02004865 old_o = http_hdr_rewind(&txn->req);
Willy Tarreaud1de8af2012-05-18 22:12:14 +02004866 if (old_o) {
4867 /* The request was already skipped, let's restore it */
Willy Tarreau9b28e032012-10-12 23:49:43 +02004868 b_rew(chn->buf, old_o);
Willy Tarreau877e78d2013-04-07 18:48:08 +02004869 txn->req.next += old_o;
4870 txn->req.sov += old_o;
Willy Tarreaud1de8af2012-05-18 22:12:14 +02004871 }
4872
Willy Tarreau9b28e032012-10-12 23:49:43 +02004873 old_i = chn->buf->i;
4874 while (http_find_header2(hdr_name, hdr_name_len, txn->req.chn->buf->p, &txn->hdr_idx, &ctx)) {
Mark Lamourinec2247f02012-01-04 13:02:01 -05004875 /* remove any existing values from the header */
Willy Tarreau6acf7c92012-03-09 13:30:45 +01004876 http_remove_header2(&txn->req, &txn->hdr_idx, &ctx);
Mark Lamourinec2247f02012-01-04 13:02:01 -05004877 }
4878
4879 /* Add the new header requested with the server value */
Willy Tarreau19d14ef2012-10-29 16:51:55 +01004880 hdr_val = trash.str;
Mark Lamourinec2247f02012-01-04 13:02:01 -05004881 memcpy(hdr_val, hdr_name, hdr_name_len);
4882 hdr_val += hdr_name_len;
4883 *hdr_val++ = ':';
4884 *hdr_val++ = ' ';
Willy Tarreau19d14ef2012-10-29 16:51:55 +01004885 hdr_val += strlcpy2(hdr_val, srv_name, trash.str + trash.size - hdr_val);
4886 http_header_add_tail2(&txn->req, &txn->hdr_idx, trash.str, hdr_val - trash.str);
Mark Lamourinec2247f02012-01-04 13:02:01 -05004887
Willy Tarreaud1de8af2012-05-18 22:12:14 +02004888 if (old_o) {
4889 /* If this was a forwarded request, we must readjust the amount of
4890 * data to be forwarded in order to take into account the size
Willy Tarreau877e78d2013-04-07 18:48:08 +02004891 * variations. Note that the current state is >= HTTP_MSG_BODY,
4892 * so we don't have to adjust ->sol.
Willy Tarreaud1de8af2012-05-18 22:12:14 +02004893 */
Willy Tarreau877e78d2013-04-07 18:48:08 +02004894 old_o += chn->buf->i - old_i;
4895 b_adv(chn->buf, old_o);
4896 txn->req.next -= old_o;
4897 txn->req.sov -= old_o;
Willy Tarreaud1de8af2012-05-18 22:12:14 +02004898 }
4899
Mark Lamourinec2247f02012-01-04 13:02:01 -05004900 return 0;
4901}
4902
Willy Tarreau610ecce2010-01-04 21:15:02 +01004903/* Terminate current transaction and prepare a new one. This is very tricky
4904 * right now but it works.
4905 */
Willy Tarreau87b09662015-04-03 00:22:06 +02004906void http_end_txn_clean_session(struct stream *s)
Willy Tarreau610ecce2010-01-04 21:15:02 +01004907{
Willy Tarreaueee5b512015-04-03 23:46:31 +02004908 int prev_status = s->txn->status;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004909 struct proxy *fe = strm_sess(s)->fe;
Willy Tarreau068621e2013-12-23 15:11:25 +01004910
Willy Tarreau610ecce2010-01-04 21:15:02 +01004911 /* FIXME: We need a more portable way of releasing a backend's and a
4912 * server's connections. We need a safer way to reinitialize buffer
4913 * flags. We also need a more accurate method for computing per-request
4914 * data.
4915 */
Willy Tarreau610ecce2010-01-04 21:15:02 +01004916
Willy Tarreau4213a112013-12-15 10:25:42 +01004917 /* unless we're doing keep-alive, we want to quickly close the connection
4918 * to the server.
4919 */
Willy Tarreaueee5b512015-04-03 23:46:31 +02004920 if (((s->txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) ||
Willy Tarreau350f4872014-11-28 14:42:25 +01004921 !si_conn_ready(&s->si[1])) {
4922 s->si[1].flags |= SI_FL_NOLINGER | SI_FL_NOHALF;
4923 si_shutr(&s->si[1]);
4924 si_shutw(&s->si[1]);
Willy Tarreau4213a112013-12-15 10:25:42 +01004925 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01004926
Willy Tarreaue7dff022015-04-03 01:14:29 +02004927 if (s->flags & SF_BE_ASSIGNED) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01004928 s->be->beconn--;
Willy Tarreau2d5cd472012-03-01 23:34:37 +01004929 if (unlikely(s->srv_conn))
4930 sess_change_server(s, NULL);
4931 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01004932
4933 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Willy Tarreau87b09662015-04-03 00:22:06 +02004934 stream_process_counters(s);
Willy Tarreau610ecce2010-01-04 21:15:02 +01004935
Willy Tarreaueee5b512015-04-03 23:46:31 +02004936 if (s->txn->status) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01004937 int n;
4938
Willy Tarreaueee5b512015-04-03 23:46:31 +02004939 n = s->txn->status / 100;
Willy Tarreau610ecce2010-01-04 21:15:02 +01004940 if (n < 1 || n > 5)
4941 n = 0;
4942
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004943 if (fe->mode == PR_MODE_HTTP) {
4944 fe->fe_counters.p.http.rsp[n]++;
Willy Tarreaue7dff022015-04-03 01:14:29 +02004945 if (s->comp_algo && (s->flags & SF_COMP_READY))
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004946 fe->fe_counters.p.http.comp_rsp++;
Willy Tarreau5e16cbc2012-11-24 14:54:13 +01004947 }
Willy Tarreaue7dff022015-04-03 01:14:29 +02004948 if ((s->flags & SF_BE_ASSIGNED) &&
Willy Tarreau5e16cbc2012-11-24 14:54:13 +01004949 (s->be->mode == PR_MODE_HTTP)) {
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01004950 s->be->be_counters.p.http.rsp[n]++;
Willy Tarreau5e16cbc2012-11-24 14:54:13 +01004951 s->be->be_counters.p.http.cum_req++;
Willy Tarreaue7dff022015-04-03 01:14:29 +02004952 if (s->comp_algo && (s->flags & SF_COMP_READY))
Willy Tarreau5e16cbc2012-11-24 14:54:13 +01004953 s->be->be_counters.p.http.comp_rsp++;
4954 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01004955 }
4956
4957 /* don't count other requests' data */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01004958 s->logs.bytes_in -= s->req.buf->i;
4959 s->logs.bytes_out -= s->res.buf->i;
Willy Tarreau610ecce2010-01-04 21:15:02 +01004960
4961 /* let's do a final log if we need it */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004962 if (!LIST_ISEMPTY(&fe->logformat) && s->logs.logwait &&
Willy Tarreaue7dff022015-04-03 01:14:29 +02004963 !(s->flags & SF_MONITOR) &&
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02004964 (!(fe->options & PR_O_NULLNOLOG) || s->req.total)) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01004965 s->do_log(s);
4966 }
4967
Willy Tarreaud713bcc2014-06-25 15:36:04 +02004968 /* stop tracking content-based counters */
Willy Tarreau87b09662015-04-03 00:22:06 +02004969 stream_stop_content_counters(s);
4970 stream_update_time_stats(s);
Willy Tarreau4bfc5802014-06-17 12:19:18 +02004971
Willy Tarreau610ecce2010-01-04 21:15:02 +01004972 s->logs.accept_date = date; /* user-visible date for logging */
4973 s->logs.tv_accept = now; /* corrected date for internal use */
4974 tv_zero(&s->logs.tv_request);
4975 s->logs.t_queue = -1;
4976 s->logs.t_connect = -1;
4977 s->logs.t_data = -1;
4978 s->logs.t_close = 0;
4979 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
4980 s->logs.srv_queue_size = 0; /* we will get this number soon */
4981
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01004982 s->logs.bytes_in = s->req.total = s->req.buf->i;
4983 s->logs.bytes_out = s->res.total = s->res.buf->i;
Willy Tarreau610ecce2010-01-04 21:15:02 +01004984
4985 if (s->pend_pos)
4986 pendconn_free(s->pend_pos);
4987
Willy Tarreau3fdb3662012-11-12 00:42:33 +01004988 if (objt_server(s->target)) {
Willy Tarreaue7dff022015-04-03 01:14:29 +02004989 if (s->flags & SF_CURR_SESS) {
4990 s->flags &= ~SF_CURR_SESS;
Willy Tarreau3fdb3662012-11-12 00:42:33 +01004991 objt_server(s->target)->cur_sess--;
Willy Tarreau610ecce2010-01-04 21:15:02 +01004992 }
Willy Tarreau3fdb3662012-11-12 00:42:33 +01004993 if (may_dequeue_tasks(objt_server(s->target), s->be))
4994 process_srv_queue(objt_server(s->target));
Willy Tarreau610ecce2010-01-04 21:15:02 +01004995 }
4996
Willy Tarreau3fdb3662012-11-12 00:42:33 +01004997 s->target = NULL;
Willy Tarreau610ecce2010-01-04 21:15:02 +01004998
Willy Tarreau4213a112013-12-15 10:25:42 +01004999 /* only release our endpoint if we don't intend to reuse the
5000 * connection.
5001 */
Willy Tarreaueee5b512015-04-03 23:46:31 +02005002 if (((s->txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) ||
Willy Tarreau350f4872014-11-28 14:42:25 +01005003 !si_conn_ready(&s->si[1])) {
5004 si_release_endpoint(&s->si[1]);
Willy Tarreau4213a112013-12-15 10:25:42 +01005005 }
5006
Willy Tarreau350f4872014-11-28 14:42:25 +01005007 s->si[1].state = s->si[1].prev_state = SI_ST_INI;
5008 s->si[1].err_type = SI_ET_NONE;
5009 s->si[1].conn_retries = 0; /* used for logging too */
5010 s->si[1].exp = TICK_ETERNITY;
Willy Tarreau87b09662015-04-03 00:22:06 +02005011 s->si[1].flags &= SI_FL_ISBACK | SI_FL_DONT_WAKE; /* we're in the context of process_stream */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005012 s->req.flags &= ~(CF_SHUTW|CF_SHUTW_NOW|CF_AUTO_CONNECT|CF_WRITE_ERROR|CF_STREAMER|CF_STREAMER_FAST|CF_NEVER_WAIT|CF_WAKE_CONNECT|CF_WROTE_DATA);
5013 s->res.flags &= ~(CF_SHUTR|CF_SHUTR_NOW|CF_READ_ATTACHED|CF_READ_ERROR|CF_READ_NOEXP|CF_STREAMER|CF_STREAMER_FAST|CF_WRITE_PARTIAL|CF_NEVER_WAIT|CF_WROTE_DATA);
Willy Tarreaue7dff022015-04-03 01:14:29 +02005014 s->flags &= ~(SF_DIRECT|SF_ASSIGNED|SF_ADDR_SET|SF_BE_ASSIGNED|SF_FORCE_PRST|SF_IGNORE_PRST);
5015 s->flags &= ~(SF_CURR_SESS|SF_REDIRECTABLE|SF_SRV_REUSED);
5016 s->flags &= ~(SF_ERR_MASK|SF_FINST_MASK|SF_REDISP);
Willy Tarreau543db622012-11-15 16:41:22 +01005017
Willy Tarreaueee5b512015-04-03 23:46:31 +02005018 s->txn->meth = 0;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005019 http_reset_txn(s);
Willy Tarreaueee5b512015-04-03 23:46:31 +02005020 s->txn->flags |= TX_NOT_FIRST | TX_WAIT_NEXT_RQ;
Willy Tarreau068621e2013-12-23 15:11:25 +01005021
5022 if (prev_status == 401 || prev_status == 407) {
5023 /* In HTTP keep-alive mode, if we receive a 401, we still have
5024 * a chance of being able to send the visitor again to the same
5025 * server over the same connection. This is required by some
5026 * broken protocols such as NTLM, and anyway whenever there is
5027 * an opportunity for sending the challenge to the proper place,
5028 * it's better to do it (at least it helps with debugging).
5029 */
Willy Tarreaueee5b512015-04-03 23:46:31 +02005030 s->txn->flags |= TX_PREFER_LAST;
Willy Tarreau068621e2013-12-23 15:11:25 +01005031 }
5032
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005033 if (fe->options2 & PR_O2_INDEPSTR)
Willy Tarreau350f4872014-11-28 14:42:25 +01005034 s->si[1].flags |= SI_FL_INDEP_STR;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005035
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005036 if (fe->options2 & PR_O2_NODELAY) {
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005037 s->req.flags |= CF_NEVER_WAIT;
5038 s->res.flags |= CF_NEVER_WAIT;
Willy Tarreau96e31212011-05-30 18:10:30 +02005039 }
5040
Willy Tarreau610ecce2010-01-04 21:15:02 +01005041 /* if the request buffer is not empty, it means we're
5042 * about to process another request, so send pending
5043 * data with MSG_MORE to merge TCP packets when possible.
Willy Tarreau065e8332010-01-08 00:30:20 +01005044 * Just don't do this if the buffer is close to be full,
5045 * because the request will wait for it to flush a little
5046 * bit before proceeding.
Willy Tarreau610ecce2010-01-04 21:15:02 +01005047 */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005048 if (s->req.buf->i) {
5049 if (s->res.buf->o &&
5050 !buffer_full(s->res.buf, global.tune.maxrewrite) &&
5051 bi_end(s->res.buf) <= s->res.buf->data + s->res.buf->size - global.tune.maxrewrite)
5052 s->res.flags |= CF_EXPECT_MORE;
Willy Tarreau065e8332010-01-08 00:30:20 +01005053 }
Willy Tarreau90deb182010-01-07 00:20:41 +01005054
5055 /* we're removing the analysers, we MUST re-enable events detection */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005056 channel_auto_read(&s->req);
5057 channel_auto_close(&s->req);
5058 channel_auto_read(&s->res);
5059 channel_auto_close(&s->res);
Willy Tarreau610ecce2010-01-04 21:15:02 +01005060
Willy Tarreau27375622013-12-17 00:00:28 +01005061 /* we're in keep-alive with an idle connection, monitor it */
Willy Tarreau350f4872014-11-28 14:42:25 +01005062 si_idle_conn(&s->si[1]);
Willy Tarreau27375622013-12-17 00:00:28 +01005063
Willy Tarreaufb0afa72015-04-03 14:46:27 +02005064 s->req.analysers = strm_sess(s)->listener->analysers;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005065 s->res.analysers = 0;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005066}
5067
5068
5069/* This function updates the request state machine according to the response
5070 * state machine and buffer flags. It returns 1 if it changes anything (flag
5071 * or state), otherwise zero. It ignores any state before HTTP_MSG_DONE, as
5072 * it is only used to find when a request/response couple is complete. Both
5073 * this function and its equivalent should loop until both return zero. It
5074 * can set its own state to DONE, CLOSING, CLOSED, TUNNEL, ERROR.
5075 */
Willy Tarreau87b09662015-04-03 00:22:06 +02005076int http_sync_req_state(struct stream *s)
Willy Tarreau610ecce2010-01-04 21:15:02 +01005077{
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005078 struct channel *chn = &s->req;
Willy Tarreaueee5b512015-04-03 23:46:31 +02005079 struct http_txn *txn = s->txn;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005080 unsigned int old_flags = chn->flags;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005081 unsigned int old_state = txn->req.msg_state;
5082
Willy Tarreau610ecce2010-01-04 21:15:02 +01005083 if (unlikely(txn->req.msg_state < HTTP_MSG_BODY))
5084 return 0;
5085
5086 if (txn->req.msg_state == HTTP_MSG_DONE) {
Willy Tarreau90deb182010-01-07 00:20:41 +01005087 /* No need to read anymore, the request was completely parsed.
Willy Tarreau58bd8fd2010-09-28 14:16:41 +02005088 * We can shut the read side unless we want to abort_on_close,
5089 * or we have a POST request. The issue with POST requests is
5090 * that some browsers still send a CRLF after the request, and
5091 * this CRLF must be read so that it does not remain in the kernel
5092 * buffers, otherwise a close could cause an RST on some systems
5093 * (eg: Linux).
Willy Tarreau3988d932013-12-27 23:03:08 +01005094 * Note that if we're using keep-alive on the client side, we'd
5095 * rather poll now and keep the polling enabled for the whole
Willy Tarreau87b09662015-04-03 00:22:06 +02005096 * stream's life than enabling/disabling it between each
Willy Tarreau3988d932013-12-27 23:03:08 +01005097 * response and next request.
Willy Tarreau90deb182010-01-07 00:20:41 +01005098 */
Willy Tarreau3988d932013-12-27 23:03:08 +01005099 if (((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_SCL) &&
5100 ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) &&
5101 !(s->be->options & PR_O_ABRT_CLOSE) &&
5102 txn->meth != HTTP_METH_POST)
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005103 channel_dont_read(chn);
Willy Tarreau610ecce2010-01-04 21:15:02 +01005104
Willy Tarreau40f151a2012-12-20 12:10:09 +01005105 /* if the server closes the connection, we want to immediately react
5106 * and close the socket to save packets and syscalls.
5107 */
Willy Tarreau350f4872014-11-28 14:42:25 +01005108 s->si[1].flags |= SI_FL_NOHALF;
Willy Tarreau40f151a2012-12-20 12:10:09 +01005109
Willy Tarreau610ecce2010-01-04 21:15:02 +01005110 if (txn->rsp.msg_state == HTTP_MSG_ERROR)
5111 goto wait_other_side;
5112
5113 if (txn->rsp.msg_state < HTTP_MSG_DONE) {
5114 /* The server has not finished to respond, so we
5115 * don't want to move in order not to upset it.
5116 */
5117 goto wait_other_side;
5118 }
5119
5120 if (txn->rsp.msg_state == HTTP_MSG_TUNNEL) {
5121 /* if any side switches to tunnel mode, the other one does too */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005122 channel_auto_read(chn);
Willy Tarreau610ecce2010-01-04 21:15:02 +01005123 txn->req.msg_state = HTTP_MSG_TUNNEL;
Willy Tarreaufc47f912012-10-20 10:38:09 +02005124 chn->flags |= CF_NEVER_WAIT;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005125 goto wait_other_side;
5126 }
5127
5128 /* When we get here, it means that both the request and the
5129 * response have finished receiving. Depending on the connection
5130 * mode, we'll have to wait for the last bytes to leave in either
5131 * direction, and sometimes for a close to be effective.
5132 */
5133
Willy Tarreaucce7fa42010-01-16 23:19:39 +01005134 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) {
5135 /* Server-close mode : queue a connection close to the server */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005136 if (!(chn->flags & (CF_SHUTW|CF_SHUTW_NOW)))
5137 channel_shutw_now(chn);
Willy Tarreaucce7fa42010-01-16 23:19:39 +01005138 }
5139 else if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO) {
5140 /* Option forceclose is set, or either side wants to close,
5141 * let's enforce it now that we're not expecting any new
Willy Tarreau87b09662015-04-03 00:22:06 +02005142 * data to come. The caller knows the stream is complete
Willy Tarreaucce7fa42010-01-16 23:19:39 +01005143 * once both states are CLOSED.
5144 */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005145 if (!(chn->flags & (CF_SHUTW|CF_SHUTW_NOW))) {
5146 channel_shutr_now(chn);
5147 channel_shutw_now(chn);
Willy Tarreau610ecce2010-01-04 21:15:02 +01005148 }
Willy Tarreaucce7fa42010-01-16 23:19:39 +01005149 }
5150 else {
Willy Tarreau4213a112013-12-15 10:25:42 +01005151 /* The last possible modes are keep-alive and tunnel. Tunnel mode
5152 * will not have any analyser so it needs to poll for reads.
Willy Tarreaucce7fa42010-01-16 23:19:39 +01005153 */
Willy Tarreau4213a112013-12-15 10:25:42 +01005154 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_TUN) {
5155 channel_auto_read(chn);
5156 txn->req.msg_state = HTTP_MSG_TUNNEL;
5157 chn->flags |= CF_NEVER_WAIT;
5158 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01005159 }
5160
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005161 if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01005162 /* if we've just closed an output, let's switch */
Willy Tarreau350f4872014-11-28 14:42:25 +01005163 s->si[1].flags |= SI_FL_NOLINGER; /* we want to close ASAP */
Willy Tarreaucce7fa42010-01-16 23:19:39 +01005164
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005165 if (!channel_is_empty(chn)) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01005166 txn->req.msg_state = HTTP_MSG_CLOSING;
5167 goto http_msg_closing;
5168 }
5169 else {
5170 txn->req.msg_state = HTTP_MSG_CLOSED;
5171 goto http_msg_closed;
5172 }
5173 }
Willy Tarreaucce7fa42010-01-16 23:19:39 +01005174 goto wait_other_side;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005175 }
5176
5177 if (txn->req.msg_state == HTTP_MSG_CLOSING) {
5178 http_msg_closing:
5179 /* nothing else to forward, just waiting for the output buffer
5180 * to be empty and for the shutw_now to take effect.
5181 */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005182 if (channel_is_empty(chn)) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01005183 txn->req.msg_state = HTTP_MSG_CLOSED;
5184 goto http_msg_closed;
5185 }
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005186 else if (chn->flags & CF_SHUTW) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01005187 txn->req.msg_state = HTTP_MSG_ERROR;
5188 goto wait_other_side;
5189 }
5190 }
5191
5192 if (txn->req.msg_state == HTTP_MSG_CLOSED) {
5193 http_msg_closed:
Willy Tarreau3988d932013-12-27 23:03:08 +01005194 /* see above in MSG_DONE why we only do this in these states */
5195 if (((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_SCL) &&
5196 ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_KAL) &&
5197 !(s->be->options & PR_O_ABRT_CLOSE))
Willy Tarreau2e7a1652013-12-15 15:32:10 +01005198 channel_dont_read(chn);
Willy Tarreau610ecce2010-01-04 21:15:02 +01005199 goto wait_other_side;
5200 }
5201
5202 wait_other_side:
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005203 return txn->req.msg_state != old_state || chn->flags != old_flags;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005204}
5205
5206
5207/* This function updates the response state machine according to the request
5208 * state machine and buffer flags. It returns 1 if it changes anything (flag
5209 * or state), otherwise zero. It ignores any state before HTTP_MSG_DONE, as
5210 * it is only used to find when a request/response couple is complete. Both
5211 * this function and its equivalent should loop until both return zero. It
5212 * can set its own state to DONE, CLOSING, CLOSED, TUNNEL, ERROR.
5213 */
Willy Tarreau87b09662015-04-03 00:22:06 +02005214int http_sync_res_state(struct stream *s)
Willy Tarreau610ecce2010-01-04 21:15:02 +01005215{
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005216 struct channel *chn = &s->res;
Willy Tarreaueee5b512015-04-03 23:46:31 +02005217 struct http_txn *txn = s->txn;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005218 unsigned int old_flags = chn->flags;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005219 unsigned int old_state = txn->rsp.msg_state;
5220
Willy Tarreau610ecce2010-01-04 21:15:02 +01005221 if (unlikely(txn->rsp.msg_state < HTTP_MSG_BODY))
5222 return 0;
5223
5224 if (txn->rsp.msg_state == HTTP_MSG_DONE) {
5225 /* In theory, we don't need to read anymore, but we must
Willy Tarreau90deb182010-01-07 00:20:41 +01005226 * still monitor the server connection for a possible close
5227 * while the request is being uploaded, so we don't disable
5228 * reading.
Willy Tarreau610ecce2010-01-04 21:15:02 +01005229 */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005230 /* channel_dont_read(chn); */
Willy Tarreau610ecce2010-01-04 21:15:02 +01005231
5232 if (txn->req.msg_state == HTTP_MSG_ERROR)
5233 goto wait_other_side;
5234
5235 if (txn->req.msg_state < HTTP_MSG_DONE) {
5236 /* The client seems to still be sending data, probably
5237 * because we got an error response during an upload.
5238 * We have the choice of either breaking the connection
5239 * or letting it pass through. Let's do the later.
5240 */
5241 goto wait_other_side;
5242 }
5243
5244 if (txn->req.msg_state == HTTP_MSG_TUNNEL) {
5245 /* if any side switches to tunnel mode, the other one does too */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005246 channel_auto_read(chn);
Willy Tarreau610ecce2010-01-04 21:15:02 +01005247 txn->rsp.msg_state = HTTP_MSG_TUNNEL;
Willy Tarreaufc47f912012-10-20 10:38:09 +02005248 chn->flags |= CF_NEVER_WAIT;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005249 goto wait_other_side;
5250 }
5251
5252 /* When we get here, it means that both the request and the
5253 * response have finished receiving. Depending on the connection
5254 * mode, we'll have to wait for the last bytes to leave in either
5255 * direction, and sometimes for a close to be effective.
5256 */
5257
5258 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) {
5259 /* Server-close mode : shut read and wait for the request
5260 * side to close its output buffer. The caller will detect
5261 * when we're in DONE and the other is in CLOSED and will
5262 * catch that for the final cleanup.
5263 */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005264 if (!(chn->flags & (CF_SHUTR|CF_SHUTR_NOW)))
5265 channel_shutr_now(chn);
Willy Tarreau610ecce2010-01-04 21:15:02 +01005266 }
Willy Tarreaucce7fa42010-01-16 23:19:39 +01005267 else if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO) {
5268 /* Option forceclose is set, or either side wants to close,
5269 * let's enforce it now that we're not expecting any new
Willy Tarreau87b09662015-04-03 00:22:06 +02005270 * data to come. The caller knows the stream is complete
Willy Tarreaucce7fa42010-01-16 23:19:39 +01005271 * once both states are CLOSED.
Willy Tarreau610ecce2010-01-04 21:15:02 +01005272 */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005273 if (!(chn->flags & (CF_SHUTW|CF_SHUTW_NOW))) {
5274 channel_shutr_now(chn);
5275 channel_shutw_now(chn);
Willy Tarreaucce7fa42010-01-16 23:19:39 +01005276 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01005277 }
5278 else {
Willy Tarreau4213a112013-12-15 10:25:42 +01005279 /* The last possible modes are keep-alive and tunnel. Tunnel will
5280 * need to forward remaining data. Keep-alive will need to monitor
5281 * for connection closing.
Willy Tarreau610ecce2010-01-04 21:15:02 +01005282 */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005283 channel_auto_read(chn);
Willy Tarreaufc47f912012-10-20 10:38:09 +02005284 chn->flags |= CF_NEVER_WAIT;
Willy Tarreau4213a112013-12-15 10:25:42 +01005285 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_TUN)
5286 txn->rsp.msg_state = HTTP_MSG_TUNNEL;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005287 }
5288
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005289 if (chn->flags & (CF_SHUTW|CF_SHUTW_NOW)) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01005290 /* if we've just closed an output, let's switch */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005291 if (!channel_is_empty(chn)) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01005292 txn->rsp.msg_state = HTTP_MSG_CLOSING;
5293 goto http_msg_closing;
5294 }
5295 else {
5296 txn->rsp.msg_state = HTTP_MSG_CLOSED;
5297 goto http_msg_closed;
5298 }
5299 }
5300 goto wait_other_side;
5301 }
5302
5303 if (txn->rsp.msg_state == HTTP_MSG_CLOSING) {
5304 http_msg_closing:
5305 /* nothing else to forward, just waiting for the output buffer
5306 * to be empty and for the shutw_now to take effect.
5307 */
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005308 if (channel_is_empty(chn)) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01005309 txn->rsp.msg_state = HTTP_MSG_CLOSED;
5310 goto http_msg_closed;
5311 }
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005312 else if (chn->flags & CF_SHUTW) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01005313 txn->rsp.msg_state = HTTP_MSG_ERROR;
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01005314 s->be->be_counters.cli_aborts++;
Willy Tarreau3fdb3662012-11-12 00:42:33 +01005315 if (objt_server(s->target))
5316 objt_server(s->target)->counters.cli_aborts++;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005317 goto wait_other_side;
5318 }
5319 }
5320
5321 if (txn->rsp.msg_state == HTTP_MSG_CLOSED) {
5322 http_msg_closed:
5323 /* drop any pending data */
Willy Tarreau319f7452015-01-14 20:32:59 +01005324 channel_truncate(chn);
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005325 channel_auto_close(chn);
5326 channel_auto_read(chn);
Willy Tarreau610ecce2010-01-04 21:15:02 +01005327 goto wait_other_side;
5328 }
5329
5330 wait_other_side:
Willy Tarreaufc47f912012-10-20 10:38:09 +02005331 /* We force the response to leave immediately if we're waiting for the
5332 * other side, since there is no pending shutdown to push it out.
5333 */
5334 if (!channel_is_empty(chn))
5335 chn->flags |= CF_SEND_DONTWAIT;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02005336 return txn->rsp.msg_state != old_state || chn->flags != old_flags;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005337}
5338
5339
5340/* Resync the request and response state machines. Return 1 if either state
5341 * changes.
5342 */
Willy Tarreau87b09662015-04-03 00:22:06 +02005343int http_resync_states(struct stream *s)
Willy Tarreau610ecce2010-01-04 21:15:02 +01005344{
Willy Tarreaueee5b512015-04-03 23:46:31 +02005345 struct http_txn *txn = s->txn;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005346 int old_req_state = txn->req.msg_state;
5347 int old_res_state = txn->rsp.msg_state;
5348
Willy Tarreau610ecce2010-01-04 21:15:02 +01005349 http_sync_req_state(s);
5350 while (1) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01005351 if (!http_sync_res_state(s))
5352 break;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005353 if (!http_sync_req_state(s))
5354 break;
5355 }
Willy Tarreau3ce10ff2014-04-22 08:24:38 +02005356
Willy Tarreau610ecce2010-01-04 21:15:02 +01005357 /* OK, both state machines agree on a compatible state.
5358 * There are a few cases we're interested in :
5359 * - HTTP_MSG_TUNNEL on either means we have to disable both analysers
5360 * - HTTP_MSG_CLOSED on both sides means we've reached the end in both
5361 * directions, so let's simply disable both analysers.
5362 * - HTTP_MSG_CLOSED on the response only means we must abort the
5363 * request.
5364 * - HTTP_MSG_CLOSED on the request and HTTP_MSG_DONE on the response
5365 * with server-close mode means we've completed one request and we
5366 * must re-initialize the server connection.
5367 */
5368
5369 if (txn->req.msg_state == HTTP_MSG_TUNNEL ||
5370 txn->rsp.msg_state == HTTP_MSG_TUNNEL ||
5371 (txn->req.msg_state == HTTP_MSG_CLOSED &&
5372 txn->rsp.msg_state == HTTP_MSG_CLOSED)) {
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005373 s->req.analysers = 0;
5374 channel_auto_close(&s->req);
5375 channel_auto_read(&s->req);
5376 s->res.analysers = 0;
5377 channel_auto_close(&s->res);
5378 channel_auto_read(&s->res);
Willy Tarreau610ecce2010-01-04 21:15:02 +01005379 }
Willy Tarreau40f151a2012-12-20 12:10:09 +01005380 else if ((txn->req.msg_state >= HTTP_MSG_DONE &&
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005381 (txn->rsp.msg_state == HTTP_MSG_CLOSED || (s->res.flags & CF_SHUTW))) ||
Willy Tarreau2fa144c2010-01-04 23:13:26 +01005382 txn->rsp.msg_state == HTTP_MSG_ERROR ||
Willy Tarreau40f151a2012-12-20 12:10:09 +01005383 txn->req.msg_state == HTTP_MSG_ERROR) {
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005384 s->res.analysers = 0;
5385 channel_auto_close(&s->res);
5386 channel_auto_read(&s->res);
5387 s->req.analysers = 0;
5388 channel_abort(&s->req);
5389 channel_auto_close(&s->req);
5390 channel_auto_read(&s->req);
5391 channel_truncate(&s->req);
Willy Tarreau610ecce2010-01-04 21:15:02 +01005392 }
Willy Tarreau4213a112013-12-15 10:25:42 +01005393 else if ((txn->req.msg_state == HTTP_MSG_DONE ||
5394 txn->req.msg_state == HTTP_MSG_CLOSED) &&
Willy Tarreau610ecce2010-01-04 21:15:02 +01005395 txn->rsp.msg_state == HTTP_MSG_DONE &&
Willy Tarreau4213a112013-12-15 10:25:42 +01005396 ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL ||
5397 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL)) {
5398 /* server-close/keep-alive: terminate this transaction,
5399 * possibly killing the server connection and reinitialize
5400 * a fresh-new transaction.
Willy Tarreau610ecce2010-01-04 21:15:02 +01005401 */
5402 http_end_txn_clean_session(s);
5403 }
5404
Willy Tarreau610ecce2010-01-04 21:15:02 +01005405 return txn->req.msg_state != old_req_state ||
5406 txn->rsp.msg_state != old_res_state;
5407}
5408
Willy Tarreaud98cf932009-12-27 22:54:55 +01005409/* This function is an analyser which forwards request body (including chunk
5410 * sizes if any). It is called as soon as we must forward, even if we forward
5411 * zero byte. The only situation where it must not be called is when we're in
5412 * tunnel mode and we want to forward till the close. It's used both to forward
5413 * remaining data and to resync after end of body. It expects the msg_state to
5414 * be between MSG_BODY and MSG_DONE (inclusive). It returns zero if it needs to
Willy Tarreau87b09662015-04-03 00:22:06 +02005415 * read more data, or 1 once we can go on with next request or end the stream.
Willy Tarreau124d9912011-03-01 20:30:48 +01005416 * When in MSG_DATA or MSG_TRAILERS, it will automatically forward chunk_len
Willy Tarreauc24715e2014-04-17 15:21:20 +02005417 * bytes of pending data + the headers if not already done.
Willy Tarreaud98cf932009-12-27 22:54:55 +01005418 */
Willy Tarreau87b09662015-04-03 00:22:06 +02005419int http_request_forward_body(struct stream *s, struct channel *req, int an_bit)
Willy Tarreaud98cf932009-12-27 22:54:55 +01005420{
Willy Tarreaufb0afa72015-04-03 14:46:27 +02005421 struct session *sess = s->sess;
Willy Tarreaueee5b512015-04-03 23:46:31 +02005422 struct http_txn *txn = s->txn;
5423 struct http_msg *msg = &s->txn->req;
Willy Tarreaud98cf932009-12-27 22:54:55 +01005424
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01005425 if (unlikely(msg->msg_state < HTTP_MSG_BODY))
5426 return 0;
5427
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02005428 if ((req->flags & (CF_READ_ERROR|CF_READ_TIMEOUT|CF_WRITE_ERROR|CF_WRITE_TIMEOUT)) ||
Willy Tarreau9b28e032012-10-12 23:49:43 +02005429 ((req->flags & CF_SHUTW) && (req->to_forward || req->buf->o))) {
Willy Tarreau4fe41902010-06-07 22:27:41 +02005430 /* Output closed while we were sending data. We must abort and
5431 * wake the other side up.
5432 */
5433 msg->msg_state = HTTP_MSG_ERROR;
5434 http_resync_states(s);
Willy Tarreau082b01c2010-01-02 23:58:04 +01005435 return 1;
5436 }
5437
Willy Tarreaud98cf932009-12-27 22:54:55 +01005438 /* Note that we don't have to send 100-continue back because we don't
5439 * need the data to complete our job, and it's up to the server to
5440 * decide whether to return 100, 417 or anything else in return of
5441 * an "Expect: 100-continue" header.
5442 */
5443
Willy Tarreaubb2e6692014-07-10 19:06:10 +02005444 if (msg->sov > 0) {
Willy Tarreaub59c7bf2014-04-22 14:29:58 +02005445 /* we have msg->sov which points to the first byte of message
5446 * body, and req->buf.p still points to the beginning of the
5447 * message. We forward the headers now, as we don't need them
5448 * anymore, and we want to flush them.
Willy Tarreaud98cf932009-12-27 22:54:55 +01005449 */
Willy Tarreaub59c7bf2014-04-22 14:29:58 +02005450 b_adv(req->buf, msg->sov);
5451 msg->next -= msg->sov;
5452 msg->sov = 0;
Willy Tarreaua458b672012-03-05 11:17:50 +01005453
Willy Tarreaub59c7bf2014-04-22 14:29:58 +02005454 /* The previous analysers guarantee that the state is somewhere
5455 * between MSG_BODY and the first MSG_DATA. So msg->sol and
5456 * msg->next are always correct.
5457 */
5458 if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) {
5459 if (msg->flags & HTTP_MSGF_TE_CHNK)
5460 msg->msg_state = HTTP_MSG_CHUNK_SIZE;
5461 else
5462 msg->msg_state = HTTP_MSG_DATA;
5463 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01005464 }
5465
Willy Tarreau7ba23542014-04-17 21:50:00 +02005466 /* Some post-connect processing might want us to refrain from starting to
5467 * forward data. Currently, the only reason for this is "balance url_param"
5468 * whichs need to parse/process the request after we've enabled forwarding.
5469 */
5470 if (unlikely(msg->flags & HTTP_MSGF_WAIT_CONN)) {
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005471 if (!(s->res.flags & CF_READ_ATTACHED)) {
Willy Tarreau7ba23542014-04-17 21:50:00 +02005472 channel_auto_connect(req);
Willy Tarreau644c1012014-04-30 18:11:11 +02005473 req->flags |= CF_WAKE_CONNECT;
Willy Tarreau7ba23542014-04-17 21:50:00 +02005474 goto missing_data;
5475 }
5476 msg->flags &= ~HTTP_MSGF_WAIT_CONN;
5477 }
5478
Willy Tarreau80a92c02014-03-12 10:41:13 +01005479 /* in most states, we should abort in case of early close */
5480 channel_auto_close(req);
5481
Willy Tarreauefdf0942014-04-24 20:08:57 +02005482 if (req->to_forward) {
5483 /* We can't process the buffer's contents yet */
5484 req->flags |= CF_WAKE_WRITE;
5485 goto missing_data;
5486 }
5487
Willy Tarreaud98cf932009-12-27 22:54:55 +01005488 while (1) {
Willy Tarreaucaabe412010-01-03 23:08:28 +01005489 if (msg->msg_state == HTTP_MSG_DATA) {
5490 /* must still forward */
Willy Tarreaubed410e2014-04-22 08:19:34 +02005491 /* we may have some pending data starting at req->buf->p */
5492 if (msg->chunk_len > req->buf->i - msg->next) {
Willy Tarreau4afd70a2014-01-25 02:26:39 +01005493 req->flags |= CF_WAKE_WRITE;
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01005494 goto missing_data;
Willy Tarreau4afd70a2014-01-25 02:26:39 +01005495 }
Willy Tarreaubed410e2014-04-22 08:19:34 +02005496 msg->next += msg->chunk_len;
5497 msg->chunk_len = 0;
Willy Tarreaucaabe412010-01-03 23:08:28 +01005498
5499 /* nothing left to forward */
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01005500 if (msg->flags & HTTP_MSGF_TE_CHNK)
Willy Tarreau54d23df2012-10-25 19:04:45 +02005501 msg->msg_state = HTTP_MSG_CHUNK_CRLF;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005502 else
Willy Tarreaucaabe412010-01-03 23:08:28 +01005503 msg->msg_state = HTTP_MSG_DONE;
Willy Tarreaucaabe412010-01-03 23:08:28 +01005504 }
5505 else if (msg->msg_state == HTTP_MSG_CHUNK_SIZE) {
Willy Tarreau124d9912011-03-01 20:30:48 +01005506 /* read the chunk size and assign it to ->chunk_len, then
Willy Tarreauc24715e2014-04-17 15:21:20 +02005507 * set ->next to point to the body and switch to DATA or
Willy Tarreaud98cf932009-12-27 22:54:55 +01005508 * TRAILERS state.
5509 */
Willy Tarreau4baf44b2012-03-09 14:10:20 +01005510 int ret = http_parse_chunk_size(msg);
Willy Tarreaud98cf932009-12-27 22:54:55 +01005511
Willy Tarreau54d23df2012-10-25 19:04:45 +02005512 if (ret == 0)
Willy Tarreaud98cf932009-12-27 22:54:55 +01005513 goto missing_data;
Willy Tarreauda7ff642010-06-23 11:44:09 +02005514 else if (ret < 0) {
Willy Tarreau87b09662015-04-03 00:22:06 +02005515 stream_inc_http_err_ctr(s);
Willy Tarreaue1582eb2010-12-12 13:10:11 +01005516 if (msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005517 http_capture_bad_message(&sess->fe->invalid_req, s, msg, HTTP_MSG_CHUNK_SIZE, s->be);
Willy Tarreaud98cf932009-12-27 22:54:55 +01005518 goto return_bad_req;
Willy Tarreauda7ff642010-06-23 11:44:09 +02005519 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01005520 /* otherwise we're in HTTP_MSG_DATA or HTTP_MSG_TRAILERS state */
Willy Tarreaud98cf932009-12-27 22:54:55 +01005521 }
Willy Tarreau54d23df2012-10-25 19:04:45 +02005522 else if (msg->msg_state == HTTP_MSG_CHUNK_CRLF) {
Willy Tarreaud98cf932009-12-27 22:54:55 +01005523 /* we want the CRLF after the data */
Willy Tarreau54d23df2012-10-25 19:04:45 +02005524 int ret = http_skip_chunk_crlf(msg);
Willy Tarreaud98cf932009-12-27 22:54:55 +01005525
5526 if (ret == 0)
5527 goto missing_data;
Willy Tarreauda7ff642010-06-23 11:44:09 +02005528 else if (ret < 0) {
Willy Tarreau87b09662015-04-03 00:22:06 +02005529 stream_inc_http_err_ctr(s);
Willy Tarreaue1582eb2010-12-12 13:10:11 +01005530 if (msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005531 http_capture_bad_message(&sess->fe->invalid_req, s, msg, HTTP_MSG_CHUNK_CRLF, s->be);
Willy Tarreaud98cf932009-12-27 22:54:55 +01005532 goto return_bad_req;
Willy Tarreauda7ff642010-06-23 11:44:09 +02005533 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01005534 /* we're in MSG_CHUNK_SIZE now */
5535 }
5536 else if (msg->msg_state == HTTP_MSG_TRAILERS) {
Willy Tarreau4baf44b2012-03-09 14:10:20 +01005537 int ret = http_forward_trailers(msg);
Willy Tarreaud98cf932009-12-27 22:54:55 +01005538
5539 if (ret == 0)
5540 goto missing_data;
Willy Tarreauda7ff642010-06-23 11:44:09 +02005541 else if (ret < 0) {
Willy Tarreau87b09662015-04-03 00:22:06 +02005542 stream_inc_http_err_ctr(s);
Willy Tarreaue1582eb2010-12-12 13:10:11 +01005543 if (msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005544 http_capture_bad_message(&sess->fe->invalid_req, s, msg, HTTP_MSG_TRAILERS, s->be);
Willy Tarreaud98cf932009-12-27 22:54:55 +01005545 goto return_bad_req;
Willy Tarreauda7ff642010-06-23 11:44:09 +02005546 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01005547 /* we're in HTTP_MSG_DONE now */
5548 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01005549 else {
Willy Tarreaue1582eb2010-12-12 13:10:11 +01005550 int old_state = msg->msg_state;
5551
Willy Tarreau610ecce2010-01-04 21:15:02 +01005552 /* other states, DONE...TUNNEL */
Willy Tarreaubed410e2014-04-22 08:19:34 +02005553
5554 /* we may have some pending data starting at req->buf->p
5555 * such as last chunk of data or trailers.
5556 */
5557 b_adv(req->buf, msg->next);
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005558 if (unlikely(!(s->req.flags & CF_WROTE_DATA)))
Willy Tarreaubb2e6692014-07-10 19:06:10 +02005559 msg->sov -= msg->next;
Willy Tarreaubed410e2014-04-22 08:19:34 +02005560 msg->next = 0;
5561
Willy Tarreau4fe41902010-06-07 22:27:41 +02005562 /* for keep-alive we don't want to forward closes on DONE */
Willy Tarreau92aa1fa2010-08-28 18:57:20 +02005563 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
5564 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL)
Willy Tarreau8263d2b2012-08-28 00:06:31 +02005565 channel_dont_close(req);
Willy Tarreau610ecce2010-01-04 21:15:02 +01005566 if (http_resync_states(s)) {
5567 /* some state changes occurred, maybe the analyser
5568 * was disabled too.
Willy Tarreauface8392010-01-03 11:37:54 +01005569 */
Willy Tarreau3fe693b2010-12-12 12:50:05 +01005570 if (unlikely(msg->msg_state == HTTP_MSG_ERROR)) {
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02005571 if (req->flags & CF_SHUTW) {
Willy Tarreau3fe693b2010-12-12 12:50:05 +01005572 /* request errors are most likely due to
5573 * the server aborting the transfer.
5574 */
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005575 goto aborted_xfer;
Willy Tarreau3fe693b2010-12-12 12:50:05 +01005576 }
Willy Tarreaue1582eb2010-12-12 13:10:11 +01005577 if (msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005578 http_capture_bad_message(&sess->fe->invalid_req, s, msg, old_state, s->be);
Willy Tarreau610ecce2010-01-04 21:15:02 +01005579 goto return_bad_req;
Willy Tarreau3fe693b2010-12-12 12:50:05 +01005580 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01005581 return 1;
Willy Tarreaub608feb2010-01-02 22:47:18 +01005582 }
Willy Tarreau5c54c712010-07-17 08:02:58 +02005583
5584 /* If "option abortonclose" is set on the backend, we
5585 * want to monitor the client's connection and forward
5586 * any shutdown notification to the server, which will
5587 * decide whether to close or to go on processing the
5588 * request.
5589 */
5590 if (s->be->options & PR_O_ABRT_CLOSE) {
Willy Tarreau8263d2b2012-08-28 00:06:31 +02005591 channel_auto_read(req);
5592 channel_auto_close(req);
Willy Tarreau5c54c712010-07-17 08:02:58 +02005593 }
Willy Tarreaueee5b512015-04-03 23:46:31 +02005594 else if (s->txn->meth == HTTP_METH_POST) {
Willy Tarreau58bd8fd2010-09-28 14:16:41 +02005595 /* POST requests may require to read extra CRLF
5596 * sent by broken browsers and which could cause
5597 * an RST to be sent upon close on some systems
5598 * (eg: Linux).
5599 */
Willy Tarreau8263d2b2012-08-28 00:06:31 +02005600 channel_auto_read(req);
Willy Tarreau58bd8fd2010-09-28 14:16:41 +02005601 }
Willy Tarreau5c54c712010-07-17 08:02:58 +02005602
Willy Tarreau610ecce2010-01-04 21:15:02 +01005603 return 0;
Willy Tarreaud98cf932009-12-27 22:54:55 +01005604 }
5605 }
5606
Willy Tarreaud98cf932009-12-27 22:54:55 +01005607 missing_data:
Willy Tarreaubed410e2014-04-22 08:19:34 +02005608 /* we may have some pending data starting at req->buf->p */
5609 b_adv(req->buf, msg->next);
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005610 if (unlikely(!(s->req.flags & CF_WROTE_DATA)))
Willy Tarreaubb2e6692014-07-10 19:06:10 +02005611 msg->sov -= msg->next + MIN(msg->chunk_len, req->buf->i);
5612
Willy Tarreaubed410e2014-04-22 08:19:34 +02005613 msg->next = 0;
5614 msg->chunk_len -= channel_forward(req, msg->chunk_len);
5615
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01005616 /* stop waiting for data if the input is closed before the end */
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02005617 if (req->flags & CF_SHUTR) {
Willy Tarreaue7dff022015-04-03 01:14:29 +02005618 if (!(s->flags & SF_ERR_MASK))
5619 s->flags |= SF_ERR_CLICL;
5620 if (!(s->flags & SF_FINST_MASK)) {
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005621 if (txn->rsp.msg_state < HTTP_MSG_ERROR)
Willy Tarreaue7dff022015-04-03 01:14:29 +02005622 s->flags |= SF_FINST_H;
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005623 else
Willy Tarreaue7dff022015-04-03 01:14:29 +02005624 s->flags |= SF_FINST_D;
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005625 }
5626
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005627 sess->fe->fe_counters.cli_aborts++;
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01005628 s->be->be_counters.cli_aborts++;
Willy Tarreau3fdb3662012-11-12 00:42:33 +01005629 if (objt_server(s->target))
5630 objt_server(s->target)->counters.cli_aborts++;
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005631
5632 goto return_bad_req_stats_ok;
Willy Tarreau79ebac62010-06-07 13:47:49 +02005633 }
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01005634
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01005635 /* waiting for the last bits to leave the buffer */
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02005636 if (req->flags & CF_SHUTW)
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005637 goto aborted_xfer;
Willy Tarreau610ecce2010-01-04 21:15:02 +01005638
Willy Tarreau92aa1fa2010-08-28 18:57:20 +02005639 /* When TE: chunked is used, we need to get there again to parse remaining
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02005640 * chunks even if the client has closed, so we don't want to set CF_DONTCLOSE.
Willy Tarreau92aa1fa2010-08-28 18:57:20 +02005641 */
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01005642 if (msg->flags & HTTP_MSGF_TE_CHNK)
Willy Tarreau8263d2b2012-08-28 00:06:31 +02005643 channel_dont_close(req);
Willy Tarreau92aa1fa2010-08-28 18:57:20 +02005644
Willy Tarreau5c620922011-05-11 19:56:11 +02005645 /* We know that more data are expected, but we couldn't send more that
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02005646 * what we did. So we always set the CF_EXPECT_MORE flag so that the
Willy Tarreau07293032011-05-30 18:29:28 +02005647 * system knows it must not set a PUSH on this first part. Interactive
Willy Tarreau869fc1e2012-03-05 08:29:20 +01005648 * modes are already handled by the stream sock layer. We must not do
5649 * this in content-length mode because it could present the MSG_MORE
5650 * flag with the last block of forwarded data, which would cause an
5651 * additional delay to be observed by the receiver.
Willy Tarreau5c620922011-05-11 19:56:11 +02005652 */
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01005653 if (msg->flags & HTTP_MSGF_TE_CHNK)
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02005654 req->flags |= CF_EXPECT_MORE;
Willy Tarreau5c620922011-05-11 19:56:11 +02005655
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01005656 return 0;
5657
Willy Tarreaud98cf932009-12-27 22:54:55 +01005658 return_bad_req: /* let's centralize all bad requests */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005659 sess->fe->fe_counters.failed_req++;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02005660 if (sess->listener->counters)
5661 sess->listener->counters->failed_req++;
Willy Tarreaubed410e2014-04-22 08:19:34 +02005662
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005663 return_bad_req_stats_ok:
Willy Tarreaubed410e2014-04-22 08:19:34 +02005664 /* we may have some pending data starting at req->buf->p */
5665 b_adv(req->buf, msg->next);
5666 msg->next = 0;
5667
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005668 txn->req.msg_state = HTTP_MSG_ERROR;
5669 if (txn->status) {
5670 /* Note: we don't send any error if some data were already sent */
Willy Tarreau350f4872014-11-28 14:42:25 +01005671 stream_int_retnclose(&s->si[0], NULL);
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005672 } else {
5673 txn->status = 400;
Willy Tarreau350f4872014-11-28 14:42:25 +01005674 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_400));
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005675 }
5676 req->analysers = 0;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005677 s->res.analysers = 0; /* we're in data phase, we want to abort both directions */
Willy Tarreaud98cf932009-12-27 22:54:55 +01005678
Willy Tarreaue7dff022015-04-03 01:14:29 +02005679 if (!(s->flags & SF_ERR_MASK))
5680 s->flags |= SF_ERR_PRXCOND;
5681 if (!(s->flags & SF_FINST_MASK)) {
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005682 if (txn->rsp.msg_state < HTTP_MSG_ERROR)
Willy Tarreaue7dff022015-04-03 01:14:29 +02005683 s->flags |= SF_FINST_H;
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005684 else
Willy Tarreaue7dff022015-04-03 01:14:29 +02005685 s->flags |= SF_FINST_D;
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005686 }
5687 return 0;
5688
5689 aborted_xfer:
5690 txn->req.msg_state = HTTP_MSG_ERROR;
5691 if (txn->status) {
5692 /* Note: we don't send any error if some data were already sent */
Willy Tarreau350f4872014-11-28 14:42:25 +01005693 stream_int_retnclose(&s->si[0], NULL);
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005694 } else {
5695 txn->status = 502;
Willy Tarreau350f4872014-11-28 14:42:25 +01005696 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_502));
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005697 }
5698 req->analysers = 0;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005699 s->res.analysers = 0; /* we're in data phase, we want to abort both directions */
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005700
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005701 sess->fe->fe_counters.srv_aborts++;
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01005702 s->be->be_counters.srv_aborts++;
Willy Tarreau3fdb3662012-11-12 00:42:33 +01005703 if (objt_server(s->target))
5704 objt_server(s->target)->counters.srv_aborts++;
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005705
Willy Tarreaue7dff022015-04-03 01:14:29 +02005706 if (!(s->flags & SF_ERR_MASK))
5707 s->flags |= SF_ERR_SRVCL;
5708 if (!(s->flags & SF_FINST_MASK)) {
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005709 if (txn->rsp.msg_state < HTTP_MSG_ERROR)
Willy Tarreaue7dff022015-04-03 01:14:29 +02005710 s->flags |= SF_FINST_H;
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005711 else
Willy Tarreaue7dff022015-04-03 01:14:29 +02005712 s->flags |= SF_FINST_D;
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01005713 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01005714 return 0;
5715}
5716
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005717/* This stream analyser waits for a complete HTTP response. It returns 1 if the
5718 * processing can continue on next analysers, or zero if it either needs more
5719 * data or wants to immediately abort the response (eg: timeout, error, ...). It
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005720 * is tied to AN_RES_WAIT_HTTP and may may remove itself from s->res.analysers
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005721 * when it has nothing left to do, and may remove any analyser when it wants to
5722 * abort.
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02005723 */
Willy Tarreau87b09662015-04-03 00:22:06 +02005724int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02005725{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005726 struct session *sess = s->sess;
Willy Tarreaueee5b512015-04-03 23:46:31 +02005727 struct http_txn *txn = s->txn;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005728 struct http_msg *msg = &txn->rsp;
Willy Tarreaub8c82c22009-10-18 23:45:12 +02005729 struct hdr_ctx ctx;
Willy Tarreaue8e785b2009-12-26 15:34:26 +01005730 int use_close_only;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005731 int cur_idx;
Krzysztof Piotr Oledzki5fb18822009-10-13 21:14:09 +02005732 int n;
Willy Tarreauadfb8562008-08-11 15:24:42 +02005733
Willy Tarreau87b09662015-04-03 00:22:06 +02005734 DPRINTF(stderr,"[%u] %s: stream=%p b=%p, exp(r,w)=%u,%u bf=%08x bh=%d analysers=%02x\n",
Willy Tarreaufa7e1022008-10-19 07:30:41 +02005735 now_ms, __FUNCTION__,
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005736 s,
Willy Tarreau3a16b2c2008-08-28 08:54:27 +02005737 rep,
5738 rep->rex, rep->wex,
5739 rep->flags,
Willy Tarreau9b28e032012-10-12 23:49:43 +02005740 rep->buf->i,
Willy Tarreau3a16b2c2008-08-28 08:54:27 +02005741 rep->analysers);
Willy Tarreau67f0eea2008-08-10 22:55:22 +02005742
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005743 /*
5744 * Now parse the partial (or complete) lines.
5745 * We will check the response syntax, and also join multi-line
5746 * headers. An index of all the lines will be elaborated while
5747 * parsing.
5748 *
5749 * For the parsing, we use a 28 states FSM.
5750 *
5751 * Here is the information we currently have :
Willy Tarreau9b28e032012-10-12 23:49:43 +02005752 * rep->buf->p = beginning of response
5753 * rep->buf->p + msg->eoh = end of processed headers / start of current one
5754 * rep->buf->p + rep->buf->i = end of input data
Willy Tarreau26927362012-05-18 23:22:52 +02005755 * msg->eol = end of current header or line (LF or CRLF)
5756 * msg->next = first non-visited byte
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005757 */
5758
Willy Tarreau628c40c2014-04-24 19:11:26 +02005759 next_one:
Willy Tarreau83e3af02009-12-28 17:39:57 +01005760 /* There's a protected area at the end of the buffer for rewriting
5761 * purposes. We don't want to start to parse the request if the
5762 * protected area is affected, because we may have to move processed
5763 * data later, which is much more complicated.
5764 */
Willy Tarreau9b28e032012-10-12 23:49:43 +02005765 if (buffer_not_empty(rep->buf) && msg->msg_state < HTTP_MSG_ERROR) {
Willy Tarreauba0902e2015-01-13 14:39:16 +01005766 if (unlikely(!channel_is_rewritable(rep))) {
Willy Tarreau379357a2013-06-08 12:55:46 +02005767 /* some data has still not left the buffer, wake us once that's done */
5768 if (rep->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_WRITE_ERROR|CF_WRITE_TIMEOUT))
5769 goto abort_response;
5770 channel_dont_close(rep);
5771 rep->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */
Willy Tarreaud7ad9f52013-12-31 17:26:25 +01005772 rep->flags |= CF_WAKE_WRITE;
Willy Tarreau379357a2013-06-08 12:55:46 +02005773 return 0;
Willy Tarreau83e3af02009-12-28 17:39:57 +01005774 }
5775
Willy Tarreau379357a2013-06-08 12:55:46 +02005776 if (unlikely(bi_end(rep->buf) < b_ptr(rep->buf, msg->next) ||
5777 bi_end(rep->buf) > rep->buf->data + rep->buf->size - global.tune.maxrewrite))
5778 buffer_slow_realign(rep->buf);
5779
Willy Tarreau9b28e032012-10-12 23:49:43 +02005780 if (likely(msg->next < rep->buf->i))
Willy Tarreaua560c212012-03-09 13:50:57 +01005781 http_msg_analyzer(msg, &txn->hdr_idx);
Willy Tarreau83e3af02009-12-28 17:39:57 +01005782 }
5783
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005784 /* 1: we might have to print this header in debug mode */
5785 if (unlikely((global.mode & MODE_DEBUG) &&
5786 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
Willy Tarreau7d59e902014-10-21 19:36:09 +02005787 msg->msg_state >= HTTP_MSG_BODY)) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005788 char *eol, *sol;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02005789
Willy Tarreau9b28e032012-10-12 23:49:43 +02005790 sol = rep->buf->p;
5791 eol = sol + (msg->sl.st.l ? msg->sl.st.l : rep->buf->i);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005792 debug_hdr("srvrep", s, sol, eol);
Willy Tarreauf5483bf2008-08-14 18:35:40 +02005793
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005794 sol += hdr_idx_first_pos(&txn->hdr_idx);
5795 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreauf5483bf2008-08-14 18:35:40 +02005796
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005797 while (cur_idx) {
5798 eol = sol + txn->hdr_idx.v[cur_idx].len;
5799 debug_hdr("srvhdr", s, sol, eol);
5800 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
5801 cur_idx = txn->hdr_idx.v[cur_idx].next;
5802 }
5803 }
Willy Tarreauf5483bf2008-08-14 18:35:40 +02005804
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005805 /*
5806 * Now we quickly check if we have found a full valid response.
5807 * If not so, we check the FD and buffer states before leaving.
5808 * A full response is indicated by the fact that we have seen
Willy Tarreau655dce92009-11-08 13:10:58 +01005809 * the double LF/CRLF, so the state is >= HTTP_MSG_BODY. Invalid
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005810 * responses are checked first.
5811 *
5812 * Depending on whether the client is still there or not, we
5813 * may send an error response back or not. Note that normally
5814 * we should only check for HTTP status there, and check I/O
5815 * errors somewhere else.
5816 */
Willy Tarreauf5483bf2008-08-14 18:35:40 +02005817
Willy Tarreau655dce92009-11-08 13:10:58 +01005818 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005819 /* Invalid response */
5820 if (unlikely(msg->msg_state == HTTP_MSG_ERROR)) {
5821 /* we detected a parsing error. We want to archive this response
5822 * in the dedicated proxy area for later troubleshooting.
5823 */
5824 hdr_response_bad:
5825 if (msg->msg_state == HTTP_MSG_ERROR || msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005826 http_capture_bad_message(&s->be->invalid_rep, s, msg, msg->msg_state, sess->fe);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005827
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01005828 s->be->be_counters.failed_resp++;
Willy Tarreau3fdb3662012-11-12 00:42:33 +01005829 if (objt_server(s->target)) {
5830 objt_server(s->target)->counters.failed_resp++;
5831 health_adjust(objt_server(s->target), HANA_STATUS_HTTP_HDRRSP);
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01005832 }
Willy Tarreau64648412010-03-05 10:41:54 +01005833 abort_response:
Willy Tarreau8263d2b2012-08-28 00:06:31 +02005834 channel_auto_close(rep);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005835 rep->analysers = 0;
5836 txn->status = 502;
Willy Tarreau350f4872014-11-28 14:42:25 +01005837 s->si[1].flags |= SI_FL_NOLINGER;
Willy Tarreau319f7452015-01-14 20:32:59 +01005838 channel_truncate(rep);
Willy Tarreau350f4872014-11-28 14:42:25 +01005839 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_502));
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005840
Willy Tarreaue7dff022015-04-03 01:14:29 +02005841 if (!(s->flags & SF_ERR_MASK))
5842 s->flags |= SF_ERR_PRXCOND;
5843 if (!(s->flags & SF_FINST_MASK))
5844 s->flags |= SF_FINST_H;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005845
5846 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02005847 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02005848
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005849 /* too large response does not fit in buffer. */
Willy Tarreau9b28e032012-10-12 23:49:43 +02005850 else if (buffer_full(rep->buf, global.tune.maxrewrite)) {
Willy Tarreaufec4d892011-09-02 20:04:57 +02005851 if (msg->err_pos < 0)
Willy Tarreau9b28e032012-10-12 23:49:43 +02005852 msg->err_pos = rep->buf->i;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005853 goto hdr_response_bad;
5854 }
Willy Tarreauf5483bf2008-08-14 18:35:40 +02005855
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005856 /* read error */
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02005857 else if (rep->flags & CF_READ_ERROR) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005858 if (msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005859 http_capture_bad_message(&s->be->invalid_rep, s, msg, msg->msg_state, sess->fe);
Willy Tarreau6b726ad2013-12-15 19:31:37 +01005860 else if (txn->flags & TX_NOT_FIRST)
5861 goto abort_keep_alive;
Willy Tarreau4076a152009-04-02 15:18:36 +02005862
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01005863 s->be->be_counters.failed_resp++;
Willy Tarreau3fdb3662012-11-12 00:42:33 +01005864 if (objt_server(s->target)) {
5865 objt_server(s->target)->counters.failed_resp++;
5866 health_adjust(objt_server(s->target), HANA_STATUS_HTTP_READ_ERROR);
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01005867 }
Willy Tarreau461f6622008-08-15 23:43:19 +02005868
Willy Tarreau8263d2b2012-08-28 00:06:31 +02005869 channel_auto_close(rep);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005870 rep->analysers = 0;
5871 txn->status = 502;
Willy Tarreau350f4872014-11-28 14:42:25 +01005872 s->si[1].flags |= SI_FL_NOLINGER;
Willy Tarreau319f7452015-01-14 20:32:59 +01005873 channel_truncate(rep);
Willy Tarreau350f4872014-11-28 14:42:25 +01005874 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_502));
Willy Tarreau816b9792009-09-15 21:25:21 +02005875
Willy Tarreaue7dff022015-04-03 01:14:29 +02005876 if (!(s->flags & SF_ERR_MASK))
5877 s->flags |= SF_ERR_SRVCL;
5878 if (!(s->flags & SF_FINST_MASK))
5879 s->flags |= SF_FINST_H;
Willy Tarreaucebf57e2008-08-15 18:16:37 +02005880 return 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02005881 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02005882
Willy Tarreau6f0a7ba2014-06-23 15:22:31 +02005883 /* read timeout : return a 504 to the client. */
5884 else if (rep->flags & CF_READ_TIMEOUT) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005885 if (msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005886 http_capture_bad_message(&s->be->invalid_rep, s, msg, msg->msg_state, sess->fe);
Willy Tarreau6b726ad2013-12-15 19:31:37 +01005887 else if (txn->flags & TX_NOT_FIRST)
5888 goto abort_keep_alive;
Willy Tarreau21d2af32008-02-14 20:25:24 +01005889
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01005890 s->be->be_counters.failed_resp++;
Willy Tarreau3fdb3662012-11-12 00:42:33 +01005891 if (objt_server(s->target)) {
5892 objt_server(s->target)->counters.failed_resp++;
5893 health_adjust(objt_server(s->target), HANA_STATUS_HTTP_READ_TIMEOUT);
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01005894 }
Willy Tarreau21d2af32008-02-14 20:25:24 +01005895
Willy Tarreau8263d2b2012-08-28 00:06:31 +02005896 channel_auto_close(rep);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005897 rep->analysers = 0;
5898 txn->status = 504;
Willy Tarreau350f4872014-11-28 14:42:25 +01005899 s->si[1].flags |= SI_FL_NOLINGER;
Willy Tarreau319f7452015-01-14 20:32:59 +01005900 channel_truncate(rep);
Willy Tarreau350f4872014-11-28 14:42:25 +01005901 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_504));
Willy Tarreau4076a152009-04-02 15:18:36 +02005902
Willy Tarreaue7dff022015-04-03 01:14:29 +02005903 if (!(s->flags & SF_ERR_MASK))
5904 s->flags |= SF_ERR_SRVTO;
5905 if (!(s->flags & SF_FINST_MASK))
5906 s->flags |= SF_FINST_H;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005907 return 0;
5908 }
Willy Tarreaua7c52762008-08-16 18:40:18 +02005909
Willy Tarreauf003d372012-11-26 13:35:37 +01005910 /* client abort with an abortonclose */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01005911 else if ((rep->flags & CF_SHUTR) && ((s->req.flags & (CF_SHUTR|CF_SHUTW)) == (CF_SHUTR|CF_SHUTW))) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005912 sess->fe->fe_counters.cli_aborts++;
Willy Tarreauf003d372012-11-26 13:35:37 +01005913 s->be->be_counters.cli_aborts++;
5914 if (objt_server(s->target))
5915 objt_server(s->target)->counters.cli_aborts++;
5916
5917 rep->analysers = 0;
5918 channel_auto_close(rep);
5919
5920 txn->status = 400;
Willy Tarreau319f7452015-01-14 20:32:59 +01005921 channel_truncate(rep);
Willy Tarreau350f4872014-11-28 14:42:25 +01005922 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_400));
Willy Tarreauf003d372012-11-26 13:35:37 +01005923
Willy Tarreaue7dff022015-04-03 01:14:29 +02005924 if (!(s->flags & SF_ERR_MASK))
5925 s->flags |= SF_ERR_CLICL;
5926 if (!(s->flags & SF_FINST_MASK))
5927 s->flags |= SF_FINST_H;
Willy Tarreauf003d372012-11-26 13:35:37 +01005928
Willy Tarreau87b09662015-04-03 00:22:06 +02005929 /* process_stream() will take care of the error */
Willy Tarreauf003d372012-11-26 13:35:37 +01005930 return 0;
5931 }
5932
Willy Tarreau3b8c08a2011-09-02 20:16:24 +02005933 /* close from server, capture the response if the server has started to respond */
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02005934 else if (rep->flags & CF_SHUTR) {
Willy Tarreau3b8c08a2011-09-02 20:16:24 +02005935 if (msg->msg_state >= HTTP_MSG_RPVER || msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005936 http_capture_bad_message(&s->be->invalid_rep, s, msg, msg->msg_state, sess->fe);
Willy Tarreau6b726ad2013-12-15 19:31:37 +01005937 else if (txn->flags & TX_NOT_FIRST)
5938 goto abort_keep_alive;
Willy Tarreau21d2af32008-02-14 20:25:24 +01005939
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01005940 s->be->be_counters.failed_resp++;
Willy Tarreau3fdb3662012-11-12 00:42:33 +01005941 if (objt_server(s->target)) {
5942 objt_server(s->target)->counters.failed_resp++;
5943 health_adjust(objt_server(s->target), HANA_STATUS_HTTP_BROKEN_PIPE);
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01005944 }
Willy Tarreau21d2af32008-02-14 20:25:24 +01005945
Willy Tarreau8263d2b2012-08-28 00:06:31 +02005946 channel_auto_close(rep);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005947 rep->analysers = 0;
5948 txn->status = 502;
Willy Tarreau350f4872014-11-28 14:42:25 +01005949 s->si[1].flags |= SI_FL_NOLINGER;
Willy Tarreau319f7452015-01-14 20:32:59 +01005950 channel_truncate(rep);
Willy Tarreau350f4872014-11-28 14:42:25 +01005951 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_502));
Willy Tarreau21d2af32008-02-14 20:25:24 +01005952
Willy Tarreaue7dff022015-04-03 01:14:29 +02005953 if (!(s->flags & SF_ERR_MASK))
5954 s->flags |= SF_ERR_SRVCL;
5955 if (!(s->flags & SF_FINST_MASK))
5956 s->flags |= SF_FINST_H;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005957 return 0;
5958 }
Krzysztof Piotr Oledzki5fb18822009-10-13 21:14:09 +02005959
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005960 /* write error to client (we don't send any message then) */
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02005961 else if (rep->flags & CF_WRITE_ERROR) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005962 if (msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005963 http_capture_bad_message(&s->be->invalid_rep, s, msg, msg->msg_state, sess->fe);
Willy Tarreau6b726ad2013-12-15 19:31:37 +01005964 else if (txn->flags & TX_NOT_FIRST)
5965 goto abort_keep_alive;
Krzysztof Piotr Oledzki5fb18822009-10-13 21:14:09 +02005966
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01005967 s->be->be_counters.failed_resp++;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005968 rep->analysers = 0;
Willy Tarreau8263d2b2012-08-28 00:06:31 +02005969 channel_auto_close(rep);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005970
Willy Tarreaue7dff022015-04-03 01:14:29 +02005971 if (!(s->flags & SF_ERR_MASK))
5972 s->flags |= SF_ERR_CLICL;
5973 if (!(s->flags & SF_FINST_MASK))
5974 s->flags |= SF_FINST_H;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005975
Willy Tarreau87b09662015-04-03 00:22:06 +02005976 /* process_stream() will take care of the error */
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005977 return 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02005978 }
Willy Tarreau21d2af32008-02-14 20:25:24 +01005979
Willy Tarreau8263d2b2012-08-28 00:06:31 +02005980 channel_dont_close(rep);
Willy Tarreau3f3997e2013-12-15 15:21:32 +01005981 rep->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005982 return 0;
5983 }
5984
5985 /* More interesting part now : we know that we have a complete
5986 * response which at least looks like HTTP. We have an indicator
5987 * of each header's length, so we can parse them quickly.
5988 */
5989
5990 if (unlikely(msg->err_pos >= 0))
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02005991 http_capture_bad_message(&s->be->invalid_rep, s, msg, msg->msg_state, sess->fe);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005992
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005993 /*
5994 * 1: get the status code
5995 */
Willy Tarreau9b28e032012-10-12 23:49:43 +02005996 n = rep->buf->p[msg->sl.st.c] - '0';
Willy Tarreaub37c27e2009-10-18 22:53:08 +02005997 if (n < 1 || n > 5)
5998 n = 0;
Willy Tarreauda7ff642010-06-23 11:44:09 +02005999 /* when the client triggers a 4xx from the server, it's most often due
6000 * to a missing object or permission. These events should be tracked
6001 * because if they happen often, it may indicate a brute force or a
6002 * vulnerability scan.
6003 */
6004 if (n == 4)
Willy Tarreau87b09662015-04-03 00:22:06 +02006005 stream_inc_http_err_ctr(s);
Willy Tarreauda7ff642010-06-23 11:44:09 +02006006
Willy Tarreau3fdb3662012-11-12 00:42:33 +01006007 if (objt_server(s->target))
6008 objt_server(s->target)->counters.p.http.rsp[n]++;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02006009
Willy Tarreau5b154472009-12-21 20:11:07 +01006010 /* check if the response is HTTP/1.1 or above */
6011 if ((msg->sl.st.v_l == 8) &&
Willy Tarreau9b28e032012-10-12 23:49:43 +02006012 ((rep->buf->p[5] > '1') ||
6013 ((rep->buf->p[5] == '1') && (rep->buf->p[7] >= '1'))))
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006014 msg->flags |= HTTP_MSGF_VER_11;
Willy Tarreau5b154472009-12-21 20:11:07 +01006015
6016 /* "connection" has not been parsed yet */
Willy Tarreau50fc7772012-11-11 22:19:57 +01006017 txn->flags &= ~(TX_HDR_CONN_PRS|TX_HDR_CONN_CLO|TX_HDR_CONN_KAL|TX_HDR_CONN_UPG|TX_CON_CLO_SET|TX_CON_KAL_SET);
Willy Tarreau5b154472009-12-21 20:11:07 +01006018
Willy Tarreaue8e785b2009-12-26 15:34:26 +01006019 /* transfer length unknown*/
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006020 msg->flags &= ~HTTP_MSGF_XFER_LEN;
Willy Tarreaue8e785b2009-12-26 15:34:26 +01006021
Willy Tarreau9b28e032012-10-12 23:49:43 +02006022 txn->status = strl2ui(rep->buf->p + msg->sl.st.c, msg->sl.st.c_l);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02006023
Willy Tarreau39650402010-03-15 19:44:39 +01006024 /* Adjust server's health based on status code. Note: status codes 501
6025 * and 505 are triggered on demand by client request, so we must not
6026 * count them as server failures.
6027 */
Willy Tarreau3fdb3662012-11-12 00:42:33 +01006028 if (objt_server(s->target)) {
Willy Tarreaud45b3d52010-05-20 11:49:03 +02006029 if (txn->status >= 100 && (txn->status < 500 || txn->status == 501 || txn->status == 505))
Willy Tarreau3fdb3662012-11-12 00:42:33 +01006030 health_adjust(objt_server(s->target), HANA_STATUS_HTTP_OK);
Willy Tarreaud45b3d52010-05-20 11:49:03 +02006031 else
Willy Tarreau3fdb3662012-11-12 00:42:33 +01006032 health_adjust(objt_server(s->target), HANA_STATUS_HTTP_STS);
Willy Tarreaud45b3d52010-05-20 11:49:03 +02006033 }
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01006034
Willy Tarreaub37c27e2009-10-18 22:53:08 +02006035 /*
6036 * 2: check for cacheability.
6037 */
6038
6039 switch (txn->status) {
Willy Tarreau628c40c2014-04-24 19:11:26 +02006040 case 100:
6041 /*
6042 * We may be facing a 100-continue response, in which case this
6043 * is not the right response, and we're waiting for the next one.
6044 * Let's allow this response to go to the client and wait for the
6045 * next one.
6046 */
6047 hdr_idx_init(&txn->hdr_idx);
6048 msg->next -= channel_forward(rep, msg->next);
6049 msg->msg_state = HTTP_MSG_RPBEFORE;
6050 txn->status = 0;
6051 s->logs.t_data = -1; /* was not a response yet */
6052 goto next_one;
6053
Willy Tarreaub37c27e2009-10-18 22:53:08 +02006054 case 200:
6055 case 203:
6056 case 206:
6057 case 300:
6058 case 301:
6059 case 410:
6060 /* RFC2616 @13.4:
6061 * "A response received with a status code of
6062 * 200, 203, 206, 300, 301 or 410 MAY be stored
6063 * by a cache (...) unless a cache-control
6064 * directive prohibits caching."
6065 *
6066 * RFC2616 @9.5: POST method :
6067 * "Responses to this method are not cacheable,
6068 * unless the response includes appropriate
6069 * Cache-Control or Expires header fields."
Willy Tarreauf5483bf2008-08-14 18:35:40 +02006070 */
Willy Tarreaub37c27e2009-10-18 22:53:08 +02006071 if (likely(txn->meth != HTTP_METH_POST) &&
Willy Tarreau67402132012-05-31 20:40:20 +02006072 ((s->be->options & PR_O_CHK_CACHE) || (s->be->ck_opts & PR_CK_NOC)))
Willy Tarreaub37c27e2009-10-18 22:53:08 +02006073 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
6074 break;
6075 default:
6076 break;
6077 }
Willy Tarreauf5483bf2008-08-14 18:35:40 +02006078
Willy Tarreaub37c27e2009-10-18 22:53:08 +02006079 /*
6080 * 3: we may need to capture headers
6081 */
6082 s->logs.logwait &= ~LW_RESP;
Willy Tarreaucb7dd012015-04-03 22:16:32 +02006083 if (unlikely((s->logs.logwait & LW_RSPHDR) && s->res_cap))
Willy Tarreau9b28e032012-10-12 23:49:43 +02006084 capture_headers(rep->buf->p, &txn->hdr_idx,
Willy Tarreaucb7dd012015-04-03 22:16:32 +02006085 s->res_cap, sess->fe->rsp_cap);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02006086
Willy Tarreaue8e785b2009-12-26 15:34:26 +01006087 /* 4: determine the transfer-length.
6088 * According to RFC2616 #4.4, amended by the HTTPbis working group,
6089 * the presence of a message-body in a RESPONSE and its transfer length
6090 * must be determined that way :
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006091 *
Willy Tarreaue8e785b2009-12-26 15:34:26 +01006092 * All responses to the HEAD request method MUST NOT include a
6093 * message-body, even though the presence of entity-header fields
6094 * might lead one to believe they do. All 1xx (informational), 204
6095 * (No Content), and 304 (Not Modified) responses MUST NOT include a
6096 * message-body. All other responses do include a message-body,
6097 * although it MAY be of zero length.
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006098 *
Willy Tarreaue8e785b2009-12-26 15:34:26 +01006099 * 1. Any response which "MUST NOT" include a message-body (such as the
6100 * 1xx, 204 and 304 responses and any response to a HEAD request) is
6101 * always terminated by the first empty line after the header fields,
6102 * regardless of the entity-header fields present in the message.
6103 *
6104 * 2. If a Transfer-Encoding header field (Section 9.7) is present and
6105 * the "chunked" transfer-coding (Section 6.2) is used, the
6106 * transfer-length is defined by the use of this transfer-coding.
6107 * If a Transfer-Encoding header field is present and the "chunked"
6108 * transfer-coding is not present, the transfer-length is defined by
6109 * the sender closing the connection.
6110 *
6111 * 3. If a Content-Length header field is present, its decimal value in
6112 * OCTETs represents both the entity-length and the transfer-length.
6113 * If a message is received with both a Transfer-Encoding header
6114 * field and a Content-Length header field, the latter MUST be ignored.
6115 *
6116 * 4. If the message uses the media type "multipart/byteranges", and
6117 * the transfer-length is not otherwise specified, then this self-
6118 * delimiting media type defines the transfer-length. This media
6119 * type MUST NOT be used unless the sender knows that the recipient
6120 * can parse it; the presence in a request of a Range header with
6121 * multiple byte-range specifiers from a 1.1 client implies that the
6122 * client can parse multipart/byteranges responses.
6123 *
6124 * 5. By the server closing the connection.
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006125 */
6126
6127 /* Skip parsing if no content length is possible. The response flags
Willy Tarreau124d9912011-03-01 20:30:48 +01006128 * remain 0 as well as the chunk_len, which may or may not mirror
Willy Tarreaue8e785b2009-12-26 15:34:26 +01006129 * the real header value, and we note that we know the response's length.
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006130 * FIXME: should we parse anyway and return an error on chunked encoding ?
6131 */
6132 if (txn->meth == HTTP_METH_HEAD ||
6133 (txn->status >= 100 && txn->status < 200) ||
Willy Tarreaue8e785b2009-12-26 15:34:26 +01006134 txn->status == 204 || txn->status == 304) {
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006135 msg->flags |= HTTP_MSGF_XFER_LEN;
Willy Tarreau91015352012-11-27 07:31:33 +01006136 s->comp_algo = NULL;
Willy Tarreaue8e785b2009-12-26 15:34:26 +01006137 goto skip_content_length;
6138 }
6139
Willy Tarreaue8e785b2009-12-26 15:34:26 +01006140 use_close_only = 0;
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006141 ctx.idx = 0;
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006142 while ((msg->flags & HTTP_MSGF_VER_11) &&
Willy Tarreau9b28e032012-10-12 23:49:43 +02006143 http_find_header2("Transfer-Encoding", 17, rep->buf->p, &txn->hdr_idx, &ctx)) {
Willy Tarreaue8e785b2009-12-26 15:34:26 +01006144 if (ctx.vlen == 7 && strncasecmp(ctx.line + ctx.val, "chunked", 7) == 0)
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006145 msg->flags |= (HTTP_MSGF_TE_CHNK | HTTP_MSGF_XFER_LEN);
6146 else if (msg->flags & HTTP_MSGF_TE_CHNK) {
Willy Tarreaue8e785b2009-12-26 15:34:26 +01006147 /* bad transfer-encoding (chunked followed by something else) */
6148 use_close_only = 1;
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006149 msg->flags &= ~(HTTP_MSGF_TE_CHNK | HTTP_MSGF_XFER_LEN);
Willy Tarreaue8e785b2009-12-26 15:34:26 +01006150 break;
6151 }
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006152 }
6153
6154 /* FIXME: below we should remove the content-length header(s) in case of chunked encoding */
6155 ctx.idx = 0;
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006156 while (!(msg->flags & HTTP_MSGF_TE_CHNK) && !use_close_only &&
Willy Tarreau9b28e032012-10-12 23:49:43 +02006157 http_find_header2("Content-Length", 14, rep->buf->p, &txn->hdr_idx, &ctx)) {
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006158 signed long long cl;
6159
Willy Tarreauad14f752011-09-02 20:33:27 +02006160 if (!ctx.vlen) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02006161 msg->err_pos = ctx.line + ctx.val - rep->buf->p;
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006162 goto hdr_response_bad;
Willy Tarreauad14f752011-09-02 20:33:27 +02006163 }
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006164
Willy Tarreauad14f752011-09-02 20:33:27 +02006165 if (strl2llrc(ctx.line + ctx.val, ctx.vlen, &cl)) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02006166 msg->err_pos = ctx.line + ctx.val - rep->buf->p;
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006167 goto hdr_response_bad; /* parse failure */
Willy Tarreauad14f752011-09-02 20:33:27 +02006168 }
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006169
Willy Tarreauad14f752011-09-02 20:33:27 +02006170 if (cl < 0) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02006171 msg->err_pos = ctx.line + ctx.val - rep->buf->p;
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006172 goto hdr_response_bad;
Willy Tarreauad14f752011-09-02 20:33:27 +02006173 }
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006174
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006175 if ((msg->flags & HTTP_MSGF_CNT_LEN) && (msg->chunk_len != cl)) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02006176 msg->err_pos = ctx.line + ctx.val - rep->buf->p;
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006177 goto hdr_response_bad; /* already specified, was different */
Willy Tarreauad14f752011-09-02 20:33:27 +02006178 }
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006179
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006180 msg->flags |= HTTP_MSGF_CNT_LEN | HTTP_MSGF_XFER_LEN;
Willy Tarreau124d9912011-03-01 20:30:48 +01006181 msg->body_len = msg->chunk_len = cl;
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006182 }
6183
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006184 if (sess->fe->comp || s->be->comp)
William Lallemand82fe75c2012-10-23 10:25:10 +02006185 select_compression_response_header(s, rep->buf);
6186
Willy Tarreaub8c82c22009-10-18 23:45:12 +02006187skip_content_length:
Willy Tarreau5b154472009-12-21 20:11:07 +01006188 /* Now we have to check if we need to modify the Connection header.
6189 * This is more difficult on the response than it is on the request,
6190 * because we can have two different HTTP versions and we don't know
6191 * how the client will interprete a response. For instance, let's say
6192 * that the client sends a keep-alive request in HTTP/1.0 and gets an
6193 * HTTP/1.1 response without any header. Maybe it will bound itself to
6194 * HTTP/1.0 because it only knows about it, and will consider the lack
6195 * of header as a close, or maybe it knows HTTP/1.1 and can consider
6196 * the lack of header as a keep-alive. Thus we will use two flags
6197 * indicating how a request MAY be understood by the client. In case
6198 * of multiple possibilities, we'll fix the header to be explicit. If
6199 * ambiguous cases such as both close and keepalive are seen, then we
6200 * will fall back to explicit close. Note that we won't take risks with
6201 * HTTP/1.0 clients which may not necessarily understand keep-alive.
Willy Tarreau60466522010-01-18 19:08:45 +01006202 * See doc/internals/connection-header.txt for the complete matrix.
Willy Tarreau5b154472009-12-21 20:11:07 +01006203 */
6204
Willy Tarreaudc008c52010-02-01 16:20:08 +01006205 if (unlikely((txn->meth == HTTP_METH_CONNECT && txn->status == 200) ||
6206 txn->status == 101)) {
6207 /* Either we've established an explicit tunnel, or we're
6208 * switching the protocol. In both cases, we're very unlikely
Willy Tarreau5843d1a2010-02-01 15:13:32 +01006209 * to understand the next protocols. We have to switch to tunnel
6210 * mode, so that we transfer the request and responses then let
6211 * this protocol pass unmodified. When we later implement specific
6212 * parsers for such protocols, we'll want to check the Upgrade
Willy Tarreaudc008c52010-02-01 16:20:08 +01006213 * header which contains information about that protocol for
6214 * responses with status 101 (eg: see RFC2817 about TLS).
Willy Tarreau5843d1a2010-02-01 15:13:32 +01006215 */
6216 txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_TUN;
6217 }
Willy Tarreaudc008c52010-02-01 16:20:08 +01006218 else if ((txn->status >= 200) && !(txn->flags & TX_HDR_CONN_PRS) &&
6219 ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN ||
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006220 ((sess->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02006221 (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL))) {
Willy Tarreau60466522010-01-18 19:08:45 +01006222 int to_del = 0;
Willy Tarreau5b154472009-12-21 20:11:07 +01006223
Willy Tarreau70dffda2014-01-30 03:07:23 +01006224 /* this situation happens when combining pretend-keepalive with httpclose. */
6225 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL &&
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006226 ((sess->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02006227 (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL))
Willy Tarreau70dffda2014-01-30 03:07:23 +01006228 txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
6229
Willy Tarreau60466522010-01-18 19:08:45 +01006230 /* on unknown transfer length, we must close */
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006231 if (!(msg->flags & HTTP_MSGF_XFER_LEN) &&
Willy Tarreau60466522010-01-18 19:08:45 +01006232 (txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN)
6233 txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
Willy Tarreau5b154472009-12-21 20:11:07 +01006234
Willy Tarreau60466522010-01-18 19:08:45 +01006235 /* now adjust header transformations depending on current state */
6236 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_TUN ||
6237 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO) {
6238 to_del |= 2; /* remove "keep-alive" on any response */
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006239 if (!(msg->flags & HTTP_MSGF_VER_11))
Willy Tarreau60466522010-01-18 19:08:45 +01006240 to_del |= 1; /* remove "close" for HTTP/1.0 responses */
Willy Tarreau5b154472009-12-21 20:11:07 +01006241 }
Willy Tarreau60466522010-01-18 19:08:45 +01006242 else { /* SCL / KAL */
6243 to_del |= 1; /* remove "close" on any response */
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006244 if (txn->req.flags & msg->flags & HTTP_MSGF_VER_11)
Willy Tarreau60466522010-01-18 19:08:45 +01006245 to_del |= 2; /* remove "keep-alive" on pure 1.1 responses */
Willy Tarreau5b154472009-12-21 20:11:07 +01006246 }
Willy Tarreau5b154472009-12-21 20:11:07 +01006247
Willy Tarreau60466522010-01-18 19:08:45 +01006248 /* Parse and remove some headers from the connection header */
Willy Tarreau6acf7c92012-03-09 13:30:45 +01006249 http_parse_connection_header(txn, msg, to_del);
Willy Tarreau5b154472009-12-21 20:11:07 +01006250
Willy Tarreau60466522010-01-18 19:08:45 +01006251 /* Some keep-alive responses are converted to Server-close if
6252 * the server wants to close.
Willy Tarreau5b154472009-12-21 20:11:07 +01006253 */
Willy Tarreau60466522010-01-18 19:08:45 +01006254 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL) {
6255 if ((txn->flags & TX_HDR_CONN_CLO) ||
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01006256 (!(txn->flags & TX_HDR_CONN_KAL) && !(msg->flags & HTTP_MSGF_VER_11)))
Willy Tarreau60466522010-01-18 19:08:45 +01006257 txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_SCL;
Willy Tarreaub608feb2010-01-02 22:47:18 +01006258 }
Willy Tarreau5b154472009-12-21 20:11:07 +01006259 }
6260
Willy Tarreau7959a552013-09-23 16:44:27 +02006261 /* we want to have the response time before we start processing it */
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02006262 s->logs.t_data = tv_ms_elapsed(&s->logs.tv_accept, &now);
Willy Tarreau7959a552013-09-23 16:44:27 +02006263
Willy Tarreauf118d9f2014-04-24 18:26:08 +02006264 /* end of job, return OK */
6265 rep->analysers &= ~an_bit;
6266 rep->analyse_exp = TICK_ETERNITY;
6267 channel_auto_close(rep);
6268 return 1;
6269
6270 abort_keep_alive:
6271 /* A keep-alive request to the server failed on a network error.
6272 * The client is required to retry. We need to close without returning
6273 * any other information so that the client retries.
6274 */
6275 txn->status = 0;
6276 rep->analysers = 0;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01006277 s->req.analysers = 0;
Willy Tarreauf118d9f2014-04-24 18:26:08 +02006278 channel_auto_close(rep);
6279 s->logs.logwait = 0;
6280 s->logs.level = 0;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01006281 s->res.flags &= ~CF_EXPECT_MORE; /* speed up sending a previous response */
Willy Tarreau319f7452015-01-14 20:32:59 +01006282 channel_truncate(rep);
Willy Tarreau350f4872014-11-28 14:42:25 +01006283 stream_int_retnclose(&s->si[0], NULL);
Willy Tarreauf118d9f2014-04-24 18:26:08 +02006284 return 0;
6285}
6286
6287/* This function performs all the processing enabled for the current response.
6288 * It normally returns 1 unless it wants to break. It relies on buffers flags,
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01006289 * and updates s->res.analysers. It might make sense to explode it into several
Willy Tarreauf118d9f2014-04-24 18:26:08 +02006290 * other functions. It works like process_request (see indications above).
6291 */
Willy Tarreau87b09662015-04-03 00:22:06 +02006292int http_process_res_common(struct stream *s, struct channel *rep, int an_bit, struct proxy *px)
Willy Tarreauf118d9f2014-04-24 18:26:08 +02006293{
Willy Tarreaufb0afa72015-04-03 14:46:27 +02006294 struct session *sess = s->sess;
Willy Tarreaueee5b512015-04-03 23:46:31 +02006295 struct http_txn *txn = s->txn;
Willy Tarreauf118d9f2014-04-24 18:26:08 +02006296 struct http_msg *msg = &txn->rsp;
6297 struct proxy *cur_proxy;
6298 struct cond_wordlist *wl;
Thierry FOURNIER9e2ef992015-02-25 13:51:19 +01006299 enum rule_result ret = HTTP_RULE_RES_CONT;
Willy Tarreauf118d9f2014-04-24 18:26:08 +02006300
Willy Tarreau87b09662015-04-03 00:22:06 +02006301 DPRINTF(stderr,"[%u] %s: stream=%p b=%p, exp(r,w)=%u,%u bf=%08x bh=%d analysers=%02x\n",
Willy Tarreauf118d9f2014-04-24 18:26:08 +02006302 now_ms, __FUNCTION__,
6303 s,
6304 rep,
6305 rep->rex, rep->wex,
6306 rep->flags,
6307 rep->buf->i,
6308 rep->analysers);
6309
6310 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) /* we need more data */
6311 return 0;
6312
Willy Tarreau70730dd2014-04-24 18:06:27 +02006313 /* The stats applet needs to adjust the Connection header but we don't
6314 * apply any filter there.
6315 */
Willy Tarreau612adb82015-03-10 15:25:54 +01006316 if (unlikely(objt_applet(s->target) == &http_stats_applet)) {
6317 rep->analysers &= ~an_bit;
6318 rep->analyse_exp = TICK_ETERNITY;
Willy Tarreau70730dd2014-04-24 18:06:27 +02006319 goto skip_filters;
Willy Tarreau612adb82015-03-10 15:25:54 +01006320 }
Willy Tarreau70730dd2014-04-24 18:06:27 +02006321
Willy Tarreau58975672014-04-24 21:13:57 +02006322 /*
6323 * We will have to evaluate the filters.
6324 * As opposed to version 1.2, now they will be evaluated in the
6325 * filters order and not in the header order. This means that
6326 * each filter has to be validated among all headers.
6327 *
6328 * Filters are tried with ->be first, then with ->fe if it is
6329 * different from ->be.
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01006330 *
6331 * Maybe we are in resume condiion. In this case I choose the
6332 * "struct proxy" which contains the rule list matching the resume
6333 * pointer. If none of theses "struct proxy" match, I initialise
6334 * the process with the first one.
6335 *
6336 * In fact, I check only correspondance betwwen the current list
6337 * pointer and the ->fe rule list. If it doesn't match, I initialize
6338 * the loop with the ->be.
Willy Tarreau58975672014-04-24 21:13:57 +02006339 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006340 if (s->current_rule_list == &sess->fe->http_res_rules)
6341 cur_proxy = sess->fe;
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01006342 else
6343 cur_proxy = s->be;
Willy Tarreau58975672014-04-24 21:13:57 +02006344 while (1) {
6345 struct proxy *rule_set = cur_proxy;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02006346
Willy Tarreau58975672014-04-24 21:13:57 +02006347 /* evaluate http-response rules */
Thierry FOURNIER9e2ef992015-02-25 13:51:19 +01006348 if (ret == HTTP_RULE_RES_CONT)
Willy Tarreau987e3fb2015-04-04 01:09:08 +02006349 ret = http_res_get_intercept_rule(cur_proxy, &cur_proxy->http_res_rules, s);
Willy Tarreaue365c0b2013-06-11 16:06:12 +02006350
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01006351 /* we need to be called again. */
6352 if (ret == HTTP_RULE_RES_YIELD) {
6353 channel_dont_close(rep);
6354 return 0;
6355 }
6356
Willy Tarreau58975672014-04-24 21:13:57 +02006357 /* try headers filters */
6358 if (rule_set->rsp_exp != NULL) {
6359 if (apply_filters_to_response(s, rep, rule_set) < 0) {
6360 return_bad_resp:
6361 if (objt_server(s->target)) {
6362 objt_server(s->target)->counters.failed_resp++;
6363 health_adjust(objt_server(s->target), HANA_STATUS_HTTP_RSP);
Willy Tarreau21d2af32008-02-14 20:25:24 +01006364 }
Willy Tarreau58975672014-04-24 21:13:57 +02006365 s->be->be_counters.failed_resp++;
6366 return_srv_prx_502:
6367 rep->analysers = 0;
6368 txn->status = 502;
6369 s->logs.t_data = -1; /* was not a valid response */
Willy Tarreau350f4872014-11-28 14:42:25 +01006370 s->si[1].flags |= SI_FL_NOLINGER;
Willy Tarreau319f7452015-01-14 20:32:59 +01006371 channel_truncate(rep);
Willy Tarreau350f4872014-11-28 14:42:25 +01006372 stream_int_retnclose(&s->si[0], http_error_message(s, HTTP_ERR_502));
Willy Tarreaue7dff022015-04-03 01:14:29 +02006373 if (!(s->flags & SF_ERR_MASK))
6374 s->flags |= SF_ERR_PRXCOND;
6375 if (!(s->flags & SF_FINST_MASK))
6376 s->flags |= SF_FINST_H;
Willy Tarreau58975672014-04-24 21:13:57 +02006377 return 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02006378 }
Willy Tarreau58975672014-04-24 21:13:57 +02006379 }
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02006380
Willy Tarreau58975672014-04-24 21:13:57 +02006381 /* has the response been denied ? */
6382 if (txn->flags & TX_SVDENY) {
6383 if (objt_server(s->target))
6384 objt_server(s->target)->counters.failed_secu++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02006385
Willy Tarreau58975672014-04-24 21:13:57 +02006386 s->be->be_counters.denied_resp++;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006387 sess->fe->fe_counters.denied_resp++;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02006388 if (sess->listener->counters)
6389 sess->listener->counters->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02006390
Willy Tarreau58975672014-04-24 21:13:57 +02006391 goto return_srv_prx_502;
6392 }
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02006393
Willy Tarreau58975672014-04-24 21:13:57 +02006394 /* add response headers from the rule sets in the same order */
6395 list_for_each_entry(wl, &rule_set->rsp_add, list) {
Willy Tarreauce730de2014-09-16 10:40:38 +02006396 if (txn->status < 200 && txn->status != 101)
Willy Tarreauf5483bf2008-08-14 18:35:40 +02006397 break;
Willy Tarreau58975672014-04-24 21:13:57 +02006398 if (wl->cond) {
Willy Tarreau15e91e12015-04-04 00:52:09 +02006399 int ret = acl_exec_cond(wl->cond, px, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL);
Willy Tarreau58975672014-04-24 21:13:57 +02006400 ret = acl_pass(ret);
6401 if (((struct acl_cond *)wl->cond)->pol == ACL_COND_UNLESS)
6402 ret = !ret;
6403 if (!ret)
6404 continue;
6405 }
6406 if (unlikely(http_header_add_tail(&txn->rsp, &txn->hdr_idx, wl->s) < 0))
6407 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02006408 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02006409
Willy Tarreau58975672014-04-24 21:13:57 +02006410 /* check whether we're already working on the frontend */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006411 if (cur_proxy == sess->fe)
Willy Tarreau58975672014-04-24 21:13:57 +02006412 break;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006413 cur_proxy = sess->fe;
Willy Tarreau58975672014-04-24 21:13:57 +02006414 }
Willy Tarreau63c9e5f2009-12-22 16:01:27 +01006415
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01006416 /* After this point, this anayzer can't return yield, so we can
6417 * remove the bit corresponding to this analyzer from the list.
6418 *
6419 * Note that the intermediate returns and goto found previously
6420 * reset the analyzers.
6421 */
6422 rep->analysers &= ~an_bit;
6423 rep->analyse_exp = TICK_ETERNITY;
6424
Willy Tarreau58975672014-04-24 21:13:57 +02006425 /* OK that's all we can do for 1xx responses */
Willy Tarreauce730de2014-09-16 10:40:38 +02006426 if (unlikely(txn->status < 200 && txn->status != 101))
Willy Tarreau58975672014-04-24 21:13:57 +02006427 goto skip_header_mangling;
Willy Tarreau63c9e5f2009-12-22 16:01:27 +01006428
Willy Tarreau58975672014-04-24 21:13:57 +02006429 /*
6430 * Now check for a server cookie.
6431 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006432 if (s->be->cookie_name || s->be->appsession_name || sess->fe->capture_name ||
Willy Tarreau58975672014-04-24 21:13:57 +02006433 (s->be->options & PR_O_CHK_CACHE))
6434 manage_server_side_cookies(s, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02006435
Willy Tarreau58975672014-04-24 21:13:57 +02006436 /*
6437 * Check for cache-control or pragma headers if required.
6438 */
Willy Tarreauce730de2014-09-16 10:40:38 +02006439 if (((s->be->options & PR_O_CHK_CACHE) || (s->be->ck_opts & PR_CK_NOC)) && txn->status != 101)
Willy Tarreau58975672014-04-24 21:13:57 +02006440 check_response_for_cacheability(s, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02006441
Willy Tarreau58975672014-04-24 21:13:57 +02006442 /*
6443 * Add server cookie in the response if needed
6444 */
6445 if (objt_server(s->target) && (s->be->ck_opts & PR_CK_INS) &&
6446 !((txn->flags & TX_SCK_FOUND) && (s->be->ck_opts & PR_CK_PSV)) &&
Willy Tarreaue7dff022015-04-03 01:14:29 +02006447 (!(s->flags & SF_DIRECT) ||
Willy Tarreau58975672014-04-24 21:13:57 +02006448 ((s->be->cookie_maxidle || txn->cookie_last_date) &&
6449 (!txn->cookie_last_date || (txn->cookie_last_date - date.tv_sec) < 0)) ||
6450 (s->be->cookie_maxlife && !txn->cookie_first_date) || // set the first_date
6451 (!s->be->cookie_maxlife && txn->cookie_first_date)) && // remove the first_date
6452 (!(s->be->ck_opts & PR_CK_POST) || (txn->meth == HTTP_METH_POST)) &&
Willy Tarreaue7dff022015-04-03 01:14:29 +02006453 !(s->flags & SF_IGNORE_PRST)) {
Willy Tarreau58975672014-04-24 21:13:57 +02006454 /* the server is known, it's not the one the client requested, or the
6455 * cookie's last seen date needs to be refreshed. We have to
6456 * insert a set-cookie here, except if we want to insert only on POST
6457 * requests and this one isn't. Note that servers which don't have cookies
6458 * (eg: some backup servers) will return a full cookie removal request.
Willy Tarreaua15645d2007-03-18 16:22:39 +01006459 */
Willy Tarreau58975672014-04-24 21:13:57 +02006460 if (!objt_server(s->target)->cookie) {
6461 chunk_printf(&trash,
6462 "Set-Cookie: %s=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/",
6463 s->be->cookie_name);
6464 }
6465 else {
6466 chunk_printf(&trash, "Set-Cookie: %s=%s", s->be->cookie_name, objt_server(s->target)->cookie);
Willy Tarreaua15645d2007-03-18 16:22:39 +01006467
Willy Tarreau58975672014-04-24 21:13:57 +02006468 if (s->be->cookie_maxidle || s->be->cookie_maxlife) {
6469 /* emit last_date, which is mandatory */
6470 trash.str[trash.len++] = COOKIE_DELIM_DATE;
6471 s30tob64((date.tv_sec+3) >> 2, trash.str + trash.len);
6472 trash.len += 5;
Willy Tarreauef4f3912010-10-07 21:00:29 +02006473
Willy Tarreau58975672014-04-24 21:13:57 +02006474 if (s->be->cookie_maxlife) {
6475 /* emit first_date, which is either the original one or
6476 * the current date.
6477 */
Willy Tarreau19d14ef2012-10-29 16:51:55 +01006478 trash.str[trash.len++] = COOKIE_DELIM_DATE;
Willy Tarreau58975672014-04-24 21:13:57 +02006479 s30tob64(txn->cookie_first_date ?
6480 txn->cookie_first_date >> 2 :
6481 (date.tv_sec+3) >> 2, trash.str + trash.len);
Willy Tarreau19d14ef2012-10-29 16:51:55 +01006482 trash.len += 5;
Willy Tarreauef4f3912010-10-07 21:00:29 +02006483 }
Willy Tarreauef4f3912010-10-07 21:00:29 +02006484 }
Willy Tarreau58975672014-04-24 21:13:57 +02006485 chunk_appendf(&trash, "; path=/");
6486 }
Willy Tarreau4992dd22012-05-31 21:02:17 +02006487
Willy Tarreau58975672014-04-24 21:13:57 +02006488 if (s->be->cookie_domain)
6489 chunk_appendf(&trash, "; domain=%s", s->be->cookie_domain);
Willy Tarreauef4f3912010-10-07 21:00:29 +02006490
Willy Tarreau58975672014-04-24 21:13:57 +02006491 if (s->be->ck_opts & PR_CK_HTTPONLY)
6492 chunk_appendf(&trash, "; HttpOnly");
Willy Tarreaubaaee002006-06-26 02:48:02 +02006493
Willy Tarreau58975672014-04-24 21:13:57 +02006494 if (s->be->ck_opts & PR_CK_SECURE)
6495 chunk_appendf(&trash, "; Secure");
Willy Tarreaubaaee002006-06-26 02:48:02 +02006496
Willy Tarreau58975672014-04-24 21:13:57 +02006497 if (unlikely(http_header_add_tail2(&txn->rsp, &txn->hdr_idx, trash.str, trash.len) < 0))
6498 goto return_bad_resp;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02006499
Willy Tarreau58975672014-04-24 21:13:57 +02006500 txn->flags &= ~TX_SCK_MASK;
Willy Tarreaue7dff022015-04-03 01:14:29 +02006501 if (objt_server(s->target)->cookie && (s->flags & SF_DIRECT))
Willy Tarreau58975672014-04-24 21:13:57 +02006502 /* the server did not change, only the date was updated */
6503 txn->flags |= TX_SCK_UPDATED;
6504 else
6505 txn->flags |= TX_SCK_INSERTED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02006506
Willy Tarreau58975672014-04-24 21:13:57 +02006507 /* Here, we will tell an eventual cache on the client side that we don't
6508 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
6509 * Some caches understand the correct form: 'no-cache="set-cookie"', but
6510 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
Willy Tarreauf5483bf2008-08-14 18:35:40 +02006511 */
Willy Tarreau58975672014-04-24 21:13:57 +02006512 if ((s->be->ck_opts & PR_CK_NOC) && (txn->flags & TX_CACHEABLE)) {
Willy Tarreauf5483bf2008-08-14 18:35:40 +02006513
Willy Tarreau58975672014-04-24 21:13:57 +02006514 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02006515
Willy Tarreau58975672014-04-24 21:13:57 +02006516 if (unlikely(http_header_add_tail2(&txn->rsp, &txn->hdr_idx,
6517 "Cache-control: private", 22) < 0))
6518 goto return_bad_resp;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02006519 }
Willy Tarreau58975672014-04-24 21:13:57 +02006520 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01006521
Willy Tarreau58975672014-04-24 21:13:57 +02006522 /*
6523 * Check if result will be cacheable with a cookie.
6524 * We'll block the response if security checks have caught
6525 * nasty things such as a cacheable cookie.
6526 */
6527 if (((txn->flags & (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_PRESENT)) ==
6528 (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_PRESENT)) &&
6529 (s->be->options & PR_O_CHK_CACHE)) {
6530 /* we're in presence of a cacheable response containing
6531 * a set-cookie header. We'll block it as requested by
6532 * the 'checkcache' option, and send an alert.
Willy Tarreaua15645d2007-03-18 16:22:39 +01006533 */
Willy Tarreau58975672014-04-24 21:13:57 +02006534 if (objt_server(s->target))
6535 objt_server(s->target)->counters.failed_secu++;
Willy Tarreau60466522010-01-18 19:08:45 +01006536
Willy Tarreau58975672014-04-24 21:13:57 +02006537 s->be->be_counters.denied_resp++;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006538 sess->fe->fe_counters.denied_resp++;
Willy Tarreaufb0afa72015-04-03 14:46:27 +02006539 if (sess->listener->counters)
6540 sess->listener->counters->denied_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01006541
Willy Tarreau58975672014-04-24 21:13:57 +02006542 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n",
6543 s->be->id, objt_server(s->target) ? objt_server(s->target)->id : "<dispatch>");
6544 send_log(s->be, LOG_ALERT,
6545 "Blocking cacheable cookie in response from instance %s, server %s.\n",
6546 s->be->id, objt_server(s->target) ? objt_server(s->target)->id : "<dispatch>");
6547 goto return_srv_prx_502;
6548 }
Willy Tarreau03945942009-12-22 16:50:27 +01006549
Willy Tarreau70730dd2014-04-24 18:06:27 +02006550 skip_filters:
Willy Tarreau58975672014-04-24 21:13:57 +02006551 /*
6552 * Adjust "Connection: close" or "Connection: keep-alive" if needed.
6553 * If an "Upgrade" token is found, the header is left untouched in order
6554 * not to have to deal with some client bugs : some of them fail an upgrade
Willy Tarreauce730de2014-09-16 10:40:38 +02006555 * if anything but "Upgrade" is present in the Connection header. We don't
6556 * want to touch any 101 response either since it's switching to another
6557 * protocol.
Willy Tarreau58975672014-04-24 21:13:57 +02006558 */
Willy Tarreauce730de2014-09-16 10:40:38 +02006559 if ((txn->status != 101) && !(txn->flags & TX_HDR_CONN_UPG) &&
Willy Tarreau58975672014-04-24 21:13:57 +02006560 (((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) ||
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006561 ((sess->fe->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL ||
Willy Tarreau58975672014-04-24 21:13:57 +02006562 (s->be->options & PR_O_HTTP_MODE) == PR_O_HTTP_PCL))) {
6563 unsigned int want_flags = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02006564
Willy Tarreau58975672014-04-24 21:13:57 +02006565 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
6566 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) {
6567 /* we want a keep-alive response here. Keep-alive header
6568 * required if either side is not 1.1.
6569 */
6570 if (!(txn->req.flags & msg->flags & HTTP_MSGF_VER_11))
6571 want_flags |= TX_CON_KAL_SET;
6572 }
6573 else {
6574 /* we want a close response here. Close header required if
6575 * the server is 1.1, regardless of the client.
6576 */
6577 if (msg->flags & HTTP_MSGF_VER_11)
6578 want_flags |= TX_CON_CLO_SET;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02006579 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01006580
Willy Tarreau58975672014-04-24 21:13:57 +02006581 if (want_flags != (txn->flags & (TX_CON_CLO_SET|TX_CON_KAL_SET)))
6582 http_change_connection_header(txn, msg, want_flags);
6583 }
6584
6585 skip_header_mangling:
6586 if ((msg->flags & HTTP_MSGF_XFER_LEN) ||
6587 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_TUN)
6588 rep->analysers |= AN_RES_HTTP_XFER_BODY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01006589
Willy Tarreau58975672014-04-24 21:13:57 +02006590 /* if the user wants to log as soon as possible, without counting
6591 * bytes from the server, then this is the right moment. We have
6592 * to temporarily assign bytes_out to log what we currently have.
6593 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006594 if (!LIST_ISEMPTY(&sess->fe->logformat) && !(s->logs.logwait & LW_BYTES)) {
Willy Tarreau58975672014-04-24 21:13:57 +02006595 s->logs.t_close = s->logs.t_data; /* to get a valid end date */
6596 s->logs.bytes_out = txn->rsp.eoh;
6597 s->do_log(s);
6598 s->logs.bytes_out = 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02006599 }
Willy Tarreaue3fa6e52010-01-04 22:57:43 +01006600 return 1;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02006601}
Willy Tarreaua15645d2007-03-18 16:22:39 +01006602
Willy Tarreaud98cf932009-12-27 22:54:55 +01006603/* This function is an analyser which forwards response body (including chunk
6604 * sizes if any). It is called as soon as we must forward, even if we forward
6605 * zero byte. The only situation where it must not be called is when we're in
6606 * tunnel mode and we want to forward till the close. It's used both to forward
6607 * remaining data and to resync after end of body. It expects the msg_state to
6608 * be between MSG_BODY and MSG_DONE (inclusive). It returns zero if it needs to
Willy Tarreau87b09662015-04-03 00:22:06 +02006609 * read more data, or 1 once we can go on with next request or end the stream.
Willy Tarreaud3510212014-04-21 11:24:13 +02006610 *
6611 * It is capable of compressing response data both in content-length mode and
6612 * in chunked mode. The state machines follows different flows depending on
6613 * whether content-length and chunked modes are used, since there are no
6614 * trailers in content-length :
6615 *
6616 * chk-mode cl-mode
6617 * ,----- BODY -----.
6618 * / \
6619 * V size > 0 V chk-mode
6620 * .--> SIZE -------------> DATA -------------> CRLF
6621 * | | size == 0 | last byte |
6622 * | v final crlf v inspected |
6623 * | TRAILERS -----------> DONE |
6624 * | |
6625 * `----------------------------------------------'
6626 *
6627 * Compression only happens in the DATA state, and must be flushed in final
6628 * states (TRAILERS/DONE) or when leaving on missing data. Normal forwarding
6629 * is performed at once on final states for all bytes parsed, or when leaving
6630 * on missing data.
Willy Tarreaud98cf932009-12-27 22:54:55 +01006631 */
Willy Tarreau87b09662015-04-03 00:22:06 +02006632int http_response_forward_body(struct stream *s, struct channel *res, int an_bit)
Willy Tarreaud98cf932009-12-27 22:54:55 +01006633{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006634 struct session *sess = s->sess;
Willy Tarreaueee5b512015-04-03 23:46:31 +02006635 struct http_txn *txn = s->txn;
6636 struct http_msg *msg = &s->txn->rsp;
Willy Tarreauf2f7d6b2014-11-24 11:55:08 +01006637 static struct buffer *tmpbuf = &buf_empty;
William Lallemand82fe75c2012-10-23 10:25:10 +02006638 int compressing = 0;
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006639 int ret;
Willy Tarreaud98cf932009-12-27 22:54:55 +01006640
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01006641 if (unlikely(msg->msg_state < HTTP_MSG_BODY))
6642 return 0;
6643
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02006644 if ((res->flags & (CF_READ_ERROR|CF_READ_TIMEOUT|CF_WRITE_ERROR|CF_WRITE_TIMEOUT)) ||
Willy Tarreau9b28e032012-10-12 23:49:43 +02006645 ((res->flags & CF_SHUTW) && (res->to_forward || res->buf->o)) ||
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01006646 !s->req.analysers) {
Willy Tarreau4fe41902010-06-07 22:27:41 +02006647 /* Output closed while we were sending data. We must abort and
6648 * wake the other side up.
6649 */
6650 msg->msg_state = HTTP_MSG_ERROR;
6651 http_resync_states(s);
Willy Tarreau082b01c2010-01-02 23:58:04 +01006652 return 1;
6653 }
6654
Willy Tarreau4fe41902010-06-07 22:27:41 +02006655 /* in most states, we should abort in case of early close */
Willy Tarreau8263d2b2012-08-28 00:06:31 +02006656 channel_auto_close(res);
Willy Tarreaub608feb2010-01-02 22:47:18 +01006657
Willy Tarreaubb2e6692014-07-10 19:06:10 +02006658 if (msg->sov > 0) {
Willy Tarreaub59c7bf2014-04-22 14:29:58 +02006659 /* we have msg->sov which points to the first byte of message
6660 * body, and res->buf.p still points to the beginning of the
6661 * message. We forward the headers now, as we don't need them
6662 * anymore, and we want to flush them.
Willy Tarreaud98cf932009-12-27 22:54:55 +01006663 */
Willy Tarreaub59c7bf2014-04-22 14:29:58 +02006664 b_adv(res->buf, msg->sov);
6665 msg->next -= msg->sov;
6666 msg->sov = 0;
Willy Tarreaua458b672012-03-05 11:17:50 +01006667
Willy Tarreaub59c7bf2014-04-22 14:29:58 +02006668 /* The previous analysers guarantee that the state is somewhere
6669 * between MSG_BODY and the first MSG_DATA. So msg->sol and
6670 * msg->next are always correct.
6671 */
6672 if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) {
6673 if (msg->flags & HTTP_MSGF_TE_CHNK)
6674 msg->msg_state = HTTP_MSG_CHUNK_SIZE;
6675 else
6676 msg->msg_state = HTTP_MSG_DATA;
6677 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01006678 }
6679
Willy Tarreauefdf0942014-04-24 20:08:57 +02006680 if (res->to_forward) {
6681 /* We can't process the buffer's contents yet */
6682 res->flags |= CF_WAKE_WRITE;
6683 goto missing_data;
6684 }
6685
Willy Tarreau32b5ab22014-04-21 11:27:29 +02006686 if (unlikely(s->comp_algo != NULL) && msg->msg_state < HTTP_MSG_TRAILERS) {
6687 /* We need a compression buffer in the DATA state to put the
6688 * output of compressed data, and in CRLF state to let the
6689 * TRAILERS state finish the job of removing the trailing CRLF.
6690 */
Willy Tarreauf2f7d6b2014-11-24 11:55:08 +01006691 if (unlikely(!tmpbuf->size)) {
Willy Tarreau32b5ab22014-04-21 11:27:29 +02006692 /* this is the first time we need the compression buffer */
Willy Tarreaue583ea52014-11-24 11:30:16 +01006693 if (b_alloc(&tmpbuf) == NULL)
Willy Tarreau32b5ab22014-04-21 11:27:29 +02006694 goto aborted_xfer; /* no memory */
6695 }
6696
6697 ret = http_compression_buffer_init(s, res->buf, tmpbuf);
Willy Tarreau4afd70a2014-01-25 02:26:39 +01006698 if (ret < 0) {
6699 res->flags |= CF_WAKE_WRITE;
William Lallemand82fe75c2012-10-23 10:25:10 +02006700 goto missing_data; /* not enough spaces in buffers */
Willy Tarreau4afd70a2014-01-25 02:26:39 +01006701 }
William Lallemand82fe75c2012-10-23 10:25:10 +02006702 compressing = 1;
6703 }
6704
Willy Tarreaud98cf932009-12-27 22:54:55 +01006705 while (1) {
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006706 switch (msg->msg_state - HTTP_MSG_DATA) {
6707 case HTTP_MSG_DATA - HTTP_MSG_DATA: /* must still forward */
Willy Tarreauc623c172014-04-18 09:53:50 +02006708 /* we may have some pending data starting at res->buf->p */
6709 if (unlikely(s->comp_algo)) {
Willy Tarreau7f2f8d52014-04-18 00:20:14 +02006710 ret = http_compression_buffer_add_data(s, res->buf, tmpbuf);
William Lallemandbf3ae612012-11-19 12:35:37 +01006711 if (ret < 0)
6712 goto aborted_xfer;
Willy Tarreauc623c172014-04-18 09:53:50 +02006713
Willy Tarreaud5a67832014-04-21 10:54:27 +02006714 if (msg->chunk_len) {
6715 /* input empty or output full */
6716 if (res->buf->i > msg->next)
6717 res->flags |= CF_WAKE_WRITE;
Willy Tarreauc623c172014-04-18 09:53:50 +02006718 goto missing_data;
6719 }
William Lallemandbf3ae612012-11-19 12:35:37 +01006720 }
Willy Tarreauc623c172014-04-18 09:53:50 +02006721 else {
Willy Tarreaud5a67832014-04-21 10:54:27 +02006722 if (msg->chunk_len > res->buf->i - msg->next) {
6723 /* output full */
6724 res->flags |= CF_WAKE_WRITE;
6725 goto missing_data;
6726 }
Willy Tarreauc623c172014-04-18 09:53:50 +02006727 msg->next += msg->chunk_len;
6728 msg->chunk_len = 0;
6729 }
Willy Tarreaucaabe412010-01-03 23:08:28 +01006730
6731 /* nothing left to forward */
William Lallemandbf3ae612012-11-19 12:35:37 +01006732 if (msg->flags & HTTP_MSGF_TE_CHNK) {
Willy Tarreau54d23df2012-10-25 19:04:45 +02006733 msg->msg_state = HTTP_MSG_CHUNK_CRLF;
William Lallemandbf3ae612012-11-19 12:35:37 +01006734 } else {
Willy Tarreaucaabe412010-01-03 23:08:28 +01006735 msg->msg_state = HTTP_MSG_DONE;
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006736 break;
William Lallemandbf3ae612012-11-19 12:35:37 +01006737 }
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006738 /* fall through for HTTP_MSG_CHUNK_CRLF */
6739
6740 case HTTP_MSG_CHUNK_CRLF - HTTP_MSG_DATA:
6741 /* we want the CRLF after the data */
6742
6743 ret = http_skip_chunk_crlf(msg);
6744 if (ret == 0)
6745 goto missing_data;
6746 else if (ret < 0) {
6747 if (msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006748 http_capture_bad_message(&s->be->invalid_rep, s, msg, HTTP_MSG_CHUNK_CRLF, sess->fe);
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006749 goto return_bad_res;
6750 }
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006751 /* we're in MSG_CHUNK_SIZE now, fall through */
6752
6753 case HTTP_MSG_CHUNK_SIZE - HTTP_MSG_DATA:
Willy Tarreau124d9912011-03-01 20:30:48 +01006754 /* read the chunk size and assign it to ->chunk_len, then
Willy Tarreauc24715e2014-04-17 15:21:20 +02006755 * set ->next to point to the body and switch to DATA or
Willy Tarreaua458b672012-03-05 11:17:50 +01006756 * TRAILERS state.
Willy Tarreaud98cf932009-12-27 22:54:55 +01006757 */
Willy Tarreaud98cf932009-12-27 22:54:55 +01006758
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006759 ret = http_parse_chunk_size(msg);
Willy Tarreau54d23df2012-10-25 19:04:45 +02006760 if (ret == 0)
Willy Tarreaud98cf932009-12-27 22:54:55 +01006761 goto missing_data;
Willy Tarreaue1582eb2010-12-12 13:10:11 +01006762 else if (ret < 0) {
6763 if (msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006764 http_capture_bad_message(&s->be->invalid_rep, s, msg, HTTP_MSG_CHUNK_SIZE, sess->fe);
Willy Tarreaud98cf932009-12-27 22:54:55 +01006765 goto return_bad_res;
Willy Tarreaue1582eb2010-12-12 13:10:11 +01006766 }
Willy Tarreau0161d622013-04-02 01:26:55 +02006767 /* otherwise we're in HTTP_MSG_DATA or HTTP_MSG_TRAILERS state */
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006768 break;
Willy Tarreau5523b322009-12-29 12:05:52 +01006769
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006770 case HTTP_MSG_TRAILERS - HTTP_MSG_DATA:
Willy Tarreau168ebc52014-04-18 00:53:43 +02006771 if (unlikely(compressing)) {
6772 /* we need to flush output contents before syncing FSMs */
6773 http_compression_buffer_end(s, &res->buf, &tmpbuf, 1);
6774 compressing = 0;
6775 }
6776
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006777 ret = http_forward_trailers(msg);
Willy Tarreaud98cf932009-12-27 22:54:55 +01006778 if (ret == 0)
6779 goto missing_data;
Willy Tarreaue1582eb2010-12-12 13:10:11 +01006780 else if (ret < 0) {
6781 if (msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006782 http_capture_bad_message(&s->be->invalid_rep, s, msg, HTTP_MSG_TRAILERS, sess->fe);
Willy Tarreaud98cf932009-12-27 22:54:55 +01006783 goto return_bad_res;
Willy Tarreaue1582eb2010-12-12 13:10:11 +01006784 }
Willy Tarreau168ebc52014-04-18 00:53:43 +02006785 /* we're in HTTP_MSG_DONE now, fall through */
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006786
6787 default:
Willy Tarreau610ecce2010-01-04 21:15:02 +01006788 /* other states, DONE...TUNNEL */
Willy Tarreau168ebc52014-04-18 00:53:43 +02006789 if (unlikely(compressing)) {
6790 /* we need to flush output contents before syncing FSMs */
6791 http_compression_buffer_end(s, &res->buf, &tmpbuf, 1);
6792 compressing = 0;
6793 }
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006794
Willy Tarreauc623c172014-04-18 09:53:50 +02006795 /* we may have some pending data starting at res->buf->p
6796 * such as a last chunk of data or trailers.
6797 */
6798 b_adv(res->buf, msg->next);
6799 msg->next = 0;
6800
Willy Tarreaud655ffe2013-04-02 01:48:58 +02006801 ret = msg->msg_state;
Willy Tarreau4fe41902010-06-07 22:27:41 +02006802 /* for keep-alive we don't want to forward closes on DONE */
Willy Tarreau92aa1fa2010-08-28 18:57:20 +02006803 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
6804 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL)
Willy Tarreau8263d2b2012-08-28 00:06:31 +02006805 channel_dont_close(res);
Willy Tarreau3ce10ff2014-04-22 08:24:38 +02006806
Willy Tarreau610ecce2010-01-04 21:15:02 +01006807 if (http_resync_states(s)) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01006808 /* some state changes occurred, maybe the analyser
6809 * was disabled too.
Willy Tarreau5523b322009-12-29 12:05:52 +01006810 */
Willy Tarreau3fe693b2010-12-12 12:50:05 +01006811 if (unlikely(msg->msg_state == HTTP_MSG_ERROR)) {
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02006812 if (res->flags & CF_SHUTW) {
Willy Tarreau3fe693b2010-12-12 12:50:05 +01006813 /* response errors are most likely due to
6814 * the client aborting the transfer.
6815 */
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01006816 goto aborted_xfer;
Willy Tarreau3fe693b2010-12-12 12:50:05 +01006817 }
Willy Tarreaue1582eb2010-12-12 13:10:11 +01006818 if (msg->err_pos >= 0)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006819 http_capture_bad_message(&s->be->invalid_rep, s, msg, ret, sess->fe);
Willy Tarreau610ecce2010-01-04 21:15:02 +01006820 goto return_bad_res;
Willy Tarreau3fe693b2010-12-12 12:50:05 +01006821 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01006822 return 1;
Willy Tarreau5523b322009-12-29 12:05:52 +01006823 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01006824 return 0;
Willy Tarreaud98cf932009-12-27 22:54:55 +01006825 }
6826 }
6827
Willy Tarreaud98cf932009-12-27 22:54:55 +01006828 missing_data:
Willy Tarreauc623c172014-04-18 09:53:50 +02006829 /* we may have some pending data starting at res->buf->p */
Willy Tarreau168ebc52014-04-18 00:53:43 +02006830 if (unlikely(compressing)) {
6831 http_compression_buffer_end(s, &res->buf, &tmpbuf, msg->msg_state >= HTTP_MSG_TRAILERS);
William Lallemand82fe75c2012-10-23 10:25:10 +02006832 compressing = 0;
6833 }
Willy Tarreauf003d372012-11-26 13:35:37 +01006834
Willy Tarreauc623c172014-04-18 09:53:50 +02006835 if ((s->comp_algo == NULL || msg->msg_state >= HTTP_MSG_TRAILERS)) {
6836 b_adv(res->buf, msg->next);
6837 msg->next = 0;
6838 msg->chunk_len -= channel_forward(res, msg->chunk_len);
6839 }
6840
Willy Tarreauf003d372012-11-26 13:35:37 +01006841 if (res->flags & CF_SHUTW)
6842 goto aborted_xfer;
6843
6844 /* stop waiting for data if the input is closed before the end. If the
6845 * client side was already closed, it means that the client has aborted,
6846 * so we don't want to count this as a server abort. Otherwise it's a
6847 * server abort.
6848 */
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02006849 if (res->flags & CF_SHUTR) {
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01006850 if ((s->req.flags & (CF_SHUTR|CF_SHUTW)) == (CF_SHUTR|CF_SHUTW))
Willy Tarreauf003d372012-11-26 13:35:37 +01006851 goto aborted_xfer;
Willy Tarreaue7dff022015-04-03 01:14:29 +02006852 if (!(s->flags & SF_ERR_MASK))
6853 s->flags |= SF_ERR_SRVCL;
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01006854 s->be->be_counters.srv_aborts++;
Willy Tarreau3fdb3662012-11-12 00:42:33 +01006855 if (objt_server(s->target))
6856 objt_server(s->target)->counters.srv_aborts++;
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01006857 goto return_bad_res_stats_ok;
Willy Tarreau40dba092010-03-04 18:14:51 +01006858 }
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01006859
Willy Tarreau40dba092010-03-04 18:14:51 +01006860 /* we need to obey the req analyser, so if it leaves, we must too */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01006861 if (!s->req.analysers)
Willy Tarreau610ecce2010-01-04 21:15:02 +01006862 goto return_bad_res;
6863
Willy Tarreau92aa1fa2010-08-28 18:57:20 +02006864 /* When TE: chunked is used, we need to get there again to parse remaining
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02006865 * chunks even if the server has closed, so we don't want to set CF_DONTCLOSE.
Willy Tarreau92aa1fa2010-08-28 18:57:20 +02006866 * Similarly, with keep-alive on the client side, we don't want to forward a
6867 * close.
6868 */
Willy Tarreau08b4d792012-10-27 01:36:34 +02006869 if ((msg->flags & HTTP_MSGF_TE_CHNK) || s->comp_algo ||
Willy Tarreau92aa1fa2010-08-28 18:57:20 +02006870 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
6871 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL)
Willy Tarreau8263d2b2012-08-28 00:06:31 +02006872 channel_dont_close(res);
Willy Tarreau92aa1fa2010-08-28 18:57:20 +02006873
Willy Tarreau5c620922011-05-11 19:56:11 +02006874 /* We know that more data are expected, but we couldn't send more that
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02006875 * what we did. So we always set the CF_EXPECT_MORE flag so that the
Willy Tarreau07293032011-05-30 18:29:28 +02006876 * system knows it must not set a PUSH on this first part. Interactive
Willy Tarreau869fc1e2012-03-05 08:29:20 +01006877 * modes are already handled by the stream sock layer. We must not do
6878 * this in content-length mode because it could present the MSG_MORE
6879 * flag with the last block of forwarded data, which would cause an
6880 * additional delay to be observed by the receiver.
Willy Tarreau5c620922011-05-11 19:56:11 +02006881 */
Willy Tarreau08b4d792012-10-27 01:36:34 +02006882 if ((msg->flags & HTTP_MSGF_TE_CHNK) || s->comp_algo)
Willy Tarreau03cdb7c2012-08-27 23:14:58 +02006883 res->flags |= CF_EXPECT_MORE;
Willy Tarreau5c620922011-05-11 19:56:11 +02006884
Willy Tarreau87b09662015-04-03 00:22:06 +02006885 /* the stream handler will take care of timeouts and errors */
Willy Tarreaud98cf932009-12-27 22:54:55 +01006886 return 0;
6887
Willy Tarreau40dba092010-03-04 18:14:51 +01006888 return_bad_res: /* let's centralize all bad responses */
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01006889 s->be->be_counters.failed_resp++;
Willy Tarreau3fdb3662012-11-12 00:42:33 +01006890 if (objt_server(s->target))
6891 objt_server(s->target)->counters.failed_resp++;
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01006892
6893 return_bad_res_stats_ok:
Willy Tarreaud01f4262014-04-21 11:00:13 +02006894 if (unlikely(compressing)) {
Willy Tarreau168ebc52014-04-18 00:53:43 +02006895 http_compression_buffer_end(s, &res->buf, &tmpbuf, msg->msg_state >= HTTP_MSG_TRAILERS);
Willy Tarreaud01f4262014-04-21 11:00:13 +02006896 compressing = 0;
6897 }
6898
Willy Tarreauc623c172014-04-18 09:53:50 +02006899 /* we may have some pending data starting at res->buf->p */
6900 if (s->comp_algo == NULL) {
6901 b_adv(res->buf, msg->next);
6902 msg->next = 0;
6903 }
6904
Willy Tarreaud98cf932009-12-27 22:54:55 +01006905 txn->rsp.msg_state = HTTP_MSG_ERROR;
Willy Tarreau148d0992010-01-10 10:21:21 +01006906 /* don't send any error message as we're in the body */
Willy Tarreau350f4872014-11-28 14:42:25 +01006907 stream_int_retnclose(&s->si[0], NULL);
Willy Tarreaud98cf932009-12-27 22:54:55 +01006908 res->analysers = 0;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01006909 s->req.analysers = 0; /* we're in data phase, we want to abort both directions */
Willy Tarreau3fdb3662012-11-12 00:42:33 +01006910 if (objt_server(s->target))
6911 health_adjust(objt_server(s->target), HANA_STATUS_HTTP_HDRRSP);
Willy Tarreaud98cf932009-12-27 22:54:55 +01006912
Willy Tarreaue7dff022015-04-03 01:14:29 +02006913 if (!(s->flags & SF_ERR_MASK))
6914 s->flags |= SF_ERR_PRXCOND;
6915 if (!(s->flags & SF_FINST_MASK))
6916 s->flags |= SF_FINST_D;
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01006917 return 0;
6918
6919 aborted_xfer:
Willy Tarreau6fef8ae2014-04-22 21:22:06 +02006920 if (unlikely(compressing)) {
6921 http_compression_buffer_end(s, &res->buf, &tmpbuf, msg->msg_state >= HTTP_MSG_TRAILERS);
6922 compressing = 0;
6923 }
6924
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01006925 txn->rsp.msg_state = HTTP_MSG_ERROR;
6926 /* don't send any error message as we're in the body */
Willy Tarreau350f4872014-11-28 14:42:25 +01006927 stream_int_retnclose(&s->si[0], NULL);
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01006928 res->analysers = 0;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01006929 s->req.analysers = 0; /* we're in data phase, we want to abort both directions */
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01006930
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006931 sess->fe->fe_counters.cli_aborts++;
Willy Tarreau7d0aaf32011-03-10 23:25:56 +01006932 s->be->be_counters.cli_aborts++;
Willy Tarreau3fdb3662012-11-12 00:42:33 +01006933 if (objt_server(s->target))
6934 objt_server(s->target)->counters.cli_aborts++;
Willy Tarreaued2fd2d2010-12-29 11:23:27 +01006935
Willy Tarreaue7dff022015-04-03 01:14:29 +02006936 if (!(s->flags & SF_ERR_MASK))
6937 s->flags |= SF_ERR_CLICL;
6938 if (!(s->flags & SF_FINST_MASK))
6939 s->flags |= SF_FINST_D;
Willy Tarreaud98cf932009-12-27 22:54:55 +01006940 return 0;
6941}
6942
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006943/* Iterate the same filter through all request headers.
6944 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01006945 * Since it can manage the switch to another backend, it updates the per-proxy
6946 * DENY stats.
Willy Tarreau58f10d72006-12-04 02:26:12 +01006947 */
Willy Tarreau87b09662015-04-03 00:22:06 +02006948int apply_filter_to_req_headers(struct stream *s, struct channel *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01006949{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006950 char *cur_ptr, *cur_end, *cur_next;
6951 int cur_idx, old_idx, last_hdr;
Willy Tarreaueee5b512015-04-03 23:46:31 +02006952 struct http_txn *txn = s->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006953 struct hdr_idx_elem *cur_hdr;
Willy Tarreau19d14ef2012-10-29 16:51:55 +01006954 int delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01006955
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006956 last_hdr = 0;
6957
Willy Tarreau9b28e032012-10-12 23:49:43 +02006958 cur_next = req->buf->p + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006959 old_idx = 0;
6960
6961 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01006962 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006963 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01006964 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006965 (exp->action == ACT_ALLOW ||
6966 exp->action == ACT_DENY ||
6967 exp->action == ACT_TARPIT))
6968 return 0;
6969
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01006970 cur_idx = txn->hdr_idx.v[old_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006971 if (!cur_idx)
6972 break;
6973
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01006974 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006975 cur_ptr = cur_next;
6976 cur_end = cur_ptr + cur_hdr->len;
6977 cur_next = cur_end + cur_hdr->cr + 1;
6978
6979 /* Now we have one header between cur_ptr and cur_end,
6980 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01006981 */
6982
Willy Tarreau15a53a42015-01-21 13:39:42 +01006983 if (regex_exec_match2(exp->preg, cur_ptr, cur_end-cur_ptr, MAX_MATCH, pmatch, 0)) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006984 switch (exp->action) {
6985 case ACT_SETBE:
6986 /* It is not possible to jump a second time.
6987 * FIXME: should we return an HTTP/500 here so that
6988 * the admin knows there's a problem ?
6989 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02006990 if (s->be != strm_sess(s)->fe)
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006991 break;
6992
6993 /* Swithing Proxy */
Willy Tarreau87b09662015-04-03 00:22:06 +02006994 stream_set_backend(s, (struct proxy *)exp->replace);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006995 last_hdr = 1;
6996 break;
6997
6998 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01006999 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007000 last_hdr = 1;
7001 break;
7002
7003 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01007004 txn->flags |= TX_CLDENY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007005 last_hdr = 1;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007006 break;
7007
7008 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01007009 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007010 last_hdr = 1;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007011 break;
7012
7013 case ACT_REPLACE:
Sasha Pachevc6002042014-05-26 12:33:48 -06007014 trash.len = exp_replace(trash.str, trash.size, cur_ptr, exp->replace, pmatch);
7015 if (trash.len < 0)
7016 return -1;
7017
Willy Tarreau19d14ef2012-10-29 16:51:55 +01007018 delta = buffer_replace2(req->buf, cur_ptr, cur_end, trash.str, trash.len);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007019 /* FIXME: if the user adds a newline in the replacement, the
7020 * index will not be recalculated for now, and the new line
7021 * will not be counted as a new header.
7022 */
7023
7024 cur_end += delta;
7025 cur_next += delta;
7026 cur_hdr->len += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01007027 http_msg_move_end(&txn->req, delta);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007028 break;
7029
7030 case ACT_REMOVE:
Willy Tarreau9b28e032012-10-12 23:49:43 +02007031 delta = buffer_replace2(req->buf, cur_ptr, cur_next, NULL, 0);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007032 cur_next += delta;
7033
Willy Tarreaufa355d42009-11-29 18:12:29 +01007034 http_msg_move_end(&txn->req, delta);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01007035 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
7036 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007037 cur_hdr->len = 0;
7038 cur_end = NULL; /* null-term has been rewritten */
Willy Tarreau26db59e2010-11-28 06:57:24 +01007039 cur_idx = old_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007040 break;
7041
7042 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01007043 }
7044
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007045 /* keep the link from this header to next one in case of later
7046 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01007047 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007048 old_idx = cur_idx;
7049 }
7050 return 0;
7051}
7052
7053
7054/* Apply the filter to the request line.
7055 * Returns 0 if nothing has been done, 1 if the filter has been applied,
7056 * or -1 if a replacement resulted in an invalid request line.
Willy Tarreaua15645d2007-03-18 16:22:39 +01007057 * Since it can manage the switch to another backend, it updates the per-proxy
7058 * DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007059 */
Willy Tarreau87b09662015-04-03 00:22:06 +02007060int apply_filter_to_req_line(struct stream *s, struct channel *req, struct hdr_exp *exp)
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007061{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007062 char *cur_ptr, *cur_end;
7063 int done;
Willy Tarreaueee5b512015-04-03 23:46:31 +02007064 struct http_txn *txn = s->txn;
Willy Tarreau19d14ef2012-10-29 16:51:55 +01007065 int delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007066
Willy Tarreau3d300592007-03-18 18:34:41 +01007067 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007068 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01007069 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007070 (exp->action == ACT_ALLOW ||
7071 exp->action == ACT_DENY ||
7072 exp->action == ACT_TARPIT))
7073 return 0;
7074 else if (exp->action == ACT_REMOVE)
7075 return 0;
7076
7077 done = 0;
7078
Willy Tarreau9b28e032012-10-12 23:49:43 +02007079 cur_ptr = req->buf->p;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01007080 cur_end = cur_ptr + txn->req.sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007081
7082 /* Now we have the request line between cur_ptr and cur_end */
7083
Willy Tarreau15a53a42015-01-21 13:39:42 +01007084 if (regex_exec_match2(exp->preg, cur_ptr, cur_end-cur_ptr, MAX_MATCH, pmatch, 0)) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007085 switch (exp->action) {
7086 case ACT_SETBE:
7087 /* It is not possible to jump a second time.
7088 * FIXME: should we return an HTTP/500 here so that
7089 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01007090 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02007091 if (s->be != strm_sess(s)->fe)
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007092 break;
7093
7094 /* Swithing Proxy */
Willy Tarreau87b09662015-04-03 00:22:06 +02007095 stream_set_backend(s, (struct proxy *)exp->replace);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007096 done = 1;
7097 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007098
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007099 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01007100 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007101 done = 1;
7102 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01007103
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007104 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01007105 txn->flags |= TX_CLDENY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007106 done = 1;
7107 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01007108
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007109 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01007110 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007111 done = 1;
7112 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01007113
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007114 case ACT_REPLACE:
Sasha Pachevc6002042014-05-26 12:33:48 -06007115 trash.len = exp_replace(trash.str, trash.size, cur_ptr, exp->replace, pmatch);
7116 if (trash.len < 0)
7117 return -1;
7118
Willy Tarreau19d14ef2012-10-29 16:51:55 +01007119 delta = buffer_replace2(req->buf, cur_ptr, cur_end, trash.str, trash.len);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007120 /* FIXME: if the user adds a newline in the replacement, the
7121 * index will not be recalculated for now, and the new line
7122 * will not be counted as a new header.
7123 */
Willy Tarreaua496b602006-12-17 23:15:24 +01007124
Willy Tarreaufa355d42009-11-29 18:12:29 +01007125 http_msg_move_end(&txn->req, delta);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007126 cur_end += delta;
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02007127 cur_end = (char *)http_parse_reqline(&txn->req,
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007128 HTTP_MSG_RQMETH,
7129 cur_ptr, cur_end + 1,
7130 NULL, NULL);
7131 if (unlikely(!cur_end))
7132 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01007133
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007134 /* we have a full request and we know that we have either a CR
7135 * or an LF at <ptr>.
7136 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01007137 txn->meth = find_http_meth(cur_ptr, txn->req.sl.rq.m_l);
7138 hdr_idx_set_start(&txn->hdr_idx, txn->req.sl.rq.l, *cur_end == '\r');
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007139 /* there is no point trying this regex on headers */
7140 return 1;
7141 }
7142 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007143 return done;
7144}
Willy Tarreau97de6242006-12-27 17:18:38 +01007145
Willy Tarreau58f10d72006-12-04 02:26:12 +01007146
Willy Tarreau58f10d72006-12-04 02:26:12 +01007147
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007148/*
Willy Tarreau87b09662015-04-03 00:22:06 +02007149 * Apply all the req filters of proxy <px> to all headers in buffer <req> of stream <s>.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007150 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
Willy Tarreaua15645d2007-03-18 16:22:39 +01007151 * unparsable request. Since it can manage the switch to another backend, it
7152 * updates the per-proxy DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007153 */
Willy Tarreau87b09662015-04-03 00:22:06 +02007154int apply_filters_to_request(struct stream *s, struct channel *req, struct proxy *px)
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007155{
Willy Tarreaueee5b512015-04-03 23:46:31 +02007156 struct http_txn *txn = s->txn;
Willy Tarreau6c123b12010-01-28 20:22:06 +01007157 struct hdr_exp *exp;
7158
7159 for (exp = px->req_exp; exp; exp = exp->next) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007160 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007161
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007162 /*
7163 * The interleaving of transformations and verdicts
7164 * makes it difficult to decide to continue or stop
7165 * the evaluation.
7166 */
7167
Willy Tarreau6c123b12010-01-28 20:22:06 +01007168 if (txn->flags & (TX_CLDENY|TX_CLTARPIT))
7169 break;
7170
Willy Tarreau3d300592007-03-18 18:34:41 +01007171 if ((txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007172 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
Willy Tarreau6c123b12010-01-28 20:22:06 +01007173 exp->action == ACT_TARPIT || exp->action == ACT_PASS))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007174 continue;
Willy Tarreau6c123b12010-01-28 20:22:06 +01007175
7176 /* if this filter had a condition, evaluate it now and skip to
7177 * next filter if the condition does not match.
7178 */
7179 if (exp->cond) {
Willy Tarreau15e91e12015-04-04 00:52:09 +02007180 ret = acl_exec_cond(exp->cond, px, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL);
Willy Tarreau6c123b12010-01-28 20:22:06 +01007181 ret = acl_pass(ret);
7182 if (((struct acl_cond *)exp->cond)->pol == ACL_COND_UNLESS)
7183 ret = !ret;
7184
7185 if (!ret)
7186 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007187 }
7188
7189 /* Apply the filter to the request line. */
Willy Tarreau6c123b12010-01-28 20:22:06 +01007190 ret = apply_filter_to_req_line(s, req, exp);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007191 if (unlikely(ret < 0))
7192 return -1;
7193
7194 if (likely(ret == 0)) {
7195 /* The filter did not match the request, it can be
7196 * iterated through all headers.
7197 */
Willy Tarreau34d4c3c2015-01-30 20:58:58 +01007198 if (unlikely(apply_filter_to_req_headers(s, req, exp) < 0))
7199 return -1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007200 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01007201 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007202 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007203}
7204
7205
Willy Tarreaua15645d2007-03-18 16:22:39 +01007206
Willy Tarreau58f10d72006-12-04 02:26:12 +01007207/*
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007208 * Try to retrieve the server associated to the appsession.
Willy Tarreau87b09662015-04-03 00:22:06 +02007209 * If the server is found, it's assigned to the stream.
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007210 */
Willy Tarreau87b09662015-04-03 00:22:06 +02007211void manage_client_side_appsession(struct stream *s, const char *buf, int len) {
Willy Tarreaueee5b512015-04-03 23:46:31 +02007212 struct http_txn *txn = s->txn;
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007213 appsess *asession = NULL;
7214 char *sessid_temp = NULL;
7215
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007216 if (len > s->be->appsession_len) {
7217 len = s->be->appsession_len;
Cyril Bontéb21570a2009-11-29 20:04:48 +01007218 }
7219
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007220 if (s->be->options2 & PR_O2_AS_REQL) {
Willy Tarreau87b09662015-04-03 00:22:06 +02007221 /* request-learn option is enabled : store the sessid in the stream for future use */
Willy Tarreaua3377ee2010-01-10 10:49:11 +01007222 if (txn->sessid != NULL) {
Willy Tarreau87b09662015-04-03 00:22:06 +02007223 /* free previously allocated memory as we don't need the stream id found in the URL anymore */
Willy Tarreaua3377ee2010-01-10 10:49:11 +01007224 pool_free2(apools.sessid, txn->sessid);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007225 }
7226
Willy Tarreaua3377ee2010-01-10 10:49:11 +01007227 if ((txn->sessid = pool_alloc2(apools.sessid)) == NULL) {
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007228 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007229 send_log(s->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007230 return;
7231 }
7232
Willy Tarreaua3377ee2010-01-10 10:49:11 +01007233 memcpy(txn->sessid, buf, len);
7234 txn->sessid[len] = 0;
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007235 }
7236
7237 if ((sessid_temp = pool_alloc2(apools.sessid)) == NULL) {
7238 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007239 send_log(s->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007240 return;
7241 }
7242
Cyril Bontéb21570a2009-11-29 20:04:48 +01007243 memcpy(sessid_temp, buf, len);
7244 sessid_temp[len] = 0;
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007245
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007246 asession = appsession_hash_lookup(&(s->be->htbl_proxy), sessid_temp);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007247 /* free previously allocated memory */
7248 pool_free2(apools.sessid, sessid_temp);
7249
7250 if (asession != NULL) {
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007251 asession->expire = tick_add_ifset(now_ms, s->be->timeout.appsession);
7252 if (!(s->be->options2 & PR_O2_AS_REQL))
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007253 asession->request_count++;
7254
7255 if (asession->serverid != NULL) {
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007256 struct server *srv = s->be->srv;
Cyril Bonté47fdd8e2010-04-25 00:00:51 +02007257
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007258 while (srv) {
7259 if (strcmp(srv->id, asession->serverid) == 0) {
Willy Tarreau892337c2014-05-13 23:41:20 +02007260 if ((srv->state != SRV_ST_STOPPED) ||
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007261 (s->be->options & PR_O_PERSIST) ||
Willy Tarreaue7dff022015-04-03 01:14:29 +02007262 (s->flags & SF_FORCE_PRST)) {
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007263 /* we found the server and it's usable */
7264 txn->flags &= ~TX_CK_MASK;
Willy Tarreau892337c2014-05-13 23:41:20 +02007265 txn->flags |= (srv->state != SRV_ST_STOPPED) ? TX_CK_VALID : TX_CK_DOWN;
Willy Tarreaue7dff022015-04-03 01:14:29 +02007266 s->flags |= SF_DIRECT | SF_ASSIGNED;
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007267 s->target = &srv->obj_type;
Willy Tarreau664beb82011-03-10 11:38:29 +01007268
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007269 break;
7270 } else {
7271 txn->flags &= ~TX_CK_MASK;
7272 txn->flags |= TX_CK_DOWN;
7273 }
7274 }
7275 srv = srv->next;
7276 }
7277 }
7278 }
7279}
7280
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007281/* Find the end of a cookie value contained between <s> and <e>. It works the
7282 * same way as with headers above except that the semi-colon also ends a token.
7283 * See RFC2965 for more information. Note that it requires a valid header to
7284 * return a valid result.
7285 */
7286char *find_cookie_value_end(char *s, const char *e)
7287{
7288 int quoted, qdpair;
7289
7290 quoted = qdpair = 0;
7291 for (; s < e; s++) {
7292 if (qdpair) qdpair = 0;
7293 else if (quoted) {
7294 if (*s == '\\') qdpair = 1;
7295 else if (*s == '"') quoted = 0;
7296 }
7297 else if (*s == '"') quoted = 1;
7298 else if (*s == ',' || *s == ';') return s;
7299 }
7300 return s;
7301}
7302
7303/* Delete a value in a header between delimiters <from> and <next> in buffer
7304 * <buf>. The number of characters displaced is returned, and the pointer to
7305 * the first delimiter is updated if required. The function tries as much as
7306 * possible to respect the following principles :
7307 * - replace <from> delimiter by the <next> one unless <from> points to a
7308 * colon, in which case <next> is simply removed
7309 * - set exactly one space character after the new first delimiter, unless
7310 * there are not enough characters in the block being moved to do so.
7311 * - remove unneeded spaces before the previous delimiter and after the new
7312 * one.
7313 *
7314 * It is the caller's responsibility to ensure that :
7315 * - <from> points to a valid delimiter or the colon ;
7316 * - <next> points to a valid delimiter or the final CR/LF ;
7317 * - there are non-space chars before <from> ;
7318 * - there is a CR/LF at or after <next>.
7319 */
Willy Tarreauaf819352012-08-27 22:08:00 +02007320int del_hdr_value(struct buffer *buf, char **from, char *next)
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007321{
7322 char *prev = *from;
7323
7324 if (*prev == ':') {
7325 /* We're removing the first value, preserve the colon and add a
7326 * space if possible.
7327 */
7328 if (!http_is_crlf[(unsigned char)*next])
7329 next++;
7330 prev++;
7331 if (prev < next)
7332 *prev++ = ' ';
7333
7334 while (http_is_spht[(unsigned char)*next])
7335 next++;
7336 } else {
7337 /* Remove useless spaces before the old delimiter. */
7338 while (http_is_spht[(unsigned char)*(prev-1)])
7339 prev--;
7340 *from = prev;
7341
7342 /* copy the delimiter and if possible a space if we're
7343 * not at the end of the line.
7344 */
7345 if (!http_is_crlf[(unsigned char)*next]) {
7346 *prev++ = *next++;
7347 if (prev + 1 < next)
7348 *prev++ = ' ';
7349 while (http_is_spht[(unsigned char)*next])
7350 next++;
7351 }
7352 }
7353 return buffer_replace2(buf, prev, next, NULL, 0);
7354}
7355
Cyril Bontébf47aeb2009-10-15 00:15:40 +02007356/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01007357 * Manage client-side cookie. It can impact performance by about 2% so it is
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007358 * desirable to call it only when needed. This code is quite complex because
7359 * of the multiple very crappy and ambiguous syntaxes we have to support. it
7360 * highly recommended not to touch this part without a good reason !
Willy Tarreau58f10d72006-12-04 02:26:12 +01007361 */
Willy Tarreau87b09662015-04-03 00:22:06 +02007362void manage_client_side_cookies(struct stream *s, struct channel *req)
Willy Tarreau58f10d72006-12-04 02:26:12 +01007363{
Willy Tarreaueee5b512015-04-03 23:46:31 +02007364 struct http_txn *txn = s->txn;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02007365 struct session *sess = s->sess;
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007366 int preserve_hdr;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01007367 int cur_idx, old_idx;
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007368 char *hdr_beg, *hdr_end, *hdr_next, *del_from;
7369 char *prev, *att_beg, *att_end, *equal, *val_beg, *val_end, *next;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007370
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007371 /* Iterate through the headers, we start with the start line. */
Willy Tarreau83969f42007-01-22 08:55:47 +01007372 old_idx = 0;
Willy Tarreau9b28e032012-10-12 23:49:43 +02007373 hdr_next = req->buf->p + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01007374
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01007375 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01007376 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01007377 int val;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007378
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01007379 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007380 hdr_beg = hdr_next;
7381 hdr_end = hdr_beg + cur_hdr->len;
7382 hdr_next = hdr_end + cur_hdr->cr + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007383
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007384 /* We have one full header between hdr_beg and hdr_end, and the
7385 * next header starts at hdr_next. We're only interested in
Willy Tarreau58f10d72006-12-04 02:26:12 +01007386 * "Cookie:" headers.
7387 */
7388
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007389 val = http_header_match2(hdr_beg, hdr_end, "Cookie", 6);
Willy Tarreauaa9dce32007-03-18 23:50:16 +01007390 if (!val) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01007391 old_idx = cur_idx;
7392 continue;
7393 }
7394
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007395 del_from = NULL; /* nothing to be deleted */
7396 preserve_hdr = 0; /* assume we may kill the whole header */
7397
Willy Tarreau58f10d72006-12-04 02:26:12 +01007398 /* Now look for cookies. Conforming to RFC2109, we have to support
7399 * attributes whose name begin with a '$', and associate them with
7400 * the right cookie, if we want to delete this cookie.
7401 * So there are 3 cases for each cookie read :
7402 * 1) it's a special attribute, beginning with a '$' : ignore it.
7403 * 2) it's a server id cookie that we *MAY* want to delete : save
7404 * some pointers on it (last semi-colon, beginning of cookie...)
7405 * 3) it's an application cookie : we *MAY* have to delete a previous
7406 * "special" cookie.
7407 * At the end of loop, if a "special" cookie remains, we may have to
7408 * remove it. If no application cookie persists in the header, we
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007409 * *MUST* delete it.
7410 *
7411 * Note: RFC2965 is unclear about the processing of spaces around
7412 * the equal sign in the ATTR=VALUE form. A careful inspection of
7413 * the RFC explicitly allows spaces before it, and not within the
7414 * tokens (attrs or values). An inspection of RFC2109 allows that
7415 * too but section 10.1.3 lets one think that spaces may be allowed
7416 * after the equal sign too, resulting in some (rare) buggy
7417 * implementations trying to do that. So let's do what servers do.
7418 * Latest ietf draft forbids spaces all around. Also, earlier RFCs
7419 * allowed quoted strings in values, with any possible character
7420 * after a backslash, including control chars and delimitors, which
7421 * causes parsing to become ambiguous. Browsers also allow spaces
7422 * within values even without quotes.
7423 *
7424 * We have to keep multiple pointers in order to support cookie
7425 * removal at the beginning, middle or end of header without
7426 * corrupting the header. All of these headers are valid :
7427 *
7428 * Cookie:NAME1=VALUE1;NAME2=VALUE2;NAME3=VALUE3\r\n
7429 * Cookie:NAME1=VALUE1;NAME2_ONLY ;NAME3=VALUE3\r\n
7430 * Cookie: NAME1 = VALUE 1 ; NAME2 = VALUE2 ; NAME3 = VALUE3\r\n
7431 * | | | | | | | | |
7432 * | | | | | | | | hdr_end <--+
7433 * | | | | | | | +--> next
7434 * | | | | | | +----> val_end
7435 * | | | | | +-----------> val_beg
7436 * | | | | +--------------> equal
7437 * | | | +----------------> att_end
7438 * | | +---------------------> att_beg
7439 * | +--------------------------> prev
7440 * +--------------------------------> hdr_beg
Willy Tarreau58f10d72006-12-04 02:26:12 +01007441 */
7442
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007443 for (prev = hdr_beg + 6; prev < hdr_end; prev = next) {
7444 /* Iterate through all cookies on this line */
7445
7446 /* find att_beg */
7447 att_beg = prev + 1;
7448 while (att_beg < hdr_end && http_is_spht[(unsigned char)*att_beg])
7449 att_beg++;
7450
7451 /* find att_end : this is the first character after the last non
7452 * space before the equal. It may be equal to hdr_end.
7453 */
7454 equal = att_end = att_beg;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007455
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007456 while (equal < hdr_end) {
7457 if (*equal == '=' || *equal == ',' || *equal == ';')
Willy Tarreau58f10d72006-12-04 02:26:12 +01007458 break;
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007459 if (http_is_spht[(unsigned char)*equal++])
7460 continue;
7461 att_end = equal;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007462 }
7463
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007464 /* here, <equal> points to '=', a delimitor or the end. <att_end>
7465 * is between <att_beg> and <equal>, both may be identical.
7466 */
7467
7468 /* look for end of cookie if there is an equal sign */
7469 if (equal < hdr_end && *equal == '=') {
7470 /* look for the beginning of the value */
7471 val_beg = equal + 1;
7472 while (val_beg < hdr_end && http_is_spht[(unsigned char)*val_beg])
7473 val_beg++;
7474
7475 /* find the end of the value, respecting quotes */
7476 next = find_cookie_value_end(val_beg, hdr_end);
7477
7478 /* make val_end point to the first white space or delimitor after the value */
7479 val_end = next;
7480 while (val_end > val_beg && http_is_spht[(unsigned char)*(val_end - 1)])
7481 val_end--;
7482 } else {
7483 val_beg = val_end = next = equal;
Willy Tarreau305ae852010-01-03 19:45:54 +01007484 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01007485
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007486 /* We have nothing to do with attributes beginning with '$'. However,
7487 * they will automatically be removed if a header before them is removed,
7488 * since they're supposed to be linked together.
7489 */
7490 if (*att_beg == '$')
7491 continue;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007492
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007493 /* Ignore cookies with no equal sign */
7494 if (equal == next) {
7495 /* This is not our cookie, so we must preserve it. But if we already
7496 * scheduled another cookie for removal, we cannot remove the
7497 * complete header, but we can remove the previous block itself.
7498 */
7499 preserve_hdr = 1;
7500 if (del_from != NULL) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02007501 int delta = del_hdr_value(req->buf, &del_from, prev);
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007502 val_end += delta;
7503 next += delta;
7504 hdr_end += delta;
7505 hdr_next += delta;
7506 cur_hdr->len += delta;
7507 http_msg_move_end(&txn->req, delta);
7508 prev = del_from;
7509 del_from = NULL;
7510 }
7511 continue;
Willy Tarreau305ae852010-01-03 19:45:54 +01007512 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01007513
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007514 /* if there are spaces around the equal sign, we need to
7515 * strip them otherwise we'll get trouble for cookie captures,
7516 * or even for rewrites. Since this happens extremely rarely,
7517 * it does not hurt performance.
Willy Tarreau58f10d72006-12-04 02:26:12 +01007518 */
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007519 if (unlikely(att_end != equal || val_beg > equal + 1)) {
7520 int stripped_before = 0;
7521 int stripped_after = 0;
7522
7523 if (att_end != equal) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02007524 stripped_before = buffer_replace2(req->buf, att_end, equal, NULL, 0);
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007525 equal += stripped_before;
7526 val_beg += stripped_before;
7527 }
7528
7529 if (val_beg > equal + 1) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02007530 stripped_after = buffer_replace2(req->buf, equal + 1, val_beg, NULL, 0);
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007531 val_beg += stripped_after;
7532 stripped_before += stripped_after;
7533 }
7534
7535 val_end += stripped_before;
7536 next += stripped_before;
7537 hdr_end += stripped_before;
7538 hdr_next += stripped_before;
7539 cur_hdr->len += stripped_before;
7540 http_msg_move_end(&txn->req, stripped_before);
Willy Tarreau58f10d72006-12-04 02:26:12 +01007541 }
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007542 /* now everything is as on the diagram above */
Willy Tarreau58f10d72006-12-04 02:26:12 +01007543
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007544 /* First, let's see if we want to capture this cookie. We check
7545 * that we don't already have a client side cookie, because we
7546 * can only capture one. Also as an optimisation, we ignore
7547 * cookies shorter than the declared name.
7548 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02007549 if (sess->fe->capture_name != NULL && txn->cli_cookie == NULL &&
7550 (val_end - att_beg >= sess->fe->capture_namelen) &&
7551 memcmp(att_beg, sess->fe->capture_name, sess->fe->capture_namelen) == 0) {
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007552 int log_len = val_end - att_beg;
7553
7554 if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) {
7555 Alert("HTTP logging : out of memory.\n");
7556 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02007557 if (log_len > sess->fe->capture_len)
7558 log_len = sess->fe->capture_len;
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007559 memcpy(txn->cli_cookie, att_beg, log_len);
7560 txn->cli_cookie[log_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007561 }
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007562 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01007563
Willy Tarreaubca99692010-10-06 19:25:55 +02007564 /* Persistence cookies in passive, rewrite or insert mode have the
7565 * following form :
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007566 *
Willy Tarreaubca99692010-10-06 19:25:55 +02007567 * Cookie: NAME=SRV[|<lastseen>[|<firstseen>]]
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007568 *
Willy Tarreaubca99692010-10-06 19:25:55 +02007569 * For cookies in prefix mode, the form is :
7570 *
7571 * Cookie: NAME=SRV~VALUE
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007572 */
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007573 if ((att_end - att_beg == s->be->cookie_len) && (s->be->cookie_name != NULL) &&
7574 (memcmp(att_beg, s->be->cookie_name, att_end - att_beg) == 0)) {
7575 struct server *srv = s->be->srv;
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007576 char *delim;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007577
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007578 /* if we're in cookie prefix mode, we'll search the delimitor so that we
7579 * have the server ID between val_beg and delim, and the original cookie between
7580 * delim+1 and val_end. Otherwise, delim==val_end :
7581 *
7582 * Cookie: NAME=SRV; # in all but prefix modes
7583 * Cookie: NAME=SRV~OPAQUE ; # in prefix mode
7584 * | || || | |+-> next
7585 * | || || | +--> val_end
7586 * | || || +---------> delim
7587 * | || |+------------> val_beg
7588 * | || +-------------> att_end = equal
7589 * | |+-----------------> att_beg
7590 * | +------------------> prev
7591 * +-------------------------> hdr_beg
7592 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01007593
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007594 if (s->be->ck_opts & PR_CK_PFX) {
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007595 for (delim = val_beg; delim < val_end; delim++)
7596 if (*delim == COOKIE_DELIM)
7597 break;
Willy Tarreaubca99692010-10-06 19:25:55 +02007598 } else {
7599 char *vbar1;
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007600 delim = val_end;
Willy Tarreaubca99692010-10-06 19:25:55 +02007601 /* Now check if the cookie contains a date field, which would
7602 * appear after a vertical bar ('|') just after the server name
7603 * and before the delimiter.
7604 */
7605 vbar1 = memchr(val_beg, COOKIE_DELIM_DATE, val_end - val_beg);
7606 if (vbar1) {
7607 /* OK, so left of the bar is the server's cookie and
Willy Tarreauf64d1412010-10-07 20:06:11 +02007608 * right is the last seen date. It is a base64 encoded
7609 * 30-bit value representing the UNIX date since the
7610 * epoch in 4-second quantities.
Willy Tarreaubca99692010-10-06 19:25:55 +02007611 */
Willy Tarreauf64d1412010-10-07 20:06:11 +02007612 int val;
Willy Tarreaubca99692010-10-06 19:25:55 +02007613 delim = vbar1++;
Willy Tarreauf64d1412010-10-07 20:06:11 +02007614 if (val_end - vbar1 >= 5) {
7615 val = b64tos30(vbar1);
7616 if (val > 0)
7617 txn->cookie_last_date = val << 2;
7618 }
7619 /* look for a second vertical bar */
7620 vbar1 = memchr(vbar1, COOKIE_DELIM_DATE, val_end - vbar1);
7621 if (vbar1 && (val_end - vbar1 > 5)) {
7622 val = b64tos30(vbar1 + 1);
7623 if (val > 0)
7624 txn->cookie_first_date = val << 2;
7625 }
Willy Tarreaubca99692010-10-06 19:25:55 +02007626 }
7627 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01007628
Willy Tarreauf64d1412010-10-07 20:06:11 +02007629 /* if the cookie has an expiration date and the proxy wants to check
7630 * it, then we do that now. We first check if the cookie is too old,
7631 * then only if it has expired. We detect strict overflow because the
7632 * time resolution here is not great (4 seconds). Cookies with dates
7633 * in the future are ignored if their offset is beyond one day. This
7634 * allows an admin to fix timezone issues without expiring everyone
7635 * and at the same time avoids keeping unwanted side effects for too
7636 * long.
7637 */
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007638 if (txn->cookie_first_date && s->be->cookie_maxlife &&
7639 (((signed)(date.tv_sec - txn->cookie_first_date) > (signed)s->be->cookie_maxlife) ||
Willy Tarreauef4f3912010-10-07 21:00:29 +02007640 ((signed)(txn->cookie_first_date - date.tv_sec) > 86400))) {
Willy Tarreauf64d1412010-10-07 20:06:11 +02007641 txn->flags &= ~TX_CK_MASK;
7642 txn->flags |= TX_CK_OLD;
7643 delim = val_beg; // let's pretend we have not found the cookie
7644 txn->cookie_first_date = 0;
7645 txn->cookie_last_date = 0;
7646 }
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007647 else if (txn->cookie_last_date && s->be->cookie_maxidle &&
7648 (((signed)(date.tv_sec - txn->cookie_last_date) > (signed)s->be->cookie_maxidle) ||
Willy Tarreauef4f3912010-10-07 21:00:29 +02007649 ((signed)(txn->cookie_last_date - date.tv_sec) > 86400))) {
Willy Tarreauf64d1412010-10-07 20:06:11 +02007650 txn->flags &= ~TX_CK_MASK;
7651 txn->flags |= TX_CK_EXPIRED;
7652 delim = val_beg; // let's pretend we have not found the cookie
7653 txn->cookie_first_date = 0;
7654 txn->cookie_last_date = 0;
7655 }
7656
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007657 /* Here, we'll look for the first running server which supports the cookie.
7658 * This allows to share a same cookie between several servers, for example
7659 * to dedicate backup servers to specific servers only.
7660 * However, to prevent clients from sticking to cookie-less backup server
7661 * when they have incidentely learned an empty cookie, we simply ignore
7662 * empty cookies and mark them as invalid.
7663 * The same behaviour is applied when persistence must be ignored.
7664 */
Willy Tarreaue7dff022015-04-03 01:14:29 +02007665 if ((delim == val_beg) || (s->flags & (SF_IGNORE_PRST | SF_ASSIGNED)))
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007666 srv = NULL;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007667
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007668 while (srv) {
7669 if (srv->cookie && (srv->cklen == delim - val_beg) &&
7670 !memcmp(val_beg, srv->cookie, delim - val_beg)) {
Willy Tarreau892337c2014-05-13 23:41:20 +02007671 if ((srv->state != SRV_ST_STOPPED) ||
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007672 (s->be->options & PR_O_PERSIST) ||
Willy Tarreaue7dff022015-04-03 01:14:29 +02007673 (s->flags & SF_FORCE_PRST)) {
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007674 /* we found the server and we can use it */
7675 txn->flags &= ~TX_CK_MASK;
Willy Tarreau892337c2014-05-13 23:41:20 +02007676 txn->flags |= (srv->state != SRV_ST_STOPPED) ? TX_CK_VALID : TX_CK_DOWN;
Willy Tarreaue7dff022015-04-03 01:14:29 +02007677 s->flags |= SF_DIRECT | SF_ASSIGNED;
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007678 s->target = &srv->obj_type;
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007679 break;
7680 } else {
7681 /* we found a server, but it's down,
7682 * mark it as such and go on in case
7683 * another one is available.
7684 */
7685 txn->flags &= ~TX_CK_MASK;
7686 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007687 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01007688 }
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007689 srv = srv->next;
7690 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01007691
Willy Tarreauf64d1412010-10-07 20:06:11 +02007692 if (!srv && !(txn->flags & (TX_CK_DOWN|TX_CK_EXPIRED|TX_CK_OLD))) {
Willy Tarreauc89ccb62012-04-05 21:18:22 +02007693 /* no server matched this cookie or we deliberately skipped it */
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007694 txn->flags &= ~TX_CK_MASK;
Willy Tarreaue7dff022015-04-03 01:14:29 +02007695 if ((s->flags & (SF_IGNORE_PRST | SF_ASSIGNED)))
Willy Tarreauc89ccb62012-04-05 21:18:22 +02007696 txn->flags |= TX_CK_UNUSED;
7697 else
7698 txn->flags |= TX_CK_INVALID;
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007699 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01007700
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007701 /* depending on the cookie mode, we may have to either :
7702 * - delete the complete cookie if we're in insert+indirect mode, so that
7703 * the server never sees it ;
7704 * - remove the server id from the cookie value, and tag the cookie as an
7705 * application cookie so that it does not get accidentely removed later,
7706 * if we're in cookie prefix mode
7707 */
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007708 if ((s->be->ck_opts & PR_CK_PFX) && (delim != val_end)) {
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007709 int delta; /* negative */
Willy Tarreau58f10d72006-12-04 02:26:12 +01007710
Willy Tarreau9b28e032012-10-12 23:49:43 +02007711 delta = buffer_replace2(req->buf, val_beg, delim + 1, NULL, 0);
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007712 val_end += delta;
7713 next += delta;
7714 hdr_end += delta;
7715 hdr_next += delta;
7716 cur_hdr->len += delta;
7717 http_msg_move_end(&txn->req, delta);
Willy Tarreau58f10d72006-12-04 02:26:12 +01007718
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007719 del_from = NULL;
7720 preserve_hdr = 1; /* we want to keep this cookie */
7721 }
7722 else if (del_from == NULL &&
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007723 (s->be->ck_opts & (PR_CK_INS | PR_CK_IND)) == (PR_CK_INS | PR_CK_IND)) {
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007724 del_from = prev;
7725 }
7726 } else {
7727 /* This is not our cookie, so we must preserve it. But if we already
7728 * scheduled another cookie for removal, we cannot remove the
7729 * complete header, but we can remove the previous block itself.
7730 */
7731 preserve_hdr = 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007732
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007733 if (del_from != NULL) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02007734 int delta = del_hdr_value(req->buf, &del_from, prev);
Willy Tarreaub8105542010-11-24 18:31:28 +01007735 if (att_beg >= del_from)
7736 att_beg += delta;
7737 if (att_end >= del_from)
7738 att_end += delta;
7739 val_beg += delta;
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007740 val_end += delta;
7741 next += delta;
7742 hdr_end += delta;
7743 hdr_next += delta;
7744 cur_hdr->len += delta;
7745 http_msg_move_end(&txn->req, delta);
7746 prev = del_from;
7747 del_from = NULL;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007748 }
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007749 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01007750
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007751 /* Look for the appsession cookie unless persistence must be ignored */
Willy Tarreaue7dff022015-04-03 01:14:29 +02007752 if (!(s->flags & SF_IGNORE_PRST) && (s->be->appsession_name != NULL)) {
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007753 int cmp_len, value_len;
7754 char *value_begin;
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02007755
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007756 if (s->be->options2 & PR_O2_AS_PFX) {
7757 cmp_len = MIN(val_end - att_beg, s->be->appsession_name_len);
7758 value_begin = att_beg + s->be->appsession_name_len;
7759 value_len = val_end - att_beg - s->be->appsession_name_len;
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007760 } else {
7761 cmp_len = att_end - att_beg;
7762 value_begin = val_beg;
7763 value_len = val_end - val_beg;
7764 }
Cyril Bontéb21570a2009-11-29 20:04:48 +01007765
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007766 /* let's see if the cookie is our appcookie */
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02007767 if (cmp_len == s->be->appsession_name_len &&
7768 memcmp(att_beg, s->be->appsession_name, cmp_len) == 0) {
7769 manage_client_side_appsession(s, value_begin, value_len);
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007770 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01007771 }
7772
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007773 /* continue with next cookie on this header line */
7774 att_beg = next;
7775 } /* for each cookie */
Willy Tarreau58f10d72006-12-04 02:26:12 +01007776
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007777 /* There are no more cookies on this line.
7778 * We may still have one (or several) marked for deletion at the
7779 * end of the line. We must do this now in two ways :
7780 * - if some cookies must be preserved, we only delete from the
7781 * mark to the end of line ;
7782 * - if nothing needs to be preserved, simply delete the whole header
Willy Tarreau58f10d72006-12-04 02:26:12 +01007783 */
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007784 if (del_from) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01007785 int delta;
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007786 if (preserve_hdr) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02007787 delta = del_hdr_value(req->buf, &del_from, hdr_end);
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007788 hdr_end = del_from;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007789 cur_hdr->len += delta;
7790 } else {
Willy Tarreau9b28e032012-10-12 23:49:43 +02007791 delta = buffer_replace2(req->buf, hdr_beg, hdr_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01007792
7793 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01007794 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
7795 txn->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007796 cur_hdr->len = 0;
Willy Tarreau26db59e2010-11-28 06:57:24 +01007797 cur_idx = old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01007798 }
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007799 hdr_next += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01007800 http_msg_move_end(&txn->req, delta);
Willy Tarreau58f10d72006-12-04 02:26:12 +01007801 }
7802
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007803 /* check next header */
Willy Tarreau58f10d72006-12-04 02:26:12 +01007804 old_idx = cur_idx;
Willy Tarreaueb7b0a22010-08-31 16:45:02 +02007805 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01007806}
7807
7808
Willy Tarreaua15645d2007-03-18 16:22:39 +01007809/* Iterate the same filter through all response headers contained in <rtr>.
7810 * Returns 1 if this filter can be stopped upon return, otherwise 0.
7811 */
Willy Tarreau87b09662015-04-03 00:22:06 +02007812int apply_filter_to_resp_headers(struct stream *s, struct channel *rtr, struct hdr_exp *exp)
Willy Tarreaua15645d2007-03-18 16:22:39 +01007813{
Willy Tarreaua15645d2007-03-18 16:22:39 +01007814 char *cur_ptr, *cur_end, *cur_next;
7815 int cur_idx, old_idx, last_hdr;
Willy Tarreaueee5b512015-04-03 23:46:31 +02007816 struct http_txn *txn = s->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01007817 struct hdr_idx_elem *cur_hdr;
Willy Tarreau19d14ef2012-10-29 16:51:55 +01007818 int delta;
Willy Tarreaua15645d2007-03-18 16:22:39 +01007819
7820 last_hdr = 0;
7821
Willy Tarreau9b28e032012-10-12 23:49:43 +02007822 cur_next = rtr->buf->p + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreaua15645d2007-03-18 16:22:39 +01007823 old_idx = 0;
7824
7825 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01007826 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01007827 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01007828 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01007829 (exp->action == ACT_ALLOW ||
7830 exp->action == ACT_DENY))
7831 return 0;
7832
7833 cur_idx = txn->hdr_idx.v[old_idx].next;
7834 if (!cur_idx)
7835 break;
7836
7837 cur_hdr = &txn->hdr_idx.v[cur_idx];
7838 cur_ptr = cur_next;
7839 cur_end = cur_ptr + cur_hdr->len;
7840 cur_next = cur_end + cur_hdr->cr + 1;
7841
7842 /* Now we have one header between cur_ptr and cur_end,
7843 * and the next header starts at cur_next.
7844 */
7845
Willy Tarreau15a53a42015-01-21 13:39:42 +01007846 if (regex_exec_match2(exp->preg, cur_ptr, cur_end-cur_ptr, MAX_MATCH, pmatch, 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01007847 switch (exp->action) {
7848 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01007849 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01007850 last_hdr = 1;
7851 break;
7852
7853 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01007854 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01007855 last_hdr = 1;
7856 break;
7857
7858 case ACT_REPLACE:
Sasha Pachevc6002042014-05-26 12:33:48 -06007859 trash.len = exp_replace(trash.str, trash.size, cur_ptr, exp->replace, pmatch);
7860 if (trash.len < 0)
7861 return -1;
7862
Willy Tarreau19d14ef2012-10-29 16:51:55 +01007863 delta = buffer_replace2(rtr->buf, cur_ptr, cur_end, trash.str, trash.len);
Willy Tarreaua15645d2007-03-18 16:22:39 +01007864 /* FIXME: if the user adds a newline in the replacement, the
7865 * index will not be recalculated for now, and the new line
7866 * will not be counted as a new header.
7867 */
7868
7869 cur_end += delta;
7870 cur_next += delta;
7871 cur_hdr->len += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01007872 http_msg_move_end(&txn->rsp, delta);
Willy Tarreaua15645d2007-03-18 16:22:39 +01007873 break;
7874
7875 case ACT_REMOVE:
Willy Tarreau9b28e032012-10-12 23:49:43 +02007876 delta = buffer_replace2(rtr->buf, cur_ptr, cur_next, NULL, 0);
Willy Tarreaua15645d2007-03-18 16:22:39 +01007877 cur_next += delta;
7878
Willy Tarreaufa355d42009-11-29 18:12:29 +01007879 http_msg_move_end(&txn->rsp, delta);
Willy Tarreaua15645d2007-03-18 16:22:39 +01007880 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
7881 txn->hdr_idx.used--;
7882 cur_hdr->len = 0;
7883 cur_end = NULL; /* null-term has been rewritten */
Willy Tarreau26db59e2010-11-28 06:57:24 +01007884 cur_idx = old_idx;
Willy Tarreaua15645d2007-03-18 16:22:39 +01007885 break;
7886
7887 }
7888 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01007889
7890 /* keep the link from this header to next one in case of later
7891 * removal of next header.
7892 */
7893 old_idx = cur_idx;
7894 }
7895 return 0;
7896}
7897
7898
7899/* Apply the filter to the status line in the response buffer <rtr>.
7900 * Returns 0 if nothing has been done, 1 if the filter has been applied,
7901 * or -1 if a replacement resulted in an invalid status line.
7902 */
Willy Tarreau87b09662015-04-03 00:22:06 +02007903int apply_filter_to_sts_line(struct stream *s, struct channel *rtr, struct hdr_exp *exp)
Willy Tarreaua15645d2007-03-18 16:22:39 +01007904{
Willy Tarreaua15645d2007-03-18 16:22:39 +01007905 char *cur_ptr, *cur_end;
7906 int done;
Willy Tarreaueee5b512015-04-03 23:46:31 +02007907 struct http_txn *txn = s->txn;
Willy Tarreau19d14ef2012-10-29 16:51:55 +01007908 int delta;
Willy Tarreaua15645d2007-03-18 16:22:39 +01007909
7910
Willy Tarreau3d300592007-03-18 18:34:41 +01007911 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01007912 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01007913 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01007914 (exp->action == ACT_ALLOW ||
7915 exp->action == ACT_DENY))
7916 return 0;
7917 else if (exp->action == ACT_REMOVE)
7918 return 0;
7919
7920 done = 0;
7921
Willy Tarreau9b28e032012-10-12 23:49:43 +02007922 cur_ptr = rtr->buf->p;
Willy Tarreau1ba0e5f2010-06-07 13:57:32 +02007923 cur_end = cur_ptr + txn->rsp.sl.st.l;
Willy Tarreaua15645d2007-03-18 16:22:39 +01007924
7925 /* Now we have the status line between cur_ptr and cur_end */
7926
Willy Tarreau15a53a42015-01-21 13:39:42 +01007927 if (regex_exec_match2(exp->preg, cur_ptr, cur_end-cur_ptr, MAX_MATCH, pmatch, 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01007928 switch (exp->action) {
7929 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01007930 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01007931 done = 1;
7932 break;
7933
7934 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01007935 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01007936 done = 1;
7937 break;
7938
7939 case ACT_REPLACE:
Sasha Pachevc6002042014-05-26 12:33:48 -06007940 trash.len = exp_replace(trash.str, trash.size, cur_ptr, exp->replace, pmatch);
7941 if (trash.len < 0)
7942 return -1;
7943
Willy Tarreau19d14ef2012-10-29 16:51:55 +01007944 delta = buffer_replace2(rtr->buf, cur_ptr, cur_end, trash.str, trash.len);
Willy Tarreaua15645d2007-03-18 16:22:39 +01007945 /* FIXME: if the user adds a newline in the replacement, the
7946 * index will not be recalculated for now, and the new line
7947 * will not be counted as a new header.
7948 */
7949
Willy Tarreaufa355d42009-11-29 18:12:29 +01007950 http_msg_move_end(&txn->rsp, delta);
Willy Tarreaua15645d2007-03-18 16:22:39 +01007951 cur_end += delta;
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02007952 cur_end = (char *)http_parse_stsline(&txn->rsp,
Willy Tarreau02785762007-04-03 14:45:44 +02007953 HTTP_MSG_RPVER,
Willy Tarreaua15645d2007-03-18 16:22:39 +01007954 cur_ptr, cur_end + 1,
7955 NULL, NULL);
7956 if (unlikely(!cur_end))
7957 return -1;
7958
7959 /* we have a full respnse and we know that we have either a CR
7960 * or an LF at <ptr>.
7961 */
Willy Tarreau9b28e032012-10-12 23:49:43 +02007962 txn->status = strl2ui(rtr->buf->p + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
Willy Tarreau1ba0e5f2010-06-07 13:57:32 +02007963 hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.st.l, *cur_end == '\r');
Willy Tarreaua15645d2007-03-18 16:22:39 +01007964 /* there is no point trying this regex on headers */
7965 return 1;
7966 }
7967 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01007968 return done;
7969}
7970
7971
7972
7973/*
Willy Tarreau87b09662015-04-03 00:22:06 +02007974 * Apply all the resp filters of proxy <px> to all headers in buffer <rtr> of stream <s>.
Willy Tarreaua15645d2007-03-18 16:22:39 +01007975 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
7976 * unparsable response.
7977 */
Willy Tarreau87b09662015-04-03 00:22:06 +02007978int apply_filters_to_response(struct stream *s, struct channel *rtr, struct proxy *px)
Willy Tarreaua15645d2007-03-18 16:22:39 +01007979{
Willy Tarreaueee5b512015-04-03 23:46:31 +02007980 struct http_txn *txn = s->txn;
Willy Tarreaufdb563c2010-01-31 15:43:27 +01007981 struct hdr_exp *exp;
7982
7983 for (exp = px->rsp_exp; exp; exp = exp->next) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01007984 int ret;
7985
7986 /*
7987 * The interleaving of transformations and verdicts
7988 * makes it difficult to decide to continue or stop
7989 * the evaluation.
7990 */
7991
Willy Tarreaufdb563c2010-01-31 15:43:27 +01007992 if (txn->flags & TX_SVDENY)
7993 break;
7994
Willy Tarreau3d300592007-03-18 18:34:41 +01007995 if ((txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01007996 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
7997 exp->action == ACT_PASS)) {
7998 exp = exp->next;
7999 continue;
8000 }
8001
Willy Tarreaufdb563c2010-01-31 15:43:27 +01008002 /* if this filter had a condition, evaluate it now and skip to
8003 * next filter if the condition does not match.
8004 */
8005 if (exp->cond) {
Willy Tarreau15e91e12015-04-04 00:52:09 +02008006 ret = acl_exec_cond(exp->cond, px, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL);
Willy Tarreaufdb563c2010-01-31 15:43:27 +01008007 ret = acl_pass(ret);
8008 if (((struct acl_cond *)exp->cond)->pol == ACL_COND_UNLESS)
8009 ret = !ret;
8010 if (!ret)
8011 continue;
8012 }
8013
Willy Tarreaua15645d2007-03-18 16:22:39 +01008014 /* Apply the filter to the status line. */
Willy Tarreaufdb563c2010-01-31 15:43:27 +01008015 ret = apply_filter_to_sts_line(s, rtr, exp);
Willy Tarreaua15645d2007-03-18 16:22:39 +01008016 if (unlikely(ret < 0))
8017 return -1;
8018
8019 if (likely(ret == 0)) {
8020 /* The filter did not match the response, it can be
8021 * iterated through all headers.
8022 */
Sasha Pachevc6002042014-05-26 12:33:48 -06008023 if (unlikely(apply_filter_to_resp_headers(s, rtr, exp) < 0))
8024 return -1;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008025 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01008026 }
8027 return 0;
8028}
8029
8030
Willy Tarreaua15645d2007-03-18 16:22:39 +01008031/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01008032 * Manage server-side cookies. It can impact performance by about 2% so it is
Willy Tarreau24581ba2010-08-31 22:39:35 +02008033 * desirable to call it only when needed. This function is also used when we
8034 * just need to know if there is a cookie (eg: for check-cache).
Willy Tarreaua15645d2007-03-18 16:22:39 +01008035 */
Willy Tarreau87b09662015-04-03 00:22:06 +02008036void manage_server_side_cookies(struct stream *s, struct channel *res)
Willy Tarreaua15645d2007-03-18 16:22:39 +01008037{
Willy Tarreaueee5b512015-04-03 23:46:31 +02008038 struct http_txn *txn = s->txn;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02008039 struct session *sess = s->sess;
Willy Tarreau827aee92011-03-10 16:55:02 +01008040 struct server *srv;
Willy Tarreau24581ba2010-08-31 22:39:35 +02008041 int is_cookie2;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008042 int cur_idx, old_idx, delta;
Willy Tarreau24581ba2010-08-31 22:39:35 +02008043 char *hdr_beg, *hdr_end, *hdr_next;
8044 char *prev, *att_beg, *att_end, *equal, *val_beg, *val_end, *next;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008045
Willy Tarreaua15645d2007-03-18 16:22:39 +01008046 /* Iterate through the headers.
8047 * we start with the start line.
8048 */
8049 old_idx = 0;
Willy Tarreau9b28e032012-10-12 23:49:43 +02008050 hdr_next = res->buf->p + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreaua15645d2007-03-18 16:22:39 +01008051
8052 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
8053 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01008054 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008055
8056 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau24581ba2010-08-31 22:39:35 +02008057 hdr_beg = hdr_next;
8058 hdr_end = hdr_beg + cur_hdr->len;
8059 hdr_next = hdr_end + cur_hdr->cr + 1;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008060
Willy Tarreau24581ba2010-08-31 22:39:35 +02008061 /* We have one full header between hdr_beg and hdr_end, and the
8062 * next header starts at hdr_next. We're only interested in
8063 * "Set-Cookie" and "Set-Cookie2" headers.
Willy Tarreaua15645d2007-03-18 16:22:39 +01008064 */
8065
Willy Tarreau24581ba2010-08-31 22:39:35 +02008066 is_cookie2 = 0;
8067 prev = hdr_beg + 10;
8068 val = http_header_match2(hdr_beg, hdr_end, "Set-Cookie", 10);
Willy Tarreauaa9dce32007-03-18 23:50:16 +01008069 if (!val) {
Willy Tarreau24581ba2010-08-31 22:39:35 +02008070 val = http_header_match2(hdr_beg, hdr_end, "Set-Cookie2", 11);
8071 if (!val) {
8072 old_idx = cur_idx;
8073 continue;
8074 }
8075 is_cookie2 = 1;
8076 prev = hdr_beg + 11;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008077 }
8078
Willy Tarreau24581ba2010-08-31 22:39:35 +02008079 /* OK, right now we know we have a Set-Cookie* at hdr_beg, and
8080 * <prev> points to the colon.
8081 */
Willy Tarreauf1348312010-10-07 15:54:11 +02008082 txn->flags |= TX_SCK_PRESENT;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008083
Willy Tarreau24581ba2010-08-31 22:39:35 +02008084 /* Maybe we only wanted to see if there was a Set-Cookie (eg:
8085 * check-cache is enabled) and we are not interested in checking
8086 * them. Warning, the cookie capture is declared in the frontend.
Willy Tarreaufd39dda2008-10-17 12:01:58 +02008087 */
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008088 if (s->be->cookie_name == NULL &&
8089 s->be->appsession_name == NULL &&
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02008090 sess->fe->capture_name == NULL)
Willy Tarreaua15645d2007-03-18 16:22:39 +01008091 return;
8092
Willy Tarreau24581ba2010-08-31 22:39:35 +02008093 /* OK so now we know we have to process this response cookie.
8094 * The format of the Set-Cookie header is slightly different
8095 * from the format of the Cookie header in that it does not
8096 * support the comma as a cookie delimiter (thus the header
8097 * cannot be folded) because the Expires attribute described in
8098 * the original Netscape's spec may contain an unquoted date
8099 * with a comma inside. We have to live with this because
8100 * many browsers don't support Max-Age and some browsers don't
8101 * support quoted strings. However the Set-Cookie2 header is
8102 * clean.
8103 *
8104 * We have to keep multiple pointers in order to support cookie
8105 * removal at the beginning, middle or end of header without
8106 * corrupting the header (in case of set-cookie2). A special
8107 * pointer, <scav> points to the beginning of the set-cookie-av
8108 * fields after the first semi-colon. The <next> pointer points
8109 * either to the end of line (set-cookie) or next unquoted comma
8110 * (set-cookie2). All of these headers are valid :
8111 *
8112 * Set-Cookie: NAME1 = VALUE 1 ; Secure; Path="/"\r\n
8113 * Set-Cookie:NAME=VALUE; Secure; Expires=Thu, 01-Jan-1970 00:00:01 GMT\r\n
8114 * Set-Cookie: NAME = VALUE ; Secure; Expires=Thu, 01-Jan-1970 00:00:01 GMT\r\n
8115 * Set-Cookie2: NAME1 = VALUE 1 ; Max-Age=0, NAME2=VALUE2; Discard\r\n
8116 * | | | | | | | | | |
8117 * | | | | | | | | +-> next hdr_end <--+
8118 * | | | | | | | +------------> scav
8119 * | | | | | | +--------------> val_end
8120 * | | | | | +--------------------> val_beg
8121 * | | | | +----------------------> equal
8122 * | | | +------------------------> att_end
8123 * | | +----------------------------> att_beg
8124 * | +------------------------------> prev
8125 * +-----------------------------------------> hdr_beg
8126 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01008127
Willy Tarreau24581ba2010-08-31 22:39:35 +02008128 for (; prev < hdr_end; prev = next) {
8129 /* Iterate through all cookies on this line */
Willy Tarreaua15645d2007-03-18 16:22:39 +01008130
Willy Tarreau24581ba2010-08-31 22:39:35 +02008131 /* find att_beg */
8132 att_beg = prev + 1;
8133 while (att_beg < hdr_end && http_is_spht[(unsigned char)*att_beg])
8134 att_beg++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008135
Willy Tarreau24581ba2010-08-31 22:39:35 +02008136 /* find att_end : this is the first character after the last non
8137 * space before the equal. It may be equal to hdr_end.
8138 */
8139 equal = att_end = att_beg;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008140
Willy Tarreau24581ba2010-08-31 22:39:35 +02008141 while (equal < hdr_end) {
8142 if (*equal == '=' || *equal == ';' || (is_cookie2 && *equal == ','))
8143 break;
8144 if (http_is_spht[(unsigned char)*equal++])
8145 continue;
8146 att_end = equal;
8147 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01008148
Willy Tarreau24581ba2010-08-31 22:39:35 +02008149 /* here, <equal> points to '=', a delimitor or the end. <att_end>
8150 * is between <att_beg> and <equal>, both may be identical.
8151 */
8152
8153 /* look for end of cookie if there is an equal sign */
8154 if (equal < hdr_end && *equal == '=') {
8155 /* look for the beginning of the value */
8156 val_beg = equal + 1;
8157 while (val_beg < hdr_end && http_is_spht[(unsigned char)*val_beg])
8158 val_beg++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008159
Willy Tarreau24581ba2010-08-31 22:39:35 +02008160 /* find the end of the value, respecting quotes */
8161 next = find_cookie_value_end(val_beg, hdr_end);
8162
8163 /* make val_end point to the first white space or delimitor after the value */
8164 val_end = next;
8165 while (val_end > val_beg && http_is_spht[(unsigned char)*(val_end - 1)])
8166 val_end--;
8167 } else {
8168 /* <equal> points to next comma, semi-colon or EOL */
8169 val_beg = val_end = next = equal;
8170 }
8171
8172 if (next < hdr_end) {
8173 /* Set-Cookie2 supports multiple cookies, and <next> points to
8174 * a colon or semi-colon before the end. So skip all attr-value
8175 * pairs and look for the next comma. For Set-Cookie, since
8176 * commas are permitted in values, skip to the end.
8177 */
8178 if (is_cookie2)
8179 next = find_hdr_value_end(next, hdr_end);
8180 else
8181 next = hdr_end;
8182 }
8183
8184 /* Now everything is as on the diagram above */
8185
8186 /* Ignore cookies with no equal sign */
8187 if (equal == val_end)
8188 continue;
8189
8190 /* If there are spaces around the equal sign, we need to
8191 * strip them otherwise we'll get trouble for cookie captures,
8192 * or even for rewrites. Since this happens extremely rarely,
8193 * it does not hurt performance.
Willy Tarreaua15645d2007-03-18 16:22:39 +01008194 */
Willy Tarreau24581ba2010-08-31 22:39:35 +02008195 if (unlikely(att_end != equal || val_beg > equal + 1)) {
8196 int stripped_before = 0;
8197 int stripped_after = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008198
Willy Tarreau24581ba2010-08-31 22:39:35 +02008199 if (att_end != equal) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02008200 stripped_before = buffer_replace2(res->buf, att_end, equal, NULL, 0);
Willy Tarreau24581ba2010-08-31 22:39:35 +02008201 equal += stripped_before;
8202 val_beg += stripped_before;
8203 }
8204
8205 if (val_beg > equal + 1) {
Willy Tarreau9b28e032012-10-12 23:49:43 +02008206 stripped_after = buffer_replace2(res->buf, equal + 1, val_beg, NULL, 0);
Willy Tarreau24581ba2010-08-31 22:39:35 +02008207 val_beg += stripped_after;
8208 stripped_before += stripped_after;
8209 }
8210
8211 val_end += stripped_before;
8212 next += stripped_before;
8213 hdr_end += stripped_before;
8214 hdr_next += stripped_before;
8215 cur_hdr->len += stripped_before;
Willy Tarreau1fc1f452011-04-07 22:35:37 +02008216 http_msg_move_end(&txn->rsp, stripped_before);
Willy Tarreau24581ba2010-08-31 22:39:35 +02008217 }
8218
8219 /* First, let's see if we want to capture this cookie. We check
8220 * that we don't already have a server side cookie, because we
8221 * can only capture one. Also as an optimisation, we ignore
8222 * cookies shorter than the declared name.
8223 */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02008224 if (sess->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01008225 txn->srv_cookie == NULL &&
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02008226 (val_end - att_beg >= sess->fe->capture_namelen) &&
8227 memcmp(att_beg, sess->fe->capture_name, sess->fe->capture_namelen) == 0) {
Willy Tarreau24581ba2010-08-31 22:39:35 +02008228 int log_len = val_end - att_beg;
Willy Tarreau086b3b42007-05-13 21:45:51 +02008229 if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01008230 Alert("HTTP logging : out of memory.\n");
8231 }
Willy Tarreauf70fc752010-11-19 11:27:18 +01008232 else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02008233 if (log_len > sess->fe->capture_len)
8234 log_len = sess->fe->capture_len;
Willy Tarreauf70fc752010-11-19 11:27:18 +01008235 memcpy(txn->srv_cookie, att_beg, log_len);
8236 txn->srv_cookie[log_len] = 0;
8237 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01008238 }
8239
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008240 srv = objt_server(s->target);
Willy Tarreaua15645d2007-03-18 16:22:39 +01008241 /* now check if we need to process it for persistence */
Willy Tarreaue7dff022015-04-03 01:14:29 +02008242 if (!(s->flags & SF_IGNORE_PRST) &&
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008243 (att_end - att_beg == s->be->cookie_len) && (s->be->cookie_name != NULL) &&
8244 (memcmp(att_beg, s->be->cookie_name, att_end - att_beg) == 0)) {
Willy Tarreauf1348312010-10-07 15:54:11 +02008245 /* assume passive cookie by default */
8246 txn->flags &= ~TX_SCK_MASK;
8247 txn->flags |= TX_SCK_FOUND;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008248
8249 /* If the cookie is in insert mode on a known server, we'll delete
8250 * this occurrence because we'll insert another one later.
8251 * We'll delete it too if the "indirect" option is set and we're in
Willy Tarreau24581ba2010-08-31 22:39:35 +02008252 * a direct access.
8253 */
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008254 if (s->be->ck_opts & PR_CK_PSV) {
Willy Tarreauba4c5be2010-10-23 12:46:42 +02008255 /* The "preserve" flag was set, we don't want to touch the
8256 * server's cookie.
8257 */
8258 }
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008259 else if ((srv && (s->be->ck_opts & PR_CK_INS)) ||
Willy Tarreaue7dff022015-04-03 01:14:29 +02008260 ((s->flags & SF_DIRECT) && (s->be->ck_opts & PR_CK_IND))) {
Willy Tarreau24581ba2010-08-31 22:39:35 +02008261 /* this cookie must be deleted */
8262 if (*prev == ':' && next == hdr_end) {
8263 /* whole header */
Willy Tarreau9b28e032012-10-12 23:49:43 +02008264 delta = buffer_replace2(res->buf, hdr_beg, hdr_next, NULL, 0);
Willy Tarreau24581ba2010-08-31 22:39:35 +02008265 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
8266 txn->hdr_idx.used--;
8267 cur_hdr->len = 0;
Willy Tarreau26db59e2010-11-28 06:57:24 +01008268 cur_idx = old_idx;
Willy Tarreau24581ba2010-08-31 22:39:35 +02008269 hdr_next += delta;
8270 http_msg_move_end(&txn->rsp, delta);
8271 /* note: while both invalid now, <next> and <hdr_end>
8272 * are still equal, so the for() will stop as expected.
8273 */
8274 } else {
8275 /* just remove the value */
Willy Tarreau9b28e032012-10-12 23:49:43 +02008276 int delta = del_hdr_value(res->buf, &prev, next);
Willy Tarreau24581ba2010-08-31 22:39:35 +02008277 next = prev;
8278 hdr_end += delta;
8279 hdr_next += delta;
8280 cur_hdr->len += delta;
8281 http_msg_move_end(&txn->rsp, delta);
8282 }
Willy Tarreauf1348312010-10-07 15:54:11 +02008283 txn->flags &= ~TX_SCK_MASK;
Willy Tarreau3d300592007-03-18 18:34:41 +01008284 txn->flags |= TX_SCK_DELETED;
Willy Tarreau24581ba2010-08-31 22:39:35 +02008285 /* and go on with next cookie */
Willy Tarreaua15645d2007-03-18 16:22:39 +01008286 }
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008287 else if (srv && srv->cookie && (s->be->ck_opts & PR_CK_RW)) {
Willy Tarreau24581ba2010-08-31 22:39:35 +02008288 /* replace bytes val_beg->val_end with the cookie name associated
Willy Tarreaua15645d2007-03-18 16:22:39 +01008289 * with this server since we know it.
8290 */
Willy Tarreau9b28e032012-10-12 23:49:43 +02008291 delta = buffer_replace2(res->buf, val_beg, val_end, srv->cookie, srv->cklen);
Willy Tarreau24581ba2010-08-31 22:39:35 +02008292 next += delta;
8293 hdr_end += delta;
8294 hdr_next += delta;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008295 cur_hdr->len += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01008296 http_msg_move_end(&txn->rsp, delta);
Willy Tarreaua15645d2007-03-18 16:22:39 +01008297
Willy Tarreauf1348312010-10-07 15:54:11 +02008298 txn->flags &= ~TX_SCK_MASK;
8299 txn->flags |= TX_SCK_REPLACED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008300 }
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008301 else if (srv && srv->cookie && (s->be->ck_opts & PR_CK_PFX)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01008302 /* insert the cookie name associated with this server
Willy Tarreau24581ba2010-08-31 22:39:35 +02008303 * before existing cookie, and insert a delimiter between them..
Willy Tarreaua15645d2007-03-18 16:22:39 +01008304 */
Willy Tarreau9b28e032012-10-12 23:49:43 +02008305 delta = buffer_replace2(res->buf, val_beg, val_beg, srv->cookie, srv->cklen + 1);
Willy Tarreau24581ba2010-08-31 22:39:35 +02008306 next += delta;
8307 hdr_end += delta;
8308 hdr_next += delta;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008309 cur_hdr->len += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01008310 http_msg_move_end(&txn->rsp, delta);
Willy Tarreaua15645d2007-03-18 16:22:39 +01008311
Willy Tarreau827aee92011-03-10 16:55:02 +01008312 val_beg[srv->cklen] = COOKIE_DELIM;
Willy Tarreauf1348312010-10-07 15:54:11 +02008313 txn->flags &= ~TX_SCK_MASK;
8314 txn->flags |= TX_SCK_REPLACED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008315 }
8316 }
Cyril Bonté47fdd8e2010-04-25 00:00:51 +02008317 /* next, let's see if the cookie is our appcookie, unless persistence must be ignored */
Willy Tarreaue7dff022015-04-03 01:14:29 +02008318 else if (!(s->flags & SF_IGNORE_PRST) && (s->be->appsession_name != NULL)) {
Cyril Bontéb21570a2009-11-29 20:04:48 +01008319 int cmp_len, value_len;
8320 char *value_begin;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008321
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008322 if (s->be->options2 & PR_O2_AS_PFX) {
8323 cmp_len = MIN(val_end - att_beg, s->be->appsession_name_len);
8324 value_begin = att_beg + s->be->appsession_name_len;
8325 value_len = MIN(s->be->appsession_len, val_end - att_beg - s->be->appsession_name_len);
Cyril Bontéb21570a2009-11-29 20:04:48 +01008326 } else {
Willy Tarreau24581ba2010-08-31 22:39:35 +02008327 cmp_len = att_end - att_beg;
8328 value_begin = val_beg;
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008329 value_len = MIN(s->be->appsession_len, val_end - val_beg);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008330 }
Cyril Bontéb21570a2009-11-29 20:04:48 +01008331
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008332 if ((cmp_len == s->be->appsession_name_len) &&
8333 (memcmp(att_beg, s->be->appsession_name, s->be->appsession_name_len) == 0)) {
Willy Tarreau24581ba2010-08-31 22:39:35 +02008334 /* free a possibly previously allocated memory */
8335 pool_free2(apools.sessid, txn->sessid);
8336
Willy Tarreau87b09662015-04-03 00:22:06 +02008337 /* Store the sessid in the stream for future use */
Willy Tarreaua3377ee2010-01-10 10:49:11 +01008338 if ((txn->sessid = pool_alloc2(apools.sessid)) == NULL) {
Cyril Bontéb21570a2009-11-29 20:04:48 +01008339 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008340 send_log(s->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
Cyril Bontéb21570a2009-11-29 20:04:48 +01008341 return;
8342 }
Willy Tarreaua3377ee2010-01-10 10:49:11 +01008343 memcpy(txn->sessid, value_begin, value_len);
8344 txn->sessid[value_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008345 }
Willy Tarreau24581ba2010-08-31 22:39:35 +02008346 }
8347 /* that's done for this cookie, check the next one on the same
8348 * line when next != hdr_end (only if is_cookie2).
8349 */
8350 }
8351 /* check next header */
Willy Tarreaua15645d2007-03-18 16:22:39 +01008352 old_idx = cur_idx;
Willy Tarreau24581ba2010-08-31 22:39:35 +02008353 }
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008354
Willy Tarreaua3377ee2010-01-10 10:49:11 +01008355 if (txn->sessid != NULL) {
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008356 appsess *asession = NULL;
8357 /* only do insert, if lookup fails */
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008358 asession = appsession_hash_lookup(&(s->be->htbl_proxy), txn->sessid);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008359 if (asession == NULL) {
Willy Tarreau1fac7532010-01-09 19:23:06 +01008360 size_t server_id_len;
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008361 if ((asession = pool_alloc2(pool2_appsess)) == NULL) {
8362 Alert("Not enough Memory process_srv():asession:calloc().\n");
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008363 send_log(s->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008364 return;
8365 }
Willy Tarreau77eb9b82010-11-19 11:29:06 +01008366 asession->serverid = NULL; /* to avoid a double free in case of allocation error */
8367
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008368 if ((asession->sessid = pool_alloc2(apools.sessid)) == NULL) {
8369 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008370 send_log(s->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
8371 s->be->htbl_proxy.destroy(asession);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008372 return;
8373 }
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008374 memcpy(asession->sessid, txn->sessid, s->be->appsession_len);
8375 asession->sessid[s->be->appsession_len] = 0;
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008376
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008377 server_id_len = strlen(objt_server(s->target)->id) + 1;
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008378 if ((asession->serverid = pool_alloc2(apools.serverid)) == NULL) {
Willy Tarreau77eb9b82010-11-19 11:29:06 +01008379 Alert("Not enough Memory process_srv():asession->serverid:malloc().\n");
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008380 send_log(s->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
8381 s->be->htbl_proxy.destroy(asession);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008382 return;
8383 }
8384 asession->serverid[0] = '\0';
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008385 memcpy(asession->serverid, objt_server(s->target)->id, server_id_len);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008386
8387 asession->request_count = 0;
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008388 appsession_hash_insert(&(s->be->htbl_proxy), asession);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008389 }
8390
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008391 asession->expire = tick_add_ifset(now_ms, s->be->timeout.appsession);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02008392 asession->request_count++;
8393 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01008394}
8395
8396
Willy Tarreaua15645d2007-03-18 16:22:39 +01008397/*
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008398 * Check if response is cacheable or not. Updates s->flags.
Willy Tarreaua15645d2007-03-18 16:22:39 +01008399 */
Willy Tarreau87b09662015-04-03 00:22:06 +02008400void check_response_for_cacheability(struct stream *s, struct channel *rtr)
Willy Tarreaua15645d2007-03-18 16:22:39 +01008401{
Willy Tarreaueee5b512015-04-03 23:46:31 +02008402 struct http_txn *txn = s->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008403 char *p1, *p2;
8404
8405 char *cur_ptr, *cur_end, *cur_next;
8406 int cur_idx;
8407
Willy Tarreau5df51872007-11-25 16:20:08 +01008408 if (!(txn->flags & TX_CACHEABLE))
Willy Tarreaua15645d2007-03-18 16:22:39 +01008409 return;
8410
8411 /* Iterate through the headers.
8412 * we start with the start line.
8413 */
8414 cur_idx = 0;
Willy Tarreau9b28e032012-10-12 23:49:43 +02008415 cur_next = rtr->buf->p + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreaua15645d2007-03-18 16:22:39 +01008416
8417 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
8418 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01008419 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008420
8421 cur_hdr = &txn->hdr_idx.v[cur_idx];
8422 cur_ptr = cur_next;
8423 cur_end = cur_ptr + cur_hdr->len;
8424 cur_next = cur_end + cur_hdr->cr + 1;
8425
8426 /* We have one full header between cur_ptr and cur_end, and the
8427 * next header starts at cur_next. We're only interested in
8428 * "Cookie:" headers.
8429 */
8430
Willy Tarreauaa9dce32007-03-18 23:50:16 +01008431 val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
8432 if (val) {
8433 if ((cur_end - (cur_ptr + val) >= 8) &&
8434 strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
8435 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
8436 return;
8437 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01008438 }
8439
Willy Tarreauaa9dce32007-03-18 23:50:16 +01008440 val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
8441 if (!val)
Willy Tarreaua15645d2007-03-18 16:22:39 +01008442 continue;
8443
8444 /* OK, right now we know we have a cache-control header at cur_ptr */
8445
Willy Tarreauaa9dce32007-03-18 23:50:16 +01008446 p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01008447
8448 if (p1 >= cur_end) /* no more info */
8449 continue;
8450
8451 /* p1 is at the beginning of the value */
8452 p2 = p1;
8453
Willy Tarreau8f8e6452007-06-17 21:51:38 +02008454 while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((unsigned char)*p2))
Willy Tarreaua15645d2007-03-18 16:22:39 +01008455 p2++;
8456
8457 /* we have a complete value between p1 and p2 */
8458 if (p2 < cur_end && *p2 == '=') {
8459 /* we have something of the form no-cache="set-cookie" */
8460 if ((cur_end - p1 >= 21) &&
8461 strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0
8462 && (p1[20] == '"' || p1[20] == ','))
Willy Tarreau3d300592007-03-18 18:34:41 +01008463 txn->flags &= ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008464 continue;
8465 }
8466
8467 /* OK, so we know that either p2 points to the end of string or to a comma */
8468 if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) ||
Willy Tarreau5b15f902013-07-04 12:46:56 +02008469 ((p2 - p1 == 8) && strncasecmp(p1, "no-cache", 8) == 0) ||
Willy Tarreaua15645d2007-03-18 16:22:39 +01008470 ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) ||
8471 ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) ||
8472 ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) {
Willy Tarreau3d300592007-03-18 18:34:41 +01008473 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008474 return;
8475 }
8476
8477 if ((p2 - p1 == 6) && strncasecmp(p1, "public", 6) == 0) {
Willy Tarreau3d300592007-03-18 18:34:41 +01008478 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01008479 continue;
8480 }
8481 }
8482}
8483
8484
Willy Tarreau58f10d72006-12-04 02:26:12 +01008485/*
8486 * Try to retrieve a known appsession in the URI, then the associated server.
Willy Tarreau87b09662015-04-03 00:22:06 +02008487 * If the server is found, it's assigned to the stream.
Willy Tarreau58f10d72006-12-04 02:26:12 +01008488 */
Willy Tarreau87b09662015-04-03 00:22:06 +02008489void get_srv_from_appsession(struct stream *s, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01008490{
Cyril Bontéb21570a2009-11-29 20:04:48 +01008491 char *end_params, *first_param, *cur_param, *next_param;
8492 char separator;
8493 int value_len;
8494
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008495 int mode = s->be->options2 & PR_O2_AS_M_ANY;
Willy Tarreau58f10d72006-12-04 02:26:12 +01008496
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008497 if (s->be->appsession_name == NULL ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02008498 (s->txn->meth != HTTP_METH_GET && s->txn->meth != HTTP_METH_POST && s->txn->meth != HTTP_METH_HEAD)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01008499 return;
Cyril Bontéb21570a2009-11-29 20:04:48 +01008500 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01008501
Cyril Bontéb21570a2009-11-29 20:04:48 +01008502 first_param = NULL;
8503 switch (mode) {
8504 case PR_O2_AS_M_PP:
8505 first_param = memchr(begin, ';', len);
8506 break;
8507 case PR_O2_AS_M_QS:
8508 first_param = memchr(begin, '?', len);
8509 break;
8510 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01008511
Cyril Bontéb21570a2009-11-29 20:04:48 +01008512 if (first_param == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01008513 return;
Cyril Bontéb21570a2009-11-29 20:04:48 +01008514 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01008515
Cyril Bontéb21570a2009-11-29 20:04:48 +01008516 switch (mode) {
8517 case PR_O2_AS_M_PP:
8518 if ((end_params = memchr(first_param, '?', len - (begin - first_param))) == NULL) {
8519 end_params = (char *) begin + len;
8520 }
8521 separator = ';';
8522 break;
8523 case PR_O2_AS_M_QS:
8524 end_params = (char *) begin + len;
8525 separator = '&';
8526 break;
8527 default:
8528 /* unknown mode, shouldn't happen */
8529 return;
8530 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01008531
Cyril Bontéb21570a2009-11-29 20:04:48 +01008532 cur_param = next_param = end_params;
8533 while (cur_param > first_param) {
8534 cur_param--;
8535 if ((cur_param[0] == separator) || (cur_param == first_param)) {
8536 /* let's see if this is the appsession parameter */
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008537 if ((cur_param + s->be->appsession_name_len + 1 < next_param) &&
8538 ((s->be->options2 & PR_O2_AS_PFX) || cur_param[s->be->appsession_name_len + 1] == '=') &&
8539 (strncasecmp(cur_param + 1, s->be->appsession_name, s->be->appsession_name_len) == 0)) {
Cyril Bontéb21570a2009-11-29 20:04:48 +01008540 /* Cool... it's the right one */
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008541 cur_param += s->be->appsession_name_len + (s->be->options2 & PR_O2_AS_PFX ? 1 : 2);
8542 value_len = MIN(s->be->appsession_len, next_param - cur_param);
Cyril Bontéb21570a2009-11-29 20:04:48 +01008543 if (value_len > 0) {
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008544 manage_client_side_appsession(s, cur_param, value_len);
Cyril Bontéb21570a2009-11-29 20:04:48 +01008545 }
8546 break;
8547 }
8548 next_param = cur_param;
8549 }
8550 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01008551#if defined(DEBUG_HASH)
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02008552 Alert("get_srv_from_appsession\n");
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008553 appsession_hash_dump(&(s->be->htbl_proxy));
Willy Tarreau58f10d72006-12-04 02:26:12 +01008554#endif
Willy Tarreau58f10d72006-12-04 02:26:12 +01008555}
8556
Willy Tarreaub2513902006-12-17 14:52:38 +01008557/*
Cyril Bonté70be45d2010-10-12 00:14:35 +02008558 * In a GET, HEAD or POST request, check if the requested URI matches the stats uri
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01008559 * for the current backend.
Willy Tarreaub2513902006-12-17 14:52:38 +01008560 *
Cyril Bonté70be45d2010-10-12 00:14:35 +02008561 * It is assumed that the request is either a HEAD, GET, or POST and that the
Willy Tarreau295a8372011-03-10 11:25:07 +01008562 * uri_auth field is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01008563 *
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01008564 * Returns 1 if stats should be provided, otherwise 0.
Willy Tarreaub2513902006-12-17 14:52:38 +01008565 */
Willy Tarreau295a8372011-03-10 11:25:07 +01008566int stats_check_uri(struct stream_interface *si, struct http_txn *txn, struct proxy *backend)
Willy Tarreaub2513902006-12-17 14:52:38 +01008567{
8568 struct uri_auth *uri_auth = backend->uri_auth;
Willy Tarreau3a215be2012-03-09 21:39:51 +01008569 struct http_msg *msg = &txn->req;
Willy Tarreau9b28e032012-10-12 23:49:43 +02008570 const char *uri = msg->chn->buf->p+ msg->sl.rq.u;
Willy Tarreaub2513902006-12-17 14:52:38 +01008571
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01008572 if (!uri_auth)
8573 return 0;
8574
Cyril Bonté70be45d2010-10-12 00:14:35 +02008575 if (txn->meth != HTTP_METH_GET && txn->meth != HTTP_METH_HEAD && txn->meth != HTTP_METH_POST)
Krzysztof Piotr Oledzki8c8bd452010-01-29 19:29:32 +01008576 return 0;
8577
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01008578 /* check URI size */
Willy Tarreau3a215be2012-03-09 21:39:51 +01008579 if (uri_auth->uri_len > msg->sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01008580 return 0;
8581
Willy Tarreau414e9bb2013-11-23 00:30:38 +01008582 if (memcmp(uri, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01008583 return 0;
8584
Willy Tarreaub2513902006-12-17 14:52:38 +01008585 return 1;
8586}
8587
Willy Tarreau4076a152009-04-02 15:18:36 +02008588/*
8589 * Capture a bad request or response and archive it in the proxy's structure.
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02008590 * By default it tries to report the error position as msg->err_pos. However if
8591 * this one is not set, it will then report msg->next, which is the last known
8592 * parsing point. The function is able to deal with wrapping buffers. It always
Willy Tarreaucdbdd522012-10-12 22:51:15 +02008593 * displays buffers as a contiguous area starting at buf->p.
Willy Tarreau4076a152009-04-02 15:18:36 +02008594 */
Willy Tarreau87b09662015-04-03 00:22:06 +02008595void http_capture_bad_message(struct error_snapshot *es, struct stream *s,
Willy Tarreau8a0cef22012-03-09 13:39:23 +01008596 struct http_msg *msg,
Willy Tarreau3770f232013-12-07 00:01:53 +01008597 enum ht_state state, struct proxy *other_end)
Willy Tarreau4076a152009-04-02 15:18:36 +02008598{
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02008599 struct session *sess = strm_sess(s);
Willy Tarreaucdbdd522012-10-12 22:51:15 +02008600 struct channel *chn = msg->chn;
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02008601 int len1, len2;
Willy Tarreau8a0cef22012-03-09 13:39:23 +01008602
Willy Tarreau9b28e032012-10-12 23:49:43 +02008603 es->len = MIN(chn->buf->i, sizeof(es->buf));
8604 len1 = chn->buf->data + chn->buf->size - chn->buf->p;
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02008605 len1 = MIN(len1, es->len);
8606 len2 = es->len - len1; /* remaining data if buffer wraps */
8607
Willy Tarreau9b28e032012-10-12 23:49:43 +02008608 memcpy(es->buf, chn->buf->p, len1);
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02008609 if (len2)
Willy Tarreau9b28e032012-10-12 23:49:43 +02008610 memcpy(es->buf + len1, chn->buf->data, len2);
Willy Tarreau81f2fb92010-12-12 13:09:08 +01008611
Willy Tarreau4076a152009-04-02 15:18:36 +02008612 if (msg->err_pos >= 0)
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02008613 es->pos = msg->err_pos;
Willy Tarreau81f2fb92010-12-12 13:09:08 +01008614 else
Willy Tarreau69d8c5d2012-05-08 09:44:41 +02008615 es->pos = msg->next;
Willy Tarreau81f2fb92010-12-12 13:09:08 +01008616
Willy Tarreau4076a152009-04-02 15:18:36 +02008617 es->when = date; // user-visible date
8618 es->sid = s->uniq_id;
Willy Tarreau3fdb3662012-11-12 00:42:33 +01008619 es->srv = objt_server(s->target);
Willy Tarreau4076a152009-04-02 15:18:36 +02008620 es->oe = other_end;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02008621 if (objt_conn(sess->origin))
8622 es->src = __objt_conn(sess->origin)->addr.from;
Willy Tarreaub363a1f2013-10-01 10:45:07 +02008623 else
8624 memset(&es->src, 0, sizeof(es->src));
8625
Willy Tarreau078272e2010-12-12 12:46:33 +01008626 es->state = state;
Willy Tarreau10479e42010-12-12 14:00:34 +01008627 es->ev_id = error_snapshot_id++;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02008628 es->b_flags = chn->flags;
Willy Tarreaud04b1bc2012-05-08 11:03:10 +02008629 es->s_flags = s->flags;
Willy Tarreaueee5b512015-04-03 23:46:31 +02008630 es->t_flags = s->txn->flags;
Willy Tarreaud04b1bc2012-05-08 11:03:10 +02008631 es->m_flags = msg->flags;
Willy Tarreau9b28e032012-10-12 23:49:43 +02008632 es->b_out = chn->buf->o;
8633 es->b_wrap = chn->buf->data + chn->buf->size - chn->buf->p;
Willy Tarreaucdbdd522012-10-12 22:51:15 +02008634 es->b_tot = chn->total;
Willy Tarreaud04b1bc2012-05-08 11:03:10 +02008635 es->m_clen = msg->chunk_len;
8636 es->m_blen = msg->body_len;
Willy Tarreau4076a152009-04-02 15:18:36 +02008637}
Willy Tarreaub2513902006-12-17 14:52:38 +01008638
Willy Tarreau294c4732011-12-16 21:35:50 +01008639/* Return in <vptr> and <vlen> the pointer and length of occurrence <occ> of
8640 * header whose name is <hname> of length <hlen>. If <ctx> is null, lookup is
8641 * performed over the whole headers. Otherwise it must contain a valid header
8642 * context, initialised with ctx->idx=0 for the first lookup in a series. If
8643 * <occ> is positive or null, occurrence #occ from the beginning (or last ctx)
8644 * is returned. Occ #0 and #1 are equivalent. If <occ> is negative (and no less
8645 * than -MAX_HDR_HISTORY), the occurrence is counted from the last one which is
Willy Tarreau04ff9f12013-06-10 18:39:42 +02008646 * -1. The value fetch stops at commas, so this function is suited for use with
8647 * list headers.
Willy Tarreau294c4732011-12-16 21:35:50 +01008648 * The return value is 0 if nothing was found, or non-zero otherwise.
Willy Tarreaubce70882009-09-07 11:51:47 +02008649 */
Willy Tarreau185b5c42012-04-26 15:11:51 +02008650unsigned int http_get_hdr(const struct http_msg *msg, const char *hname, int hlen,
Willy Tarreau294c4732011-12-16 21:35:50 +01008651 struct hdr_idx *idx, int occ,
8652 struct hdr_ctx *ctx, char **vptr, int *vlen)
Willy Tarreaubce70882009-09-07 11:51:47 +02008653{
Willy Tarreau294c4732011-12-16 21:35:50 +01008654 struct hdr_ctx local_ctx;
8655 char *ptr_hist[MAX_HDR_HISTORY];
8656 int len_hist[MAX_HDR_HISTORY];
Willy Tarreaubce70882009-09-07 11:51:47 +02008657 unsigned int hist_ptr;
Willy Tarreau294c4732011-12-16 21:35:50 +01008658 int found;
Willy Tarreaubce70882009-09-07 11:51:47 +02008659
Willy Tarreau294c4732011-12-16 21:35:50 +01008660 if (!ctx) {
8661 local_ctx.idx = 0;
8662 ctx = &local_ctx;
8663 }
8664
Willy Tarreaubce70882009-09-07 11:51:47 +02008665 if (occ >= 0) {
Willy Tarreau294c4732011-12-16 21:35:50 +01008666 /* search from the beginning */
Willy Tarreau9b28e032012-10-12 23:49:43 +02008667 while (http_find_header2(hname, hlen, msg->chn->buf->p, idx, ctx)) {
Willy Tarreaubce70882009-09-07 11:51:47 +02008668 occ--;
8669 if (occ <= 0) {
Willy Tarreau294c4732011-12-16 21:35:50 +01008670 *vptr = ctx->line + ctx->val;
8671 *vlen = ctx->vlen;
8672 return 1;
Willy Tarreaubce70882009-09-07 11:51:47 +02008673 }
8674 }
Willy Tarreau294c4732011-12-16 21:35:50 +01008675 return 0;
Willy Tarreaubce70882009-09-07 11:51:47 +02008676 }
8677
8678 /* negative occurrence, we scan all the list then walk back */
8679 if (-occ > MAX_HDR_HISTORY)
8680 return 0;
8681
Willy Tarreau294c4732011-12-16 21:35:50 +01008682 found = hist_ptr = 0;
Willy Tarreau9b28e032012-10-12 23:49:43 +02008683 while (http_find_header2(hname, hlen, msg->chn->buf->p, idx, ctx)) {
Willy Tarreau294c4732011-12-16 21:35:50 +01008684 ptr_hist[hist_ptr] = ctx->line + ctx->val;
8685 len_hist[hist_ptr] = ctx->vlen;
8686 if (++hist_ptr >= MAX_HDR_HISTORY)
Willy Tarreaubce70882009-09-07 11:51:47 +02008687 hist_ptr = 0;
8688 found++;
8689 }
8690 if (-occ > found)
8691 return 0;
8692 /* OK now we have the last occurrence in [hist_ptr-1], and we need to
Willy Tarreau67dad272013-06-12 22:27:44 +02008693 * find occurrence -occ. 0 <= hist_ptr < MAX_HDR_HISTORY, and we have
8694 * -10 <= occ <= -1. So we have to check [hist_ptr%MAX_HDR_HISTORY+occ]
8695 * to remain in the 0..9 range.
Willy Tarreaubce70882009-09-07 11:51:47 +02008696 */
Willy Tarreau67dad272013-06-12 22:27:44 +02008697 hist_ptr += occ + MAX_HDR_HISTORY;
Willy Tarreaubce70882009-09-07 11:51:47 +02008698 if (hist_ptr >= MAX_HDR_HISTORY)
8699 hist_ptr -= MAX_HDR_HISTORY;
Willy Tarreau294c4732011-12-16 21:35:50 +01008700 *vptr = ptr_hist[hist_ptr];
8701 *vlen = len_hist[hist_ptr];
8702 return 1;
Willy Tarreaubce70882009-09-07 11:51:47 +02008703}
8704
Willy Tarreau04ff9f12013-06-10 18:39:42 +02008705/* Return in <vptr> and <vlen> the pointer and length of occurrence <occ> of
8706 * header whose name is <hname> of length <hlen>. If <ctx> is null, lookup is
8707 * performed over the whole headers. Otherwise it must contain a valid header
8708 * context, initialised with ctx->idx=0 for the first lookup in a series. If
8709 * <occ> is positive or null, occurrence #occ from the beginning (or last ctx)
8710 * is returned. Occ #0 and #1 are equivalent. If <occ> is negative (and no less
8711 * than -MAX_HDR_HISTORY), the occurrence is counted from the last one which is
8712 * -1. This function differs from http_get_hdr() in that it only returns full
8713 * line header values and does not stop at commas.
8714 * The return value is 0 if nothing was found, or non-zero otherwise.
8715 */
8716unsigned int http_get_fhdr(const struct http_msg *msg, const char *hname, int hlen,
8717 struct hdr_idx *idx, int occ,
8718 struct hdr_ctx *ctx, char **vptr, int *vlen)
8719{
8720 struct hdr_ctx local_ctx;
8721 char *ptr_hist[MAX_HDR_HISTORY];
8722 int len_hist[MAX_HDR_HISTORY];
8723 unsigned int hist_ptr;
8724 int found;
8725
8726 if (!ctx) {
8727 local_ctx.idx = 0;
8728 ctx = &local_ctx;
8729 }
8730
8731 if (occ >= 0) {
8732 /* search from the beginning */
8733 while (http_find_full_header2(hname, hlen, msg->chn->buf->p, idx, ctx)) {
8734 occ--;
8735 if (occ <= 0) {
8736 *vptr = ctx->line + ctx->val;
8737 *vlen = ctx->vlen;
8738 return 1;
8739 }
8740 }
8741 return 0;
8742 }
8743
8744 /* negative occurrence, we scan all the list then walk back */
8745 if (-occ > MAX_HDR_HISTORY)
8746 return 0;
8747
8748 found = hist_ptr = 0;
8749 while (http_find_full_header2(hname, hlen, msg->chn->buf->p, idx, ctx)) {
8750 ptr_hist[hist_ptr] = ctx->line + ctx->val;
8751 len_hist[hist_ptr] = ctx->vlen;
8752 if (++hist_ptr >= MAX_HDR_HISTORY)
8753 hist_ptr = 0;
8754 found++;
8755 }
8756 if (-occ > found)
8757 return 0;
8758 /* OK now we have the last occurrence in [hist_ptr-1], and we need to
8759 * find occurrence -occ, so we have to check [hist_ptr+occ].
8760 */
8761 hist_ptr += occ;
8762 if (hist_ptr >= MAX_HDR_HISTORY)
8763 hist_ptr -= MAX_HDR_HISTORY;
8764 *vptr = ptr_hist[hist_ptr];
8765 *vlen = len_hist[hist_ptr];
8766 return 1;
8767}
8768
Willy Tarreaubaaee002006-06-26 02:48:02 +02008769/*
Willy Tarreaue92693a2012-09-24 21:13:39 +02008770 * Print a debug line with a header. Always stop at the first CR or LF char,
8771 * so it is safe to pass it a full buffer if needed. If <err> is not NULL, an
8772 * arrow is printed after the line which contains the pointer.
Willy Tarreau58f10d72006-12-04 02:26:12 +01008773 */
Willy Tarreau87b09662015-04-03 00:22:06 +02008774void debug_hdr(const char *dir, struct stream *s, const char *start, const char *end)
Willy Tarreau58f10d72006-12-04 02:26:12 +01008775{
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02008776 struct session *sess = strm_sess(s);
Willy Tarreau19d14ef2012-10-29 16:51:55 +01008777 int max;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02008778
Willy Tarreauf1fd9dc2014-04-24 20:47:57 +02008779 chunk_printf(&trash, "%08x:%s.%s[%04x:%04x]: ", s->uniq_id, s->be->id,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02008780 dir,
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02008781 objt_conn(sess->origin) ? (unsigned short)objt_conn(sess->origin)->t.sock.fd : -1,
Willy Tarreau350f4872014-11-28 14:42:25 +01008782 objt_conn(s->si[1].end) ? (unsigned short)objt_conn(s->si[1].end)->t.sock.fd : -1);
Willy Tarreaue92693a2012-09-24 21:13:39 +02008783
8784 for (max = 0; start + max < end; max++)
8785 if (start[max] == '\r' || start[max] == '\n')
8786 break;
8787
Willy Tarreau19d14ef2012-10-29 16:51:55 +01008788 UBOUND(max, trash.size - trash.len - 3);
8789 trash.len += strlcpy2(trash.str + trash.len, start, max + 1);
8790 trash.str[trash.len++] = '\n';
Willy Tarreau89efaed2013-12-13 15:14:55 +01008791 shut_your_big_mouth_gcc(write(1, trash.str, trash.len));
Willy Tarreau58f10d72006-12-04 02:26:12 +01008792}
8793
Willy Tarreaueee5b512015-04-03 23:46:31 +02008794
8795/* Allocate a new HTTP transaction for stream <s> unless there is one already.
8796 * The hdr_idx is allocated as well. In case of allocation failure, everything
8797 * allocated is freed and NULL is returned. Otherwise the new transaction is
8798 * assigned to the stream and returned.
8799 */
8800struct http_txn *http_alloc_txn(struct stream *s)
8801{
8802 struct http_txn *txn = s->txn;
8803
8804 if (txn)
8805 return txn;
8806
8807 txn = pool_alloc2(pool2_http_txn);
8808 if (!txn)
8809 return txn;
8810
8811 txn->hdr_idx.size = global.tune.max_http_hdr;
8812 txn->hdr_idx.v = pool_alloc2(pool2_hdr_idx);
8813 if (!txn->hdr_idx.v) {
8814 pool_free2(pool2_http_txn, txn);
8815 return NULL;
8816 }
8817
8818 s->txn = txn;
8819 return txn;
8820}
8821
Willy Tarreau0937bc42009-12-22 15:03:09 +01008822/*
Willy Tarreau87b09662015-04-03 00:22:06 +02008823 * Initialize a new HTTP transaction for stream <s>. It is assumed that all
Willy Tarreau0937bc42009-12-22 15:03:09 +01008824 * the required fields are properly allocated and that we only need to (re)init
8825 * them. This should be used before processing any new request.
8826 */
Willy Tarreau87b09662015-04-03 00:22:06 +02008827void http_init_txn(struct stream *s)
Willy Tarreau0937bc42009-12-22 15:03:09 +01008828{
Willy Tarreaueee5b512015-04-03 23:46:31 +02008829 struct http_txn *txn = s->txn;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02008830 struct proxy *fe = strm_sess(s)->fe;
Willy Tarreau0937bc42009-12-22 15:03:09 +01008831
8832 txn->flags = 0;
8833 txn->status = -1;
8834
Willy Tarreauf64d1412010-10-07 20:06:11 +02008835 txn->cookie_first_date = 0;
8836 txn->cookie_last_date = 0;
8837
Willy Tarreaueee5b512015-04-03 23:46:31 +02008838 txn->sessid = NULL;
8839 txn->srv_cookie = NULL;
8840 txn->cli_cookie = NULL;
8841 txn->uri = NULL;
8842
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01008843 txn->req.flags = 0;
Willy Tarreau26927362012-05-18 23:22:52 +02008844 txn->req.sol = txn->req.eol = txn->req.eoh = 0; /* relative to the buffer */
Willy Tarreaua458b672012-03-05 11:17:50 +01008845 txn->req.next = 0;
Willy Tarreaua36fc4d2012-02-17 17:39:37 +01008846 txn->rsp.flags = 0;
Willy Tarreau26927362012-05-18 23:22:52 +02008847 txn->rsp.sol = txn->rsp.eol = txn->rsp.eoh = 0; /* relative to the buffer */
Willy Tarreaua458b672012-03-05 11:17:50 +01008848 txn->rsp.next = 0;
Willy Tarreau124d9912011-03-01 20:30:48 +01008849 txn->req.chunk_len = 0LL;
8850 txn->req.body_len = 0LL;
8851 txn->rsp.chunk_len = 0LL;
8852 txn->rsp.body_len = 0LL;
Willy Tarreau0937bc42009-12-22 15:03:09 +01008853 txn->req.msg_state = HTTP_MSG_RQBEFORE; /* at the very beginning of the request */
8854 txn->rsp.msg_state = HTTP_MSG_RPBEFORE; /* at the very beginning of the response */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01008855 txn->req.chn = &s->req;
8856 txn->rsp.chn = &s->res;
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01008857
8858 txn->auth.method = HTTP_AUTH_UNKNOWN;
Willy Tarreau0937bc42009-12-22 15:03:09 +01008859
8860 txn->req.err_pos = txn->rsp.err_pos = -2; /* block buggy requests/responses */
8861 if (fe->options2 & PR_O2_REQBUG_OK)
8862 txn->req.err_pos = -1; /* let buggy requests pass */
8863
Willy Tarreau0937bc42009-12-22 15:03:09 +01008864 if (txn->hdr_idx.v)
8865 hdr_idx_init(&txn->hdr_idx);
8866}
8867
8868/* to be used at the end of a transaction */
Willy Tarreau87b09662015-04-03 00:22:06 +02008869void http_end_txn(struct stream *s)
Willy Tarreau0937bc42009-12-22 15:03:09 +01008870{
Willy Tarreaueee5b512015-04-03 23:46:31 +02008871 struct http_txn *txn = s->txn;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02008872 struct proxy *fe = strm_sess(s)->fe;
Willy Tarreau0937bc42009-12-22 15:03:09 +01008873
Willy Tarreau75195602014-03-11 15:48:55 +01008874 /* release any possible compression context */
Willy Tarreaue7dff022015-04-03 01:14:29 +02008875 if (s->flags & SF_COMP_READY)
Willy Tarreau75195602014-03-11 15:48:55 +01008876 s->comp_algo->end(&s->comp_ctx);
8877 s->comp_algo = NULL;
Willy Tarreaue7dff022015-04-03 01:14:29 +02008878 s->flags &= ~SF_COMP_READY;
Willy Tarreau75195602014-03-11 15:48:55 +01008879
Willy Tarreau0937bc42009-12-22 15:03:09 +01008880 /* these ones will have been dynamically allocated */
8881 pool_free2(pool2_requri, txn->uri);
8882 pool_free2(pool2_capture, txn->cli_cookie);
8883 pool_free2(pool2_capture, txn->srv_cookie);
Willy Tarreaua3377ee2010-01-10 10:49:11 +01008884 pool_free2(apools.sessid, txn->sessid);
William Lallemanda73203e2012-03-12 12:48:57 +01008885 pool_free2(pool2_uniqueid, s->unique_id);
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +01008886
William Lallemanda73203e2012-03-12 12:48:57 +01008887 s->unique_id = NULL;
Willy Tarreaua3377ee2010-01-10 10:49:11 +01008888 txn->sessid = NULL;
Willy Tarreau0937bc42009-12-22 15:03:09 +01008889 txn->uri = NULL;
8890 txn->srv_cookie = NULL;
8891 txn->cli_cookie = NULL;
Willy Tarreau46023632010-01-07 22:51:47 +01008892
Willy Tarreaucb7dd012015-04-03 22:16:32 +02008893 if (s->req_cap) {
Willy Tarreau46023632010-01-07 22:51:47 +01008894 struct cap_hdr *h;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02008895 for (h = fe->req_cap; h; h = h->next)
Willy Tarreaucb7dd012015-04-03 22:16:32 +02008896 pool_free2(h->pool, s->req_cap[h->index]);
8897 memset(s->req_cap, 0, fe->nb_req_cap * sizeof(void *));
Willy Tarreau46023632010-01-07 22:51:47 +01008898 }
8899
Willy Tarreaucb7dd012015-04-03 22:16:32 +02008900 if (s->res_cap) {
Willy Tarreau46023632010-01-07 22:51:47 +01008901 struct cap_hdr *h;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02008902 for (h = fe->rsp_cap; h; h = h->next)
Willy Tarreaucb7dd012015-04-03 22:16:32 +02008903 pool_free2(h->pool, s->res_cap[h->index]);
8904 memset(s->res_cap, 0, fe->nb_rsp_cap * sizeof(void *));
Willy Tarreau46023632010-01-07 22:51:47 +01008905 }
8906
Willy Tarreau0937bc42009-12-22 15:03:09 +01008907}
8908
8909/* to be used at the end of a transaction to prepare a new one */
Willy Tarreau87b09662015-04-03 00:22:06 +02008910void http_reset_txn(struct stream *s)
Willy Tarreau0937bc42009-12-22 15:03:09 +01008911{
8912 http_end_txn(s);
8913 http_init_txn(s);
8914
Thierry FOURNIERbc4c1ac2015-02-25 13:36:14 +01008915 /* reinitialise the current rule list pointer to NULL. We are sure that
8916 * any rulelist match the NULL pointer.
8917 */
8918 s->current_rule_list = NULL;
8919
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02008920 s->be = strm_sess(s)->fe;
8921 s->logs.logwait = strm_sess(s)->fe->to_log;
Willy Tarreauabcd5142013-06-11 17:18:02 +02008922 s->logs.level = 0;
Willy Tarreau87b09662015-04-03 00:22:06 +02008923 stream_del_srv_conn(s);
Willy Tarreau3fdb3662012-11-12 00:42:33 +01008924 s->target = NULL;
Emeric Brunb982a3d2010-01-04 15:45:53 +01008925 /* re-init store persistence */
8926 s->store_count = 0;
Willy Tarreau1f0da242014-01-25 11:01:50 +01008927 s->uniq_id = global.req_count++;
Emeric Brunb982a3d2010-01-04 15:45:53 +01008928
Willy Tarreau0937bc42009-12-22 15:03:09 +01008929 s->pend_pos = NULL;
Willy Tarreau0937bc42009-12-22 15:03:09 +01008930
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01008931 s->req.flags |= CF_READ_DONTWAIT; /* one read is usually enough */
Willy Tarreau0937bc42009-12-22 15:03:09 +01008932
Willy Tarreau739cfba2010-01-25 23:11:14 +01008933 /* We must trim any excess data from the response buffer, because we
8934 * may have blocked an invalid response from a server that we don't
8935 * want to accidentely forward once we disable the analysers, nor do
8936 * we want those data to come along with next response. A typical
8937 * example of such data would be from a buggy server responding to
8938 * a HEAD with some data, or sending more than the advertised
8939 * content-length.
8940 */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01008941 if (unlikely(s->res.buf->i))
8942 s->res.buf->i = 0;
Willy Tarreau739cfba2010-01-25 23:11:14 +01008943
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02008944 s->req.rto = strm_sess(s)->fe->timeout.client;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01008945 s->req.wto = TICK_ETERNITY;
Willy Tarreau0937bc42009-12-22 15:03:09 +01008946
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01008947 s->res.rto = TICK_ETERNITY;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02008948 s->res.wto = strm_sess(s)->fe->timeout.client;
Willy Tarreau0937bc42009-12-22 15:03:09 +01008949
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01008950 s->req.rex = TICK_ETERNITY;
8951 s->req.wex = TICK_ETERNITY;
8952 s->req.analyse_exp = TICK_ETERNITY;
8953 s->res.rex = TICK_ETERNITY;
8954 s->res.wex = TICK_ETERNITY;
8955 s->res.analyse_exp = TICK_ETERNITY;
Willy Tarreau0937bc42009-12-22 15:03:09 +01008956}
Willy Tarreau58f10d72006-12-04 02:26:12 +01008957
Sasha Pachev218f0642014-06-16 12:05:59 -06008958void free_http_res_rules(struct list *r)
8959{
8960 struct http_res_rule *tr, *pr;
8961
8962 list_for_each_entry_safe(pr, tr, r, list) {
8963 LIST_DEL(&pr->list);
Thierry FOURNIER09af0d62014-06-18 11:35:54 +02008964 regex_free(&pr->arg.hdr_add.re);
Sasha Pachev218f0642014-06-16 12:05:59 -06008965 free(pr);
8966 }
8967}
8968
8969void free_http_req_rules(struct list *r)
8970{
Willy Tarreauff011f22011-01-06 17:51:27 +01008971 struct http_req_rule *tr, *pr;
8972
8973 list_for_each_entry_safe(pr, tr, r, list) {
8974 LIST_DEL(&pr->list);
Willy Tarreau20b0de52012-12-24 15:45:22 +01008975 if (pr->action == HTTP_REQ_ACT_AUTH)
Willy Tarreau5c2e1982012-12-24 12:00:25 +01008976 free(pr->arg.auth.realm);
Willy Tarreauff011f22011-01-06 17:51:27 +01008977
Thierry FOURNIER09af0d62014-06-18 11:35:54 +02008978 regex_free(&pr->arg.hdr_add.re);
Willy Tarreauff011f22011-01-06 17:51:27 +01008979 free(pr);
8980 }
8981}
8982
Willy Tarreaue365c0b2013-06-11 16:06:12 +02008983/* parse an "http-request" rule */
Willy Tarreauff011f22011-01-06 17:51:27 +01008984struct http_req_rule *parse_http_req_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
8985{
8986 struct http_req_rule *rule;
William Lallemand73025dd2014-04-24 14:38:37 +02008987 struct http_req_action_kw *custom = NULL;
Willy Tarreauff011f22011-01-06 17:51:27 +01008988 int cur_arg;
Thierry FOURNIER09af0d62014-06-18 11:35:54 +02008989 char *error;
Willy Tarreauff011f22011-01-06 17:51:27 +01008990
8991 rule = (struct http_req_rule*)calloc(1, sizeof(struct http_req_rule));
8992 if (!rule) {
8993 Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
Willy Tarreau81499eb2012-12-27 12:19:02 +01008994 goto out_err;
Willy Tarreauff011f22011-01-06 17:51:27 +01008995 }
8996
Willy Tarreau5c2e1982012-12-24 12:00:25 +01008997 if (!strcmp(args[0], "allow")) {
Willy Tarreauff011f22011-01-06 17:51:27 +01008998 rule->action = HTTP_REQ_ACT_ALLOW;
8999 cur_arg = 1;
Willy Tarreau5bd67592014-04-28 22:00:46 +02009000 } else if (!strcmp(args[0], "deny") || !strcmp(args[0], "block")) {
Willy Tarreauff011f22011-01-06 17:51:27 +01009001 rule->action = HTTP_REQ_ACT_DENY;
9002 cur_arg = 1;
Willy Tarreauccbcc372012-12-27 12:37:57 +01009003 } else if (!strcmp(args[0], "tarpit")) {
9004 rule->action = HTTP_REQ_ACT_TARPIT;
9005 cur_arg = 1;
Willy Tarreauff011f22011-01-06 17:51:27 +01009006 } else if (!strcmp(args[0], "auth")) {
Willy Tarreau20b0de52012-12-24 15:45:22 +01009007 rule->action = HTTP_REQ_ACT_AUTH;
Willy Tarreauff011f22011-01-06 17:51:27 +01009008 cur_arg = 1;
9009
9010 while(*args[cur_arg]) {
9011 if (!strcmp(args[cur_arg], "realm")) {
Willy Tarreau5c2e1982012-12-24 12:00:25 +01009012 rule->arg.auth.realm = strdup(args[cur_arg + 1]);
Willy Tarreauff011f22011-01-06 17:51:27 +01009013 cur_arg+=2;
9014 continue;
9015 } else
9016 break;
9017 }
Willy Tarreauf4c43c12013-06-11 17:01:13 +02009018 } else if (!strcmp(args[0], "set-nice")) {
9019 rule->action = HTTP_REQ_ACT_SET_NICE;
9020 cur_arg = 1;
9021
9022 if (!*args[cur_arg] ||
9023 (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
9024 Alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (integer value).\n",
9025 file, linenum, args[0]);
9026 goto out_err;
9027 }
9028 rule->arg.nice = atoi(args[cur_arg]);
9029 if (rule->arg.nice < -1024)
9030 rule->arg.nice = -1024;
9031 else if (rule->arg.nice > 1024)
9032 rule->arg.nice = 1024;
9033 cur_arg++;
Willy Tarreau42cf39e2013-06-11 18:51:32 +02009034 } else if (!strcmp(args[0], "set-tos")) {
9035#ifdef IP_TOS
9036 char *err;
9037 rule->action = HTTP_REQ_ACT_SET_TOS;
9038 cur_arg = 1;
9039
9040 if (!*args[cur_arg] ||
9041 (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
9042 Alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (integer/hex value).\n",
9043 file, linenum, args[0]);
9044 goto out_err;
9045 }
9046
9047 rule->arg.tos = strtol(args[cur_arg], &err, 0);
9048 if (err && *err != '\0') {
9049 Alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-request %s' (integer/hex value expected).\n",
9050 file, linenum, err, args[0]);
9051 goto out_err;
9052 }
9053 cur_arg++;
9054#else
9055 Alert("parsing [%s:%d]: 'http-request %s' is not supported on this platform (IP_TOS undefined).\n", file, linenum, args[0]);
9056 goto out_err;
9057#endif
Willy Tarreau51347ed2013-06-11 19:34:13 +02009058 } else if (!strcmp(args[0], "set-mark")) {
9059#ifdef SO_MARK
9060 char *err;
9061 rule->action = HTTP_REQ_ACT_SET_MARK;
9062 cur_arg = 1;
9063
9064 if (!*args[cur_arg] ||
9065 (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
9066 Alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (integer/hex value).\n",
9067 file, linenum, args[0]);
9068 goto out_err;
9069 }
9070
9071 rule->arg.mark = strtoul(args[cur_arg], &err, 0);
9072 if (err && *err != '\0') {
9073 Alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-request %s' (integer/hex value expected).\n",
9074 file, linenum, err, args[0]);
9075 goto out_err;
9076 }
9077 cur_arg++;
9078 global.last_checks |= LSTCHK_NETADM;
9079#else
9080 Alert("parsing [%s:%d]: 'http-request %s' is not supported on this platform (SO_MARK undefined).\n", file, linenum, args[0]);
9081 goto out_err;
9082#endif
Willy Tarreau9a355ec2013-06-11 17:45:46 +02009083 } else if (!strcmp(args[0], "set-log-level")) {
9084 rule->action = HTTP_REQ_ACT_SET_LOGL;
9085 cur_arg = 1;
9086
9087 if (!*args[cur_arg] ||
9088 (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
9089 bad_log_level:
9090 Alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument (log level name or 'silent').\n",
9091 file, linenum, args[0]);
9092 goto out_err;
9093 }
9094 if (strcmp(args[cur_arg], "silent") == 0)
9095 rule->arg.loglevel = -1;
9096 else if ((rule->arg.loglevel = get_log_level(args[cur_arg]) + 1) == 0)
9097 goto bad_log_level;
9098 cur_arg++;
Willy Tarreau20b0de52012-12-24 15:45:22 +01009099 } else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0) {
9100 rule->action = *args[0] == 'a' ? HTTP_REQ_ACT_ADD_HDR : HTTP_REQ_ACT_SET_HDR;
9101 cur_arg = 1;
9102
Willy Tarreau8d1c5162013-04-03 14:13:58 +02009103 if (!*args[cur_arg] || !*args[cur_arg+1] ||
9104 (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
Willy Tarreau20b0de52012-12-24 15:45:22 +01009105 Alert("parsing [%s:%d]: 'http-request %s' expects exactly 2 arguments.\n",
9106 file, linenum, args[0]);
Willy Tarreau81499eb2012-12-27 12:19:02 +01009107 goto out_err;
Willy Tarreau20b0de52012-12-24 15:45:22 +01009108 }
9109
9110 rule->arg.hdr_add.name = strdup(args[cur_arg]);
9111 rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
9112 LIST_INIT(&rule->arg.hdr_add.fmt);
Willy Tarreaua4312fa2013-04-02 16:34:32 +02009113
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +01009114 proxy->conf.args.ctx = ARGC_HRQ;
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01009115 parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
Thierry FOURNIEReeaa9512014-02-11 14:00:19 +01009116 (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
9117 file, linenum);
Willy Tarreau59ad1a22014-01-29 14:39:58 +01009118 free(proxy->conf.lfs_file);
9119 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9120 proxy->conf.lfs_line = proxy->conf.args.line;
Willy Tarreau20b0de52012-12-24 15:45:22 +01009121 cur_arg += 2;
Willy Tarreaub8543922014-06-17 18:58:26 +02009122 } else if (strcmp(args[0], "replace-header") == 0 || strcmp(args[0], "replace-value") == 0) {
9123 rule->action = args[0][8] == 'h' ? HTTP_REQ_ACT_REPLACE_HDR : HTTP_REQ_ACT_REPLACE_VAL;
Sasha Pachev218f0642014-06-16 12:05:59 -06009124 cur_arg = 1;
9125
9126 if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2] ||
Baptiste Assmann92df3702014-06-24 11:10:00 +02009127 (*args[cur_arg+3] && strcmp(args[cur_arg+3], "if") != 0 && strcmp(args[cur_arg+3], "unless") != 0)) {
Sasha Pachev218f0642014-06-16 12:05:59 -06009128 Alert("parsing [%s:%d]: 'http-request %s' expects exactly 3 arguments.\n",
9129 file, linenum, args[0]);
9130 goto out_err;
9131 }
9132
9133 rule->arg.hdr_add.name = strdup(args[cur_arg]);
9134 rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
9135 LIST_INIT(&rule->arg.hdr_add.fmt);
9136
Thierry FOURNIER09af0d62014-06-18 11:35:54 +02009137 error = NULL;
9138 if (!regex_comp(args[cur_arg + 1], &rule->arg.hdr_add.re, 1, 1, &error)) {
9139 Alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum,
9140 args[cur_arg + 1], error);
9141 free(error);
Sasha Pachev218f0642014-06-16 12:05:59 -06009142 goto out_err;
9143 }
9144
9145 proxy->conf.args.ctx = ARGC_HRQ;
9146 parse_logformat_string(args[cur_arg + 2], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
9147 (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
9148 file, linenum);
9149
9150 free(proxy->conf.lfs_file);
9151 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9152 proxy->conf.lfs_line = proxy->conf.args.line;
9153 cur_arg += 3;
Thierry FOURNIERdad3d1d2014-04-22 18:07:25 +02009154 } else if (strcmp(args[0], "del-header") == 0) {
9155 rule->action = HTTP_REQ_ACT_DEL_HDR;
9156 cur_arg = 1;
9157
9158 if (!*args[cur_arg] ||
9159 (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
9160 Alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
9161 file, linenum, args[0]);
9162 goto out_err;
9163 }
9164
9165 rule->arg.hdr_add.name = strdup(args[cur_arg]);
9166 rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
9167
9168 proxy->conf.args.ctx = ARGC_HRQ;
9169 free(proxy->conf.lfs_file);
9170 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9171 proxy->conf.lfs_line = proxy->conf.args.line;
9172 cur_arg += 1;
Willy Tarreau09448f72014-06-25 18:12:15 +02009173 } else if (strncmp(args[0], "track-sc", 8) == 0 &&
9174 args[0][9] == '\0' && args[0][8] >= '0' &&
Willy Tarreaue1cfc1f2014-10-17 11:53:05 +02009175 args[0][8] < '0' + MAX_SESS_STKCTR) { /* track-sc 0..9 */
Willy Tarreau09448f72014-06-25 18:12:15 +02009176 struct sample_expr *expr;
9177 unsigned int where;
9178 char *err = NULL;
9179
9180 cur_arg = 1;
9181 proxy->conf.args.ctx = ARGC_TRK;
9182
9183 expr = sample_parse_expr((char **)args, &cur_arg, file, linenum, &err, &proxy->conf.args);
9184 if (!expr) {
9185 Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
9186 file, linenum, proxy_type_str(proxy), proxy->id, args[0], err);
9187 free(err);
9188 goto out_err;
9189 }
9190
9191 where = 0;
9192 if (proxy->cap & PR_CAP_FE)
9193 where |= SMP_VAL_FE_HRQ_HDR;
9194 if (proxy->cap & PR_CAP_BE)
9195 where |= SMP_VAL_BE_HRQ_HDR;
9196
9197 if (!(expr->fetch->val & where)) {
9198 Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule :"
9199 " fetch method '%s' extracts information from '%s', none of which is available here.\n",
9200 file, linenum, proxy_type_str(proxy), proxy->id, args[0],
9201 args[cur_arg-1], sample_src_names(expr->fetch->use));
9202 free(expr);
9203 goto out_err;
9204 }
9205
9206 if (strcmp(args[cur_arg], "table") == 0) {
9207 cur_arg++;
9208 if (!args[cur_arg]) {
9209 Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : missing table name.\n",
9210 file, linenum, proxy_type_str(proxy), proxy->id, args[0]);
9211 free(expr);
9212 goto out_err;
9213 }
9214 /* we copy the table name for now, it will be resolved later */
9215 rule->act_prm.trk_ctr.table.n = strdup(args[cur_arg]);
9216 cur_arg++;
9217 }
9218 rule->act_prm.trk_ctr.expr = expr;
9219 rule->action = HTTP_REQ_ACT_TRK_SC0 + args[0][8] - '0';
Willy Tarreau81499eb2012-12-27 12:19:02 +01009220 } else if (strcmp(args[0], "redirect") == 0) {
9221 struct redirect_rule *redir;
Willy Tarreau6d4890c2013-11-18 18:04:25 +01009222 char *errmsg = NULL;
Willy Tarreau81499eb2012-12-27 12:19:02 +01009223
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01009224 if ((redir = http_parse_redirect_rule(file, linenum, proxy, (const char **)args + 1, &errmsg, 1)) == NULL) {
Willy Tarreau81499eb2012-12-27 12:19:02 +01009225 Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
9226 file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
9227 goto out_err;
9228 }
9229
9230 /* this redirect rule might already contain a parsed condition which
9231 * we'll pass to the http-request rule.
9232 */
9233 rule->action = HTTP_REQ_ACT_REDIR;
9234 rule->arg.redir = redir;
9235 rule->cond = redir->cond;
9236 redir->cond = NULL;
9237 cur_arg = 2;
9238 return rule;
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009239 } else if (strncmp(args[0], "add-acl", 7) == 0) {
9240 /* http-request add-acl(<reference (acl name)>) <key pattern> */
9241 rule->action = HTTP_REQ_ACT_ADD_ACL;
9242 /*
9243 * '+ 8' for 'add-acl('
9244 * '- 9' for 'add-acl(' + trailing ')'
9245 */
Willy Tarreau6c09c2c2014-04-25 21:38:08 +02009246 rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009247
9248 cur_arg = 1;
9249
9250 if (!*args[cur_arg] ||
9251 (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
9252 Alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
9253 file, linenum, args[0]);
9254 goto out_err;
9255 }
9256
9257 LIST_INIT(&rule->arg.map.key);
9258 proxy->conf.args.ctx = ARGC_HRQ;
9259 parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
9260 (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
9261 file, linenum);
9262 free(proxy->conf.lfs_file);
9263 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9264 proxy->conf.lfs_line = proxy->conf.args.line;
9265 cur_arg += 1;
9266 } else if (strncmp(args[0], "del-acl", 7) == 0) {
9267 /* http-request del-acl(<reference (acl name)>) <key pattern> */
9268 rule->action = HTTP_REQ_ACT_DEL_ACL;
9269 /*
9270 * '+ 8' for 'del-acl('
9271 * '- 9' for 'del-acl(' + trailing ')'
9272 */
Willy Tarreau6c09c2c2014-04-25 21:38:08 +02009273 rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009274
9275 cur_arg = 1;
9276
9277 if (!*args[cur_arg] ||
9278 (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
9279 Alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
9280 file, linenum, args[0]);
9281 goto out_err;
9282 }
9283
9284 LIST_INIT(&rule->arg.map.key);
9285 proxy->conf.args.ctx = ARGC_HRQ;
9286 parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
9287 (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
9288 file, linenum);
9289 free(proxy->conf.lfs_file);
9290 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9291 proxy->conf.lfs_line = proxy->conf.args.line;
9292 cur_arg += 1;
9293 } else if (strncmp(args[0], "del-map", 7) == 0) {
9294 /* http-request del-map(<reference (map name)>) <key pattern> */
9295 rule->action = HTTP_REQ_ACT_DEL_MAP;
9296 /*
9297 * '+ 8' for 'del-map('
9298 * '- 9' for 'del-map(' + trailing ')'
9299 */
Willy Tarreau6c09c2c2014-04-25 21:38:08 +02009300 rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009301
9302 cur_arg = 1;
9303
9304 if (!*args[cur_arg] ||
9305 (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
9306 Alert("parsing [%s:%d]: 'http-request %s' expects exactly 1 argument.\n",
9307 file, linenum, args[0]);
9308 goto out_err;
9309 }
9310
9311 LIST_INIT(&rule->arg.map.key);
9312 proxy->conf.args.ctx = ARGC_HRQ;
9313 parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
9314 (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
9315 file, linenum);
9316 free(proxy->conf.lfs_file);
9317 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9318 proxy->conf.lfs_line = proxy->conf.args.line;
9319 cur_arg += 1;
9320 } else if (strncmp(args[0], "set-map", 7) == 0) {
9321 /* http-request set-map(<reference (map name)>) <key pattern> <value pattern> */
9322 rule->action = HTTP_REQ_ACT_SET_MAP;
9323 /*
9324 * '+ 8' for 'set-map('
9325 * '- 9' for 'set-map(' + trailing ')'
9326 */
Willy Tarreau6c09c2c2014-04-25 21:38:08 +02009327 rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009328
9329 cur_arg = 1;
9330
9331 if (!*args[cur_arg] || !*args[cur_arg+1] ||
9332 (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
9333 Alert("parsing [%s:%d]: 'http-request %s' expects exactly 2 arguments.\n",
9334 file, linenum, args[0]);
9335 goto out_err;
9336 }
9337
9338 LIST_INIT(&rule->arg.map.key);
9339 LIST_INIT(&rule->arg.map.value);
9340 proxy->conf.args.ctx = ARGC_HRQ;
9341
9342 /* key pattern */
9343 parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
9344 (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
9345 file, linenum);
9346
9347 /* value pattern */
9348 parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.map.value, LOG_OPT_HTTP,
9349 (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
9350 file, linenum);
9351 free(proxy->conf.lfs_file);
9352 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9353 proxy->conf.lfs_line = proxy->conf.args.line;
9354
9355 cur_arg += 2;
William Lallemand73025dd2014-04-24 14:38:37 +02009356 } else if (((custom = action_http_req_custom(args[0])) != NULL)) {
9357 char *errmsg = NULL;
9358 cur_arg = 1;
9359 /* try in the module list */
9360 if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) < 0) {
9361 Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-request %s' rule : %s.\n",
9362 file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
9363 free(errmsg);
9364 goto out_err;
9365 }
Willy Tarreauff011f22011-01-06 17:51:27 +01009366 } else {
Sasha Pachev218f0642014-06-16 12:05:59 -06009367 Alert("parsing [%s:%d]: 'http-request' expects 'allow', 'deny', 'auth', 'redirect', 'tarpit', 'add-header', 'set-header', 'replace-header', 'replace-value', 'set-nice', 'set-tos', 'set-mark', 'set-log-level', 'add-acl', 'del-acl', 'del-map', 'set-map', but got '%s'%s.\n",
Willy Tarreau5c2e1982012-12-24 12:00:25 +01009368 file, linenum, args[0], *args[0] ? "" : " (missing argument)");
Willy Tarreau81499eb2012-12-27 12:19:02 +01009369 goto out_err;
Willy Tarreauff011f22011-01-06 17:51:27 +01009370 }
9371
9372 if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
9373 struct acl_cond *cond;
Willy Tarreaub7451bb2012-04-27 12:38:15 +02009374 char *errmsg = NULL;
Willy Tarreauff011f22011-01-06 17:51:27 +01009375
Willy Tarreaub7451bb2012-04-27 12:38:15 +02009376 if ((cond = build_acl_cond(file, linenum, proxy, args+cur_arg, &errmsg)) == NULL) {
9377 Alert("parsing [%s:%d] : error detected while parsing an 'http-request %s' condition : %s.\n",
9378 file, linenum, args[0], errmsg);
9379 free(errmsg);
Willy Tarreau81499eb2012-12-27 12:19:02 +01009380 goto out_err;
Willy Tarreauff011f22011-01-06 17:51:27 +01009381 }
9382 rule->cond = cond;
9383 }
9384 else if (*args[cur_arg]) {
9385 Alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth' or"
9386 " either 'if' or 'unless' followed by a condition but found '%s'.\n",
9387 file, linenum, args[0], args[cur_arg]);
Willy Tarreau81499eb2012-12-27 12:19:02 +01009388 goto out_err;
Willy Tarreauff011f22011-01-06 17:51:27 +01009389 }
9390
9391 return rule;
Willy Tarreau81499eb2012-12-27 12:19:02 +01009392 out_err:
9393 free(rule);
9394 return NULL;
Willy Tarreauff011f22011-01-06 17:51:27 +01009395}
9396
Willy Tarreaue365c0b2013-06-11 16:06:12 +02009397/* parse an "http-respose" rule */
9398struct http_res_rule *parse_http_res_cond(const char **args, const char *file, int linenum, struct proxy *proxy)
9399{
9400 struct http_res_rule *rule;
William Lallemand73025dd2014-04-24 14:38:37 +02009401 struct http_res_action_kw *custom = NULL;
Willy Tarreaue365c0b2013-06-11 16:06:12 +02009402 int cur_arg;
Thierry FOURNIER09af0d62014-06-18 11:35:54 +02009403 char *error;
Willy Tarreaue365c0b2013-06-11 16:06:12 +02009404
9405 rule = calloc(1, sizeof(*rule));
9406 if (!rule) {
9407 Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
9408 goto out_err;
9409 }
9410
9411 if (!strcmp(args[0], "allow")) {
9412 rule->action = HTTP_RES_ACT_ALLOW;
9413 cur_arg = 1;
9414 } else if (!strcmp(args[0], "deny")) {
9415 rule->action = HTTP_RES_ACT_DENY;
9416 cur_arg = 1;
Willy Tarreauf4c43c12013-06-11 17:01:13 +02009417 } else if (!strcmp(args[0], "set-nice")) {
9418 rule->action = HTTP_RES_ACT_SET_NICE;
9419 cur_arg = 1;
9420
9421 if (!*args[cur_arg] ||
9422 (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
9423 Alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (integer value).\n",
9424 file, linenum, args[0]);
9425 goto out_err;
9426 }
9427 rule->arg.nice = atoi(args[cur_arg]);
9428 if (rule->arg.nice < -1024)
9429 rule->arg.nice = -1024;
9430 else if (rule->arg.nice > 1024)
9431 rule->arg.nice = 1024;
9432 cur_arg++;
Willy Tarreau42cf39e2013-06-11 18:51:32 +02009433 } else if (!strcmp(args[0], "set-tos")) {
9434#ifdef IP_TOS
9435 char *err;
9436 rule->action = HTTP_RES_ACT_SET_TOS;
9437 cur_arg = 1;
9438
9439 if (!*args[cur_arg] ||
9440 (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
9441 Alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (integer/hex value).\n",
9442 file, linenum, args[0]);
9443 goto out_err;
9444 }
9445
9446 rule->arg.tos = strtol(args[cur_arg], &err, 0);
9447 if (err && *err != '\0') {
9448 Alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-response %s' (integer/hex value expected).\n",
9449 file, linenum, err, args[0]);
9450 goto out_err;
9451 }
9452 cur_arg++;
9453#else
9454 Alert("parsing [%s:%d]: 'http-response %s' is not supported on this platform (IP_TOS undefined).\n", file, linenum, args[0]);
9455 goto out_err;
9456#endif
Willy Tarreau51347ed2013-06-11 19:34:13 +02009457 } else if (!strcmp(args[0], "set-mark")) {
9458#ifdef SO_MARK
9459 char *err;
9460 rule->action = HTTP_RES_ACT_SET_MARK;
9461 cur_arg = 1;
9462
9463 if (!*args[cur_arg] ||
9464 (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
9465 Alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (integer/hex value).\n",
9466 file, linenum, args[0]);
9467 goto out_err;
9468 }
9469
9470 rule->arg.mark = strtoul(args[cur_arg], &err, 0);
9471 if (err && *err != '\0') {
9472 Alert("parsing [%s:%d]: invalid character starting at '%s' in 'http-response %s' (integer/hex value expected).\n",
9473 file, linenum, err, args[0]);
9474 goto out_err;
9475 }
9476 cur_arg++;
9477 global.last_checks |= LSTCHK_NETADM;
9478#else
9479 Alert("parsing [%s:%d]: 'http-response %s' is not supported on this platform (SO_MARK undefined).\n", file, linenum, args[0]);
9480 goto out_err;
9481#endif
Willy Tarreau9a355ec2013-06-11 17:45:46 +02009482 } else if (!strcmp(args[0], "set-log-level")) {
9483 rule->action = HTTP_RES_ACT_SET_LOGL;
9484 cur_arg = 1;
9485
9486 if (!*args[cur_arg] ||
9487 (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
9488 bad_log_level:
9489 Alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument (log level name or 'silent').\n",
9490 file, linenum, args[0]);
9491 goto out_err;
9492 }
9493 if (strcmp(args[cur_arg], "silent") == 0)
9494 rule->arg.loglevel = -1;
9495 else if ((rule->arg.loglevel = get_log_level(args[cur_arg] + 1)) == 0)
9496 goto bad_log_level;
9497 cur_arg++;
Willy Tarreaue365c0b2013-06-11 16:06:12 +02009498 } else if (strcmp(args[0], "add-header") == 0 || strcmp(args[0], "set-header") == 0) {
9499 rule->action = *args[0] == 'a' ? HTTP_RES_ACT_ADD_HDR : HTTP_RES_ACT_SET_HDR;
9500 cur_arg = 1;
9501
9502 if (!*args[cur_arg] || !*args[cur_arg+1] ||
9503 (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
9504 Alert("parsing [%s:%d]: 'http-response %s' expects exactly 2 arguments.\n",
9505 file, linenum, args[0]);
9506 goto out_err;
9507 }
9508
9509 rule->arg.hdr_add.name = strdup(args[cur_arg]);
9510 rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
9511 LIST_INIT(&rule->arg.hdr_add.fmt);
9512
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +01009513 proxy->conf.args.ctx = ARGC_HRS;
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01009514 parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
Thierry FOURNIEReeaa9512014-02-11 14:00:19 +01009515 (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
9516 file, linenum);
Willy Tarreau59ad1a22014-01-29 14:39:58 +01009517 free(proxy->conf.lfs_file);
9518 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9519 proxy->conf.lfs_line = proxy->conf.args.line;
Willy Tarreaue365c0b2013-06-11 16:06:12 +02009520 cur_arg += 2;
Sasha Pachev218f0642014-06-16 12:05:59 -06009521 } else if (strcmp(args[0], "replace-header") == 0 || strcmp(args[0], "replace-value") == 0) {
Willy Tarreaub8543922014-06-17 18:58:26 +02009522 rule->action = args[0][8] == 'h' ? HTTP_RES_ACT_REPLACE_HDR : HTTP_RES_ACT_REPLACE_VAL;
Sasha Pachev218f0642014-06-16 12:05:59 -06009523 cur_arg = 1;
9524
9525 if (!*args[cur_arg] || !*args[cur_arg+1] || !*args[cur_arg+2] ||
Baptiste Assmann12cb00b2014-08-08 17:29:06 +02009526 (*args[cur_arg+3] && strcmp(args[cur_arg+3], "if") != 0 && strcmp(args[cur_arg+3], "unless") != 0)) {
9527 Alert("parsing [%s:%d]: 'http-response %s' expects exactly 3 arguments.\n",
Sasha Pachev218f0642014-06-16 12:05:59 -06009528 file, linenum, args[0]);
9529 goto out_err;
9530 }
9531
9532 rule->arg.hdr_add.name = strdup(args[cur_arg]);
9533 rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
9534 LIST_INIT(&rule->arg.hdr_add.fmt);
9535
Thierry FOURNIER09af0d62014-06-18 11:35:54 +02009536 error = NULL;
9537 if (!regex_comp(args[cur_arg + 1], &rule->arg.hdr_add.re, 1, 1, &error)) {
9538 Alert("parsing [%s:%d] : '%s' : %s.\n", file, linenum,
9539 args[cur_arg + 1], error);
9540 free(error);
Sasha Pachev218f0642014-06-16 12:05:59 -06009541 goto out_err;
9542 }
9543
9544 proxy->conf.args.ctx = ARGC_HRQ;
9545 parse_logformat_string(args[cur_arg + 2], proxy, &rule->arg.hdr_add.fmt, LOG_OPT_HTTP,
9546 (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
9547 file, linenum);
9548
9549 free(proxy->conf.lfs_file);
9550 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9551 proxy->conf.lfs_line = proxy->conf.args.line;
9552 cur_arg += 3;
Thierry FOURNIERdad3d1d2014-04-22 18:07:25 +02009553 } else if (strcmp(args[0], "del-header") == 0) {
9554 rule->action = HTTP_RES_ACT_DEL_HDR;
9555 cur_arg = 1;
9556
9557 if (!*args[cur_arg] ||
9558 (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
9559 Alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument.\n",
9560 file, linenum, args[0]);
9561 goto out_err;
9562 }
9563
9564 rule->arg.hdr_add.name = strdup(args[cur_arg]);
9565 rule->arg.hdr_add.name_len = strlen(rule->arg.hdr_add.name);
9566
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009567 proxy->conf.args.ctx = ARGC_HRS;
9568 free(proxy->conf.lfs_file);
9569 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9570 proxy->conf.lfs_line = proxy->conf.args.line;
9571 cur_arg += 1;
9572 } else if (strncmp(args[0], "add-acl", 7) == 0) {
9573 /* http-request add-acl(<reference (acl name)>) <key pattern> */
9574 rule->action = HTTP_RES_ACT_ADD_ACL;
9575 /*
9576 * '+ 8' for 'add-acl('
9577 * '- 9' for 'add-acl(' + trailing ')'
9578 */
Willy Tarreau6c09c2c2014-04-25 21:38:08 +02009579 rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009580
9581 cur_arg = 1;
9582
9583 if (!*args[cur_arg] ||
9584 (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
9585 Alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument.\n",
9586 file, linenum, args[0]);
9587 goto out_err;
9588 }
9589
9590 LIST_INIT(&rule->arg.map.key);
Thierry FOURNIERdad3d1d2014-04-22 18:07:25 +02009591 proxy->conf.args.ctx = ARGC_HRS;
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009592 parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
9593 (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
9594 file, linenum);
Thierry FOURNIERdad3d1d2014-04-22 18:07:25 +02009595 free(proxy->conf.lfs_file);
9596 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9597 proxy->conf.lfs_line = proxy->conf.args.line;
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009598
Thierry FOURNIERdad3d1d2014-04-22 18:07:25 +02009599 cur_arg += 1;
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009600 } else if (strncmp(args[0], "del-acl", 7) == 0) {
9601 /* http-response del-acl(<reference (acl name)>) <key pattern> */
9602 rule->action = HTTP_RES_ACT_DEL_ACL;
9603 /*
9604 * '+ 8' for 'del-acl('
9605 * '- 9' for 'del-acl(' + trailing ')'
9606 */
Willy Tarreau6c09c2c2014-04-25 21:38:08 +02009607 rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009608
9609 cur_arg = 1;
9610
9611 if (!*args[cur_arg] ||
9612 (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
9613 Alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument.\n",
9614 file, linenum, args[0]);
9615 goto out_err;
9616 }
9617
9618 LIST_INIT(&rule->arg.map.key);
9619 proxy->conf.args.ctx = ARGC_HRS;
9620 parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
9621 (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
9622 file, linenum);
9623 free(proxy->conf.lfs_file);
9624 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9625 proxy->conf.lfs_line = proxy->conf.args.line;
9626 cur_arg += 1;
9627 } else if (strncmp(args[0], "del-map", 7) == 0) {
9628 /* http-response del-map(<reference (map name)>) <key pattern> */
9629 rule->action = HTTP_RES_ACT_DEL_MAP;
9630 /*
9631 * '+ 8' for 'del-map('
9632 * '- 9' for 'del-map(' + trailing ')'
9633 */
Willy Tarreau6c09c2c2014-04-25 21:38:08 +02009634 rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009635
9636 cur_arg = 1;
9637
9638 if (!*args[cur_arg] ||
9639 (*args[cur_arg+1] && strcmp(args[cur_arg+1], "if") != 0 && strcmp(args[cur_arg+1], "unless") != 0)) {
9640 Alert("parsing [%s:%d]: 'http-response %s' expects exactly 1 argument.\n",
9641 file, linenum, args[0]);
9642 goto out_err;
9643 }
9644
9645 LIST_INIT(&rule->arg.map.key);
9646 proxy->conf.args.ctx = ARGC_HRS;
9647 parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
9648 (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
9649 file, linenum);
9650 free(proxy->conf.lfs_file);
9651 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9652 proxy->conf.lfs_line = proxy->conf.args.line;
9653 cur_arg += 1;
9654 } else if (strncmp(args[0], "set-map", 7) == 0) {
9655 /* http-response set-map(<reference (map name)>) <key pattern> <value pattern> */
9656 rule->action = HTTP_RES_ACT_SET_MAP;
9657 /*
9658 * '+ 8' for 'set-map('
9659 * '- 9' for 'set-map(' + trailing ')'
9660 */
Willy Tarreau6c09c2c2014-04-25 21:38:08 +02009661 rule->arg.map.ref = my_strndup(args[0] + 8, strlen(args[0]) - 9);
Baptiste Assmannfabcbe02014-04-24 22:16:59 +02009662
9663 cur_arg = 1;
9664
9665 if (!*args[cur_arg] || !*args[cur_arg+1] ||
9666 (*args[cur_arg+2] && strcmp(args[cur_arg+2], "if") != 0 && strcmp(args[cur_arg+2], "unless") != 0)) {
9667 Alert("parsing [%s:%d]: 'http-response %s' expects exactly 2 arguments.\n",
9668 file, linenum, args[0]);
9669 goto out_err;
9670 }
9671
9672 LIST_INIT(&rule->arg.map.key);
9673 LIST_INIT(&rule->arg.map.value);
9674
9675 proxy->conf.args.ctx = ARGC_HRS;
9676
9677 /* key pattern */
9678 parse_logformat_string(args[cur_arg], proxy, &rule->arg.map.key, LOG_OPT_HTTP,
9679 (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
9680 file, linenum);
9681
9682 /* value pattern */
9683 parse_logformat_string(args[cur_arg + 1], proxy, &rule->arg.map.value, LOG_OPT_HTTP,
9684 (proxy->cap & PR_CAP_BE) ? SMP_VAL_BE_HRS_HDR : SMP_VAL_FE_HRS_HDR,
9685 file, linenum);
9686
9687 free(proxy->conf.lfs_file);
9688 proxy->conf.lfs_file = strdup(proxy->conf.args.file);
9689 proxy->conf.lfs_line = proxy->conf.args.line;
9690
9691 cur_arg += 2;
William Lallemand73025dd2014-04-24 14:38:37 +02009692 } else if (((custom = action_http_res_custom(args[0])) != NULL)) {
9693 char *errmsg = NULL;
9694 cur_arg = 1;
9695 /* try in the module list */
9696 if (custom->parse(args, &cur_arg, proxy, rule, &errmsg) < 0) {
9697 Alert("parsing [%s:%d] : error detected in %s '%s' while parsing 'http-response %s' rule : %s.\n",
9698 file, linenum, proxy_type_str(proxy), proxy->id, args[0], errmsg);
9699 free(errmsg);
9700 goto out_err;
9701 }
Willy Tarreaue365c0b2013-06-11 16:06:12 +02009702 } else {
Sasha Pachev218f0642014-06-16 12:05:59 -06009703 Alert("parsing [%s:%d]: 'http-response' expects 'allow', 'deny', 'redirect', 'add-header', 'del-header', 'set-header', 'replace-header', 'replace-value', 'set-nice', 'set-tos', 'set-mark', 'set-log-level', 'del-acl', 'add-acl', 'del-map', 'set-map', but got '%s'%s.\n",
Willy Tarreaue365c0b2013-06-11 16:06:12 +02009704 file, linenum, args[0], *args[0] ? "" : " (missing argument)");
9705 goto out_err;
9706 }
9707
9708 if (strcmp(args[cur_arg], "if") == 0 || strcmp(args[cur_arg], "unless") == 0) {
9709 struct acl_cond *cond;
9710 char *errmsg = NULL;
9711
9712 if ((cond = build_acl_cond(file, linenum, proxy, args+cur_arg, &errmsg)) == NULL) {
9713 Alert("parsing [%s:%d] : error detected while parsing an 'http-response %s' condition : %s.\n",
9714 file, linenum, args[0], errmsg);
9715 free(errmsg);
9716 goto out_err;
9717 }
9718 rule->cond = cond;
9719 }
9720 else if (*args[cur_arg]) {
9721 Alert("parsing [%s:%d]: 'http-response %s' expects"
9722 " either 'if' or 'unless' followed by a condition but found '%s'.\n",
9723 file, linenum, args[0], args[cur_arg]);
9724 goto out_err;
9725 }
9726
9727 return rule;
9728 out_err:
9729 free(rule);
9730 return NULL;
9731}
9732
Willy Tarreau4baae242012-12-27 12:00:31 +01009733/* Parses a redirect rule. Returns the redirect rule on success or NULL on error,
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01009734 * with <err> filled with the error message. If <use_fmt> is not null, builds a
9735 * dynamic log-format rule instead of a static string.
Willy Tarreau4baae242012-12-27 12:00:31 +01009736 */
9737struct redirect_rule *http_parse_redirect_rule(const char *file, int linenum, struct proxy *curproxy,
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01009738 const char **args, char **errmsg, int use_fmt)
Willy Tarreau4baae242012-12-27 12:00:31 +01009739{
9740 struct redirect_rule *rule;
9741 int cur_arg;
9742 int type = REDIRECT_TYPE_NONE;
9743 int code = 302;
9744 const char *destination = NULL;
9745 const char *cookie = NULL;
9746 int cookie_set = 0;
9747 unsigned int flags = REDIRECT_FLAG_NONE;
9748 struct acl_cond *cond = NULL;
9749
9750 cur_arg = 0;
9751 while (*(args[cur_arg])) {
9752 if (strcmp(args[cur_arg], "location") == 0) {
9753 if (!*args[cur_arg + 1])
9754 goto missing_arg;
9755
9756 type = REDIRECT_TYPE_LOCATION;
9757 cur_arg++;
9758 destination = args[cur_arg];
9759 }
9760 else if (strcmp(args[cur_arg], "prefix") == 0) {
9761 if (!*args[cur_arg + 1])
9762 goto missing_arg;
9763
9764 type = REDIRECT_TYPE_PREFIX;
9765 cur_arg++;
9766 destination = args[cur_arg];
9767 }
9768 else if (strcmp(args[cur_arg], "scheme") == 0) {
9769 if (!*args[cur_arg + 1])
9770 goto missing_arg;
9771
9772 type = REDIRECT_TYPE_SCHEME;
9773 cur_arg++;
9774 destination = args[cur_arg];
9775 }
9776 else if (strcmp(args[cur_arg], "set-cookie") == 0) {
9777 if (!*args[cur_arg + 1])
9778 goto missing_arg;
9779
9780 cur_arg++;
9781 cookie = args[cur_arg];
9782 cookie_set = 1;
9783 }
9784 else if (strcmp(args[cur_arg], "clear-cookie") == 0) {
9785 if (!*args[cur_arg + 1])
9786 goto missing_arg;
9787
9788 cur_arg++;
9789 cookie = args[cur_arg];
9790 cookie_set = 0;
9791 }
9792 else if (strcmp(args[cur_arg], "code") == 0) {
9793 if (!*args[cur_arg + 1])
9794 goto missing_arg;
9795
9796 cur_arg++;
9797 code = atol(args[cur_arg]);
Yves Lafon3e8d1ae2013-03-11 11:06:05 -04009798 if (code < 301 || code > 308 || (code > 303 && code < 307)) {
Willy Tarreau4baae242012-12-27 12:00:31 +01009799 memprintf(errmsg,
Yves Lafon3e8d1ae2013-03-11 11:06:05 -04009800 "'%s': unsupported HTTP code '%s' (must be one of 301, 302, 303, 307 or 308)",
Willy Tarreau4baae242012-12-27 12:00:31 +01009801 args[cur_arg - 1], args[cur_arg]);
9802 return NULL;
9803 }
9804 }
9805 else if (!strcmp(args[cur_arg],"drop-query")) {
9806 flags |= REDIRECT_FLAG_DROP_QS;
9807 }
9808 else if (!strcmp(args[cur_arg],"append-slash")) {
9809 flags |= REDIRECT_FLAG_APPEND_SLASH;
9810 }
9811 else if (strcmp(args[cur_arg], "if") == 0 ||
9812 strcmp(args[cur_arg], "unless") == 0) {
9813 cond = build_acl_cond(file, linenum, curproxy, (const char **)args + cur_arg, errmsg);
9814 if (!cond) {
9815 memprintf(errmsg, "error in condition: %s", *errmsg);
9816 return NULL;
9817 }
9818 break;
9819 }
9820 else {
9821 memprintf(errmsg,
9822 "expects 'code', 'prefix', 'location', 'scheme', 'set-cookie', 'clear-cookie', 'drop-query' or 'append-slash' (was '%s')",
9823 args[cur_arg]);
9824 return NULL;
9825 }
9826 cur_arg++;
9827 }
9828
9829 if (type == REDIRECT_TYPE_NONE) {
9830 memprintf(errmsg, "redirection type expected ('prefix', 'location', or 'scheme')");
9831 return NULL;
9832 }
9833
9834 rule = (struct redirect_rule *)calloc(1, sizeof(*rule));
9835 rule->cond = cond;
Willy Tarreau60e08382013-12-03 00:48:45 +01009836 LIST_INIT(&rule->rdr_fmt);
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01009837
9838 if (!use_fmt) {
9839 /* old-style static redirect rule */
9840 rule->rdr_str = strdup(destination);
9841 rule->rdr_len = strlen(destination);
9842 }
9843 else {
9844 /* log-format based redirect rule */
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01009845
9846 /* Parse destination. Note that in the REDIRECT_TYPE_PREFIX case,
9847 * if prefix == "/", we don't want to add anything, otherwise it
9848 * makes it hard for the user to configure a self-redirection.
9849 */
Godbachd9722032014-12-18 15:44:58 +08009850 curproxy->conf.args.ctx = ARGC_RDR;
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01009851 if (!(type == REDIRECT_TYPE_PREFIX && destination[0] == '/' && destination[1] == '\0')) {
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01009852 parse_logformat_string(destination, curproxy, &rule->rdr_fmt, LOG_OPT_HTTP,
Thierry FOURNIEReeaa9512014-02-11 14:00:19 +01009853 (curproxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
9854 file, linenum);
Willy Tarreau59ad1a22014-01-29 14:39:58 +01009855 free(curproxy->conf.lfs_file);
9856 curproxy->conf.lfs_file = strdup(curproxy->conf.args.file);
9857 curproxy->conf.lfs_line = curproxy->conf.args.line;
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +01009858 }
9859 }
9860
Willy Tarreau4baae242012-12-27 12:00:31 +01009861 if (cookie) {
9862 /* depending on cookie_set, either we want to set the cookie, or to clear it.
9863 * a clear consists in appending "; path=/; Max-Age=0;" at the end.
9864 */
9865 rule->cookie_len = strlen(cookie);
9866 if (cookie_set) {
9867 rule->cookie_str = malloc(rule->cookie_len + 10);
9868 memcpy(rule->cookie_str, cookie, rule->cookie_len);
9869 memcpy(rule->cookie_str + rule->cookie_len, "; path=/;", 10);
9870 rule->cookie_len += 9;
9871 } else {
9872 rule->cookie_str = malloc(rule->cookie_len + 21);
9873 memcpy(rule->cookie_str, cookie, rule->cookie_len);
9874 memcpy(rule->cookie_str + rule->cookie_len, "; path=/; Max-Age=0;", 21);
9875 rule->cookie_len += 20;
9876 }
9877 }
9878 rule->type = type;
9879 rule->code = code;
9880 rule->flags = flags;
9881 LIST_INIT(&rule->list);
9882 return rule;
9883
9884 missing_arg:
9885 memprintf(errmsg, "missing argument for '%s'", args[cur_arg]);
9886 return NULL;
9887}
9888
Willy Tarreau8797c062007-05-07 00:55:35 +02009889/************************************************************************/
9890/* The code below is dedicated to ACL parsing and matching */
9891/************************************************************************/
9892
9893
Willy Tarreau14174bc2012-04-16 14:34:04 +02009894/* This function ensures that the prerequisites for an L7 fetch are ready,
9895 * which means that a request or response is ready. If some data is missing,
9896 * a parsing attempt is made. This is useful in TCP-based ACLs which are able
Willy Tarreau24e32d82012-04-23 23:55:44 +02009897 * to extract data from L7. If <req_vol> is non-null during a request prefetch,
9898 * another test is made to ensure the required information is not gone.
Willy Tarreau14174bc2012-04-16 14:34:04 +02009899 *
9900 * The function returns :
Willy Tarreau506d0502013-07-06 13:29:24 +02009901 * 0 with SMP_F_MAY_CHANGE in the sample flags if some data is missing to
9902 * decide whether or not an HTTP message is present ;
9903 * 0 if the requested data cannot be fetched or if it is certain that
9904 * we'll never have any HTTP message there ;
Willy Tarreau14174bc2012-04-16 14:34:04 +02009905 * 1 if an HTTP message is ready
9906 */
9907static int
Willy Tarreau15e91e12015-04-04 00:52:09 +02009908smp_prefetch_http(struct proxy *px, struct stream *s, unsigned int opt,
Willy Tarreau24e32d82012-04-23 23:55:44 +02009909 const struct arg *args, struct sample *smp, int req_vol)
Willy Tarreau14174bc2012-04-16 14:34:04 +02009910{
Willy Tarreau15e91e12015-04-04 00:52:09 +02009911 struct http_txn *txn = s->txn;
Willy Tarreau14174bc2012-04-16 14:34:04 +02009912 struct http_msg *msg = &txn->req;
9913
Willy Tarreaueee5b512015-04-03 23:46:31 +02009914 /* Note: this function may only be used from places where
9915 * http_init_txn() has already been done, and implies that <s>,
9916 * <txn>, and <hdr_idx.v> are properly set. An extra check protects
9917 * against an eventual mistake in the fetch capability matrix.
Willy Tarreau14174bc2012-04-16 14:34:04 +02009918 */
9919
9920 if (unlikely(!s || !txn))
9921 return 0;
9922
9923 /* Check for a dependency on a request */
Willy Tarreauf853c462012-04-23 18:53:56 +02009924 smp->type = SMP_T_BOOL;
Willy Tarreau14174bc2012-04-16 14:34:04 +02009925
Willy Tarreau32a6f2e2012-04-25 10:13:36 +02009926 if ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) {
Willy Tarreauaae75e32013-03-29 12:31:49 +01009927 /* If the buffer does not leave enough free space at the end,
9928 * we must first realign it.
9929 */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01009930 if (s->req.buf->p > s->req.buf->data &&
9931 s->req.buf->i + s->req.buf->p > s->req.buf->data + s->req.buf->size - global.tune.maxrewrite)
9932 buffer_slow_realign(s->req.buf);
Willy Tarreauaae75e32013-03-29 12:31:49 +01009933
Willy Tarreau14174bc2012-04-16 14:34:04 +02009934 if (unlikely(txn->req.msg_state < HTTP_MSG_BODY)) {
Willy Tarreau472b1ee2013-10-14 22:41:30 +02009935 if (msg->msg_state == HTTP_MSG_ERROR)
Willy Tarreau506d0502013-07-06 13:29:24 +02009936 return 0;
Willy Tarreau14174bc2012-04-16 14:34:04 +02009937
9938 /* Try to decode HTTP request */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01009939 if (likely(msg->next < s->req.buf->i))
Willy Tarreau14174bc2012-04-16 14:34:04 +02009940 http_msg_analyzer(msg, &txn->hdr_idx);
9941
9942 /* Still no valid request ? */
9943 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
Willy Tarreau3bf1b2b2012-08-27 20:46:07 +02009944 if ((msg->msg_state == HTTP_MSG_ERROR) ||
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01009945 buffer_full(s->req.buf, global.tune.maxrewrite)) {
Willy Tarreau506d0502013-07-06 13:29:24 +02009946 return 0;
Willy Tarreau14174bc2012-04-16 14:34:04 +02009947 }
9948 /* wait for final state */
Willy Tarreau37406352012-04-23 16:16:37 +02009949 smp->flags |= SMP_F_MAY_CHANGE;
Willy Tarreau14174bc2012-04-16 14:34:04 +02009950 return 0;
9951 }
9952
9953 /* OK we just got a valid HTTP request. We have some minor
9954 * preparation to perform so that further checks can rely
9955 * on HTTP tests.
9956 */
Willy Tarreauaae75e32013-03-29 12:31:49 +01009957
9958 /* If the request was parsed but was too large, we must absolutely
9959 * return an error so that it is not processed. At the moment this
9960 * cannot happen, but if the parsers are to change in the future,
9961 * we want this check to be maintained.
9962 */
Willy Tarreau22ec1ea2014-11-27 20:45:39 +01009963 if (unlikely(s->req.buf->i + s->req.buf->p >
9964 s->req.buf->data + s->req.buf->size - global.tune.maxrewrite)) {
Willy Tarreauaae75e32013-03-29 12:31:49 +01009965 msg->msg_state = HTTP_MSG_ERROR;
Willy Tarreau506d0502013-07-06 13:29:24 +02009966 smp->data.uint = 1;
Willy Tarreauaae75e32013-03-29 12:31:49 +01009967 return 1;
9968 }
9969
Willy Tarreau9b28e032012-10-12 23:49:43 +02009970 txn->meth = find_http_meth(msg->chn->buf->p, msg->sl.rq.m_l);
Willy Tarreau14174bc2012-04-16 14:34:04 +02009971 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
Willy Tarreaue7dff022015-04-03 01:14:29 +02009972 s->flags |= SF_REDIRECTABLE;
Willy Tarreau14174bc2012-04-16 14:34:04 +02009973
Willy Tarreau506d0502013-07-06 13:29:24 +02009974 if (unlikely(msg->sl.rq.v_l == 0) && !http_upgrade_v09_to_v10(txn))
9975 return 0;
Willy Tarreau14174bc2012-04-16 14:34:04 +02009976 }
9977
Willy Tarreau506d0502013-07-06 13:29:24 +02009978 if (req_vol && txn->rsp.msg_state != HTTP_MSG_RPBEFORE) {
Willy Tarreau14174bc2012-04-16 14:34:04 +02009979 return 0; /* data might have moved and indexes changed */
Willy Tarreau506d0502013-07-06 13:29:24 +02009980 }
Willy Tarreau14174bc2012-04-16 14:34:04 +02009981
9982 /* otherwise everything's ready for the request */
9983 }
Willy Tarreau24e32d82012-04-23 23:55:44 +02009984 else {
9985 /* Check for a dependency on a response */
Willy Tarreau506d0502013-07-06 13:29:24 +02009986 if (txn->rsp.msg_state < HTTP_MSG_BODY) {
9987 smp->flags |= SMP_F_MAY_CHANGE;
Willy Tarreau14174bc2012-04-16 14:34:04 +02009988 return 0;
Willy Tarreau506d0502013-07-06 13:29:24 +02009989 }
Willy Tarreau14174bc2012-04-16 14:34:04 +02009990 }
9991
9992 /* everything's OK */
Willy Tarreau506d0502013-07-06 13:29:24 +02009993 smp->data.uint = 1;
Willy Tarreau14174bc2012-04-16 14:34:04 +02009994 return 1;
9995}
Willy Tarreau8797c062007-05-07 00:55:35 +02009996
Willy Tarreau6c616e02014-06-25 16:56:41 +02009997/* Note: these functinos *do* modify the sample. Even in case of success, at
9998 * least the type and uint value are modified.
9999 */
Willy Tarreauc0239e02012-04-16 14:42:55 +020010000#define CHECK_HTTP_MESSAGE_FIRST() \
Willy Tarreau15e91e12015-04-04 00:52:09 +020010001 do { int r = smp_prefetch_http(px, strm, opt, args, smp, 1); if (r <= 0) return r; } while (0)
Willy Tarreauc0239e02012-04-16 14:42:55 +020010002
Willy Tarreau24e32d82012-04-23 23:55:44 +020010003#define CHECK_HTTP_MESSAGE_FIRST_PERM() \
Willy Tarreau15e91e12015-04-04 00:52:09 +020010004 do { int r = smp_prefetch_http(px, strm, opt, args, smp, 0); if (r <= 0) return r; } while (0)
Willy Tarreau24e32d82012-04-23 23:55:44 +020010005
Willy Tarreau8797c062007-05-07 00:55:35 +020010006
10007/* 1. Check on METHOD
10008 * We use the pre-parsed method if it is known, and store its number as an
10009 * integer. If it is unknown, we use the pointer and the length.
10010 */
Thierry FOURNIERe47e4e22014-04-28 11:18:57 +020010011static int pat_parse_meth(const char *text, struct pattern *pattern, int mflags, char **err)
Willy Tarreau8797c062007-05-07 00:55:35 +020010012{
10013 int len, meth;
10014
Thierry FOURNIER580c32c2014-01-24 10:58:12 +010010015 len = strlen(text);
10016 meth = find_http_meth(text, len);
Willy Tarreau8797c062007-05-07 00:55:35 +020010017
10018 pattern->val.i = meth;
10019 if (meth == HTTP_METH_OTHER) {
Willy Tarreau912c1192014-08-29 15:15:50 +020010020 pattern->ptr.str = (char *)text;
Willy Tarreau8797c062007-05-07 00:55:35 +020010021 pattern->len = len;
10022 }
Thierry FOURNIERd4373142013-12-17 01:10:10 +010010023 else {
10024 pattern->ptr.str = NULL;
10025 pattern->len = 0;
Thierry FOURNIERd4373142013-12-17 01:10:10 +010010026 }
Willy Tarreau8797c062007-05-07 00:55:35 +020010027 return 1;
10028}
10029
Willy Tarreau8e5e9552011-12-16 15:38:49 +010010030/* This function fetches the method of current HTTP request and stores
10031 * it in the global pattern struct as a chunk. There are two possibilities :
10032 * - if the method is known (not HTTP_METH_OTHER), its identifier is stored
10033 * in <len> and <ptr> is NULL ;
10034 * - if the method is unknown (HTTP_METH_OTHER), <ptr> points to the text and
10035 * <len> to its length.
Thierry FOURNIERa65b3432013-11-28 18:22:00 +010010036 * This is intended to be used with pat_match_meth() only.
Willy Tarreau8e5e9552011-12-16 15:38:49 +010010037 */
Willy Tarreaud41f8d82007-06-10 10:06:18 +020010038static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010039smp_fetch_meth(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010040 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau8797c062007-05-07 00:55:35 +020010041{
10042 int meth;
Willy Tarreau15e91e12015-04-04 00:52:09 +020010043 struct http_txn *txn = strm->txn;
Willy Tarreau8797c062007-05-07 00:55:35 +020010044
Willy Tarreau24e32d82012-04-23 23:55:44 +020010045 CHECK_HTTP_MESSAGE_FIRST_PERM();
Willy Tarreauc11416f2007-06-17 16:58:38 +020010046
Willy Tarreau8797c062007-05-07 00:55:35 +020010047 meth = txn->meth;
Thierry FOURNIERd4373142013-12-17 01:10:10 +010010048 smp->type = SMP_T_METH;
10049 smp->data.meth.meth = meth;
Willy Tarreau8797c062007-05-07 00:55:35 +020010050 if (meth == HTTP_METH_OTHER) {
Willy Tarreauc11416f2007-06-17 16:58:38 +020010051 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
10052 /* ensure the indexes are not affected */
10053 return 0;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010054 smp->flags |= SMP_F_CONST;
Thierry FOURNIERd4373142013-12-17 01:10:10 +010010055 smp->data.meth.str.len = txn->req.sl.rq.m_l;
10056 smp->data.meth.str.str = txn->req.chn->buf->p;
Willy Tarreau8797c062007-05-07 00:55:35 +020010057 }
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010058 smp->flags |= SMP_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +020010059 return 1;
10060}
10061
Willy Tarreau8e5e9552011-12-16 15:38:49 +010010062/* See above how the method is stored in the global pattern */
Thierry FOURNIER5338eea2013-12-16 14:22:13 +010010063static struct pattern *pat_match_meth(struct sample *smp, struct pattern_expr *expr, int fill)
Willy Tarreau8797c062007-05-07 00:55:35 +020010064{
Willy Tarreauc8d7c962007-06-17 08:20:33 +020010065 int icase;
Thierry FOURNIER5338eea2013-12-16 14:22:13 +010010066 struct pattern_list *lst;
10067 struct pattern *pattern;
Willy Tarreauc8d7c962007-06-17 08:20:33 +020010068
Thierry FOURNIER5338eea2013-12-16 14:22:13 +010010069 list_for_each_entry(lst, &expr->patterns, list) {
10070 pattern = &lst->pat;
Willy Tarreau8797c062007-05-07 00:55:35 +020010071
Thierry FOURNIER5338eea2013-12-16 14:22:13 +010010072 /* well-known method */
10073 if (pattern->val.i != HTTP_METH_OTHER) {
10074 if (smp->data.meth.meth == pattern->val.i)
10075 return pattern;
10076 else
10077 continue;
10078 }
Willy Tarreauc8d7c962007-06-17 08:20:33 +020010079
Thierry FOURNIER5338eea2013-12-16 14:22:13 +010010080 /* Other method, we must compare the strings */
10081 if (pattern->len != smp->data.meth.str.len)
10082 continue;
10083
Thierry FOURNIERe47e4e22014-04-28 11:18:57 +020010084 icase = expr->mflags & PAT_MF_IGNORE_CASE;
Willy Tarreau4de2a942014-08-28 20:42:57 +020010085 if ((icase && strncasecmp(pattern->ptr.str, smp->data.meth.str.str, smp->data.meth.str.len) == 0) ||
10086 (!icase && strncmp(pattern->ptr.str, smp->data.meth.str.str, smp->data.meth.str.len) == 0))
Thierry FOURNIER5338eea2013-12-16 14:22:13 +010010087 return pattern;
10088 }
10089 return NULL;
Willy Tarreau8797c062007-05-07 00:55:35 +020010090}
10091
Willy Tarreaud41f8d82007-06-10 10:06:18 +020010092static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010093smp_fetch_rqver(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010094 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau8797c062007-05-07 00:55:35 +020010095{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010096 struct http_txn *txn = strm->txn;
Willy Tarreau8797c062007-05-07 00:55:35 +020010097 char *ptr;
10098 int len;
10099
Willy Tarreauc0239e02012-04-16 14:42:55 +020010100 CHECK_HTTP_MESSAGE_FIRST();
Willy Tarreauc11416f2007-06-17 16:58:38 +020010101
Willy Tarreau8797c062007-05-07 00:55:35 +020010102 len = txn->req.sl.rq.v_l;
Willy Tarreau9b28e032012-10-12 23:49:43 +020010103 ptr = txn->req.chn->buf->p + txn->req.sl.rq.v;
Willy Tarreau8797c062007-05-07 00:55:35 +020010104
10105 while ((len-- > 0) && (*ptr++ != '/'));
10106 if (len <= 0)
10107 return 0;
10108
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010109 smp->type = SMP_T_STR;
Willy Tarreauf853c462012-04-23 18:53:56 +020010110 smp->data.str.str = ptr;
10111 smp->data.str.len = len;
Willy Tarreau8797c062007-05-07 00:55:35 +020010112
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010113 smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
Willy Tarreau8797c062007-05-07 00:55:35 +020010114 return 1;
10115}
10116
Willy Tarreaud41f8d82007-06-10 10:06:18 +020010117static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010118smp_fetch_stver(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010119 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau8797c062007-05-07 00:55:35 +020010120{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010121 struct http_txn *txn;
Willy Tarreau8797c062007-05-07 00:55:35 +020010122 char *ptr;
10123 int len;
10124
Willy Tarreauc0239e02012-04-16 14:42:55 +020010125 CHECK_HTTP_MESSAGE_FIRST();
Willy Tarreauc11416f2007-06-17 16:58:38 +020010126
Willy Tarreau15e91e12015-04-04 00:52:09 +020010127 txn = strm->txn;
Willy Tarreauf26b2522012-12-14 08:33:14 +010010128 if (txn->rsp.msg_state < HTTP_MSG_BODY)
10129 return 0;
10130
Willy Tarreau8797c062007-05-07 00:55:35 +020010131 len = txn->rsp.sl.st.v_l;
Willy Tarreau9b28e032012-10-12 23:49:43 +020010132 ptr = txn->rsp.chn->buf->p;
Willy Tarreau8797c062007-05-07 00:55:35 +020010133
10134 while ((len-- > 0) && (*ptr++ != '/'));
10135 if (len <= 0)
10136 return 0;
10137
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010138 smp->type = SMP_T_STR;
Willy Tarreauf853c462012-04-23 18:53:56 +020010139 smp->data.str.str = ptr;
10140 smp->data.str.len = len;
Willy Tarreau8797c062007-05-07 00:55:35 +020010141
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010142 smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
Willy Tarreau8797c062007-05-07 00:55:35 +020010143 return 1;
10144}
10145
10146/* 3. Check on Status Code. We manipulate integers here. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +020010147static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010148smp_fetch_stcode(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010149 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau8797c062007-05-07 00:55:35 +020010150{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010151 struct http_txn *txn;
Willy Tarreau8797c062007-05-07 00:55:35 +020010152 char *ptr;
10153 int len;
10154
Willy Tarreauc0239e02012-04-16 14:42:55 +020010155 CHECK_HTTP_MESSAGE_FIRST();
Willy Tarreauc11416f2007-06-17 16:58:38 +020010156
Willy Tarreau15e91e12015-04-04 00:52:09 +020010157 txn = strm->txn;
Willy Tarreauf26b2522012-12-14 08:33:14 +010010158 if (txn->rsp.msg_state < HTTP_MSG_BODY)
10159 return 0;
10160
Willy Tarreau8797c062007-05-07 00:55:35 +020010161 len = txn->rsp.sl.st.c_l;
Willy Tarreau9b28e032012-10-12 23:49:43 +020010162 ptr = txn->rsp.chn->buf->p + txn->rsp.sl.st.c;
Willy Tarreau8797c062007-05-07 00:55:35 +020010163
Willy Tarreauf853c462012-04-23 18:53:56 +020010164 smp->type = SMP_T_UINT;
10165 smp->data.uint = __strl2ui(ptr, len);
Willy Tarreau37406352012-04-23 16:16:37 +020010166 smp->flags = SMP_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +020010167 return 1;
10168}
10169
10170/* 4. Check on URL/URI. A pointer to the URI is stored. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +020010171static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010172smp_fetch_url(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010173 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau8797c062007-05-07 00:55:35 +020010174{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010175 struct http_txn *txn;
Willy Tarreau8797c062007-05-07 00:55:35 +020010176
Willy Tarreauc0239e02012-04-16 14:42:55 +020010177 CHECK_HTTP_MESSAGE_FIRST();
Willy Tarreauc11416f2007-06-17 16:58:38 +020010178
Willy Tarreau15e91e12015-04-04 00:52:09 +020010179 txn = strm->txn;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010180 smp->type = SMP_T_STR;
Willy Tarreauf853c462012-04-23 18:53:56 +020010181 smp->data.str.len = txn->req.sl.rq.u_l;
Willy Tarreau9b28e032012-10-12 23:49:43 +020010182 smp->data.str.str = txn->req.chn->buf->p + txn->req.sl.rq.u;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010183 smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
Willy Tarreau8797c062007-05-07 00:55:35 +020010184 return 1;
10185}
10186
Alexandre Cassen5eb1a902007-11-29 15:43:32 +010010187static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010188smp_fetch_url_ip(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010189 const struct arg *args, struct sample *smp, const char *kw, void *private)
Alexandre Cassen5eb1a902007-11-29 15:43:32 +010010190{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010191 struct http_txn *txn;
Willy Tarreau4c804ec2013-09-30 14:37:14 +020010192 struct sockaddr_storage addr;
Alexandre Cassen5eb1a902007-11-29 15:43:32 +010010193
Willy Tarreauc0239e02012-04-16 14:42:55 +020010194 CHECK_HTTP_MESSAGE_FIRST();
Alexandre Cassen5eb1a902007-11-29 15:43:32 +010010195
Willy Tarreau15e91e12015-04-04 00:52:09 +020010196 txn = strm->txn;
Thierry FOURNIER9f95e402014-03-21 14:51:46 +010010197 url2sa(txn->req.chn->buf->p + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &addr, NULL);
Willy Tarreau4c804ec2013-09-30 14:37:14 +020010198 if (((struct sockaddr_in *)&addr)->sin_family != AF_INET)
Willy Tarreauf4362b32011-12-16 17:49:52 +010010199 return 0;
Alexandre Cassen5eb1a902007-11-29 15:43:32 +010010200
Willy Tarreau4c804ec2013-09-30 14:37:14 +020010201 smp->type = SMP_T_IPV4;
10202 smp->data.ipv4 = ((struct sockaddr_in *)&addr)->sin_addr;
Willy Tarreau37406352012-04-23 16:16:37 +020010203 smp->flags = 0;
Alexandre Cassen5eb1a902007-11-29 15:43:32 +010010204 return 1;
10205}
10206
10207static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010208smp_fetch_url_port(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010209 const struct arg *args, struct sample *smp, const char *kw, void *private)
Alexandre Cassen5eb1a902007-11-29 15:43:32 +010010210{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010211 struct http_txn *txn;
Willy Tarreau4c804ec2013-09-30 14:37:14 +020010212 struct sockaddr_storage addr;
Alexandre Cassen5eb1a902007-11-29 15:43:32 +010010213
Willy Tarreauc0239e02012-04-16 14:42:55 +020010214 CHECK_HTTP_MESSAGE_FIRST();
Alexandre Cassen5eb1a902007-11-29 15:43:32 +010010215
Willy Tarreau15e91e12015-04-04 00:52:09 +020010216 txn = strm->txn;
Thierry FOURNIER9f95e402014-03-21 14:51:46 +010010217 url2sa(txn->req.chn->buf->p + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &addr, NULL);
Willy Tarreau4c804ec2013-09-30 14:37:14 +020010218 if (((struct sockaddr_in *)&addr)->sin_family != AF_INET)
10219 return 0;
Alexandre Cassen5eb1a902007-11-29 15:43:32 +010010220
Willy Tarreau4c804ec2013-09-30 14:37:14 +020010221 smp->type = SMP_T_UINT;
10222 smp->data.uint = ntohs(((struct sockaddr_in *)&addr)->sin_port);
Willy Tarreau21e5b0e2012-04-23 19:25:44 +020010223 smp->flags = 0;
Alexandre Cassen5eb1a902007-11-29 15:43:32 +010010224 return 1;
10225}
10226
Willy Tarreau185b5c42012-04-26 15:11:51 +020010227/* Fetch an HTTP header. A pointer to the beginning of the value is returned.
10228 * Accepts an optional argument of type string containing the header field name,
10229 * and an optional argument of type signed or unsigned integer to request an
10230 * explicit occurrence of the header. Note that in the event of a missing name,
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010231 * headers are considered from the first one. It does not stop on commas and
10232 * returns full lines instead (useful for User-Agent or Date for example).
10233 */
10234static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010235smp_fetch_fhdr(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010236 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010237{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010238 struct hdr_idx *idx;
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010239 struct hdr_ctx *ctx = smp->ctx.a[0];
Willy Tarreau15e91e12015-04-04 00:52:09 +020010240 const struct http_msg *msg;
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010241 int occ = 0;
10242 const char *name_str = NULL;
10243 int name_len = 0;
10244
10245 if (!ctx) {
10246 /* first call */
10247 ctx = &static_hdr_ctx;
10248 ctx->idx = 0;
10249 smp->ctx.a[0] = ctx;
10250 }
10251
10252 if (args) {
10253 if (args[0].type != ARGT_STR)
10254 return 0;
10255 name_str = args[0].data.str.str;
10256 name_len = args[0].data.str.len;
10257
10258 if (args[1].type == ARGT_UINT || args[1].type == ARGT_SINT)
10259 occ = args[1].data.uint;
10260 }
10261
10262 CHECK_HTTP_MESSAGE_FIRST();
10263
Willy Tarreau15e91e12015-04-04 00:52:09 +020010264 idx = &strm->txn->hdr_idx;
10265 msg = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &strm->txn->req : &strm->txn->rsp;
10266
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010267 if (ctx && !(smp->flags & SMP_F_NOT_LAST))
10268 /* search for header from the beginning */
10269 ctx->idx = 0;
10270
10271 if (!occ && !(opt & SMP_OPT_ITERATE))
10272 /* no explicit occurrence and single fetch => last header by default */
10273 occ = -1;
10274
10275 if (!occ)
10276 /* prepare to report multiple occurrences for ACL fetches */
10277 smp->flags |= SMP_F_NOT_LAST;
10278
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010279 smp->type = SMP_T_STR;
10280 smp->flags |= SMP_F_VOL_HDR | SMP_F_CONST;
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010281 if (http_get_fhdr(msg, name_str, name_len, idx, occ, ctx, &smp->data.str.str, &smp->data.str.len))
10282 return 1;
10283
10284 smp->flags &= ~SMP_F_NOT_LAST;
10285 return 0;
10286}
10287
10288/* 6. Check on HTTP header count. The number of occurrences is returned.
10289 * Accepts exactly 1 argument of type string. It does not stop on commas and
10290 * returns full lines instead (useful for User-Agent or Date for example).
10291 */
10292static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010293smp_fetch_fhdr_cnt(struct proxy *px, struct stream *strm, unsigned int opt,
10294 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010295{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010296 struct hdr_idx *idx;
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010297 struct hdr_ctx ctx;
Willy Tarreau15e91e12015-04-04 00:52:09 +020010298 const struct http_msg *msg;
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010299 int cnt;
Willy Tarreau601a4d12015-04-01 19:16:09 +020010300 const char *name = NULL;
10301 int len = 0;
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010302
Willy Tarreau601a4d12015-04-01 19:16:09 +020010303 if (args && args->type == ARGT_STR) {
10304 name = args->data.str.str;
10305 len = args->data.str.len;
10306 }
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010307
10308 CHECK_HTTP_MESSAGE_FIRST();
10309
Willy Tarreau15e91e12015-04-04 00:52:09 +020010310 idx = &strm->txn->hdr_idx;
10311 msg = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &strm->txn->req : &strm->txn->rsp;
10312
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010313 ctx.idx = 0;
10314 cnt = 0;
Willy Tarreau601a4d12015-04-01 19:16:09 +020010315 while (http_find_full_header2(name, len, msg->chn->buf->p, idx, &ctx))
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010316 cnt++;
10317
10318 smp->type = SMP_T_UINT;
10319 smp->data.uint = cnt;
10320 smp->flags = SMP_F_VOL_HDR;
10321 return 1;
10322}
10323
Willy Tarreaueb27ec72015-02-20 13:55:29 +010010324static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010325smp_fetch_hdr_names(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010326 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaueb27ec72015-02-20 13:55:29 +010010327{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010328 struct hdr_idx *idx;
Willy Tarreaueb27ec72015-02-20 13:55:29 +010010329 struct hdr_ctx ctx;
Willy Tarreau15e91e12015-04-04 00:52:09 +020010330 const struct http_msg *msg;
Willy Tarreaueb27ec72015-02-20 13:55:29 +010010331 struct chunk *temp;
10332 char del = ',';
10333
10334 if (args && args->type == ARGT_STR)
10335 del = *args[0].data.str.str;
10336
10337 CHECK_HTTP_MESSAGE_FIRST();
10338
Willy Tarreau15e91e12015-04-04 00:52:09 +020010339 idx = &strm->txn->hdr_idx;
10340 msg = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &strm->txn->req : &strm->txn->rsp;
10341
Willy Tarreaueb27ec72015-02-20 13:55:29 +010010342 temp = get_trash_chunk();
10343
10344 ctx.idx = 0;
10345 while (http_find_next_header(msg->chn->buf->p, idx, &ctx)) {
10346 if (temp->len)
10347 temp->str[temp->len++] = del;
10348 memcpy(temp->str + temp->len, ctx.line, ctx.del);
10349 temp->len += ctx.del;
10350 }
10351
10352 smp->type = SMP_T_STR;
10353 smp->data.str.str = temp->str;
10354 smp->data.str.len = temp->len;
10355 smp->flags = SMP_F_VOL_HDR;
10356 return 1;
10357}
10358
Willy Tarreau04ff9f12013-06-10 18:39:42 +020010359/* Fetch an HTTP header. A pointer to the beginning of the value is returned.
10360 * Accepts an optional argument of type string containing the header field name,
10361 * and an optional argument of type signed or unsigned integer to request an
10362 * explicit occurrence of the header. Note that in the event of a missing name,
Willy Tarreau185b5c42012-04-26 15:11:51 +020010363 * headers are considered from the first one.
Willy Tarreauc11416f2007-06-17 16:58:38 +020010364 */
Willy Tarreau33a7e692007-06-10 19:45:56 +020010365static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010366smp_fetch_hdr(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010367 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau33a7e692007-06-10 19:45:56 +020010368{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010369 struct hdr_idx *idx;
Willy Tarreaua890d072013-04-02 12:01:06 +020010370 struct hdr_ctx *ctx = smp->ctx.a[0];
Willy Tarreau15e91e12015-04-04 00:52:09 +020010371 const struct http_msg *msg;
Willy Tarreau185b5c42012-04-26 15:11:51 +020010372 int occ = 0;
10373 const char *name_str = NULL;
10374 int name_len = 0;
Willy Tarreaue333ec92012-04-16 16:26:40 +020010375
Willy Tarreaua890d072013-04-02 12:01:06 +020010376 if (!ctx) {
10377 /* first call */
10378 ctx = &static_hdr_ctx;
10379 ctx->idx = 0;
Willy Tarreauffb6f082013-04-02 23:16:53 +020010380 smp->ctx.a[0] = ctx;
Willy Tarreaua890d072013-04-02 12:01:06 +020010381 }
10382
Willy Tarreau185b5c42012-04-26 15:11:51 +020010383 if (args) {
10384 if (args[0].type != ARGT_STR)
10385 return 0;
10386 name_str = args[0].data.str.str;
10387 name_len = args[0].data.str.len;
10388
10389 if (args[1].type == ARGT_UINT || args[1].type == ARGT_SINT)
10390 occ = args[1].data.uint;
10391 }
Willy Tarreau34db1082012-04-19 17:16:54 +020010392
Willy Tarreaue333ec92012-04-16 16:26:40 +020010393 CHECK_HTTP_MESSAGE_FIRST();
Willy Tarreau33a7e692007-06-10 19:45:56 +020010394
Willy Tarreau15e91e12015-04-04 00:52:09 +020010395 idx = &strm->txn->hdr_idx;
10396 msg = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &strm->txn->req : &strm->txn->rsp;
10397
Willy Tarreau185b5c42012-04-26 15:11:51 +020010398 if (ctx && !(smp->flags & SMP_F_NOT_LAST))
Willy Tarreau33a7e692007-06-10 19:45:56 +020010399 /* search for header from the beginning */
10400 ctx->idx = 0;
10401
Willy Tarreau185b5c42012-04-26 15:11:51 +020010402 if (!occ && !(opt & SMP_OPT_ITERATE))
10403 /* no explicit occurrence and single fetch => last header by default */
10404 occ = -1;
10405
10406 if (!occ)
10407 /* prepare to report multiple occurrences for ACL fetches */
Willy Tarreau37406352012-04-23 16:16:37 +020010408 smp->flags |= SMP_F_NOT_LAST;
Willy Tarreau664092c2011-12-16 19:11:42 +010010409
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010410 smp->type = SMP_T_STR;
10411 smp->flags |= SMP_F_VOL_HDR | SMP_F_CONST;
Willy Tarreau185b5c42012-04-26 15:11:51 +020010412 if (http_get_hdr(msg, name_str, name_len, idx, occ, ctx, &smp->data.str.str, &smp->data.str.len))
Willy Tarreau33a7e692007-06-10 19:45:56 +020010413 return 1;
Willy Tarreau33a7e692007-06-10 19:45:56 +020010414
Willy Tarreau37406352012-04-23 16:16:37 +020010415 smp->flags &= ~SMP_F_NOT_LAST;
Willy Tarreau33a7e692007-06-10 19:45:56 +020010416 return 0;
10417}
10418
Willy Tarreauc11416f2007-06-17 16:58:38 +020010419/* 6. Check on HTTP header count. The number of occurrences is returned.
Willy Tarreau34db1082012-04-19 17:16:54 +020010420 * Accepts exactly 1 argument of type string.
Willy Tarreauc11416f2007-06-17 16:58:38 +020010421 */
10422static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010423smp_fetch_hdr_cnt(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010424 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau33a7e692007-06-10 19:45:56 +020010425{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010426 struct hdr_idx *idx;
Willy Tarreau33a7e692007-06-10 19:45:56 +020010427 struct hdr_ctx ctx;
Willy Tarreau15e91e12015-04-04 00:52:09 +020010428 const struct http_msg *msg;
Willy Tarreau33a7e692007-06-10 19:45:56 +020010429 int cnt;
Willy Tarreau601a4d12015-04-01 19:16:09 +020010430 const char *name = NULL;
10431 int len = 0;
Willy Tarreau8797c062007-05-07 00:55:35 +020010432
Willy Tarreau601a4d12015-04-01 19:16:09 +020010433 if (args && args->type == ARGT_STR) {
10434 name = args->data.str.str;
10435 len = args->data.str.len;
10436 }
Willy Tarreau34db1082012-04-19 17:16:54 +020010437
Willy Tarreaue333ec92012-04-16 16:26:40 +020010438 CHECK_HTTP_MESSAGE_FIRST();
10439
Willy Tarreau15e91e12015-04-04 00:52:09 +020010440 idx = &strm->txn->hdr_idx;
10441 msg = ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) ? &strm->txn->req : &strm->txn->rsp;
10442
Willy Tarreau33a7e692007-06-10 19:45:56 +020010443 ctx.idx = 0;
10444 cnt = 0;
Willy Tarreau601a4d12015-04-01 19:16:09 +020010445 while (http_find_header2(name, len, msg->chn->buf->p, idx, &ctx))
Willy Tarreau33a7e692007-06-10 19:45:56 +020010446 cnt++;
10447
Willy Tarreauf853c462012-04-23 18:53:56 +020010448 smp->type = SMP_T_UINT;
10449 smp->data.uint = cnt;
Willy Tarreau37406352012-04-23 16:16:37 +020010450 smp->flags = SMP_F_VOL_HDR;
Willy Tarreau33a7e692007-06-10 19:45:56 +020010451 return 1;
10452}
10453
Willy Tarreau185b5c42012-04-26 15:11:51 +020010454/* Fetch an HTTP header's integer value. The integer value is returned. It
10455 * takes a mandatory argument of type string and an optional one of type int
10456 * to designate a specific occurrence. It returns an unsigned integer, which
10457 * may or may not be appropriate for everything.
Willy Tarreau33a7e692007-06-10 19:45:56 +020010458 */
10459static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010460smp_fetch_hdr_val(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010461 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau33a7e692007-06-10 19:45:56 +020010462{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010463 int ret = smp_fetch_hdr(px, strm, opt, args, smp, kw, private);
Willy Tarreaue333ec92012-04-16 16:26:40 +020010464
Willy Tarreauf853c462012-04-23 18:53:56 +020010465 if (ret > 0) {
10466 smp->type = SMP_T_UINT;
10467 smp->data.uint = strl2ic(smp->data.str.str, smp->data.str.len);
10468 }
Willy Tarreau33a7e692007-06-10 19:45:56 +020010469
Willy Tarreaud53e2422012-04-16 17:21:11 +020010470 return ret;
Willy Tarreau33a7e692007-06-10 19:45:56 +020010471}
10472
Cyril Bonté69fa9922012-10-25 00:01:06 +020010473/* Fetch an HTTP header's IP value. takes a mandatory argument of type string
10474 * and an optional one of type int to designate a specific occurrence.
10475 * It returns an IPv4 or IPv6 address.
Willy Tarreau106f9792009-09-19 07:54:16 +020010476 */
10477static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010478smp_fetch_hdr_ip(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010479 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau106f9792009-09-19 07:54:16 +020010480{
Willy Tarreaud53e2422012-04-16 17:21:11 +020010481 int ret;
Willy Tarreaue333ec92012-04-16 16:26:40 +020010482
Willy Tarreau15e91e12015-04-04 00:52:09 +020010483 while ((ret = smp_fetch_hdr(px, strm, opt, args, smp, kw, private)) > 0) {
Cyril Bonté69fa9922012-10-25 00:01:06 +020010484 if (url2ipv4((char *)smp->data.str.str, &smp->data.ipv4)) {
10485 smp->type = SMP_T_IPV4;
Willy Tarreaud53e2422012-04-16 17:21:11 +020010486 break;
Cyril Bonté69fa9922012-10-25 00:01:06 +020010487 } else {
Willy Tarreau47ca5452012-12-23 20:22:19 +010010488 struct chunk *temp = get_trash_chunk();
Cyril Bonté69fa9922012-10-25 00:01:06 +020010489 if (smp->data.str.len < temp->size - 1) {
10490 memcpy(temp->str, smp->data.str.str, smp->data.str.len);
10491 temp->str[smp->data.str.len] = '\0';
10492 if (inet_pton(AF_INET6, temp->str, &smp->data.ipv6)) {
10493 smp->type = SMP_T_IPV6;
10494 break;
10495 }
10496 }
10497 }
10498
Willy Tarreaud53e2422012-04-16 17:21:11 +020010499 /* if the header doesn't match an IP address, fetch next one */
Willy Tarreau185b5c42012-04-26 15:11:51 +020010500 if (!(smp->flags & SMP_F_NOT_LAST))
10501 return 0;
Willy Tarreau106f9792009-09-19 07:54:16 +020010502 }
Willy Tarreaud53e2422012-04-16 17:21:11 +020010503 return ret;
Willy Tarreau106f9792009-09-19 07:54:16 +020010504}
10505
Willy Tarreau737b0c12007-06-10 21:28:46 +020010506/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at
10507 * the first '/' after the possible hostname, and ends before the possible '?'.
10508 */
10509static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010510smp_fetch_path(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010511 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau737b0c12007-06-10 21:28:46 +020010512{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010513 struct http_txn *txn;
Willy Tarreau737b0c12007-06-10 21:28:46 +020010514 char *ptr, *end;
Willy Tarreau33a7e692007-06-10 19:45:56 +020010515
Willy Tarreauc0239e02012-04-16 14:42:55 +020010516 CHECK_HTTP_MESSAGE_FIRST();
Willy Tarreauc11416f2007-06-17 16:58:38 +020010517
Willy Tarreau15e91e12015-04-04 00:52:09 +020010518 txn = strm->txn;
Willy Tarreau9b28e032012-10-12 23:49:43 +020010519 end = txn->req.chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
Willy Tarreau21d2af32008-02-14 20:25:24 +010010520 ptr = http_get_path(txn);
10521 if (!ptr)
Willy Tarreau737b0c12007-06-10 21:28:46 +020010522 return 0;
10523
10524 /* OK, we got the '/' ! */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010525 smp->type = SMP_T_STR;
Willy Tarreauf853c462012-04-23 18:53:56 +020010526 smp->data.str.str = ptr;
Willy Tarreau737b0c12007-06-10 21:28:46 +020010527
10528 while (ptr < end && *ptr != '?')
10529 ptr++;
10530
Willy Tarreauf853c462012-04-23 18:53:56 +020010531 smp->data.str.len = ptr - smp->data.str.str;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010532 smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
Willy Tarreau737b0c12007-06-10 21:28:46 +020010533 return 1;
10534}
10535
Willy Tarreaua7ad50c2012-04-29 15:39:40 +020010536/* This produces a concatenation of the first occurrence of the Host header
10537 * followed by the path component if it begins with a slash ('/'). This means
10538 * that '*' will not be added, resulting in exactly the first Host entry.
10539 * If no Host header is found, then the path is returned as-is. The returned
10540 * value is stored in the trash so it does not need to be marked constant.
Willy Tarreaub169eba2013-12-16 15:14:43 +010010541 * The returned sample is of type string.
Willy Tarreaua7ad50c2012-04-29 15:39:40 +020010542 */
10543static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010544smp_fetch_base(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010545 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaua7ad50c2012-04-29 15:39:40 +020010546{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010547 struct http_txn *txn;
Willy Tarreaua7ad50c2012-04-29 15:39:40 +020010548 char *ptr, *end, *beg;
10549 struct hdr_ctx ctx;
Willy Tarreau3caf2af2014-06-24 17:27:02 +020010550 struct chunk *temp;
Willy Tarreaua7ad50c2012-04-29 15:39:40 +020010551
10552 CHECK_HTTP_MESSAGE_FIRST();
10553
Willy Tarreau15e91e12015-04-04 00:52:09 +020010554 txn = strm->txn;
Willy Tarreaua7ad50c2012-04-29 15:39:40 +020010555 ctx.idx = 0;
Willy Tarreau877e78d2013-04-07 18:48:08 +020010556 if (!http_find_header2("Host", 4, txn->req.chn->buf->p, &txn->hdr_idx, &ctx) || !ctx.vlen)
Willy Tarreau15e91e12015-04-04 00:52:09 +020010557 return smp_fetch_path(px, strm, opt, args, smp, kw, private);
Willy Tarreaua7ad50c2012-04-29 15:39:40 +020010558
10559 /* OK we have the header value in ctx.line+ctx.val for ctx.vlen bytes */
Willy Tarreau3caf2af2014-06-24 17:27:02 +020010560 temp = get_trash_chunk();
10561 memcpy(temp->str, ctx.line + ctx.val, ctx.vlen);
Willy Tarreaua7ad50c2012-04-29 15:39:40 +020010562 smp->type = SMP_T_STR;
Willy Tarreau3caf2af2014-06-24 17:27:02 +020010563 smp->data.str.str = temp->str;
Willy Tarreaua7ad50c2012-04-29 15:39:40 +020010564 smp->data.str.len = ctx.vlen;
10565
10566 /* now retrieve the path */
Willy Tarreau877e78d2013-04-07 18:48:08 +020010567 end = txn->req.chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
Willy Tarreaua7ad50c2012-04-29 15:39:40 +020010568 beg = http_get_path(txn);
10569 if (!beg)
10570 beg = end;
10571
10572 for (ptr = beg; ptr < end && *ptr != '?'; ptr++);
10573
10574 if (beg < ptr && *beg == '/') {
10575 memcpy(smp->data.str.str + smp->data.str.len, beg, ptr - beg);
10576 smp->data.str.len += ptr - beg;
10577 }
10578
10579 smp->flags = SMP_F_VOL_1ST;
10580 return 1;
10581}
10582
Willy Tarreauab1f7b72012-12-09 13:38:54 +010010583/* This produces a 32-bit hash of the concatenation of the first occurrence of
10584 * the Host header followed by the path component if it begins with a slash ('/').
10585 * This means that '*' will not be added, resulting in exactly the first Host
10586 * entry. If no Host header is found, then the path is used. The resulting value
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000010587 * is hashed using the path hash followed by a full avalanche hash and provides a
10588 * 32-bit integer value. This fetch is useful for tracking per-path activity on
Willy Tarreauab1f7b72012-12-09 13:38:54 +010010589 * high-traffic sites without having to store whole paths.
10590 */
Thierry FOURNIER055b9d52014-07-15 16:11:07 +020010591int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010592smp_fetch_base32(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010593 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreauab1f7b72012-12-09 13:38:54 +010010594{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010595 struct http_txn *txn;
Willy Tarreauab1f7b72012-12-09 13:38:54 +010010596 struct hdr_ctx ctx;
10597 unsigned int hash = 0;
10598 char *ptr, *beg, *end;
10599 int len;
10600
10601 CHECK_HTTP_MESSAGE_FIRST();
10602
Willy Tarreau15e91e12015-04-04 00:52:09 +020010603 txn = strm->txn;
Willy Tarreauab1f7b72012-12-09 13:38:54 +010010604 ctx.idx = 0;
Willy Tarreau877e78d2013-04-07 18:48:08 +020010605 if (http_find_header2("Host", 4, txn->req.chn->buf->p, &txn->hdr_idx, &ctx)) {
Willy Tarreauab1f7b72012-12-09 13:38:54 +010010606 /* OK we have the header value in ctx.line+ctx.val for ctx.vlen bytes */
10607 ptr = ctx.line + ctx.val;
10608 len = ctx.vlen;
10609 while (len--)
10610 hash = *(ptr++) + (hash << 6) + (hash << 16) - hash;
10611 }
10612
10613 /* now retrieve the path */
Willy Tarreau877e78d2013-04-07 18:48:08 +020010614 end = txn->req.chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
Willy Tarreauab1f7b72012-12-09 13:38:54 +010010615 beg = http_get_path(txn);
10616 if (!beg)
10617 beg = end;
10618
10619 for (ptr = beg; ptr < end && *ptr != '?'; ptr++);
10620
10621 if (beg < ptr && *beg == '/') {
10622 while (beg < ptr)
10623 hash = *(beg++) + (hash << 6) + (hash << 16) - hash;
10624 }
10625 hash = full_hash(hash);
10626
10627 smp->type = SMP_T_UINT;
10628 smp->data.uint = hash;
10629 smp->flags = SMP_F_VOL_1ST;
10630 return 1;
10631}
10632
Willy Tarreau4a550602012-12-09 14:53:32 +010010633/* This concatenates the source address with the 32-bit hash of the Host and
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000010634 * path as returned by smp_fetch_base32(). The idea is to have per-source and
10635 * per-path counters. The result is a binary block from 8 to 20 bytes depending
10636 * on the source address length. The path hash is stored before the address so
Willy Tarreau4a550602012-12-09 14:53:32 +010010637 * that in environments where IPv6 is insignificant, truncating the output to
10638 * 8 bytes would still work.
10639 */
10640static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010641smp_fetch_base32_src(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010642 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau4a550602012-12-09 14:53:32 +010010643{
Willy Tarreau47ca5452012-12-23 20:22:19 +010010644 struct chunk *temp;
Willy Tarreau15e91e12015-04-04 00:52:09 +020010645 struct session *sess = strm_sess(strm);
Willy Tarreau9ad7bd42015-04-03 19:19:59 +020010646 struct connection *cli_conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +020010647
10648 if (!cli_conn)
10649 return 0;
Willy Tarreau4a550602012-12-09 14:53:32 +010010650
Willy Tarreau15e91e12015-04-04 00:52:09 +020010651 if (!smp_fetch_base32(px, strm, opt, args, smp, kw, private))
Willy Tarreau4a550602012-12-09 14:53:32 +010010652 return 0;
10653
Willy Tarreau47ca5452012-12-23 20:22:19 +010010654 temp = get_trash_chunk();
Willy Tarreau5ad6e1d2014-07-15 21:34:06 +020010655 *(unsigned int *)temp->str = htonl(smp->data.uint);
10656 temp->len += sizeof(unsigned int);
Willy Tarreau4a550602012-12-09 14:53:32 +010010657
Willy Tarreaub363a1f2013-10-01 10:45:07 +020010658 switch (cli_conn->addr.from.ss_family) {
Willy Tarreau4a550602012-12-09 14:53:32 +010010659 case AF_INET:
Willy Tarreaub363a1f2013-10-01 10:45:07 +020010660 memcpy(temp->str + temp->len, &((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr, 4);
Willy Tarreau4a550602012-12-09 14:53:32 +010010661 temp->len += 4;
10662 break;
10663 case AF_INET6:
Willy Tarreaub363a1f2013-10-01 10:45:07 +020010664 memcpy(temp->str + temp->len, &((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr, 16);
Willy Tarreau4a550602012-12-09 14:53:32 +010010665 temp->len += 16;
10666 break;
10667 default:
10668 return 0;
10669 }
10670
10671 smp->data.str = *temp;
10672 smp->type = SMP_T_BIN;
10673 return 1;
10674}
10675
Willy Tarreau49ad95c2015-01-19 15:06:26 +010010676/* Extracts the query string, which comes after the question mark '?'. If no
10677 * question mark is found, nothing is returned. Otherwise it returns a sample
10678 * of type string carrying the whole query string.
10679 */
10680static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010681smp_fetch_query(struct proxy *px, struct stream *strm, unsigned int opt,
10682 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau49ad95c2015-01-19 15:06:26 +010010683{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010684 struct http_txn *txn;
Willy Tarreau49ad95c2015-01-19 15:06:26 +010010685 char *ptr, *end;
10686
10687 CHECK_HTTP_MESSAGE_FIRST();
10688
Willy Tarreau15e91e12015-04-04 00:52:09 +020010689 txn = strm->txn;
Willy Tarreau49ad95c2015-01-19 15:06:26 +010010690 ptr = txn->req.chn->buf->p + txn->req.sl.rq.u;
10691 end = ptr + txn->req.sl.rq.u_l;
10692
10693 /* look up the '?' */
10694 do {
10695 if (ptr == end)
10696 return 0;
10697 } while (*ptr++ != '?');
10698
10699 smp->type = SMP_T_STR;
10700 smp->data.str.str = ptr;
10701 smp->data.str.len = end - ptr;
10702 smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
10703 return 1;
10704}
10705
Willy Tarreau2492d5b2009-07-11 00:06:00 +020010706static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010707smp_fetch_proto_http(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010708 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau2492d5b2009-07-11 00:06:00 +020010709{
Willy Tarreau2492d5b2009-07-11 00:06:00 +020010710 /* Note: hdr_idx.v cannot be NULL in this ACL because the ACL is tagged
10711 * as a layer7 ACL, which involves automatic allocation of hdr_idx.
10712 */
Willy Tarreau2492d5b2009-07-11 00:06:00 +020010713
Willy Tarreau24e32d82012-04-23 23:55:44 +020010714 CHECK_HTTP_MESSAGE_FIRST_PERM();
Willy Tarreau2492d5b2009-07-11 00:06:00 +020010715
Willy Tarreauf853c462012-04-23 18:53:56 +020010716 smp->type = SMP_T_BOOL;
Willy Tarreau197e10a2012-04-23 19:18:42 +020010717 smp->data.uint = 1;
Willy Tarreau2492d5b2009-07-11 00:06:00 +020010718 return 1;
10719}
10720
Willy Tarreau7f18e522010-10-22 20:04:13 +020010721/* return a valid test if the current request is the first one on the connection */
10722static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010723smp_fetch_http_first_req(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010724 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau7f18e522010-10-22 20:04:13 +020010725{
Willy Tarreauf853c462012-04-23 18:53:56 +020010726 smp->type = SMP_T_BOOL;
Willy Tarreau15e91e12015-04-04 00:52:09 +020010727 smp->data.uint = !(strm->txn->flags & TX_NOT_FIRST);
Willy Tarreau7f18e522010-10-22 20:04:13 +020010728 return 1;
10729}
10730
Willy Tarreau34db1082012-04-19 17:16:54 +020010731/* Accepts exactly 1 argument of type userlist */
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +010010732static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010733smp_fetch_http_auth(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010734 const struct arg *args, struct sample *smp, const char *kw, void *private)
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +010010735{
10736
Willy Tarreau24e32d82012-04-23 23:55:44 +020010737 if (!args || args->type != ARGT_USR)
Willy Tarreau34db1082012-04-19 17:16:54 +020010738 return 0;
10739
Willy Tarreauc0239e02012-04-16 14:42:55 +020010740 CHECK_HTTP_MESSAGE_FIRST();
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +010010741
Willy Tarreau15e91e12015-04-04 00:52:09 +020010742 if (!get_http_auth(strm))
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +010010743 return 0;
10744
Willy Tarreauf853c462012-04-23 18:53:56 +020010745 smp->type = SMP_T_BOOL;
Willy Tarreau15e91e12015-04-04 00:52:09 +020010746 smp->data.uint = check_user(args->data.usr, strm->txn->auth.user, strm->txn->auth.pass);
Krzysztof Piotr Oledzkif9423ae2010-01-29 19:26:18 +010010747 return 1;
10748}
Willy Tarreau8797c062007-05-07 00:55:35 +020010749
Willy Tarreau4a3fd4c2012-05-10 23:18:26 +020010750/* Accepts exactly 1 argument of type userlist */
10751static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010752smp_fetch_http_auth_grp(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010753 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau4a3fd4c2012-05-10 23:18:26 +020010754{
Willy Tarreau4a3fd4c2012-05-10 23:18:26 +020010755 if (!args || args->type != ARGT_USR)
10756 return 0;
10757
10758 CHECK_HTTP_MESSAGE_FIRST();
10759
Willy Tarreau15e91e12015-04-04 00:52:09 +020010760 if (!get_http_auth(strm))
Willy Tarreau4a3fd4c2012-05-10 23:18:26 +020010761 return 0;
10762
Willy Tarreau4a3fd4c2012-05-10 23:18:26 +020010763 /* if the user does not belong to the userlist or has a wrong password,
10764 * report that it unconditionally does not match. Otherwise we return
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010010765 * a string containing the username.
Willy Tarreau4a3fd4c2012-05-10 23:18:26 +020010766 */
Willy Tarreau15e91e12015-04-04 00:52:09 +020010767 if (!check_user(args->data.usr, strm->txn->auth.user, strm->txn->auth.pass))
Thierry FOURNIER9eec0a62014-01-22 18:38:02 +010010768 return 0;
10769
10770 /* pat_match_auth() will need the user list */
10771 smp->ctx.a[0] = args->data.usr;
10772
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010773 smp->type = SMP_T_STR;
10774 smp->flags = SMP_F_CONST;
Willy Tarreau15e91e12015-04-04 00:52:09 +020010775 smp->data.str.str = strm->txn->auth.user;
10776 smp->data.str.len = strlen(strm->txn->auth.user);
Willy Tarreau4a3fd4c2012-05-10 23:18:26 +020010777
10778 return 1;
10779}
10780
Willy Tarreau04aa6a92012-04-06 18:57:55 +020010781/* Try to find the next occurrence of a cookie name in a cookie header value.
10782 * The lookup begins at <hdr>. The pointer and size of the next occurrence of
10783 * the cookie value is returned into *value and *value_l, and the function
10784 * returns a pointer to the next pointer to search from if the value was found.
10785 * Otherwise if the cookie was not found, NULL is returned and neither value
10786 * nor value_l are touched. The input <hdr> string should first point to the
10787 * header's value, and the <hdr_end> pointer must point to the first character
10788 * not part of the value. <list> must be non-zero if value may represent a list
10789 * of values (cookie headers). This makes it faster to abort parsing when no
10790 * list is expected.
10791 */
10792static char *
10793extract_cookie_value(char *hdr, const char *hdr_end,
10794 char *cookie_name, size_t cookie_name_l, int list,
Willy Tarreau3fb818c2012-04-11 17:21:08 +020010795 char **value, int *value_l)
Willy Tarreau04aa6a92012-04-06 18:57:55 +020010796{
10797 char *equal, *att_end, *att_beg, *val_beg, *val_end;
10798 char *next;
10799
10800 /* we search at least a cookie name followed by an equal, and more
10801 * generally something like this :
10802 * Cookie: NAME1 = VALUE 1 ; NAME2 = VALUE2 ; NAME3 = VALUE3\r\n
10803 */
10804 for (att_beg = hdr; att_beg + cookie_name_l + 1 < hdr_end; att_beg = next + 1) {
10805 /* Iterate through all cookies on this line */
10806
10807 while (att_beg < hdr_end && http_is_spht[(unsigned char)*att_beg])
10808 att_beg++;
10809
10810 /* find att_end : this is the first character after the last non
10811 * space before the equal. It may be equal to hdr_end.
10812 */
10813 equal = att_end = att_beg;
10814
10815 while (equal < hdr_end) {
10816 if (*equal == '=' || *equal == ';' || (list && *equal == ','))
10817 break;
10818 if (http_is_spht[(unsigned char)*equal++])
10819 continue;
10820 att_end = equal;
10821 }
10822
10823 /* here, <equal> points to '=', a delimitor or the end. <att_end>
10824 * is between <att_beg> and <equal>, both may be identical.
10825 */
10826
10827 /* look for end of cookie if there is an equal sign */
10828 if (equal < hdr_end && *equal == '=') {
10829 /* look for the beginning of the value */
10830 val_beg = equal + 1;
10831 while (val_beg < hdr_end && http_is_spht[(unsigned char)*val_beg])
10832 val_beg++;
10833
10834 /* find the end of the value, respecting quotes */
10835 next = find_cookie_value_end(val_beg, hdr_end);
10836
10837 /* make val_end point to the first white space or delimitor after the value */
10838 val_end = next;
10839 while (val_end > val_beg && http_is_spht[(unsigned char)*(val_end - 1)])
10840 val_end--;
10841 } else {
10842 val_beg = val_end = next = equal;
10843 }
10844
10845 /* We have nothing to do with attributes beginning with '$'. However,
10846 * they will automatically be removed if a header before them is removed,
10847 * since they're supposed to be linked together.
10848 */
10849 if (*att_beg == '$')
10850 continue;
10851
10852 /* Ignore cookies with no equal sign */
10853 if (equal == next)
10854 continue;
10855
10856 /* Now we have the cookie name between att_beg and att_end, and
10857 * its value between val_beg and val_end.
10858 */
10859
10860 if (att_end - att_beg == cookie_name_l &&
10861 memcmp(att_beg, cookie_name, cookie_name_l) == 0) {
10862 /* let's return this value and indicate where to go on from */
10863 *value = val_beg;
10864 *value_l = val_end - val_beg;
10865 return next + 1;
10866 }
10867
10868 /* Set-Cookie headers only have the name in the first attr=value part */
10869 if (!list)
10870 break;
10871 }
10872
10873 return NULL;
10874}
10875
William Lallemanda43ba4e2014-01-28 18:14:25 +010010876/* Fetch a captured HTTP request header. The index is the position of
10877 * the "capture" option in the configuration file
10878 */
10879static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010880smp_fetch_capture_header_req(struct proxy *px, struct stream *strm, unsigned int opt,
10881 const struct arg *args, struct sample *smp, const char *kw, void *private)
William Lallemanda43ba4e2014-01-28 18:14:25 +010010882{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010883 struct proxy *fe = strm_sess(strm)->fe;
William Lallemanda43ba4e2014-01-28 18:14:25 +010010884 int idx;
10885
10886 if (!args || args->type != ARGT_UINT)
10887 return 0;
10888
10889 idx = args->data.uint;
10890
Willy Tarreau15e91e12015-04-04 00:52:09 +020010891 if (idx > (fe->nb_req_cap - 1) || strm->req_cap == NULL || strm->req_cap[idx] == NULL)
William Lallemanda43ba4e2014-01-28 18:14:25 +010010892 return 0;
10893
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010894 smp->type = SMP_T_STR;
10895 smp->flags |= SMP_F_CONST;
Willy Tarreau15e91e12015-04-04 00:52:09 +020010896 smp->data.str.str = strm->req_cap[idx];
10897 smp->data.str.len = strlen(strm->req_cap[idx]);
William Lallemanda43ba4e2014-01-28 18:14:25 +010010898
10899 return 1;
10900}
10901
10902/* Fetch a captured HTTP response header. The index is the position of
10903 * the "capture" option in the configuration file
10904 */
10905static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010906smp_fetch_capture_header_res(struct proxy *px, struct stream *strm, unsigned int opt,
10907 const struct arg *args, struct sample *smp, const char *kw, void *private)
William Lallemanda43ba4e2014-01-28 18:14:25 +010010908{
Willy Tarreau15e91e12015-04-04 00:52:09 +020010909 struct proxy *fe = strm_sess(strm)->fe;
William Lallemanda43ba4e2014-01-28 18:14:25 +010010910 int idx;
10911
10912 if (!args || args->type != ARGT_UINT)
10913 return 0;
10914
10915 idx = args->data.uint;
10916
Willy Tarreau15e91e12015-04-04 00:52:09 +020010917 if (idx > (fe->nb_rsp_cap - 1) || strm->res_cap == NULL || strm->res_cap[idx] == NULL)
William Lallemanda43ba4e2014-01-28 18:14:25 +010010918 return 0;
10919
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010920 smp->type = SMP_T_STR;
10921 smp->flags |= SMP_F_CONST;
Willy Tarreau15e91e12015-04-04 00:52:09 +020010922 smp->data.str.str = strm->res_cap[idx];
10923 smp->data.str.len = strlen(strm->res_cap[idx]);
William Lallemanda43ba4e2014-01-28 18:14:25 +010010924
10925 return 1;
10926}
10927
William Lallemand65ad6e12014-01-31 15:08:02 +010010928/* Extracts the METHOD in the HTTP request, the txn->uri should be filled before the call */
10929static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010930smp_fetch_capture_req_method(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010931 const struct arg *args, struct sample *smp, const char *kw, void *private)
William Lallemand65ad6e12014-01-31 15:08:02 +010010932{
10933 struct chunk *temp;
Willy Tarreau15e91e12015-04-04 00:52:09 +020010934 struct http_txn *txn = strm->txn;
William Lallemand96a77852014-02-05 00:30:02 +010010935 char *ptr;
William Lallemand65ad6e12014-01-31 15:08:02 +010010936
Willy Tarreau15e91e12015-04-04 00:52:09 +020010937 if (!txn || !txn->uri)
William Lallemand65ad6e12014-01-31 15:08:02 +010010938 return 0;
10939
William Lallemand96a77852014-02-05 00:30:02 +010010940 ptr = txn->uri;
William Lallemand65ad6e12014-01-31 15:08:02 +010010941
William Lallemand96a77852014-02-05 00:30:02 +010010942 while (*ptr != ' ' && *ptr != '\0') /* find first space */
10943 ptr++;
William Lallemand65ad6e12014-01-31 15:08:02 +010010944
William Lallemand96a77852014-02-05 00:30:02 +010010945 temp = get_trash_chunk();
10946 temp->str = txn->uri;
10947 temp->len = ptr - txn->uri;
William Lallemand65ad6e12014-01-31 15:08:02 +010010948 smp->data.str = *temp;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010949 smp->type = SMP_T_STR;
10950 smp->flags = SMP_F_CONST;
William Lallemand65ad6e12014-01-31 15:08:02 +010010951
10952 return 1;
10953
10954}
10955
10956/* Extracts the path in the HTTP request, the txn->uri should be filled before the call */
10957static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010958smp_fetch_capture_req_uri(struct proxy *px, struct stream *strm, unsigned int opt,
10959 const struct arg *args, struct sample *smp, const char *kw, void *private)
William Lallemand65ad6e12014-01-31 15:08:02 +010010960{
10961 struct chunk *temp;
Willy Tarreau15e91e12015-04-04 00:52:09 +020010962 struct http_txn *txn = strm->txn;
William Lallemand65ad6e12014-01-31 15:08:02 +010010963 char *ptr;
William Lallemand65ad6e12014-01-31 15:08:02 +010010964
Willy Tarreau15e91e12015-04-04 00:52:09 +020010965 if (!txn || !txn->uri)
William Lallemand65ad6e12014-01-31 15:08:02 +010010966 return 0;
William Lallemand96a77852014-02-05 00:30:02 +010010967
William Lallemand65ad6e12014-01-31 15:08:02 +010010968 ptr = txn->uri;
10969
10970 while (*ptr != ' ' && *ptr != '\0') /* find first space */
10971 ptr++;
William Lallemand96a77852014-02-05 00:30:02 +010010972
William Lallemand65ad6e12014-01-31 15:08:02 +010010973 if (!*ptr)
10974 return 0;
10975
10976 ptr++; /* skip the space */
10977
10978 temp = get_trash_chunk();
William Lallemand96a77852014-02-05 00:30:02 +010010979 ptr = temp->str = http_get_path_from_string(ptr);
William Lallemand65ad6e12014-01-31 15:08:02 +010010980 if (!ptr)
10981 return 0;
10982 while (*ptr != ' ' && *ptr != '\0') /* find space after URI */
10983 ptr++;
William Lallemand65ad6e12014-01-31 15:08:02 +010010984
10985 smp->data.str = *temp;
William Lallemand96a77852014-02-05 00:30:02 +010010986 smp->data.str.len = ptr - temp->str;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010010987 smp->type = SMP_T_STR;
10988 smp->flags = SMP_F_CONST;
William Lallemand65ad6e12014-01-31 15:08:02 +010010989
10990 return 1;
10991}
10992
Willy Tarreau3c1b5ec2014-04-24 23:41:57 +020010993/* Retrieves the HTTP version from the request (either 1.0 or 1.1) and emits it
10994 * as a string (either "HTTP/1.0" or "HTTP/1.1").
10995 */
10996static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020010997smp_fetch_capture_req_ver(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010010998 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau3c1b5ec2014-04-24 23:41:57 +020010999{
Willy Tarreau15e91e12015-04-04 00:52:09 +020011000 struct http_txn *txn = strm->txn;
Willy Tarreau3c1b5ec2014-04-24 23:41:57 +020011001
Willy Tarreau15e91e12015-04-04 00:52:09 +020011002 if (!txn || txn->req.msg_state < HTTP_MSG_HDR_FIRST)
Willy Tarreau3c1b5ec2014-04-24 23:41:57 +020011003 return 0;
11004
11005 if (txn->req.flags & HTTP_MSGF_VER_11)
11006 smp->data.str.str = "HTTP/1.1";
11007 else
11008 smp->data.str.str = "HTTP/1.0";
11009
11010 smp->data.str.len = 8;
11011 smp->type = SMP_T_STR;
11012 smp->flags = SMP_F_CONST;
11013 return 1;
11014
11015}
11016
11017/* Retrieves the HTTP version from the response (either 1.0 or 1.1) and emits it
11018 * as a string (either "HTTP/1.0" or "HTTP/1.1").
11019 */
11020static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020011021smp_fetch_capture_res_ver(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010011022 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau3c1b5ec2014-04-24 23:41:57 +020011023{
Willy Tarreau15e91e12015-04-04 00:52:09 +020011024 struct http_txn *txn = strm->txn;
Willy Tarreau3c1b5ec2014-04-24 23:41:57 +020011025
Willy Tarreau15e91e12015-04-04 00:52:09 +020011026 if (!txn || txn->rsp.msg_state < HTTP_MSG_HDR_FIRST)
Willy Tarreau3c1b5ec2014-04-24 23:41:57 +020011027 return 0;
11028
11029 if (txn->rsp.flags & HTTP_MSGF_VER_11)
11030 smp->data.str.str = "HTTP/1.1";
11031 else
11032 smp->data.str.str = "HTTP/1.0";
11033
11034 smp->data.str.len = 8;
11035 smp->type = SMP_T_STR;
11036 smp->flags = SMP_F_CONST;
11037 return 1;
11038
11039}
11040
William Lallemand65ad6e12014-01-31 15:08:02 +010011041
Willy Tarreaue333ec92012-04-16 16:26:40 +020011042/* Iterate over all cookies present in a message. The context is stored in
Willy Tarreau37406352012-04-23 16:16:37 +020011043 * smp->ctx.a[0] for the in-header position, smp->ctx.a[1] for the
Willy Tarreaua890d072013-04-02 12:01:06 +020011044 * end-of-header-value, and smp->ctx.a[2] for the hdr_ctx. Depending on
Willy Tarreaue333ec92012-04-16 16:26:40 +020011045 * the direction, multiple cookies may be parsed on the same line or not.
Willy Tarreau24e32d82012-04-23 23:55:44 +020011046 * The cookie name is in args and the name length in args->data.str.len.
Willy Tarreau28376d62012-04-26 21:26:10 +020011047 * Accepts exactly 1 argument of type string. If the input options indicate
11048 * that no iterating is desired, then only last value is fetched if any.
William Lallemand07c8b242014-05-02 17:11:07 +020011049 * The returned sample is of type CSTR. Can be used to parse cookies in other
11050 * files.
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011051 */
Willy Tarreau15e91e12015-04-04 00:52:09 +020011052int smp_fetch_cookie(struct proxy *px, struct stream *strm, unsigned int opt,
11053 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011054{
Willy Tarreau15e91e12015-04-04 00:52:09 +020011055 struct http_txn *txn;
11056 struct hdr_idx *idx;
Willy Tarreaua890d072013-04-02 12:01:06 +020011057 struct hdr_ctx *ctx = smp->ctx.a[2];
Willy Tarreaue333ec92012-04-16 16:26:40 +020011058 const struct http_msg *msg;
11059 const char *hdr_name;
11060 int hdr_name_len;
11061 char *sol;
Willy Tarreau28376d62012-04-26 21:26:10 +020011062 int occ = 0;
11063 int found = 0;
Willy Tarreaue333ec92012-04-16 16:26:40 +020011064
Willy Tarreau24e32d82012-04-23 23:55:44 +020011065 if (!args || args->type != ARGT_STR)
Willy Tarreau34db1082012-04-19 17:16:54 +020011066 return 0;
11067
Willy Tarreaua890d072013-04-02 12:01:06 +020011068 if (!ctx) {
11069 /* first call */
11070 ctx = &static_hdr_ctx;
11071 ctx->idx = 0;
11072 smp->ctx.a[2] = ctx;
11073 }
11074
Willy Tarreaue333ec92012-04-16 16:26:40 +020011075 CHECK_HTTP_MESSAGE_FIRST();
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011076
Willy Tarreau15e91e12015-04-04 00:52:09 +020011077 txn = strm->txn;
11078 idx = &strm->txn->hdr_idx;
11079
Willy Tarreau32a6f2e2012-04-25 10:13:36 +020011080 if ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) {
Willy Tarreaue333ec92012-04-16 16:26:40 +020011081 msg = &txn->req;
11082 hdr_name = "Cookie";
11083 hdr_name_len = 6;
11084 } else {
11085 msg = &txn->rsp;
11086 hdr_name = "Set-Cookie";
11087 hdr_name_len = 10;
11088 }
11089
Willy Tarreau28376d62012-04-26 21:26:10 +020011090 if (!occ && !(opt & SMP_OPT_ITERATE))
11091 /* no explicit occurrence and single fetch => last cookie by default */
11092 occ = -1;
11093
11094 /* OK so basically here, either we want only one value and it's the
11095 * last one, or we want to iterate over all of them and we fetch the
11096 * next one.
11097 */
11098
Willy Tarreau9b28e032012-10-12 23:49:43 +020011099 sol = msg->chn->buf->p;
Willy Tarreau37406352012-04-23 16:16:37 +020011100 if (!(smp->flags & SMP_F_NOT_LAST)) {
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011101 /* search for the header from the beginning, we must first initialize
11102 * the search parameters.
11103 */
Willy Tarreau37406352012-04-23 16:16:37 +020011104 smp->ctx.a[0] = NULL;
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011105 ctx->idx = 0;
11106 }
11107
Willy Tarreau28376d62012-04-26 21:26:10 +020011108 smp->flags |= SMP_F_VOL_HDR;
11109
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011110 while (1) {
Willy Tarreau37406352012-04-23 16:16:37 +020011111 /* Note: smp->ctx.a[0] == NULL every time we need to fetch a new header */
11112 if (!smp->ctx.a[0]) {
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011113 if (!http_find_header2(hdr_name, hdr_name_len, sol, idx, ctx))
11114 goto out;
11115
Willy Tarreau24e32d82012-04-23 23:55:44 +020011116 if (ctx->vlen < args->data.str.len + 1)
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011117 continue;
11118
Willy Tarreau37406352012-04-23 16:16:37 +020011119 smp->ctx.a[0] = ctx->line + ctx->val;
11120 smp->ctx.a[1] = smp->ctx.a[0] + ctx->vlen;
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011121 }
11122
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010011123 smp->type = SMP_T_STR;
11124 smp->flags |= SMP_F_CONST;
Willy Tarreau37406352012-04-23 16:16:37 +020011125 smp->ctx.a[0] = extract_cookie_value(smp->ctx.a[0], smp->ctx.a[1],
Willy Tarreau24e32d82012-04-23 23:55:44 +020011126 args->data.str.str, args->data.str.len,
Willy Tarreau32a6f2e2012-04-25 10:13:36 +020011127 (opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ,
Willy Tarreauf853c462012-04-23 18:53:56 +020011128 &smp->data.str.str,
11129 &smp->data.str.len);
Willy Tarreau37406352012-04-23 16:16:37 +020011130 if (smp->ctx.a[0]) {
Willy Tarreau28376d62012-04-26 21:26:10 +020011131 found = 1;
11132 if (occ >= 0) {
11133 /* one value was returned into smp->data.str.{str,len} */
11134 smp->flags |= SMP_F_NOT_LAST;
11135 return 1;
11136 }
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011137 }
Willy Tarreau28376d62012-04-26 21:26:10 +020011138 /* if we're looking for last occurrence, let's loop */
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011139 }
Willy Tarreau28376d62012-04-26 21:26:10 +020011140 /* all cookie headers and values were scanned. If we're looking for the
11141 * last occurrence, we may return it now.
11142 */
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011143 out:
Willy Tarreau37406352012-04-23 16:16:37 +020011144 smp->flags &= ~SMP_F_NOT_LAST;
Willy Tarreau28376d62012-04-26 21:26:10 +020011145 return found;
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011146}
11147
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011148/* Iterate over all cookies present in a request to count how many occurrences
Willy Tarreau24e32d82012-04-23 23:55:44 +020011149 * match the name in args and args->data.str.len. If <multi> is non-null, then
Willy Tarreaub169eba2013-12-16 15:14:43 +010011150 * multiple cookies may be parsed on the same line. The returned sample is of
11151 * type UINT. Accepts exactly 1 argument of type string.
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011152 */
11153static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020011154smp_fetch_cookie_cnt(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010011155 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011156{
Willy Tarreau15e91e12015-04-04 00:52:09 +020011157 struct http_txn *txn;
11158 struct hdr_idx *idx;
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011159 struct hdr_ctx ctx;
Willy Tarreaue333ec92012-04-16 16:26:40 +020011160 const struct http_msg *msg;
11161 const char *hdr_name;
11162 int hdr_name_len;
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011163 int cnt;
11164 char *val_beg, *val_end;
Willy Tarreaue333ec92012-04-16 16:26:40 +020011165 char *sol;
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011166
Willy Tarreau24e32d82012-04-23 23:55:44 +020011167 if (!args || args->type != ARGT_STR)
Willy Tarreau34db1082012-04-19 17:16:54 +020011168 return 0;
11169
Willy Tarreaue333ec92012-04-16 16:26:40 +020011170 CHECK_HTTP_MESSAGE_FIRST();
11171
Willy Tarreau15e91e12015-04-04 00:52:09 +020011172 txn = strm->txn;
11173 idx = &strm->txn->hdr_idx;
11174
Willy Tarreau32a6f2e2012-04-25 10:13:36 +020011175 if ((opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ) {
Willy Tarreaue333ec92012-04-16 16:26:40 +020011176 msg = &txn->req;
11177 hdr_name = "Cookie";
11178 hdr_name_len = 6;
11179 } else {
11180 msg = &txn->rsp;
11181 hdr_name = "Set-Cookie";
11182 hdr_name_len = 10;
11183 }
11184
Willy Tarreau9b28e032012-10-12 23:49:43 +020011185 sol = msg->chn->buf->p;
Willy Tarreau46787ed2012-04-11 17:28:40 +020011186 val_end = val_beg = NULL;
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011187 ctx.idx = 0;
11188 cnt = 0;
11189
11190 while (1) {
11191 /* Note: val_beg == NULL every time we need to fetch a new header */
11192 if (!val_beg) {
11193 if (!http_find_header2(hdr_name, hdr_name_len, sol, idx, &ctx))
11194 break;
11195
Willy Tarreau24e32d82012-04-23 23:55:44 +020011196 if (ctx.vlen < args->data.str.len + 1)
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011197 continue;
11198
11199 val_beg = ctx.line + ctx.val;
11200 val_end = val_beg + ctx.vlen;
11201 }
11202
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010011203 smp->type = SMP_T_STR;
11204 smp->flags |= SMP_F_CONST;
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011205 while ((val_beg = extract_cookie_value(val_beg, val_end,
Willy Tarreau24e32d82012-04-23 23:55:44 +020011206 args->data.str.str, args->data.str.len,
Willy Tarreau32a6f2e2012-04-25 10:13:36 +020011207 (opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ,
Willy Tarreauf853c462012-04-23 18:53:56 +020011208 &smp->data.str.str,
11209 &smp->data.str.len))) {
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011210 cnt++;
11211 }
11212 }
11213
Willy Tarreaub169eba2013-12-16 15:14:43 +010011214 smp->type = SMP_T_UINT;
Willy Tarreauf853c462012-04-23 18:53:56 +020011215 smp->data.uint = cnt;
Willy Tarreau37406352012-04-23 16:16:37 +020011216 smp->flags |= SMP_F_VOL_HDR;
Willy Tarreau04aa6a92012-04-06 18:57:55 +020011217 return 1;
11218}
11219
Willy Tarreau51539362012-05-08 12:46:28 +020011220/* Fetch an cookie's integer value. The integer value is returned. It
11221 * takes a mandatory argument of type string. It relies on smp_fetch_cookie().
11222 */
11223static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020011224smp_fetch_cookie_val(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010011225 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreau51539362012-05-08 12:46:28 +020011226{
Willy Tarreau15e91e12015-04-04 00:52:09 +020011227 int ret = smp_fetch_cookie(px, strm, opt, args, smp, kw, private);
Willy Tarreau51539362012-05-08 12:46:28 +020011228
11229 if (ret > 0) {
11230 smp->type = SMP_T_UINT;
11231 smp->data.uint = strl2ic(smp->data.str.str, smp->data.str.len);
11232 }
11233
11234 return ret;
11235}
11236
Willy Tarreau8797c062007-05-07 00:55:35 +020011237/************************************************************************/
Willy Tarreau12785782012-04-27 21:37:17 +020011238/* The code below is dedicated to sample fetches */
Willy Tarreau4a568972010-05-12 08:08:50 +020011239/************************************************************************/
11240
David Cournapeau16023ee2010-12-23 20:55:41 +090011241/*
11242 * Given a path string and its length, find the position of beginning of the
11243 * query string. Returns NULL if no query string is found in the path.
11244 *
11245 * Example: if path = "/foo/bar/fubar?yo=mama;ye=daddy", and n = 22:
11246 *
11247 * find_query_string(path, n) points to "yo=mama;ye=daddy" string.
11248 */
bedis4c75cca2012-10-05 08:38:24 +020011249static inline char *find_param_list(char *path, size_t path_l, char delim)
David Cournapeau16023ee2010-12-23 20:55:41 +090011250{
11251 char *p;
Emeric Brun485479d2010-09-23 18:02:19 +020011252
bedis4c75cca2012-10-05 08:38:24 +020011253 p = memchr(path, delim, path_l);
David Cournapeau16023ee2010-12-23 20:55:41 +090011254 return p ? p + 1 : NULL;
11255}
11256
bedis4c75cca2012-10-05 08:38:24 +020011257static inline int is_param_delimiter(char c, char delim)
David Cournapeau16023ee2010-12-23 20:55:41 +090011258{
bedis4c75cca2012-10-05 08:38:24 +020011259 return c == '&' || c == ';' || c == delim;
David Cournapeau16023ee2010-12-23 20:55:41 +090011260}
11261
11262/*
11263 * Given a url parameter, find the starting position of the first occurence,
11264 * or NULL if the parameter is not found.
11265 *
11266 * Example: if query_string is "yo=mama;ye=daddy" and url_param_name is "ye",
11267 * the function will return query_string+8.
11268 */
11269static char*
11270find_url_param_pos(char* query_string, size_t query_string_l,
bedis4c75cca2012-10-05 08:38:24 +020011271 char* url_param_name, size_t url_param_name_l,
11272 char delim)
David Cournapeau16023ee2010-12-23 20:55:41 +090011273{
11274 char *pos, *last;
11275
11276 pos = query_string;
11277 last = query_string + query_string_l - url_param_name_l - 1;
11278
11279 while (pos <= last) {
11280 if (pos[url_param_name_l] == '=') {
11281 if (memcmp(pos, url_param_name, url_param_name_l) == 0)
11282 return pos;
11283 pos += url_param_name_l + 1;
11284 }
bedis4c75cca2012-10-05 08:38:24 +020011285 while (pos <= last && !is_param_delimiter(*pos, delim))
David Cournapeau16023ee2010-12-23 20:55:41 +090011286 pos++;
11287 pos++;
11288 }
11289 return NULL;
11290}
11291
11292/*
11293 * Given a url parameter name, returns its value and size into *value and
11294 * *value_l respectively, and returns non-zero. If the parameter is not found,
11295 * zero is returned and value/value_l are not touched.
11296 */
11297static int
11298find_url_param_value(char* path, size_t path_l,
11299 char* url_param_name, size_t url_param_name_l,
bedis4c75cca2012-10-05 08:38:24 +020011300 char** value, int* value_l, char delim)
David Cournapeau16023ee2010-12-23 20:55:41 +090011301{
11302 char *query_string, *qs_end;
11303 char *arg_start;
11304 char *value_start, *value_end;
11305
bedis4c75cca2012-10-05 08:38:24 +020011306 query_string = find_param_list(path, path_l, delim);
David Cournapeau16023ee2010-12-23 20:55:41 +090011307 if (!query_string)
11308 return 0;
11309
11310 qs_end = path + path_l;
11311 arg_start = find_url_param_pos(query_string, qs_end - query_string,
bedis4c75cca2012-10-05 08:38:24 +020011312 url_param_name, url_param_name_l,
11313 delim);
David Cournapeau16023ee2010-12-23 20:55:41 +090011314 if (!arg_start)
11315 return 0;
11316
11317 value_start = arg_start + url_param_name_l + 1;
11318 value_end = value_start;
11319
bedis4c75cca2012-10-05 08:38:24 +020011320 while ((value_end < qs_end) && !is_param_delimiter(*value_end, delim))
David Cournapeau16023ee2010-12-23 20:55:41 +090011321 value_end++;
11322
11323 *value = value_start;
11324 *value_l = value_end - value_start;
Willy Tarreau00134332011-01-04 14:57:34 +010011325 return value_end != value_start;
David Cournapeau16023ee2010-12-23 20:55:41 +090011326}
11327
11328static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020011329smp_fetch_url_param(struct proxy *px, struct stream *strm, unsigned int opt,
Thierry FOURNIERf41a8092014-12-07 18:37:57 +010011330 const struct arg *args, struct sample *smp, const char *kw, void *private)
David Cournapeau16023ee2010-12-23 20:55:41 +090011331{
bedis4c75cca2012-10-05 08:38:24 +020011332 char delim = '?';
Willy Tarreau15e91e12015-04-04 00:52:09 +020011333 struct http_msg *msg;
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011334
bedis4c75cca2012-10-05 08:38:24 +020011335 if (!args || args[0].type != ARGT_STR ||
11336 (args[1].type && args[1].type != ARGT_STR))
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011337 return 0;
11338
11339 CHECK_HTTP_MESSAGE_FIRST();
David Cournapeau16023ee2010-12-23 20:55:41 +090011340
Willy Tarreau15e91e12015-04-04 00:52:09 +020011341 msg = &strm->txn->req;
11342
bedis4c75cca2012-10-05 08:38:24 +020011343 if (args[1].type)
11344 delim = *args[1].data.str.str;
11345
Willy Tarreau9b28e032012-10-12 23:49:43 +020011346 if (!find_url_param_value(msg->chn->buf->p + msg->sl.rq.u, msg->sl.rq.u_l,
bedis4c75cca2012-10-05 08:38:24 +020011347 args->data.str.str, args->data.str.len,
11348 &smp->data.str.str, &smp->data.str.len,
11349 delim))
David Cournapeau16023ee2010-12-23 20:55:41 +090011350 return 0;
11351
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010011352 smp->type = SMP_T_STR;
11353 smp->flags = SMP_F_VOL_1ST | SMP_F_CONST;
David Cournapeau16023ee2010-12-23 20:55:41 +090011354 return 1;
11355}
11356
Willy Tarreaua9fddca2012-07-31 07:51:48 +020011357/* Return the signed integer value for the specified url parameter (see url_param
11358 * above).
11359 */
11360static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020011361smp_fetch_url_param_val(struct proxy *px, struct stream *strm, unsigned int opt,
11362 const struct arg *args, struct sample *smp, const char *kw, void *private)
Willy Tarreaua9fddca2012-07-31 07:51:48 +020011363{
Willy Tarreau15e91e12015-04-04 00:52:09 +020011364 int ret = smp_fetch_url_param(px, strm, opt, args, smp, kw, private);
Willy Tarreaua9fddca2012-07-31 07:51:48 +020011365
11366 if (ret > 0) {
11367 smp->type = SMP_T_UINT;
11368 smp->data.uint = strl2ic(smp->data.str.str, smp->data.str.len);
11369 }
11370
11371 return ret;
11372}
11373
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000011374/* This produces a 32-bit hash of the concatenation of the first occurrence of
11375 * the Host header followed by the path component if it begins with a slash ('/').
11376 * This means that '*' will not be added, resulting in exactly the first Host
11377 * entry. If no Host header is found, then the path is used. The resulting value
11378 * is hashed using the url hash followed by a full avalanche hash and provides a
11379 * 32-bit integer value. This fetch is useful for tracking per-URL activity on
11380 * high-traffic sites without having to store whole paths.
11381 * this differs from the base32 functions in that it includes the url parameters
11382 * as well as the path
11383 */
11384static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020011385smp_fetch_url32(struct proxy *px, struct stream *strm, unsigned int opt,
11386 const struct arg *args, struct sample *smp, const char *kw, void *private)
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000011387{
Willy Tarreau15e91e12015-04-04 00:52:09 +020011388 struct http_txn *txn;
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000011389 struct hdr_ctx ctx;
11390 unsigned int hash = 0;
11391 char *ptr, *beg, *end;
11392 int len;
11393
11394 CHECK_HTTP_MESSAGE_FIRST();
11395
Willy Tarreau15e91e12015-04-04 00:52:09 +020011396 txn = strm->txn;
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000011397 ctx.idx = 0;
Willy Tarreau877e78d2013-04-07 18:48:08 +020011398 if (http_find_header2("Host", 4, txn->req.chn->buf->p, &txn->hdr_idx, &ctx)) {
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000011399 /* OK we have the header value in ctx.line+ctx.val for ctx.vlen bytes */
11400 ptr = ctx.line + ctx.val;
11401 len = ctx.vlen;
11402 while (len--)
11403 hash = *(ptr++) + (hash << 6) + (hash << 16) - hash;
11404 }
11405
11406 /* now retrieve the path */
Willy Tarreau877e78d2013-04-07 18:48:08 +020011407 end = txn->req.chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000011408 beg = http_get_path(txn);
11409 if (!beg)
11410 beg = end;
11411
11412 for (ptr = beg; ptr < end ; ptr++);
11413
11414 if (beg < ptr && *beg == '/') {
11415 while (beg < ptr)
11416 hash = *(beg++) + (hash << 6) + (hash << 16) - hash;
11417 }
11418 hash = full_hash(hash);
11419
11420 smp->type = SMP_T_UINT;
11421 smp->data.uint = hash;
11422 smp->flags = SMP_F_VOL_1ST;
11423 return 1;
11424}
11425
11426/* This concatenates the source address with the 32-bit hash of the Host and
11427 * URL as returned by smp_fetch_base32(). The idea is to have per-source and
11428 * per-url counters. The result is a binary block from 8 to 20 bytes depending
11429 * on the source address length. The URL hash is stored before the address so
11430 * that in environments where IPv6 is insignificant, truncating the output to
11431 * 8 bytes would still work.
11432 */
11433static int
Willy Tarreau15e91e12015-04-04 00:52:09 +020011434smp_fetch_url32_src(struct proxy *px, struct stream *strm, unsigned int opt,
11435 const struct arg *args, struct sample *smp, const char *kw, void *private)
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000011436{
11437 struct chunk *temp;
Willy Tarreau15e91e12015-04-04 00:52:09 +020011438 struct session *sess = strm_sess(strm);
Willy Tarreau9ad7bd42015-04-03 19:19:59 +020011439 struct connection *cli_conn = objt_conn(sess->origin);
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000011440
Willy Tarreau15e91e12015-04-04 00:52:09 +020011441 if (!smp_fetch_url32(px, strm, opt, args, smp, kw, private))
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000011442 return 0;
11443
11444 temp = get_trash_chunk();
11445 memcpy(temp->str + temp->len, &smp->data.uint, sizeof(smp->data.uint));
11446 temp->len += sizeof(smp->data.uint);
11447
Willy Tarreaub363a1f2013-10-01 10:45:07 +020011448 switch (cli_conn->addr.from.ss_family) {
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000011449 case AF_INET:
Willy Tarreaub363a1f2013-10-01 10:45:07 +020011450 memcpy(temp->str + temp->len, &((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr, 4);
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000011451 temp->len += 4;
11452 break;
11453 case AF_INET6:
Willy Tarreaub363a1f2013-10-01 10:45:07 +020011454 memcpy(temp->str + temp->len, &((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr, 16);
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000011455 temp->len += 16;
11456 break;
11457 default:
11458 return 0;
11459 }
11460
11461 smp->data.str = *temp;
11462 smp->type = SMP_T_BIN;
11463 return 1;
11464}
11465
Willy Tarreau185b5c42012-04-26 15:11:51 +020011466/* This function is used to validate the arguments passed to any "hdr" fetch
11467 * keyword. These keywords support an optional positive or negative occurrence
11468 * number. We must ensure that the number is greater than -MAX_HDR_HISTORY. It
11469 * is assumed that the types are already the correct ones. Returns 0 on error,
11470 * non-zero if OK. If <err> is not NULL, it will be filled with a pointer to an
11471 * error message in case of error, that the caller is responsible for freeing.
11472 * The initial location must either be freeable or NULL.
11473 */
Thierry FOURNIER49f45af2014-12-08 19:50:43 +010011474int val_hdr(struct arg *arg, char **err_msg)
Willy Tarreau185b5c42012-04-26 15:11:51 +020011475{
11476 if (arg && arg[1].type == ARGT_SINT && arg[1].data.sint < -MAX_HDR_HISTORY) {
Willy Tarreaueb6cead2012-09-20 19:43:14 +020011477 memprintf(err_msg, "header occurrence must be >= %d", -MAX_HDR_HISTORY);
Willy Tarreau185b5c42012-04-26 15:11:51 +020011478 return 0;
11479 }
11480 return 1;
11481}
11482
Willy Tarreau276fae92013-07-25 14:36:01 +020011483/* takes an UINT value on input supposed to represent the time since EPOCH,
11484 * adds an optional offset found in args[0] and emits a string representing
11485 * the date in RFC-1123/5322 format.
11486 */
Willy Tarreau87b09662015-04-03 00:22:06 +020011487static int sample_conv_http_date(struct stream *stream, const struct arg *args,
Thierry FOURNIER68a556e2015-02-23 15:11:11 +010011488 struct sample *smp, void *private)
Willy Tarreau276fae92013-07-25 14:36:01 +020011489{
11490 const char day[7][4] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
11491 const char mon[12][4] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
11492 struct chunk *temp;
11493 struct tm *tm;
11494 time_t curr_date = smp->data.uint;
11495
11496 /* add offset */
11497 if (args && (args[0].type == ARGT_SINT || args[0].type == ARGT_UINT))
11498 curr_date += args[0].data.sint;
11499
11500 tm = gmtime(&curr_date);
11501
11502 temp = get_trash_chunk();
11503 temp->len = snprintf(temp->str, temp->size - temp->len,
11504 "%s, %02d %s %04d %02d:%02d:%02d GMT",
11505 day[tm->tm_wday], tm->tm_mday, mon[tm->tm_mon], 1900+tm->tm_year,
11506 tm->tm_hour, tm->tm_min, tm->tm_sec);
11507
11508 smp->data.str = *temp;
11509 smp->type = SMP_T_STR;
11510 return 1;
11511}
11512
Thierry FOURNIERad903512014-04-11 17:51:01 +020011513/* Match language range with language tag. RFC2616 14.4:
11514 *
11515 * A language-range matches a language-tag if it exactly equals
11516 * the tag, or if it exactly equals a prefix of the tag such
11517 * that the first tag character following the prefix is "-".
11518 *
11519 * Return 1 if the strings match, else return 0.
11520 */
11521static inline int language_range_match(const char *range, int range_len,
11522 const char *tag, int tag_len)
11523{
11524 const char *end = range + range_len;
11525 const char *tend = tag + tag_len;
11526 while (range < end) {
11527 if (*range == '-' && tag == tend)
11528 return 1;
11529 if (*range != *tag || tag == tend)
11530 return 0;
11531 range++;
11532 tag++;
11533 }
11534 /* Return true only if the last char of the tag is matched. */
11535 return tag == tend;
11536}
11537
11538/* Arguments: The list of expected value, the number of parts returned and the separator */
Willy Tarreau87b09662015-04-03 00:22:06 +020011539static int sample_conv_q_prefered(struct stream *stream, const struct arg *args,
Thierry FOURNIER68a556e2015-02-23 15:11:11 +010011540 struct sample *smp, void *private)
Thierry FOURNIERad903512014-04-11 17:51:01 +020011541{
11542 const char *al = smp->data.str.str;
11543 const char *end = al + smp->data.str.len;
11544 const char *token;
11545 int toklen;
11546 int qvalue;
11547 const char *str;
11548 const char *w;
11549 int best_q = 0;
11550
11551 /* Set the constant to the sample, because the output of the
11552 * function will be peek in the constant configuration string.
11553 */
11554 smp->flags |= SMP_F_CONST;
11555 smp->data.str.size = 0;
11556 smp->data.str.str = "";
11557 smp->data.str.len = 0;
11558
11559 /* Parse the accept language */
11560 while (1) {
11561
11562 /* Jump spaces, quit if the end is detected. */
Willy Tarreau506c69a2014-07-08 00:59:48 +020011563 while (al < end && isspace((unsigned char)*al))
Thierry FOURNIERad903512014-04-11 17:51:01 +020011564 al++;
11565 if (al >= end)
11566 break;
11567
11568 /* Start of the fisrt word. */
11569 token = al;
11570
11571 /* Look for separator: isspace(), ',' or ';'. Next value if 0 length word. */
Willy Tarreau506c69a2014-07-08 00:59:48 +020011572 while (al < end && *al != ';' && *al != ',' && !isspace((unsigned char)*al))
Thierry FOURNIERad903512014-04-11 17:51:01 +020011573 al++;
11574 if (al == token)
11575 goto expect_comma;
11576
11577 /* Length of the token. */
11578 toklen = al - token;
11579 qvalue = 1000;
11580
11581 /* Check if the token exists in the list. If the token not exists,
11582 * jump to the next token.
11583 */
11584 str = args[0].data.str.str;
11585 w = str;
11586 while (1) {
11587 if (*str == ';' || *str == '\0') {
11588 if (language_range_match(token, toklen, w, str-w))
11589 goto look_for_q;
11590 if (*str == '\0')
11591 goto expect_comma;
11592 w = str + 1;
11593 }
11594 str++;
11595 }
11596 goto expect_comma;
11597
11598look_for_q:
11599
11600 /* Jump spaces, quit if the end is detected. */
Willy Tarreau506c69a2014-07-08 00:59:48 +020011601 while (al < end && isspace((unsigned char)*al))
Thierry FOURNIERad903512014-04-11 17:51:01 +020011602 al++;
11603 if (al >= end)
11604 goto process_value;
11605
11606 /* If ',' is found, process the result */
11607 if (*al == ',')
11608 goto process_value;
11609
11610 /* If the character is different from ';', look
11611 * for the end of the header part in best effort.
11612 */
11613 if (*al != ';')
11614 goto expect_comma;
11615
11616 /* Assumes that the char is ';', now expect "q=". */
11617 al++;
11618
11619 /* Jump spaces, process value if the end is detected. */
Willy Tarreau506c69a2014-07-08 00:59:48 +020011620 while (al < end && isspace((unsigned char)*al))
Thierry FOURNIERad903512014-04-11 17:51:01 +020011621 al++;
11622 if (al >= end)
11623 goto process_value;
11624
11625 /* Expect 'q'. If no 'q', continue in best effort */
11626 if (*al != 'q')
11627 goto process_value;
11628 al++;
11629
11630 /* Jump spaces, process value if the end is detected. */
Willy Tarreau506c69a2014-07-08 00:59:48 +020011631 while (al < end && isspace((unsigned char)*al))
Thierry FOURNIERad903512014-04-11 17:51:01 +020011632 al++;
11633 if (al >= end)
11634 goto process_value;
11635
11636 /* Expect '='. If no '=', continue in best effort */
11637 if (*al != '=')
11638 goto process_value;
11639 al++;
11640
11641 /* Jump spaces, process value if the end is detected. */
Willy Tarreau506c69a2014-07-08 00:59:48 +020011642 while (al < end && isspace((unsigned char)*al))
Thierry FOURNIERad903512014-04-11 17:51:01 +020011643 al++;
11644 if (al >= end)
11645 goto process_value;
11646
11647 /* Parse the q value. */
11648 qvalue = parse_qvalue(al, &al);
11649
11650process_value:
11651
11652 /* If the new q value is the best q value, then store the associated
11653 * language in the response. If qvalue is the biggest value (1000),
11654 * break the process.
11655 */
11656 if (qvalue > best_q) {
11657 smp->data.str.str = (char *)w;
11658 smp->data.str.len = str - w;
11659 if (qvalue >= 1000)
11660 break;
11661 best_q = qvalue;
11662 }
11663
11664expect_comma:
11665
11666 /* Expect comma or end. If the end is detected, quit the loop. */
11667 while (al < end && *al != ',')
11668 al++;
11669 if (al >= end)
11670 break;
11671
11672 /* Comma is found, jump it and restart the analyzer. */
11673 al++;
11674 }
11675
11676 /* Set default value if required. */
11677 if (smp->data.str.len == 0 && args[1].type == ARGT_STR) {
11678 smp->data.str.str = args[1].data.str.str;
11679 smp->data.str.len = args[1].data.str.len;
11680 }
11681
11682 /* Return true only if a matching language was found. */
11683 return smp->data.str.len != 0;
11684}
11685
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011686/* This function executes one of the set-{method,path,query,uri} actions. It
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011687 * takes the string from the variable 'replace' with length 'len', then modifies
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011688 * the relevant part of the request line accordingly. Then it updates various
11689 * pointers to the next elements which were moved, and the total buffer length.
11690 * It finds the action to be performed in p[2], previously filled by function
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011691 * parse_set_req_line(). It returns 0 in case of success, -1 in case of internal
11692 * error, though this can be revisited when this code is finally exploited.
11693 *
11694 * 'action' can be '0' to replace method, '1' to replace path, '2' to replace
11695 * query string and 3 to replace uri.
11696 *
11697 * In query string case, the mark question '?' must be set at the start of the
11698 * string by the caller, event if the replacement query string is empty.
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011699 */
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011700int http_replace_req_line(int action, const char *replace, int len,
Willy Tarreau987e3fb2015-04-04 01:09:08 +020011701 struct proxy *px, struct stream *s)
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011702{
Willy Tarreau987e3fb2015-04-04 01:09:08 +020011703 struct http_txn *txn = s->txn;
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011704 char *cur_ptr, *cur_end;
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011705 int offset = 0;
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011706 int delta;
11707
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011708 switch (action) {
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011709 case 0: // method
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010011710 cur_ptr = s->req.buf->p;
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011711 cur_end = cur_ptr + txn->req.sl.rq.m_l;
11712
11713 /* adjust req line offsets and lengths */
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011714 delta = len - offset - (cur_end - cur_ptr);
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011715 txn->req.sl.rq.m_l += delta;
11716 txn->req.sl.rq.u += delta;
11717 txn->req.sl.rq.v += delta;
11718 break;
11719
11720 case 1: // path
11721 cur_ptr = http_get_path(txn);
11722 if (!cur_ptr)
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010011723 cur_ptr = s->req.buf->p + txn->req.sl.rq.u;
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011724
11725 cur_end = cur_ptr;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010011726 while (cur_end < s->req.buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l && *cur_end != '?')
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011727 cur_end++;
11728
11729 /* adjust req line offsets and lengths */
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011730 delta = len - offset - (cur_end - cur_ptr);
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011731 txn->req.sl.rq.u_l += delta;
11732 txn->req.sl.rq.v += delta;
11733 break;
11734
11735 case 2: // query
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011736 offset = 1;
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010011737 cur_ptr = s->req.buf->p + txn->req.sl.rq.u;
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011738 cur_end = cur_ptr + txn->req.sl.rq.u_l;
11739 while (cur_ptr < cur_end && *cur_ptr != '?')
11740 cur_ptr++;
11741
11742 /* skip the question mark or indicate that we must insert it
11743 * (but only if the format string is not empty then).
11744 */
11745 if (cur_ptr < cur_end)
11746 cur_ptr++;
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011747 else if (len > 1)
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011748 offset = 0;
11749
11750 /* adjust req line offsets and lengths */
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011751 delta = len - offset - (cur_end - cur_ptr);
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011752 txn->req.sl.rq.u_l += delta;
11753 txn->req.sl.rq.v += delta;
11754 break;
11755
11756 case 3: // uri
Willy Tarreau22ec1ea2014-11-27 20:45:39 +010011757 cur_ptr = s->req.buf->p + txn->req.sl.rq.u;
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011758 cur_end = cur_ptr + txn->req.sl.rq.u_l;
11759
11760 /* adjust req line offsets and lengths */
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011761 delta = len - offset - (cur_end - cur_ptr);
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011762 txn->req.sl.rq.u_l += delta;
11763 txn->req.sl.rq.v += delta;
11764 break;
11765
11766 default:
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011767 return -1;
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011768 }
11769
11770 /* commit changes and adjust end of message */
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011771 delta = buffer_replace2(s->req.buf, cur_ptr, cur_end, replace + offset, len - offset);
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011772 http_msg_move_end(&txn->req, delta);
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011773 return 0;
11774}
11775
11776/* This function executes one of the set-{method,path,query,uri} actions. It
11777 * builds a string in the trash from the specified format string. It finds
11778 * the action to be performed in p[2], previously filled by function
11779 * parse_set_req_line(). The replacement action is excuted by the function
11780 * http_action_set_req_line_exec(). It always returns 1. If an error occurs
11781 * the action is canceled, but the rule processing continue.
11782 */
Willy Tarreau987e3fb2015-04-04 01:09:08 +020011783int http_action_set_req_line(struct http_req_rule *rule, struct proxy *px, struct stream *s)
Thierry FOURNIERb77aece2015-03-14 13:55:46 +010011784{
11785 chunk_reset(&trash);
11786
11787 /* If we have to create a query string, prepare a '?'. */
11788 if (*(int *)&rule->arg.act.p[2] == 2)
11789 trash.str[trash.len++] = '?';
11790 trash.len += build_logline(s, trash.str + trash.len, trash.size - trash.len, (struct list *)&rule->arg.act.p[0]);
11791
Willy Tarreau987e3fb2015-04-04 01:09:08 +020011792 http_replace_req_line(*(int *)&rule->arg.act.p[2], trash.str, trash.len, px, s);
Thierry FOURNIER01c30122015-03-14 14:14:47 +010011793 return 1;
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010011794}
11795
11796/* parse an http-request action among :
11797 * set-method
11798 * set-path
11799 * set-query
11800 * set-uri
11801 *
11802 * All of them accept a single argument of type string representing a log-format.
11803 * The resulting rule makes use of arg->act.p[0..1] to store the log-format list
11804 * head, and p[2] to store the action as an int (0=method, 1=path, 2=query, 3=uri).
11805 * It returns 0 on success, < 0 on error.
11806 */
11807int parse_set_req_line(const char **args, int *orig_arg, struct proxy *px, struct http_req_rule *rule, char **err)
11808{
11809 int cur_arg = *orig_arg;
11810
11811 rule->action = HTTP_REQ_ACT_CUSTOM_CONT;
11812
11813 switch (args[0][4]) {
11814 case 'm' :
11815 *(int *)&rule->arg.act.p[2] = 0;
11816 rule->action_ptr = http_action_set_req_line;
11817 break;
11818 case 'p' :
11819 *(int *)&rule->arg.act.p[2] = 1;
11820 rule->action_ptr = http_action_set_req_line;
11821 break;
11822 case 'q' :
11823 *(int *)&rule->arg.act.p[2] = 2;
11824 rule->action_ptr = http_action_set_req_line;
11825 break;
11826 case 'u' :
11827 *(int *)&rule->arg.act.p[2] = 3;
11828 rule->action_ptr = http_action_set_req_line;
11829 break;
11830 default:
11831 memprintf(err, "internal error: unhandled action '%s'", args[0]);
11832 return -1;
11833 }
11834
11835 if (!*args[cur_arg] ||
11836 (*args[cur_arg + 1] && strcmp(args[cur_arg + 1], "if") != 0 && strcmp(args[cur_arg + 1], "unless") != 0)) {
11837 memprintf(err, "expects exactly 1 argument <format>");
11838 return -1;
11839 }
11840
11841 LIST_INIT((struct list *)&rule->arg.act.p[0]);
11842 proxy->conf.args.ctx = ARGC_HRQ;
11843 parse_logformat_string(args[cur_arg], proxy, (struct list *)&rule->arg.act.p[0], LOG_OPT_HTTP,
11844 (proxy->cap & PR_CAP_FE) ? SMP_VAL_FE_HRQ_HDR : SMP_VAL_BE_HRQ_HDR,
11845 proxy->conf.args.file, proxy->conf.args.line);
11846
11847 (*orig_arg)++;
11848 return 0;
11849}
11850
William Lallemand73025dd2014-04-24 14:38:37 +020011851/*
11852 * Return the struct http_req_action_kw associated to a keyword.
11853 */
11854struct http_req_action_kw *action_http_req_custom(const char *kw)
11855{
11856 if (!LIST_ISEMPTY(&http_req_keywords.list)) {
11857 struct http_req_action_kw_list *kw_list;
11858 int i;
11859
11860 list_for_each_entry(kw_list, &http_req_keywords.list, list) {
11861 for (i = 0; kw_list->kw[i].kw != NULL; i++) {
11862 if (!strcmp(kw, kw_list->kw[i].kw))
11863 return &kw_list->kw[i];
11864 }
11865 }
11866 }
11867 return NULL;
11868}
11869
11870/*
11871 * Return the struct http_res_action_kw associated to a keyword.
11872 */
11873struct http_res_action_kw *action_http_res_custom(const char *kw)
11874{
11875 if (!LIST_ISEMPTY(&http_res_keywords.list)) {
11876 struct http_res_action_kw_list *kw_list;
11877 int i;
11878
11879 list_for_each_entry(kw_list, &http_res_keywords.list, list) {
11880 for (i = 0; kw_list->kw[i].kw != NULL; i++) {
11881 if (!strcmp(kw, kw_list->kw[i].kw))
11882 return &kw_list->kw[i];
11883 }
11884 }
11885 }
11886 return NULL;
11887}
11888
Willy Tarreau4a568972010-05-12 08:08:50 +020011889/************************************************************************/
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011890/* All supported ACL keywords must be declared here. */
11891/************************************************************************/
11892
11893/* Note: must not be declared <const> as its list will be overwritten.
11894 * Please take care of keeping this list alphabetically sorted.
11895 */
Willy Tarreaudc13c112013-06-21 23:16:39 +020011896static struct acl_kw_list acl_kws = {ILH, {
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +010011897 { "base", "base", PAT_MATCH_STR },
11898 { "base_beg", "base", PAT_MATCH_BEG },
11899 { "base_dir", "base", PAT_MATCH_DIR },
11900 { "base_dom", "base", PAT_MATCH_DOM },
11901 { "base_end", "base", PAT_MATCH_END },
11902 { "base_len", "base", PAT_MATCH_LEN },
11903 { "base_reg", "base", PAT_MATCH_REG },
11904 { "base_sub", "base", PAT_MATCH_SUB },
Willy Tarreaua7ad50c2012-04-29 15:39:40 +020011905
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +010011906 { "cook", "req.cook", PAT_MATCH_STR },
11907 { "cook_beg", "req.cook", PAT_MATCH_BEG },
11908 { "cook_dir", "req.cook", PAT_MATCH_DIR },
11909 { "cook_dom", "req.cook", PAT_MATCH_DOM },
11910 { "cook_end", "req.cook", PAT_MATCH_END },
11911 { "cook_len", "req.cook", PAT_MATCH_LEN },
11912 { "cook_reg", "req.cook", PAT_MATCH_REG },
11913 { "cook_sub", "req.cook", PAT_MATCH_SUB },
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011914
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +010011915 { "hdr", "req.hdr", PAT_MATCH_STR },
11916 { "hdr_beg", "req.hdr", PAT_MATCH_BEG },
11917 { "hdr_dir", "req.hdr", PAT_MATCH_DIR },
11918 { "hdr_dom", "req.hdr", PAT_MATCH_DOM },
11919 { "hdr_end", "req.hdr", PAT_MATCH_END },
11920 { "hdr_len", "req.hdr", PAT_MATCH_LEN },
11921 { "hdr_reg", "req.hdr", PAT_MATCH_REG },
11922 { "hdr_sub", "req.hdr", PAT_MATCH_SUB },
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011923
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +010011924 /* these two declarations uses strings with list storage (in place
11925 * of tree storage). The basic match is PAT_MATCH_STR, but the indexation
11926 * and delete functions are relative to the list management. The parse
11927 * and match method are related to the corresponding fetch methods. This
11928 * is very particular ACL declaration mode.
11929 */
11930 { "http_auth_group", NULL, PAT_MATCH_STR, NULL, pat_idx_list_str, pat_del_list_ptr, NULL, pat_match_auth },
11931 { "method", NULL, PAT_MATCH_STR, pat_parse_meth, pat_idx_list_str, pat_del_list_ptr, NULL, pat_match_meth },
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011932
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +010011933 { "path", "path", PAT_MATCH_STR },
11934 { "path_beg", "path", PAT_MATCH_BEG },
11935 { "path_dir", "path", PAT_MATCH_DIR },
11936 { "path_dom", "path", PAT_MATCH_DOM },
11937 { "path_end", "path", PAT_MATCH_END },
11938 { "path_len", "path", PAT_MATCH_LEN },
11939 { "path_reg", "path", PAT_MATCH_REG },
11940 { "path_sub", "path", PAT_MATCH_SUB },
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011941
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +010011942 { "req_ver", "req.ver", PAT_MATCH_STR },
11943 { "resp_ver", "res.ver", PAT_MATCH_STR },
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011944
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +010011945 { "scook", "res.cook", PAT_MATCH_STR },
11946 { "scook_beg", "res.cook", PAT_MATCH_BEG },
11947 { "scook_dir", "res.cook", PAT_MATCH_DIR },
11948 { "scook_dom", "res.cook", PAT_MATCH_DOM },
11949 { "scook_end", "res.cook", PAT_MATCH_END },
11950 { "scook_len", "res.cook", PAT_MATCH_LEN },
11951 { "scook_reg", "res.cook", PAT_MATCH_REG },
11952 { "scook_sub", "res.cook", PAT_MATCH_SUB },
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011953
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +010011954 { "shdr", "res.hdr", PAT_MATCH_STR },
11955 { "shdr_beg", "res.hdr", PAT_MATCH_BEG },
11956 { "shdr_dir", "res.hdr", PAT_MATCH_DIR },
11957 { "shdr_dom", "res.hdr", PAT_MATCH_DOM },
11958 { "shdr_end", "res.hdr", PAT_MATCH_END },
11959 { "shdr_len", "res.hdr", PAT_MATCH_LEN },
11960 { "shdr_reg", "res.hdr", PAT_MATCH_REG },
11961 { "shdr_sub", "res.hdr", PAT_MATCH_SUB },
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011962
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +010011963 { "url", "url", PAT_MATCH_STR },
11964 { "url_beg", "url", PAT_MATCH_BEG },
11965 { "url_dir", "url", PAT_MATCH_DIR },
11966 { "url_dom", "url", PAT_MATCH_DOM },
11967 { "url_end", "url", PAT_MATCH_END },
11968 { "url_len", "url", PAT_MATCH_LEN },
11969 { "url_reg", "url", PAT_MATCH_REG },
11970 { "url_sub", "url", PAT_MATCH_SUB },
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011971
Thierry FOURNIERc5a4e982014-03-05 16:07:08 +010011972 { "urlp", "urlp", PAT_MATCH_STR },
11973 { "urlp_beg", "urlp", PAT_MATCH_BEG },
11974 { "urlp_dir", "urlp", PAT_MATCH_DIR },
11975 { "urlp_dom", "urlp", PAT_MATCH_DOM },
11976 { "urlp_end", "urlp", PAT_MATCH_END },
11977 { "urlp_len", "urlp", PAT_MATCH_LEN },
11978 { "urlp_reg", "urlp", PAT_MATCH_REG },
11979 { "urlp_sub", "urlp", PAT_MATCH_SUB },
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011980
Willy Tarreau8ed669b2013-01-11 15:49:37 +010011981 { /* END */ },
Willy Tarreau25c1ebc2012-04-25 16:21:44 +020011982}};
11983
11984/************************************************************************/
11985/* All supported pattern keywords must be declared here. */
Willy Tarreau4a568972010-05-12 08:08:50 +020011986/************************************************************************/
11987/* Note: must not be declared <const> as its list will be overwritten */
Willy Tarreaudc13c112013-06-21 23:16:39 +020011988static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010011989 { "base", smp_fetch_base, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
Willy Tarreau409bcde2013-01-08 00:31:00 +010011990 { "base32", smp_fetch_base32, 0, NULL, SMP_T_UINT, SMP_USE_HRQHV },
11991 { "base32+src", smp_fetch_base32_src, 0, NULL, SMP_T_BIN, SMP_USE_HRQHV },
11992
Willy Tarreau87b09662015-04-03 00:22:06 +020011993 /* capture are allocated and are permanent in the stream */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010011994 { "capture.req.hdr", smp_fetch_capture_header_req, ARG1(1, UINT), NULL, SMP_T_STR, SMP_USE_HRQHP },
Willy Tarreau3c1b5ec2014-04-24 23:41:57 +020011995
11996 /* retrieve these captures from the HTTP logs */
11997 { "capture.req.method", smp_fetch_capture_req_method, 0, NULL, SMP_T_STR, SMP_USE_HRQHP },
11998 { "capture.req.uri", smp_fetch_capture_req_uri, 0, NULL, SMP_T_STR, SMP_USE_HRQHP },
11999 { "capture.req.ver", smp_fetch_capture_req_ver, 0, NULL, SMP_T_STR, SMP_USE_HRQHP },
12000
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012001 { "capture.res.hdr", smp_fetch_capture_header_res, ARG1(1, UINT), NULL, SMP_T_STR, SMP_USE_HRSHP },
Willy Tarreau3c1b5ec2014-04-24 23:41:57 +020012002 { "capture.res.ver", smp_fetch_capture_res_ver, 0, NULL, SMP_T_STR, SMP_USE_HRQHP },
William Lallemanda43ba4e2014-01-28 18:14:25 +010012003
Willy Tarreau409bcde2013-01-08 00:31:00 +010012004 /* cookie is valid in both directions (eg: for "stick ...") but cook*
12005 * are only here to match the ACL's name, are request-only and are used
12006 * for ACL compatibility only.
12007 */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012008 { "cook", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
12009 { "cookie", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV },
Willy Tarreau409bcde2013-01-08 00:31:00 +010012010 { "cook_cnt", smp_fetch_cookie_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV },
12011 { "cook_val", smp_fetch_cookie_val, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV },
12012
12013 /* hdr is valid in both directions (eg: for "stick ...") but hdr_* are
12014 * only here to match the ACL's name, are request-only and are used for
12015 * ACL compatibility only.
12016 */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012017 { "hdr", smp_fetch_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV },
Willy Tarreau409bcde2013-01-08 00:31:00 +010012018 { "hdr_cnt", smp_fetch_hdr_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV },
12019 { "hdr_ip", smp_fetch_hdr_ip, ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRQHV },
12020 { "hdr_val", smp_fetch_hdr_val, ARG2(0,STR,SINT), val_hdr, SMP_T_UINT, SMP_USE_HRQHV },
12021
Willy Tarreau0a0daec2013-04-02 22:44:58 +020012022 { "http_auth", smp_fetch_http_auth, ARG1(1,USR), NULL, SMP_T_BOOL, SMP_USE_HRQHV },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012023 { "http_auth_group", smp_fetch_http_auth_grp, ARG1(1,USR), NULL, SMP_T_STR, SMP_USE_HRQHV },
Willy Tarreau409bcde2013-01-08 00:31:00 +010012024 { "http_first_req", smp_fetch_http_first_req, 0, NULL, SMP_T_BOOL, SMP_USE_HRQHP },
Thierry FOURNIERd4373142013-12-17 01:10:10 +010012025 { "method", smp_fetch_meth, 0, NULL, SMP_T_METH, SMP_USE_HRQHP },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012026 { "path", smp_fetch_path, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
Willy Tarreau49ad95c2015-01-19 15:06:26 +010012027 { "query", smp_fetch_query, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
Willy Tarreau18ed2562013-01-14 15:56:36 +010012028
12029 /* HTTP protocol on the request path */
12030 { "req.proto_http", smp_fetch_proto_http, 0, NULL, SMP_T_BOOL, SMP_USE_HRQHP },
Willy Tarreau409bcde2013-01-08 00:31:00 +010012031 { "req_proto_http", smp_fetch_proto_http, 0, NULL, SMP_T_BOOL, SMP_USE_HRQHP },
Willy Tarreau18ed2562013-01-14 15:56:36 +010012032
12033 /* HTTP version on the request path */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012034 { "req.ver", smp_fetch_rqver, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
12035 { "req_ver", smp_fetch_rqver, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
Willy Tarreau18ed2562013-01-14 15:56:36 +010012036
12037 /* HTTP version on the response path */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012038 { "res.ver", smp_fetch_stver, 0, NULL, SMP_T_STR, SMP_USE_HRSHV },
12039 { "resp_ver", smp_fetch_stver, 0, NULL, SMP_T_STR, SMP_USE_HRSHV },
Willy Tarreau409bcde2013-01-08 00:31:00 +010012040
Willy Tarreau18ed2562013-01-14 15:56:36 +010012041 /* explicit req.{cook,hdr} are used to force the fetch direction to be request-only */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012042 { "req.cook", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
Willy Tarreau18ed2562013-01-14 15:56:36 +010012043 { "req.cook_cnt", smp_fetch_cookie_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV },
12044 { "req.cook_val", smp_fetch_cookie_val, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV },
12045
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012046 { "req.fhdr", smp_fetch_fhdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRQHV },
Willy Tarreau04ff9f12013-06-10 18:39:42 +020012047 { "req.fhdr_cnt", smp_fetch_fhdr_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012048 { "req.hdr", smp_fetch_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRQHV },
Willy Tarreau18ed2562013-01-14 15:56:36 +010012049 { "req.hdr_cnt", smp_fetch_hdr_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV },
12050 { "req.hdr_ip", smp_fetch_hdr_ip, ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRQHV },
Willy Tarreaueb27ec72015-02-20 13:55:29 +010012051 { "req.hdr_names", smp_fetch_hdr_names, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
Willy Tarreau18ed2562013-01-14 15:56:36 +010012052 { "req.hdr_val", smp_fetch_hdr_val, ARG2(0,STR,SINT), val_hdr, SMP_T_UINT, SMP_USE_HRQHV },
12053
12054 /* explicit req.{cook,hdr} are used to force the fetch direction to be response-only */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012055 { "res.cook", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRSHV },
Willy Tarreau18ed2562013-01-14 15:56:36 +010012056 { "res.cook_cnt", smp_fetch_cookie_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRSHV },
12057 { "res.cook_val", smp_fetch_cookie_val, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRSHV },
12058
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012059 { "res.fhdr", smp_fetch_fhdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRSHV },
Willy Tarreau04ff9f12013-06-10 18:39:42 +020012060 { "res.fhdr_cnt", smp_fetch_fhdr_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRSHV },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012061 { "res.hdr", smp_fetch_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRSHV },
Willy Tarreau18ed2562013-01-14 15:56:36 +010012062 { "res.hdr_cnt", smp_fetch_hdr_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRSHV },
12063 { "res.hdr_ip", smp_fetch_hdr_ip, ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRSHV },
Willy Tarreaueb27ec72015-02-20 13:55:29 +010012064 { "res.hdr_names", smp_fetch_hdr_names, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRSHV },
Willy Tarreau18ed2562013-01-14 15:56:36 +010012065 { "res.hdr_val", smp_fetch_hdr_val, ARG2(0,STR,SINT), val_hdr, SMP_T_UINT, SMP_USE_HRSHV },
12066
Willy Tarreau409bcde2013-01-08 00:31:00 +010012067 /* scook is valid only on the response and is used for ACL compatibility */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012068 { "scook", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRSHV },
Willy Tarreau409bcde2013-01-08 00:31:00 +010012069 { "scook_cnt", smp_fetch_cookie_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRSHV },
12070 { "scook_val", smp_fetch_cookie_val, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRSHV },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012071 { "set-cookie", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRSHV }, /* deprecated */
Willy Tarreau409bcde2013-01-08 00:31:00 +010012072
12073 /* shdr is valid only on the response and is used for ACL compatibility */
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012074 { "shdr", smp_fetch_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRSHV },
Willy Tarreau409bcde2013-01-08 00:31:00 +010012075 { "shdr_cnt", smp_fetch_hdr_cnt, ARG1(0,STR), NULL, SMP_T_UINT, SMP_USE_HRSHV },
12076 { "shdr_ip", smp_fetch_hdr_ip, ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRSHV },
12077 { "shdr_val", smp_fetch_hdr_val, ARG2(0,STR,SINT), val_hdr, SMP_T_UINT, SMP_USE_HRSHV },
12078
12079 { "status", smp_fetch_stcode, 0, NULL, SMP_T_UINT, SMP_USE_HRSHP },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012080 { "url", smp_fetch_url, 0, NULL, SMP_T_STR, SMP_USE_HRQHV },
Neil - HAProxy List39c63c52013-11-04 13:48:42 +000012081 { "url32", smp_fetch_url32, 0, NULL, SMP_T_UINT, SMP_USE_HRQHV },
12082 { "url32+src", smp_fetch_url32_src, 0, NULL, SMP_T_BIN, SMP_USE_HRQHV },
Willy Tarreau409bcde2013-01-08 00:31:00 +010012083 { "url_ip", smp_fetch_url_ip, 0, NULL, SMP_T_IPV4, SMP_USE_HRQHV },
12084 { "url_port", smp_fetch_url_port, 0, NULL, SMP_T_UINT, SMP_USE_HRQHV },
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010012085 { "url_param", smp_fetch_url_param, ARG2(1,STR,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
12086 { "urlp" , smp_fetch_url_param, ARG2(1,STR,STR), NULL, SMP_T_STR, SMP_USE_HRQHV },
Willy Tarreau409bcde2013-01-08 00:31:00 +010012087 { "urlp_val", smp_fetch_url_param_val, ARG2(1,STR,STR), NULL, SMP_T_UINT, SMP_USE_HRQHV },
12088 { /* END */ },
Willy Tarreau4a568972010-05-12 08:08:50 +020012089}};
12090
Willy Tarreau8797c062007-05-07 00:55:35 +020012091
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010012092/************************************************************************/
12093/* All supported converter keywords must be declared here. */
12094/************************************************************************/
Willy Tarreau276fae92013-07-25 14:36:01 +020012095/* Note: must not be declared <const> as its list will be overwritten */
12096static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Thierry FOURNIERad903512014-04-11 17:51:01 +020012097 { "http_date", sample_conv_http_date, ARG1(0,SINT), NULL, SMP_T_UINT, SMP_T_STR},
12098 { "language", sample_conv_q_prefered, ARG2(1,STR,STR), NULL, SMP_T_STR, SMP_T_STR},
Willy Tarreau276fae92013-07-25 14:36:01 +020012099 { NULL, NULL, 0, 0, 0 },
12100}};
12101
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010012102/************************************************************************/
12103/* All supported http-request action keywords must be declared here. */
12104/************************************************************************/
12105struct http_req_action_kw_list http_req_actions = {
12106 .scope = "http",
12107 .kw = {
12108 { "set-method", parse_set_req_line },
12109 { "set-path", parse_set_req_line },
12110 { "set-query", parse_set_req_line },
12111 { "set-uri", parse_set_req_line },
Willy Tarreaucb703b02015-04-03 09:52:01 +020012112 { NULL, NULL }
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010012113 }
12114};
12115
Willy Tarreau8797c062007-05-07 00:55:35 +020012116__attribute__((constructor))
12117static void __http_protocol_init(void)
12118{
12119 acl_register_keywords(&acl_kws);
Willy Tarreau12785782012-04-27 21:37:17 +020012120 sample_register_fetches(&sample_fetch_keywords);
Willy Tarreau276fae92013-07-25 14:36:01 +020012121 sample_register_convs(&sample_conv_kws);
Willy Tarreaua0dc23f2015-01-22 20:46:11 +010012122 http_req_keywords_register(&http_req_actions);
Willy Tarreau8797c062007-05-07 00:55:35 +020012123}
12124
12125
Willy Tarreau58f10d72006-12-04 02:26:12 +010012126/*
Willy Tarreaubaaee002006-06-26 02:48:02 +020012127 * Local variables:
12128 * c-indent-level: 8
12129 * c-basic-offset: 8
12130 * End:
12131 */