blob: a8612a4f10c954a7572e297872d3090d1c3cbc64 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * HTTP protocol analyzer
3 *
Willy Tarreau7c669d72008-06-20 15:04:11 +02004 * Copyright 2000-2008 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 Tarreau2dd0d472006-06-29 17:53:05 +020026#include <common/appsession.h>
27#include <common/compat.h>
28#include <common/config.h>
Willy Tarreaua4cd1f52006-12-16 19:57:26 +010029#include <common/debug.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020030#include <common/memory.h>
31#include <common/mini-clist.h>
32#include <common/standard.h>
Willy Tarreau0c303ee2008-07-07 00:09:58 +020033#include <common/ticks.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020034#include <common/time.h>
35#include <common/uri_auth.h>
36#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020037
38#include <types/capture.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020039#include <types/global.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020040
Willy Tarreau8797c062007-05-07 00:55:35 +020041#include <proto/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020042#include <proto/backend.h>
43#include <proto/buffers.h>
Maik Broemme2850cb42009-04-17 18:53:21 +020044#include <proto/client.h>
Willy Tarreau91861262007-10-17 17:06:05 +020045#include <proto/dumpstats.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020046#include <proto/fd.h>
47#include <proto/log.h>
Willy Tarreau58f10d72006-12-04 02:26:12 +010048#include <proto/hdr_idx.h>
Willy Tarreaub6866442008-07-14 23:54:42 +020049#include <proto/proto_tcp.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020050#include <proto/proto_http.h>
Willy Tarreau7f062c42009-03-05 18:43:00 +010051#include <proto/proxy.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020052#include <proto/queue.h>
Willy Tarreau7f062c42009-03-05 18:43:00 +010053#include <proto/server.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020054#include <proto/session.h>
Willy Tarreaucff64112008-11-03 06:26:53 +010055#include <proto/stream_interface.h>
Willy Tarreau2d212792008-08-27 21:41:35 +020056#include <proto/stream_sock.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020057#include <proto/task.h>
58
Willy Tarreau6d1a9882007-01-07 02:03:04 +010059#ifdef CONFIG_HAP_TCPSPLICE
60#include <libtcpsplice.h>
61#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020062
Willy Tarreau58f10d72006-12-04 02:26:12 +010063#define DEBUG_PARSE_NO_SPEEDUP
64#undef DEBUG_PARSE_NO_SPEEDUP
65
Willy Tarreau976f1ee2006-12-17 10:06:03 +010066/* This is used to perform a quick jump as an alternative to a break/continue
67 * instruction. The first argument is the label for normal operation, and the
68 * second one is the break/continue instruction in the no_speedup mode.
69 */
70
71#ifdef DEBUG_PARSE_NO_SPEEDUP
72#define QUICK_JUMP(x,y) y
73#else
74#define QUICK_JUMP(x,y) goto x
75#endif
76
Willy Tarreau1c47f852006-07-09 08:22:27 +020077/* This is used by remote monitoring */
Willy Tarreau0f772532006-12-23 20:51:41 +010078const char HTTP_200[] =
Willy Tarreau1c47f852006-07-09 08:22:27 +020079 "HTTP/1.0 200 OK\r\n"
80 "Cache-Control: no-cache\r\n"
81 "Connection: close\r\n"
82 "Content-Type: text/html\r\n"
83 "\r\n"
84 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
85
Willy Tarreau0f772532006-12-23 20:51:41 +010086const struct chunk http_200_chunk = {
87 .str = (char *)&HTTP_200,
88 .len = sizeof(HTTP_200)-1
89};
90
Willy Tarreaub463dfb2008-06-07 23:08:56 +020091const char *HTTP_301 =
92 "HTTP/1.0 301 Moved Permantenly\r\n"
93 "Cache-Control: no-cache\r\n"
94 "Connection: close\r\n"
95 "Location: "; /* not terminated since it will be concatenated with the URL */
96
Willy Tarreau0f772532006-12-23 20:51:41 +010097const char *HTTP_302 =
98 "HTTP/1.0 302 Found\r\n"
99 "Cache-Control: no-cache\r\n"
100 "Connection: close\r\n"
101 "Location: "; /* not terminated since it will be concatenated with the URL */
102
103/* same as 302 except that the browser MUST retry with the GET method */
104const char *HTTP_303 =
105 "HTTP/1.0 303 See Other\r\n"
106 "Cache-Control: no-cache\r\n"
107 "Connection: close\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 Tarreau0f772532006-12-23 20:51:41 +0100120
121const int http_err_codes[HTTP_ERR_SIZE] = {
122 [HTTP_ERR_400] = 400,
123 [HTTP_ERR_403] = 403,
124 [HTTP_ERR_408] = 408,
125 [HTTP_ERR_500] = 500,
126 [HTTP_ERR_502] = 502,
127 [HTTP_ERR_503] = 503,
128 [HTTP_ERR_504] = 504,
129};
130
Willy Tarreau80587432006-12-24 17:47:20 +0100131static const char *http_err_msgs[HTTP_ERR_SIZE] = {
Willy Tarreau0f772532006-12-23 20:51:41 +0100132 [HTTP_ERR_400] =
Willy Tarreau80587432006-12-24 17:47:20 +0100133 "HTTP/1.0 400 Bad request\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +0100134 "Cache-Control: no-cache\r\n"
135 "Connection: close\r\n"
136 "Content-Type: text/html\r\n"
137 "\r\n"
138 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
139
140 [HTTP_ERR_403] =
141 "HTTP/1.0 403 Forbidden\r\n"
142 "Cache-Control: no-cache\r\n"
143 "Connection: close\r\n"
144 "Content-Type: text/html\r\n"
145 "\r\n"
146 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
147
148 [HTTP_ERR_408] =
149 "HTTP/1.0 408 Request Time-out\r\n"
150 "Cache-Control: no-cache\r\n"
151 "Connection: close\r\n"
152 "Content-Type: text/html\r\n"
153 "\r\n"
154 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
155
156 [HTTP_ERR_500] =
157 "HTTP/1.0 500 Server Error\r\n"
158 "Cache-Control: no-cache\r\n"
159 "Connection: close\r\n"
160 "Content-Type: text/html\r\n"
161 "\r\n"
162 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n",
163
164 [HTTP_ERR_502] =
165 "HTTP/1.0 502 Bad Gateway\r\n"
166 "Cache-Control: no-cache\r\n"
167 "Connection: close\r\n"
168 "Content-Type: text/html\r\n"
169 "\r\n"
170 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n",
171
172 [HTTP_ERR_503] =
173 "HTTP/1.0 503 Service Unavailable\r\n"
174 "Cache-Control: no-cache\r\n"
175 "Connection: close\r\n"
176 "Content-Type: text/html\r\n"
177 "\r\n"
178 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n",
179
180 [HTTP_ERR_504] =
181 "HTTP/1.0 504 Gateway Time-out\r\n"
182 "Cache-Control: no-cache\r\n"
183 "Connection: close\r\n"
184 "Content-Type: text/html\r\n"
185 "\r\n"
186 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n",
187
188};
189
Willy Tarreau80587432006-12-24 17:47:20 +0100190/* We must put the messages here since GCC cannot initialize consts depending
191 * on strlen().
192 */
193struct chunk http_err_chunks[HTTP_ERR_SIZE];
194
Willy Tarreau42250582007-04-01 01:30:43 +0200195#define FD_SETS_ARE_BITFIELDS
196#ifdef FD_SETS_ARE_BITFIELDS
197/*
198 * This map is used with all the FD_* macros to check whether a particular bit
199 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
200 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
201 * byte should be encoded. Be careful to always pass bytes from 0 to 255
202 * exclusively to the macros.
203 */
204fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
205fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
206
207#else
208#error "Check if your OS uses bitfields for fd_sets"
209#endif
210
Willy Tarreau80587432006-12-24 17:47:20 +0100211void init_proto_http()
212{
Willy Tarreau42250582007-04-01 01:30:43 +0200213 int i;
214 char *tmp;
Willy Tarreau80587432006-12-24 17:47:20 +0100215 int msg;
Willy Tarreau42250582007-04-01 01:30:43 +0200216
Willy Tarreau80587432006-12-24 17:47:20 +0100217 for (msg = 0; msg < HTTP_ERR_SIZE; msg++) {
218 if (!http_err_msgs[msg]) {
219 Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n", msg);
220 abort();
221 }
222
223 http_err_chunks[msg].str = (char *)http_err_msgs[msg];
224 http_err_chunks[msg].len = strlen(http_err_msgs[msg]);
225 }
Willy Tarreau42250582007-04-01 01:30:43 +0200226
227 /* initialize the log header encoding map : '{|}"#' should be encoded with
228 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
229 * URL encoding only requires '"', '#' to be encoded as well as non-
230 * printable characters above.
231 */
232 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
233 memset(url_encode_map, 0, sizeof(url_encode_map));
234 for (i = 0; i < 32; i++) {
235 FD_SET(i, hdr_encode_map);
236 FD_SET(i, url_encode_map);
237 }
238 for (i = 127; i < 256; i++) {
239 FD_SET(i, hdr_encode_map);
240 FD_SET(i, url_encode_map);
241 }
242
243 tmp = "\"#{|}";
244 while (*tmp) {
245 FD_SET(*tmp, hdr_encode_map);
246 tmp++;
247 }
248
249 tmp = "\"#";
250 while (*tmp) {
251 FD_SET(*tmp, url_encode_map);
252 tmp++;
253 }
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200254
255 /* memory allocations */
256 pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED);
Willy Tarreau086b3b42007-05-13 21:45:51 +0200257 pool2_capture = create_pool("capture", CAPTURE_LEN, MEM_F_SHARED);
Willy Tarreau80587432006-12-24 17:47:20 +0100258}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200259
Willy Tarreau53b6c742006-12-17 13:37:46 +0100260/*
261 * We have 26 list of methods (1 per first letter), each of which can have
262 * up to 3 entries (2 valid, 1 null).
263 */
264struct http_method_desc {
265 http_meth_t meth;
266 int len;
267 const char text[8];
268};
269
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100270const struct http_method_desc http_methods[26][3] = {
Willy Tarreau53b6c742006-12-17 13:37:46 +0100271 ['C' - 'A'] = {
272 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
273 },
274 ['D' - 'A'] = {
275 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
276 },
277 ['G' - 'A'] = {
278 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
279 },
280 ['H' - 'A'] = {
281 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
282 },
283 ['P' - 'A'] = {
284 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
285 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
286 },
287 ['T' - 'A'] = {
288 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
289 },
290 /* rest is empty like this :
291 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
292 */
293};
294
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100295/* It is about twice as fast on recent architectures to lookup a byte in a
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +0200296 * table than to perform a boolean AND or OR between two tests. Refer to
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100297 * RFC2616 for those chars.
298 */
299
300const char http_is_spht[256] = {
301 [' '] = 1, ['\t'] = 1,
302};
303
304const char http_is_crlf[256] = {
305 ['\r'] = 1, ['\n'] = 1,
306};
307
308const char http_is_lws[256] = {
309 [' '] = 1, ['\t'] = 1,
310 ['\r'] = 1, ['\n'] = 1,
311};
312
313const char http_is_sep[256] = {
314 ['('] = 1, [')'] = 1, ['<'] = 1, ['>'] = 1,
315 ['@'] = 1, [','] = 1, [';'] = 1, [':'] = 1,
316 ['"'] = 1, ['/'] = 1, ['['] = 1, [']'] = 1,
317 ['{'] = 1, ['}'] = 1, ['?'] = 1, ['='] = 1,
318 [' '] = 1, ['\t'] = 1, ['\\'] = 1,
319};
320
321const char http_is_ctl[256] = {
322 [0 ... 31] = 1,
323 [127] = 1,
324};
325
326/*
327 * A token is any ASCII char that is neither a separator nor a CTL char.
328 * Do not overwrite values in assignment since gcc-2.95 will not handle
329 * them correctly. Instead, define every non-CTL char's status.
330 */
331const char http_is_token[256] = {
332 [' '] = 0, ['!'] = 1, ['"'] = 0, ['#'] = 1,
333 ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1,
334 ['('] = 0, [')'] = 0, ['*'] = 1, ['+'] = 1,
335 [','] = 0, ['-'] = 1, ['.'] = 1, ['/'] = 0,
336 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1,
337 ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1,
338 ['8'] = 1, ['9'] = 1, [':'] = 0, [';'] = 0,
339 ['<'] = 0, ['='] = 0, ['>'] = 0, ['?'] = 0,
340 ['@'] = 0, ['A'] = 1, ['B'] = 1, ['C'] = 1,
341 ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1,
342 ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1,
343 ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1,
344 ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1,
345 ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1,
346 ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 0,
347 ['\\'] = 0, [']'] = 0, ['^'] = 1, ['_'] = 1,
348 ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1,
349 ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1,
350 ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1,
351 ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1,
352 ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1,
353 ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1,
354 ['x'] = 1, ['y'] = 1, ['z'] = 1, ['{'] = 0,
355 ['|'] = 1, ['}'] = 0, ['~'] = 1,
356};
357
358
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100359/*
360 * An http ver_token is any ASCII which can be found in an HTTP version,
361 * which includes 'H', 'T', 'P', '/', '.' and any digit.
362 */
363const char http_is_ver_token[256] = {
364 ['.'] = 1, ['/'] = 1,
365 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1,
366 ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1,
367 ['H'] = 1, ['P'] = 1, ['T'] = 1,
368};
369
370
Willy Tarreaubaaee002006-06-26 02:48:02 +0200371#ifdef DEBUG_FULL
Willy Tarreau67f0eea2008-08-10 22:55:22 +0200372static char *cli_stnames[4] = { "DAT", "SHR", "SHW", "CLS" };
Willy Tarreaubaaee002006-06-26 02:48:02 +0200373#endif
374
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100375/*
376 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
377 * CRLF. Text length is measured first, so it cannot be NULL.
378 * The header is also automatically added to the index <hdr_idx>, and the end
379 * of headers is automatically adjusted. The number of bytes added is returned
380 * on success, otherwise <0 is returned indicating an error.
381 */
382int http_header_add_tail(struct buffer *b, struct http_msg *msg,
383 struct hdr_idx *hdr_idx, const char *text)
384{
385 int bytes, len;
386
387 len = strlen(text);
388 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
389 if (!bytes)
390 return -1;
391 msg->eoh += bytes;
392 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
393}
394
395/*
396 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
397 * CRLF. <len> bytes are copied, not counting the CRLF. If <text> is NULL, then
398 * the buffer is only opened and the space reserved, but nothing is copied.
399 * The header is also automatically added to the index <hdr_idx>, and the end
400 * of headers is automatically adjusted. The number of bytes added is returned
401 * on success, otherwise <0 is returned indicating an error.
402 */
403int http_header_add_tail2(struct buffer *b, struct http_msg *msg,
404 struct hdr_idx *hdr_idx, const char *text, int len)
405{
406 int bytes;
407
408 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
409 if (!bytes)
410 return -1;
411 msg->eoh += bytes;
412 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
413}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200414
415/*
Willy Tarreauaa9dce32007-03-18 23:50:16 +0100416 * Checks if <hdr> is exactly <name> for <len> chars, and ends with a colon.
417 * If so, returns the position of the first non-space character relative to
418 * <hdr>, or <end>-<hdr> if not found before. If no value is found, it tries
419 * to return a pointer to the place after the first space. Returns 0 if the
420 * header name does not match. Checks are case-insensitive.
421 */
422int http_header_match2(const char *hdr, const char *end,
423 const char *name, int len)
424{
425 const char *val;
426
427 if (hdr + len >= end)
428 return 0;
429 if (hdr[len] != ':')
430 return 0;
431 if (strncasecmp(hdr, name, len) != 0)
432 return 0;
433 val = hdr + len + 1;
434 while (val < end && HTTP_IS_SPHT(*val))
435 val++;
436 if ((val >= end) && (len + 2 <= end - hdr))
437 return len + 2; /* we may replace starting from second space */
438 return val - hdr;
439}
440
Willy Tarreau33a7e692007-06-10 19:45:56 +0200441/* Find the end of the header value contained between <s> and <e>.
442 * See RFC2616, par 2.2 for more information. Note that it requires
443 * a valid header to return a valid result.
444 */
445const char *find_hdr_value_end(const char *s, const char *e)
446{
447 int quoted, qdpair;
448
449 quoted = qdpair = 0;
450 for (; s < e; s++) {
451 if (qdpair) qdpair = 0;
452 else if (quoted && *s == '\\') qdpair = 1;
453 else if (quoted && *s == '"') quoted = 0;
454 else if (*s == '"') quoted = 1;
455 else if (*s == ',') return s;
456 }
457 return s;
458}
459
460/* Find the first or next occurrence of header <name> in message buffer <sol>
461 * using headers index <idx>, and return it in the <ctx> structure. This
462 * structure holds everything necessary to use the header and find next
463 * occurrence. If its <idx> member is 0, the header is searched from the
464 * beginning. Otherwise, the next occurrence is returned. The function returns
465 * 1 when it finds a value, and 0 when there is no more.
466 */
467int http_find_header2(const char *name, int len,
468 const char *sol, struct hdr_idx *idx,
469 struct hdr_ctx *ctx)
470{
Willy Tarreau33a7e692007-06-10 19:45:56 +0200471 const char *eol, *sov;
472 int cur_idx;
473
474 if (ctx->idx) {
475 /* We have previously returned a value, let's search
476 * another one on the same line.
477 */
478 cur_idx = ctx->idx;
479 sol = ctx->line;
480 sov = sol + ctx->val + ctx->vlen;
481 eol = sol + idx->v[cur_idx].len;
482
483 if (sov >= eol)
484 /* no more values in this header */
485 goto next_hdr;
486
487 /* values remaining for this header, skip the comma */
488 sov++;
489 while (sov < eol && http_is_lws[(unsigned char)*sov])
490 sov++;
491
492 goto return_hdr;
493 }
494
495 /* first request for this header */
496 sol += hdr_idx_first_pos(idx);
497 cur_idx = hdr_idx_first_idx(idx);
498
499 while (cur_idx) {
500 eol = sol + idx->v[cur_idx].len;
501
Willy Tarreau1ad7c6d2007-06-10 21:42:55 +0200502 if (len == 0) {
503 /* No argument was passed, we want any header.
504 * To achieve this, we simply build a fake request. */
505 while (sol + len < eol && sol[len] != ':')
506 len++;
507 name = sol;
508 }
509
Willy Tarreau33a7e692007-06-10 19:45:56 +0200510 if ((len < eol - sol) &&
511 (sol[len] == ':') &&
512 (strncasecmp(sol, name, len) == 0)) {
513
514 sov = sol + len + 1;
515 while (sov < eol && http_is_lws[(unsigned char)*sov])
516 sov++;
517 return_hdr:
518 ctx->line = sol;
519 ctx->idx = cur_idx;
520 ctx->val = sov - sol;
521
522 eol = find_hdr_value_end(sov, eol);
523 ctx->vlen = eol - sov;
524 return 1;
525 }
526 next_hdr:
527 sol = eol + idx->v[cur_idx].cr + 1;
528 cur_idx = idx->v[cur_idx].next;
529 }
530 return 0;
531}
532
533int http_find_header(const char *name,
534 const char *sol, struct hdr_idx *idx,
535 struct hdr_ctx *ctx)
536{
537 return http_find_header2(name, strlen(name), sol, idx, ctx);
538}
539
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100540/* This function handles a server error at the stream interface level. The
541 * stream interface is assumed to be already in a closed state. An optional
542 * message is copied into the input buffer, and an HTTP status code stored.
543 * The error flags are set to the values in arguments. Any pending request
Willy Tarreau6f0aa472009-03-08 20:33:29 +0100544 * in this buffer will be lost.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200545 */
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100546static void http_server_error(struct session *t, struct stream_interface *si,
547 int err, int finst, int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200548{
Willy Tarreau6f0aa472009-03-08 20:33:29 +0100549 buffer_erase(si->ob);
550 buffer_erase(si->ib);
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100551 buffer_write_ena(si->ib);
Willy Tarreau0f772532006-12-23 20:51:41 +0100552 if (status > 0 && msg) {
Willy Tarreau3bac9ff2007-03-18 17:31:28 +0100553 t->txn.status = status;
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100554 buffer_write(si->ib, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200555 }
556 if (!(t->flags & SN_ERR_MASK))
557 t->flags |= err;
558 if (!(t->flags & SN_FINST_MASK))
559 t->flags |= finst;
560}
561
Willy Tarreau80587432006-12-24 17:47:20 +0100562/* This function returns the appropriate error location for the given session
563 * and message.
564 */
565
566struct chunk *error_message(struct session *s, int msgnum)
567{
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200568 if (s->be->errmsg[msgnum].str)
569 return &s->be->errmsg[msgnum];
Willy Tarreau80587432006-12-24 17:47:20 +0100570 else if (s->fe->errmsg[msgnum].str)
571 return &s->fe->errmsg[msgnum];
572 else
573 return &http_err_chunks[msgnum];
574}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200575
Willy Tarreau53b6c742006-12-17 13:37:46 +0100576/*
577 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
578 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
579 */
580static http_meth_t find_http_meth(const char *str, const int len)
581{
582 unsigned char m;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100583 const struct http_method_desc *h;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100584
585 m = ((unsigned)*str - 'A');
586
587 if (m < 26) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100588 for (h = http_methods[m]; h->len > 0; h++) {
589 if (unlikely(h->len != len))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100590 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100591 if (likely(memcmp(str, h->text, h->len) == 0))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100592 return h->meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100593 };
594 return HTTP_METH_OTHER;
595 }
596 return HTTP_METH_NONE;
597
598}
599
Willy Tarreau21d2af32008-02-14 20:25:24 +0100600/* Parse the URI from the given transaction (which is assumed to be in request
601 * phase) and look for the "/" beginning the PATH. If not found, return NULL.
602 * It is returned otherwise.
603 */
604static char *
605http_get_path(struct http_txn *txn)
606{
607 char *ptr, *end;
608
609 ptr = txn->req.sol + txn->req.sl.rq.u;
610 end = ptr + txn->req.sl.rq.u_l;
611
612 if (ptr >= end)
613 return NULL;
614
615 /* RFC2616, par. 5.1.2 :
616 * Request-URI = "*" | absuri | abspath | authority
617 */
618
619 if (*ptr == '*')
620 return NULL;
621
622 if (isalpha((unsigned char)*ptr)) {
623 /* this is a scheme as described by RFC3986, par. 3.1 */
624 ptr++;
625 while (ptr < end &&
626 (isalnum((unsigned char)*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.'))
627 ptr++;
628 /* skip '://' */
629 if (ptr == end || *ptr++ != ':')
630 return NULL;
631 if (ptr == end || *ptr++ != '/')
632 return NULL;
633 if (ptr == end || *ptr++ != '/')
634 return NULL;
635 }
636 /* skip [user[:passwd]@]host[:[port]] */
637
638 while (ptr < end && *ptr != '/')
639 ptr++;
640
641 if (ptr == end)
642 return NULL;
643
644 /* OK, we got the '/' ! */
645 return ptr;
646}
647
Willy Tarreauefb453c2008-10-26 20:49:47 +0100648/* Returns a 302 for a redirectable request. This may only be called just after
649 * the stream interface has moved to SI_ST_ASS. Unprocessable requests are
650 * left unchanged and will follow normal proxy processing.
651 */
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100652void perform_http_redirect(struct session *s, struct stream_interface *si)
Willy Tarreauefb453c2008-10-26 20:49:47 +0100653{
654 struct http_txn *txn;
655 struct chunk rdr;
656 char *path;
657 int len;
658
659 /* 1: create the response header */
660 rdr.len = strlen(HTTP_302);
661 rdr.str = trash;
662 memcpy(rdr.str, HTTP_302, rdr.len);
663
664 /* 2: add the server's prefix */
665 if (rdr.len + s->srv->rdr_len > sizeof(trash))
666 return;
667
668 memcpy(rdr.str + rdr.len, s->srv->rdr_pfx, s->srv->rdr_len);
669 rdr.len += s->srv->rdr_len;
670
671 /* 3: add the request URI */
672 txn = &s->txn;
673 path = http_get_path(txn);
674 if (!path)
675 return;
676
677 len = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
678 if (rdr.len + len > sizeof(trash) - 4) /* 4 for CRLF-CRLF */
679 return;
680
681 memcpy(rdr.str + rdr.len, path, len);
682 rdr.len += len;
683 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
684 rdr.len += 4;
685
686 /* prepare to return without error. */
Willy Tarreau99126c32008-11-27 10:30:51 +0100687 si->shutr(si);
688 si->shutw(si);
Willy Tarreauefb453c2008-10-26 20:49:47 +0100689 si->err_type = SI_ET_NONE;
690 si->err_loc = NULL;
691 si->state = SI_ST_CLO;
692
693 /* send the message */
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100694 http_server_error(s, si, SN_ERR_PRXCOND, SN_FINST_C, 302, &rdr);
Willy Tarreauefb453c2008-10-26 20:49:47 +0100695
696 /* FIXME: we should increase a counter of redirects per server and per backend. */
697 if (s->srv)
Willy Tarreau7f062c42009-03-05 18:43:00 +0100698 srv_inc_sess_ctr(s->srv);
Willy Tarreauefb453c2008-10-26 20:49:47 +0100699}
700
Willy Tarreau0cac36f2008-11-30 20:44:17 +0100701/* Return the error message corresponding to si->err_type. It is assumed
Willy Tarreauefb453c2008-10-26 20:49:47 +0100702 * that the server side is closed. Note that err_type is actually a
703 * bitmask, where almost only aborts may be cumulated with other
704 * values. We consider that aborted operations are more important
705 * than timeouts or errors due to the fact that nobody else in the
706 * logs might explain incomplete retries. All others should avoid
707 * being cumulated. It should normally not be possible to have multiple
708 * aborts at once, but just in case, the first one in sequence is reported.
709 */
Willy Tarreau0cac36f2008-11-30 20:44:17 +0100710void http_return_srv_error(struct session *s, struct stream_interface *si)
Willy Tarreauefb453c2008-10-26 20:49:47 +0100711{
Willy Tarreau0cac36f2008-11-30 20:44:17 +0100712 int err_type = si->err_type;
Willy Tarreauefb453c2008-10-26 20:49:47 +0100713
714 if (err_type & SI_ET_QUEUE_ABRT)
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100715 http_server_error(s, si, SN_ERR_CLICL, SN_FINST_Q,
716 503, error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100717 else if (err_type & SI_ET_CONN_ABRT)
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100718 http_server_error(s, si, SN_ERR_CLICL, SN_FINST_C,
719 503, error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100720 else if (err_type & SI_ET_QUEUE_TO)
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100721 http_server_error(s, si, SN_ERR_SRVTO, SN_FINST_Q,
722 503, error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100723 else if (err_type & SI_ET_QUEUE_ERR)
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100724 http_server_error(s, si, SN_ERR_SRVCL, SN_FINST_Q,
725 503, error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100726 else if (err_type & SI_ET_CONN_TO)
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100727 http_server_error(s, si, SN_ERR_SRVTO, SN_FINST_C,
728 503, error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100729 else if (err_type & SI_ET_CONN_ERR)
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100730 http_server_error(s, si, SN_ERR_SRVCL, SN_FINST_C,
731 503, error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100732 else /* SI_ET_CONN_OTHER and others */
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100733 http_server_error(s, si, SN_ERR_INTERNAL, SN_FINST_C,
734 500, error_message(s, HTTP_ERR_500));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100735}
736
Willy Tarreau42250582007-04-01 01:30:43 +0200737extern const char sess_term_cond[8];
738extern const char sess_fin_state[8];
739extern const char *monthname[12];
740const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
741const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
742 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
743 unknown, Set-cookie Rewritten */
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200744struct pool_head *pool2_requri;
Willy Tarreau086b3b42007-05-13 21:45:51 +0200745struct pool_head *pool2_capture;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100746
Willy Tarreau42250582007-04-01 01:30:43 +0200747/*
748 * send a log for the session when we have enough info about it.
749 * Will not log if the frontend has no log defined.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100750 */
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100751void http_sess_log(struct session *s)
Willy Tarreau42250582007-04-01 01:30:43 +0200752{
753 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
754 struct proxy *fe = s->fe;
755 struct proxy *be = s->be;
756 struct proxy *prx_log;
757 struct http_txn *txn = &s->txn;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +0200758 int tolog, level, err;
Willy Tarreau42250582007-04-01 01:30:43 +0200759 char *uri, *h;
760 char *svid;
Willy Tarreaufe944602007-10-25 10:34:16 +0200761 struct tm tm;
Willy Tarreau42250582007-04-01 01:30:43 +0200762 static char tmpline[MAX_SYSLOG_LEN];
Willy Tarreau70089872008-06-13 21:12:51 +0200763 int t_request;
Willy Tarreau42250582007-04-01 01:30:43 +0200764 int hdr;
765
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +0200766 /* if we don't want to log normal traffic, return now */
767 err = (s->flags & (SN_ERR_MASK | SN_REDISP)) ||
768 (s->conn_retries != be->conn_retries) ||
769 txn->status >= 500;
770 if (!err && (fe->options2 & PR_O2_NOLOGNORM))
771 return;
772
Willy Tarreau42250582007-04-01 01:30:43 +0200773 if (fe->logfac1 < 0 && fe->logfac2 < 0)
774 return;
775 prx_log = fe;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100776
Willy Tarreau42250582007-04-01 01:30:43 +0200777 if (s->cli_addr.ss_family == AF_INET)
778 inet_ntop(AF_INET,
779 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
780 pn, sizeof(pn));
781 else
782 inet_ntop(AF_INET6,
783 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
784 pn, sizeof(pn));
785
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200786 get_localtime(s->logs.accept_date.tv_sec, &tm);
Willy Tarreau42250582007-04-01 01:30:43 +0200787
788 /* FIXME: let's limit ourselves to frontend logging for now. */
789 tolog = fe->to_log;
790
791 h = tmpline;
792 if (fe->to_log & LW_REQHDR &&
793 txn->req.cap &&
794 (h < tmpline + sizeof(tmpline) - 10)) {
795 *(h++) = ' ';
796 *(h++) = '{';
797 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
798 if (hdr)
799 *(h++) = '|';
800 if (txn->req.cap[hdr] != NULL)
801 h = encode_string(h, tmpline + sizeof(tmpline) - 7,
802 '#', hdr_encode_map, txn->req.cap[hdr]);
803 }
804 *(h++) = '}';
805 }
806
807 if (fe->to_log & LW_RSPHDR &&
808 txn->rsp.cap &&
809 (h < tmpline + sizeof(tmpline) - 7)) {
810 *(h++) = ' ';
811 *(h++) = '{';
812 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
813 if (hdr)
814 *(h++) = '|';
815 if (txn->rsp.cap[hdr] != NULL)
816 h = encode_string(h, tmpline + sizeof(tmpline) - 4,
817 '#', hdr_encode_map, txn->rsp.cap[hdr]);
818 }
819 *(h++) = '}';
820 }
821
822 if (h < tmpline + sizeof(tmpline) - 4) {
823 *(h++) = ' ';
824 *(h++) = '"';
825 uri = txn->uri ? txn->uri : "<BADREQ>";
826 h = encode_string(h, tmpline + sizeof(tmpline) - 1,
827 '#', url_encode_map, uri);
828 *(h++) = '"';
829 }
830 *h = '\0';
831
832 svid = (tolog & LW_SVID) ?
833 (s->data_source != DATA_SRC_STATS) ?
834 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
835
Willy Tarreau70089872008-06-13 21:12:51 +0200836 t_request = -1;
837 if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
838 t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
839
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +0200840 level = LOG_INFO;
841 if (err && (fe->options2 & PR_O2_LOGERRORS))
842 level = LOG_ERR;
843
844 send_log(prx_log, level,
Willy Tarreau42250582007-04-01 01:30:43 +0200845 "%s:%d [%02d/%s/%04d:%02d:%02d:%02d.%03d]"
Willy Tarreau1772ece2009-04-03 14:49:12 +0200846 " %s %s/%s %d/%ld/%ld/%ld/%s%ld %d %s%lld"
847 " %s %s %c%c%c%c %d/%d/%d/%d/%s%u %ld/%ld%s\n",
Willy Tarreau42250582007-04-01 01:30:43 +0200848 pn,
849 (s->cli_addr.ss_family == AF_INET) ?
850 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
851 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
Willy Tarreaufe944602007-10-25 10:34:16 +0200852 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
Willy Tarreau1772ece2009-04-03 14:49:12 +0200853 tm.tm_hour, tm.tm_min, tm.tm_sec, (int)s->logs.accept_date.tv_usec/1000,
Willy Tarreau42250582007-04-01 01:30:43 +0200854 fe->id, be->id, svid,
Willy Tarreau70089872008-06-13 21:12:51 +0200855 t_request,
856 (s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1,
Willy Tarreau42250582007-04-01 01:30:43 +0200857 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
858 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
859 (tolog & LW_BYTES) ? "" : "+", s->logs.t_close,
860 txn->status,
Willy Tarreau8b3977f2008-01-18 11:16:32 +0100861 (tolog & LW_BYTES) ? "" : "+", s->logs.bytes_out,
Willy Tarreau42250582007-04-01 01:30:43 +0200862 txn->cli_cookie ? txn->cli_cookie : "-",
863 txn->srv_cookie ? txn->srv_cookie : "-",
864 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
865 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
866 (be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-',
867 (be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-',
868 actconn, fe->feconn, be->beconn, s->srv ? s->srv->cur_sess : 0,
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100869 (s->flags & SN_REDISP)?"+":"",
870 (s->conn_retries>0)?(be->conn_retries - s->conn_retries):be->conn_retries,
Willy Tarreau42250582007-04-01 01:30:43 +0200871 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
872
873 s->logs.logwait = 0;
874}
875
Willy Tarreau117f59e2007-03-04 18:17:17 +0100876
877/*
878 * Capture headers from message starting at <som> according to header list
879 * <cap_hdr>, and fill the <idx> structure appropriately.
880 */
881void capture_headers(char *som, struct hdr_idx *idx,
882 char **cap, struct cap_hdr *cap_hdr)
883{
884 char *eol, *sol, *col, *sov;
885 int cur_idx;
886 struct cap_hdr *h;
887 int len;
888
889 sol = som + hdr_idx_first_pos(idx);
890 cur_idx = hdr_idx_first_idx(idx);
891
892 while (cur_idx) {
893 eol = sol + idx->v[cur_idx].len;
894
895 col = sol;
896 while (col < eol && *col != ':')
897 col++;
898
899 sov = col + 1;
900 while (sov < eol && http_is_lws[(unsigned char)*sov])
901 sov++;
902
903 for (h = cap_hdr; h; h = h->next) {
904 if ((h->namelen == col - sol) &&
905 (strncasecmp(sol, h->name, h->namelen) == 0)) {
906 if (cap[h->index] == NULL)
907 cap[h->index] =
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200908 pool_alloc2(h->pool);
Willy Tarreau117f59e2007-03-04 18:17:17 +0100909
910 if (cap[h->index] == NULL) {
911 Alert("HTTP capture : out of memory.\n");
912 continue;
913 }
914
915 len = eol - sov;
916 if (len > h->len)
917 len = h->len;
918
919 memcpy(cap[h->index], sov, len);
920 cap[h->index][len]=0;
921 }
922 }
923 sol = eol + idx->v[cur_idx].cr + 1;
924 cur_idx = idx->v[cur_idx].next;
925 }
926}
927
928
Willy Tarreau42250582007-04-01 01:30:43 +0200929/* either we find an LF at <ptr> or we jump to <bad>.
930 */
931#define EXPECT_LF_HERE(ptr, bad) do { if (unlikely(*(ptr) != '\n')) goto bad; } while (0)
932
933/* plays with variables <ptr>, <end> and <state>. Jumps to <good> if OK,
934 * otherwise to <http_msg_ood> with <state> set to <st>.
935 */
936#define EAT_AND_JUMP_OR_RETURN(good, st) do { \
937 ptr++; \
938 if (likely(ptr < end)) \
939 goto good; \
940 else { \
941 state = (st); \
942 goto http_msg_ood; \
943 } \
944 } while (0)
945
946
Willy Tarreaubaaee002006-06-26 02:48:02 +0200947/*
Willy Tarreaua15645d2007-03-18 16:22:39 +0100948 * This function parses a status line between <ptr> and <end>, starting with
Willy Tarreau8973c702007-01-21 23:58:29 +0100949 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
950 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
951 * will give undefined results.
952 * Note that it is upon the caller's responsibility to ensure that ptr < end,
953 * and that msg->sol points to the beginning of the response.
954 * If a complete line is found (which implies that at least one CR or LF is
955 * found before <end>, the updated <ptr> is returned, otherwise NULL is
956 * returned indicating an incomplete line (which does not mean that parts have
957 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
958 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
959 * upon next call.
960 *
Willy Tarreau9cdde232007-05-02 20:58:19 +0200961 * This function was intentionally designed to be called from
Willy Tarreau8973c702007-01-21 23:58:29 +0100962 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
963 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +0200964 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreau8973c702007-01-21 23:58:29 +0100965 */
Willy Tarreaue69eada2008-01-27 00:34:10 +0100966const char *http_parse_stsline(struct http_msg *msg, const char *msg_buf,
967 unsigned int state, const char *ptr, const char *end,
968 char **ret_ptr, unsigned int *ret_state)
Willy Tarreau8973c702007-01-21 23:58:29 +0100969{
Willy Tarreau8973c702007-01-21 23:58:29 +0100970 switch (state) {
971 http_msg_rpver:
972 case HTTP_MSG_RPVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100973 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8973c702007-01-21 23:58:29 +0100974 EAT_AND_JUMP_OR_RETURN(http_msg_rpver, HTTP_MSG_RPVER);
975
976 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +0100977 msg->sl.st.v_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +0100978 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
979 }
Willy Tarreau7552c032009-03-01 11:10:40 +0100980 state = HTTP_MSG_ERROR;
981 break;
982
Willy Tarreau8973c702007-01-21 23:58:29 +0100983 http_msg_rpver_sp:
984 case HTTP_MSG_RPVER_SP:
985 if (likely(!HTTP_IS_LWS(*ptr))) {
986 msg->sl.st.c = ptr - msg_buf;
987 goto http_msg_rpcode;
988 }
989 if (likely(HTTP_IS_SPHT(*ptr)))
990 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
991 /* so it's a CR/LF, this is invalid */
Willy Tarreau7552c032009-03-01 11:10:40 +0100992 state = HTTP_MSG_ERROR;
993 break;
Willy Tarreau8973c702007-01-21 23:58:29 +0100994
995 http_msg_rpcode:
996 case HTTP_MSG_RPCODE:
997 if (likely(!HTTP_IS_LWS(*ptr)))
998 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode, HTTP_MSG_RPCODE);
999
1000 if (likely(HTTP_IS_SPHT(*ptr))) {
1001 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
1002 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1003 }
1004
1005 /* so it's a CR/LF, so there is no reason phrase */
1006 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
1007 http_msg_rsp_reason:
1008 /* FIXME: should we support HTTP responses without any reason phrase ? */
1009 msg->sl.st.r = ptr - msg_buf;
1010 msg->sl.st.r_l = 0;
1011 goto http_msg_rpline_eol;
1012
1013 http_msg_rpcode_sp:
1014 case HTTP_MSG_RPCODE_SP:
1015 if (likely(!HTTP_IS_LWS(*ptr))) {
1016 msg->sl.st.r = ptr - msg_buf;
1017 goto http_msg_rpreason;
1018 }
1019 if (likely(HTTP_IS_SPHT(*ptr)))
1020 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1021 /* so it's a CR/LF, so there is no reason phrase */
1022 goto http_msg_rsp_reason;
1023
1024 http_msg_rpreason:
1025 case HTTP_MSG_RPREASON:
1026 if (likely(!HTTP_IS_CRLF(*ptr)))
1027 EAT_AND_JUMP_OR_RETURN(http_msg_rpreason, HTTP_MSG_RPREASON);
1028 msg->sl.st.r_l = (ptr - msg_buf) - msg->sl.st.r;
1029 http_msg_rpline_eol:
1030 /* We have seen the end of line. Note that we do not
1031 * necessarily have the \n yet, but at least we know that we
1032 * have EITHER \r OR \n, otherwise the response would not be
1033 * complete. We can then record the response length and return
1034 * to the caller which will be able to register it.
1035 */
1036 msg->sl.st.l = ptr - msg->sol;
1037 return ptr;
1038
1039#ifdef DEBUG_FULL
1040 default:
1041 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1042 exit(1);
1043#endif
1044 }
1045
1046 http_msg_ood:
Willy Tarreau7552c032009-03-01 11:10:40 +01001047 /* out of valid data */
Willy Tarreau8973c702007-01-21 23:58:29 +01001048 if (ret_state)
1049 *ret_state = state;
1050 if (ret_ptr)
1051 *ret_ptr = (char *)ptr;
1052 return NULL;
Willy Tarreau8973c702007-01-21 23:58:29 +01001053}
1054
1055
1056/*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001057 * This function parses a request line between <ptr> and <end>, starting with
1058 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
1059 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
1060 * will give undefined results.
1061 * Note that it is upon the caller's responsibility to ensure that ptr < end,
1062 * and that msg->sol points to the beginning of the request.
1063 * If a complete line is found (which implies that at least one CR or LF is
1064 * found before <end>, the updated <ptr> is returned, otherwise NULL is
1065 * returned indicating an incomplete line (which does not mean that parts have
1066 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
1067 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
1068 * upon next call.
1069 *
Willy Tarreau9cdde232007-05-02 20:58:19 +02001070 * This function was intentionally designed to be called from
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001071 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
1072 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +02001073 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001074 */
Willy Tarreaue69eada2008-01-27 00:34:10 +01001075const char *http_parse_reqline(struct http_msg *msg, const char *msg_buf,
1076 unsigned int state, const char *ptr, const char *end,
1077 char **ret_ptr, unsigned int *ret_state)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001078{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001079 switch (state) {
1080 http_msg_rqmeth:
1081 case HTTP_MSG_RQMETH:
1082 if (likely(HTTP_IS_TOKEN(*ptr)))
1083 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth, HTTP_MSG_RQMETH);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001084
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001085 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001086 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001087 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1088 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001089
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001090 if (likely(HTTP_IS_CRLF(*ptr))) {
1091 /* HTTP 0.9 request */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001092 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001093 http_msg_req09_uri:
1094 msg->sl.rq.u = ptr - msg_buf;
1095 http_msg_req09_uri_e:
1096 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1097 http_msg_req09_ver:
1098 msg->sl.rq.v = ptr - msg_buf;
1099 msg->sl.rq.v_l = 0;
1100 goto http_msg_rqline_eol;
1101 }
Willy Tarreau7552c032009-03-01 11:10:40 +01001102 state = HTTP_MSG_ERROR;
1103 break;
1104
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001105 http_msg_rqmeth_sp:
1106 case HTTP_MSG_RQMETH_SP:
1107 if (likely(!HTTP_IS_LWS(*ptr))) {
1108 msg->sl.rq.u = ptr - msg_buf;
1109 goto http_msg_rquri;
1110 }
1111 if (likely(HTTP_IS_SPHT(*ptr)))
1112 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1113 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1114 goto http_msg_req09_uri;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001115
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001116 http_msg_rquri:
1117 case HTTP_MSG_RQURI:
1118 if (likely(!HTTP_IS_LWS(*ptr)))
1119 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001120
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001121 if (likely(HTTP_IS_SPHT(*ptr))) {
1122 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1123 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1124 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001125
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001126 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1127 goto http_msg_req09_uri_e;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001128
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001129 http_msg_rquri_sp:
1130 case HTTP_MSG_RQURI_SP:
1131 if (likely(!HTTP_IS_LWS(*ptr))) {
1132 msg->sl.rq.v = ptr - msg_buf;
1133 goto http_msg_rqver;
1134 }
1135 if (likely(HTTP_IS_SPHT(*ptr)))
1136 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1137 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1138 goto http_msg_req09_ver;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001139
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001140 http_msg_rqver:
1141 case HTTP_MSG_RQVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001142 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001143 EAT_AND_JUMP_OR_RETURN(http_msg_rqver, HTTP_MSG_RQVER);
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001144
1145 if (likely(HTTP_IS_CRLF(*ptr))) {
1146 msg->sl.rq.v_l = (ptr - msg_buf) - msg->sl.rq.v;
1147 http_msg_rqline_eol:
1148 /* We have seen the end of line. Note that we do not
1149 * necessarily have the \n yet, but at least we know that we
1150 * have EITHER \r OR \n, otherwise the request would not be
1151 * complete. We can then record the request length and return
1152 * to the caller which will be able to register it.
1153 */
1154 msg->sl.rq.l = ptr - msg->sol;
1155 return ptr;
1156 }
1157
1158 /* neither an HTTP_VER token nor a CRLF */
Willy Tarreau7552c032009-03-01 11:10:40 +01001159 state = HTTP_MSG_ERROR;
1160 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001161
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001162#ifdef DEBUG_FULL
1163 default:
1164 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1165 exit(1);
1166#endif
1167 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001168
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001169 http_msg_ood:
Willy Tarreau7552c032009-03-01 11:10:40 +01001170 /* out of valid data */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001171 if (ret_state)
1172 *ret_state = state;
1173 if (ret_ptr)
1174 *ret_ptr = (char *)ptr;
1175 return NULL;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001176}
Willy Tarreau58f10d72006-12-04 02:26:12 +01001177
1178
Willy Tarreau8973c702007-01-21 23:58:29 +01001179/*
1180 * This function parses an HTTP message, either a request or a response,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001181 * depending on the initial msg->msg_state. It can be preempted everywhere
Willy Tarreau8973c702007-01-21 23:58:29 +01001182 * when data are missing and recalled at the exact same location with no
1183 * information loss. The header index is re-initialized when switching from
Willy Tarreau9cdde232007-05-02 20:58:19 +02001184 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH. It modifies msg->sol among other
1185 * fields.
Willy Tarreau8973c702007-01-21 23:58:29 +01001186 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001187void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx *idx)
1188{
Willy Tarreaue69eada2008-01-27 00:34:10 +01001189 unsigned int state; /* updated only when leaving the FSM */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001190 register char *ptr, *end; /* request pointers, to avoid dereferences */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001191
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001192 state = msg->msg_state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001193 ptr = buf->lr;
1194 end = buf->r;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001195
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001196 if (unlikely(ptr >= end))
1197 goto http_msg_ood;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001198
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001199 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +01001200 /*
1201 * First, states that are specific to the response only.
1202 * We check them first so that request and headers are
1203 * closer to each other (accessed more often).
1204 */
1205 http_msg_rpbefore:
1206 case HTTP_MSG_RPBEFORE:
1207 if (likely(HTTP_IS_TOKEN(*ptr))) {
1208 if (likely(ptr == buf->data)) {
1209 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001210 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001211 } else {
1212#if PARSE_PRESERVE_EMPTY_LINES
1213 /* only skip empty leading lines, don't remove them */
1214 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001215 msg->som = ptr - buf->data;
Willy Tarreau8973c702007-01-21 23:58:29 +01001216#else
1217 /* Remove empty leading lines, as recommended by
1218 * RFC2616. This takes a lot of time because we
1219 * must move all the buffer backwards, but this
1220 * is rarely needed. The method above will be
1221 * cleaner when we'll be able to start sending
1222 * the request from any place in the buffer.
1223 */
1224 buf->lr = ptr;
1225 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001226 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001227 msg->sol = buf->data;
1228 ptr = buf->data;
1229 end = buf->r;
1230#endif
1231 }
1232 hdr_idx_init(idx);
1233 state = HTTP_MSG_RPVER;
1234 goto http_msg_rpver;
1235 }
1236
1237 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1238 goto http_msg_invalid;
1239
1240 if (unlikely(*ptr == '\n'))
1241 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1242 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore_cr, HTTP_MSG_RPBEFORE_CR);
1243 /* stop here */
1244
1245 http_msg_rpbefore_cr:
1246 case HTTP_MSG_RPBEFORE_CR:
1247 EXPECT_LF_HERE(ptr, http_msg_invalid);
1248 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1249 /* stop here */
1250
1251 http_msg_rpver:
1252 case HTTP_MSG_RPVER:
1253 case HTTP_MSG_RPVER_SP:
1254 case HTTP_MSG_RPCODE:
1255 case HTTP_MSG_RPCODE_SP:
1256 case HTTP_MSG_RPREASON:
Willy Tarreaua15645d2007-03-18 16:22:39 +01001257 ptr = (char *)http_parse_stsline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001258 &buf->lr, &msg->msg_state);
Willy Tarreau8973c702007-01-21 23:58:29 +01001259 if (unlikely(!ptr))
1260 return;
1261
1262 /* we have a full response and we know that we have either a CR
1263 * or an LF at <ptr>.
1264 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001265 //fprintf(stderr,"som=%d rq.l=%d *ptr=0x%02x\n", msg->som, msg->sl.st.l, *ptr);
Willy Tarreau8973c702007-01-21 23:58:29 +01001266 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
1267
1268 msg->sol = ptr;
1269 if (likely(*ptr == '\r'))
1270 EAT_AND_JUMP_OR_RETURN(http_msg_rpline_end, HTTP_MSG_RPLINE_END);
1271 goto http_msg_rpline_end;
1272
1273 http_msg_rpline_end:
1274 case HTTP_MSG_RPLINE_END:
1275 /* msg->sol must point to the first of CR or LF. */
1276 EXPECT_LF_HERE(ptr, http_msg_invalid);
1277 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
1278 /* stop here */
1279
1280 /*
1281 * Second, states that are specific to the request only
1282 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001283 http_msg_rqbefore:
1284 case HTTP_MSG_RQBEFORE:
1285 if (likely(HTTP_IS_TOKEN(*ptr))) {
1286 if (likely(ptr == buf->data)) {
1287 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001288 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001289 } else {
1290#if PARSE_PRESERVE_EMPTY_LINES
1291 /* only skip empty leading lines, don't remove them */
1292 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001293 msg->som = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001294#else
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001295 /* Remove empty leading lines, as recommended by
1296 * RFC2616. This takes a lot of time because we
1297 * must move all the buffer backwards, but this
1298 * is rarely needed. The method above will be
1299 * cleaner when we'll be able to start sending
1300 * the request from any place in the buffer.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001301 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001302 buf->lr = ptr;
1303 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001304 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001305 msg->sol = buf->data;
1306 ptr = buf->data;
1307 end = buf->r;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001308#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001309 }
Willy Tarreauf0d058e2007-01-25 12:03:42 +01001310 /* we will need this when keep-alive will be supported
1311 hdr_idx_init(idx);
1312 */
Willy Tarreau8973c702007-01-21 23:58:29 +01001313 state = HTTP_MSG_RQMETH;
1314 goto http_msg_rqmeth;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001315 }
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001316
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001317 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1318 goto http_msg_invalid;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001319
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001320 if (unlikely(*ptr == '\n'))
1321 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
1322 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore_cr, HTTP_MSG_RQBEFORE_CR);
Willy Tarreau8973c702007-01-21 23:58:29 +01001323 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001324
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001325 http_msg_rqbefore_cr:
1326 case HTTP_MSG_RQBEFORE_CR:
1327 EXPECT_LF_HERE(ptr, http_msg_invalid);
1328 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
Willy Tarreau8973c702007-01-21 23:58:29 +01001329 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001330
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001331 http_msg_rqmeth:
1332 case HTTP_MSG_RQMETH:
1333 case HTTP_MSG_RQMETH_SP:
1334 case HTTP_MSG_RQURI:
1335 case HTTP_MSG_RQURI_SP:
1336 case HTTP_MSG_RQVER:
1337 ptr = (char *)http_parse_reqline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001338 &buf->lr, &msg->msg_state);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001339 if (unlikely(!ptr))
1340 return;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001341
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001342 /* we have a full request and we know that we have either a CR
1343 * or an LF at <ptr>.
1344 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001345 //fprintf(stderr,"som=%d rq.l=%d *ptr=0x%02x\n", msg->som, msg->sl.rq.l, *ptr);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001346 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001347
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001348 msg->sol = ptr;
1349 if (likely(*ptr == '\r'))
1350 EAT_AND_JUMP_OR_RETURN(http_msg_rqline_end, HTTP_MSG_RQLINE_END);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001351 goto http_msg_rqline_end;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001352
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001353 http_msg_rqline_end:
1354 case HTTP_MSG_RQLINE_END:
1355 /* check for HTTP/0.9 request : no version information available.
1356 * msg->sol must point to the first of CR or LF.
1357 */
1358 if (unlikely(msg->sl.rq.v_l == 0))
1359 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001360
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001361 EXPECT_LF_HERE(ptr, http_msg_invalid);
1362 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
Willy Tarreau8973c702007-01-21 23:58:29 +01001363 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001364
Willy Tarreau8973c702007-01-21 23:58:29 +01001365 /*
1366 * Common states below
1367 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001368 http_msg_hdr_first:
1369 case HTTP_MSG_HDR_FIRST:
1370 msg->sol = ptr;
1371 if (likely(!HTTP_IS_CRLF(*ptr))) {
1372 goto http_msg_hdr_name;
1373 }
1374
1375 if (likely(*ptr == '\r'))
1376 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1377 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001378
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001379 http_msg_hdr_name:
1380 case HTTP_MSG_HDR_NAME:
1381 /* assumes msg->sol points to the first char */
1382 if (likely(HTTP_IS_TOKEN(*ptr)))
1383 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001384
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001385 if (likely(*ptr == ':')) {
1386 msg->col = ptr - buf->data;
1387 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
1388 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001389
Willy Tarreau32a4ec02009-04-02 11:35:18 +02001390 if (likely(msg->err_pos < -1) || *ptr == '\n')
1391 goto http_msg_invalid;
1392
1393 if (msg->err_pos == -1) /* capture error pointer */
1394 msg->err_pos = ptr - buf->data; /* >= 0 now */
1395
1396 /* and we still accept this non-token character */
1397 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001398
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001399 http_msg_hdr_l1_sp:
1400 case HTTP_MSG_HDR_L1_SP:
1401 /* assumes msg->sol points to the first char and msg->col to the colon */
1402 if (likely(HTTP_IS_SPHT(*ptr)))
1403 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001404
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001405 /* header value can be basically anything except CR/LF */
1406 msg->sov = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001407
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001408 if (likely(!HTTP_IS_CRLF(*ptr))) {
1409 goto http_msg_hdr_val;
1410 }
1411
1412 if (likely(*ptr == '\r'))
1413 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lf, HTTP_MSG_HDR_L1_LF);
1414 goto http_msg_hdr_l1_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001415
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001416 http_msg_hdr_l1_lf:
1417 case HTTP_MSG_HDR_L1_LF:
1418 EXPECT_LF_HERE(ptr, http_msg_invalid);
1419 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lws, HTTP_MSG_HDR_L1_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001420
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001421 http_msg_hdr_l1_lws:
1422 case HTTP_MSG_HDR_L1_LWS:
1423 if (likely(HTTP_IS_SPHT(*ptr))) {
1424 /* replace HT,CR,LF with spaces */
1425 for (; buf->data+msg->sov < ptr; msg->sov++)
1426 buf->data[msg->sov] = ' ';
1427 goto http_msg_hdr_l1_sp;
1428 }
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001429 /* we had a header consisting only in spaces ! */
1430 msg->eol = buf->data + msg->sov;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001431 goto http_msg_complete_header;
1432
1433 http_msg_hdr_val:
1434 case HTTP_MSG_HDR_VAL:
1435 /* assumes msg->sol points to the first char, msg->col to the
1436 * colon, and msg->sov points to the first character of the
1437 * value.
1438 */
1439 if (likely(!HTTP_IS_CRLF(*ptr)))
1440 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001441
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001442 msg->eol = ptr;
1443 /* Note: we could also copy eol into ->eoh so that we have the
1444 * real header end in case it ends with lots of LWS, but is this
1445 * really needed ?
1446 */
1447 if (likely(*ptr == '\r'))
1448 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1449 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001450
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001451 http_msg_hdr_l2_lf:
1452 case HTTP_MSG_HDR_L2_LF:
1453 EXPECT_LF_HERE(ptr, http_msg_invalid);
1454 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001455
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001456 http_msg_hdr_l2_lws:
1457 case HTTP_MSG_HDR_L2_LWS:
1458 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1459 /* LWS: replace HT,CR,LF with spaces */
1460 for (; msg->eol < ptr; msg->eol++)
1461 *msg->eol = ' ';
1462 goto http_msg_hdr_val;
1463 }
1464 http_msg_complete_header:
1465 /*
1466 * It was a new header, so the last one is finished.
1467 * Assumes msg->sol points to the first char, msg->col to the
1468 * colon, msg->sov points to the first character of the value
1469 * and msg->eol to the first CR or LF so we know how the line
1470 * ends. We insert last header into the index.
1471 */
1472 /*
1473 fprintf(stderr,"registering %-2d bytes : ", msg->eol - msg->sol);
1474 write(2, msg->sol, msg->eol-msg->sol);
1475 fprintf(stderr,"\n");
1476 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001477
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001478 if (unlikely(hdr_idx_add(msg->eol - msg->sol, *msg->eol == '\r',
1479 idx, idx->tail) < 0))
1480 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001481
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001482 msg->sol = ptr;
1483 if (likely(!HTTP_IS_CRLF(*ptr))) {
1484 goto http_msg_hdr_name;
1485 }
1486
1487 if (likely(*ptr == '\r'))
1488 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1489 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001490
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001491 http_msg_last_lf:
1492 case HTTP_MSG_LAST_LF:
1493 /* Assumes msg->sol points to the first of either CR or LF */
1494 EXPECT_LF_HERE(ptr, http_msg_invalid);
1495 ptr++;
1496 buf->lr = ptr;
1497 msg->eoh = msg->sol - buf->data;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001498 msg->msg_state = HTTP_MSG_BODY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001499 return;
1500#ifdef DEBUG_FULL
1501 default:
1502 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1503 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001504#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001505 }
1506 http_msg_ood:
1507 /* out of data */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001508 msg->msg_state = state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001509 buf->lr = ptr;
1510 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001511
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001512 http_msg_invalid:
1513 /* invalid message */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001514 msg->msg_state = HTTP_MSG_ERROR;
Willy Tarreau7552c032009-03-01 11:10:40 +01001515 buf->lr = ptr;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001516 return;
1517}
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001518
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02001519/* This function performs all the processing enabled for the current request.
Willy Tarreauedcf6682008-11-30 23:15:34 +01001520 * It returns 1 if the processing can continue on next analysers, or zero if it
1521 * needs more data, encounters an error, or wants to immediately abort the
1522 * request. It relies on buffers flags, and updates s->req->analysers. Its
1523 * behaviour is rather simple:
Willy Tarreau41f40ed2008-08-21 10:05:00 +02001524 * - all enabled analysers are called in turn from the lower to the higher
1525 * bit.
Willy Tarreauedcf6682008-11-30 23:15:34 +01001526 * - the analyser must check for errors and timeouts, and react as expected.
1527 * It does not have to close anything upon error, the caller will.
1528 * - if the analyser does not have enough data, it must return 0without calling
1529 * other ones. It should also probably do a buffer_write_dis() to ensure
Willy Tarreau41f40ed2008-08-21 10:05:00 +02001530 * that unprocessed data will not be forwarded. But that probably depends on
Willy Tarreauedcf6682008-11-30 23:15:34 +01001531 * the protocol.
Willy Tarreau41f40ed2008-08-21 10:05:00 +02001532 * - if an analyser has enough data, it just has to pass on to the next
Willy Tarreauedcf6682008-11-30 23:15:34 +01001533 * analyser without using buffer_write_dis() (enabled by default).
Willy Tarreau41f40ed2008-08-21 10:05:00 +02001534 * - if an analyser thinks it has no added value anymore staying here, it must
1535 * reset its bit from the analysers flags in order not to be called anymore.
1536 *
1537 * In the future, analysers should be able to indicate that they want to be
1538 * called after XXX bytes have been received (or transfered), and the min of
1539 * all's wishes will be used to ring back (unless a special condition occurs).
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001540 */
Willy Tarreau59234e92008-11-30 23:51:27 +01001541int http_process_request(struct session *s, struct buffer *req)
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001542{
Willy Tarreau59234e92008-11-30 23:51:27 +01001543 /*
1544 * We will parse the partial (or complete) lines.
1545 * We will check the request syntax, and also join multi-line
1546 * headers. An index of all the lines will be elaborated while
1547 * parsing.
1548 *
1549 * For the parsing, we use a 28 states FSM.
1550 *
1551 * Here is the information we currently have :
Willy Tarreauf073a832009-03-01 23:21:47 +01001552 * req->data + msg->som = beginning of request
Willy Tarreau59234e92008-11-30 23:51:27 +01001553 * req->data + req->eoh = end of processed headers / start of current one
1554 * req->data + req->eol = end of current header or line (LF or CRLF)
1555 * req->lr = first non-visited byte
1556 * req->r = end of data
1557 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001558
Willy Tarreau59234e92008-11-30 23:51:27 +01001559 int cur_idx;
1560 struct http_txn *txn = &s->txn;
1561 struct http_msg *msg = &txn->req;
1562 struct proxy *cur_proxy;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001563
Willy Tarreau6bf17362009-02-24 10:48:35 +01001564 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
1565 now_ms, __FUNCTION__,
1566 s,
1567 req,
1568 req->rex, req->wex,
1569 req->flags,
1570 req->l,
1571 req->analysers);
1572
Willy Tarreau59234e92008-11-30 23:51:27 +01001573 if (likely(req->lr < req->r))
1574 http_msg_analyzer(req, msg, &txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001575
Willy Tarreau59234e92008-11-30 23:51:27 +01001576 /* 1: we might have to print this header in debug mode */
1577 if (unlikely((global.mode & MODE_DEBUG) &&
1578 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
1579 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
1580 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001581
Willy Tarreau59234e92008-11-30 23:51:27 +01001582 sol = req->data + msg->som;
1583 eol = sol + msg->sl.rq.l;
1584 debug_hdr("clireq", s, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001585
Willy Tarreau59234e92008-11-30 23:51:27 +01001586 sol += hdr_idx_first_pos(&txn->hdr_idx);
1587 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001588
Willy Tarreau59234e92008-11-30 23:51:27 +01001589 while (cur_idx) {
1590 eol = sol + txn->hdr_idx.v[cur_idx].len;
1591 debug_hdr("clihdr", s, sol, eol);
1592 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
1593 cur_idx = txn->hdr_idx.v[cur_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001594 }
Willy Tarreau59234e92008-11-30 23:51:27 +01001595 }
1596
Willy Tarreau58f10d72006-12-04 02:26:12 +01001597
Willy Tarreau59234e92008-11-30 23:51:27 +01001598 /*
1599 * Now we quickly check if we have found a full valid request.
1600 * If not so, we check the FD and buffer states before leaving.
1601 * A full request is indicated by the fact that we have seen
1602 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
1603 * requests are checked first.
1604 *
1605 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001606
Willy Tarreau59234e92008-11-30 23:51:27 +01001607 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001608 /*
Willy Tarreau59234e92008-11-30 23:51:27 +01001609 * First, let's catch bad requests.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001610 */
Willy Tarreau59234e92008-11-30 23:51:27 +01001611 if (unlikely(msg->msg_state == HTTP_MSG_ERROR))
1612 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001613
Willy Tarreau59234e92008-11-30 23:51:27 +01001614 /* 1: Since we are in header mode, if there's no space
1615 * left for headers, we won't be able to free more
1616 * later, so the session will never terminate. We
1617 * must terminate it now.
1618 */
1619 if (unlikely(req->flags & BF_FULL)) {
1620 /* FIXME: check if URI is set and return Status
1621 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001622 */
Willy Tarreau59234e92008-11-30 23:51:27 +01001623 goto return_bad_req;
1624 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001625
Willy Tarreau59234e92008-11-30 23:51:27 +01001626 /* 2: have we encountered a read error ? */
1627 else if (req->flags & BF_READ_ERROR) {
1628 /* we cannot return any message on error */
Willy Tarreau4076a152009-04-02 15:18:36 +02001629 if (msg->err_pos >= 0)
1630 http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
Willy Tarreau59234e92008-11-30 23:51:27 +01001631 msg->msg_state = HTTP_MSG_ERROR;
1632 req->analysers = 0;
1633 s->fe->failed_req++;
1634 if (!(s->flags & SN_ERR_MASK))
1635 s->flags |= SN_ERR_CLICL;
1636 if (!(s->flags & SN_FINST_MASK))
1637 s->flags |= SN_FINST_R;
1638 return 0;
1639 }
Willy Tarreauf9839bd2008-08-27 23:57:16 +02001640
Willy Tarreau59234e92008-11-30 23:51:27 +01001641 /* 3: has the read timeout expired ? */
1642 else if (req->flags & BF_READ_TIMEOUT || tick_is_expired(req->analyse_exp, now_ms)) {
1643 /* read timeout : give up with an error message. */
Willy Tarreau4076a152009-04-02 15:18:36 +02001644 if (msg->err_pos >= 0)
1645 http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
Willy Tarreau59234e92008-11-30 23:51:27 +01001646 txn->status = 408;
1647 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_408));
1648 msg->msg_state = HTTP_MSG_ERROR;
1649 req->analysers = 0;
1650 s->fe->failed_req++;
1651 if (!(s->flags & SN_ERR_MASK))
1652 s->flags |= SN_ERR_CLITO;
1653 if (!(s->flags & SN_FINST_MASK))
1654 s->flags |= SN_FINST_R;
1655 return 0;
1656 }
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02001657
Willy Tarreau59234e92008-11-30 23:51:27 +01001658 /* 4: have we encountered a close ? */
1659 else if (req->flags & BF_SHUTR) {
Willy Tarreau4076a152009-04-02 15:18:36 +02001660 if (msg->err_pos >= 0)
1661 http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
Willy Tarreau59234e92008-11-30 23:51:27 +01001662 txn->status = 400;
1663 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
1664 msg->msg_state = HTTP_MSG_ERROR;
1665 req->analysers = 0;
1666 s->fe->failed_req++;
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02001667
Willy Tarreau59234e92008-11-30 23:51:27 +01001668 if (!(s->flags & SN_ERR_MASK))
1669 s->flags |= SN_ERR_CLICL;
1670 if (!(s->flags & SN_FINST_MASK))
1671 s->flags |= SN_FINST_R;
Willy Tarreaudafde432008-08-17 01:00:46 +02001672 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001673 }
1674
Willy Tarreau59234e92008-11-30 23:51:27 +01001675 buffer_write_dis(req);
Willy Tarreau1b194fe2009-03-21 21:10:04 +01001676 req->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */
1677
Willy Tarreau59234e92008-11-30 23:51:27 +01001678 /* just set the request timeout once at the beginning of the request */
1679 if (!tick_isset(req->analyse_exp))
1680 req->analyse_exp = tick_add_ifset(now_ms, s->fe->timeout.httpreq);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001681
Willy Tarreau59234e92008-11-30 23:51:27 +01001682 /* we're not ready yet */
1683 return 0;
1684 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001685
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001686
Willy Tarreau59234e92008-11-30 23:51:27 +01001687 /****************************************************************
1688 * More interesting part now : we know that we have a complete *
1689 * request which at least looks like HTTP. We have an indicator *
1690 * of each header's length, so we can parse them quickly. *
1691 ****************************************************************/
Willy Tarreau9cdde232007-05-02 20:58:19 +02001692
Willy Tarreau4076a152009-04-02 15:18:36 +02001693 if (msg->err_pos >= 0)
1694 http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
1695
Willy Tarreau59234e92008-11-30 23:51:27 +01001696 req->analysers &= ~AN_REQ_HTTP_HDR;
1697 req->analyse_exp = TICK_ETERNITY;
1698
1699 /* ensure we keep this pointer to the beginning of the message */
1700 msg->sol = req->data + msg->som;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001701
Willy Tarreau59234e92008-11-30 23:51:27 +01001702 /*
1703 * 1: identify the method
1704 */
1705 txn->meth = find_http_meth(&req->data[msg->som], msg->sl.rq.m_l);
1706
1707 /* we can make use of server redirect on GET and HEAD */
1708 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
1709 s->flags |= SN_REDIRECTABLE;
Willy Tarreaufa7e1022008-10-19 07:30:41 +02001710
Willy Tarreau59234e92008-11-30 23:51:27 +01001711 /*
1712 * 2: check if the URI matches the monitor_uri.
1713 * We have to do this for every request which gets in, because
1714 * the monitor-uri is defined by the frontend.
1715 */
1716 if (unlikely((s->fe->monitor_uri_len != 0) &&
1717 (s->fe->monitor_uri_len == msg->sl.rq.u_l) &&
1718 !memcmp(&req->data[msg->sl.rq.u],
1719 s->fe->monitor_uri,
1720 s->fe->monitor_uri_len))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001721 /*
Willy Tarreau59234e92008-11-30 23:51:27 +01001722 * We have found the monitor URI
Willy Tarreau58f10d72006-12-04 02:26:12 +01001723 */
Willy Tarreau59234e92008-11-30 23:51:27 +01001724 struct acl_cond *cond;
1725 cur_proxy = s->fe;
Willy Tarreaub80c2302007-11-30 20:51:32 +01001726
Willy Tarreau59234e92008-11-30 23:51:27 +01001727 s->flags |= SN_MONITOR;
Willy Tarreaub80c2302007-11-30 20:51:32 +01001728
Willy Tarreau59234e92008-11-30 23:51:27 +01001729 /* Check if we want to fail this monitor request or not */
1730 list_for_each_entry(cond, &cur_proxy->mon_fail_cond, list) {
1731 int ret = acl_exec_cond(cond, cur_proxy, s, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001732
Willy Tarreau59234e92008-11-30 23:51:27 +01001733 ret = acl_pass(ret);
1734 if (cond->pol == ACL_COND_UNLESS)
1735 ret = !ret;
Willy Tarreaub80c2302007-11-30 20:51:32 +01001736
Willy Tarreau59234e92008-11-30 23:51:27 +01001737 if (ret) {
1738 /* we fail this request, let's return 503 service unavail */
1739 txn->status = 503;
1740 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_503));
1741 goto return_prx_cond;
Willy Tarreaub80c2302007-11-30 20:51:32 +01001742 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001743 }
Willy Tarreaua5555ec2008-11-30 19:02:32 +01001744
Willy Tarreau59234e92008-11-30 23:51:27 +01001745 /* nothing to fail, let's reply normaly */
1746 txn->status = 200;
1747 stream_int_retnclose(req->prod, &http_200_chunk);
1748 goto return_prx_cond;
1749 }
1750
1751 /*
1752 * 3: Maybe we have to copy the original REQURI for the logs ?
1753 * Note: we cannot log anymore if the request has been
1754 * classified as invalid.
1755 */
1756 if (unlikely(s->logs.logwait & LW_REQ)) {
1757 /* we have a complete HTTP request that we must log */
1758 if ((txn->uri = pool_alloc2(pool2_requri)) != NULL) {
1759 int urilen = msg->sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001760
Willy Tarreau59234e92008-11-30 23:51:27 +01001761 if (urilen >= REQURI_LEN)
1762 urilen = REQURI_LEN - 1;
1763 memcpy(txn->uri, &req->data[msg->som], urilen);
1764 txn->uri[urilen] = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001765
Willy Tarreau59234e92008-11-30 23:51:27 +01001766 if (!(s->logs.logwait &= ~LW_REQ))
1767 s->do_log(s);
1768 } else {
1769 Alert("HTTP logging : out of memory.\n");
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001770 }
Willy Tarreau59234e92008-11-30 23:51:27 +01001771 }
Willy Tarreau06619262006-12-17 08:37:22 +01001772
Willy Tarreau59234e92008-11-30 23:51:27 +01001773 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
1774 if (unlikely(msg->sl.rq.v_l == 0)) {
1775 int delta;
1776 char *cur_end;
1777 msg->sol = req->data + msg->som;
1778 cur_end = msg->sol + msg->sl.rq.l;
1779 delta = 0;
Willy Tarreau06619262006-12-17 08:37:22 +01001780
Willy Tarreau59234e92008-11-30 23:51:27 +01001781 if (msg->sl.rq.u_l == 0) {
1782 /* if no URI was set, add "/" */
1783 delta = buffer_replace2(req, cur_end, cur_end, " /", 2);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001784 cur_end += delta;
Willy Tarreau59234e92008-11-30 23:51:27 +01001785 msg->eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001786 }
Willy Tarreau59234e92008-11-30 23:51:27 +01001787 /* add HTTP version */
1788 delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
1789 msg->eoh += delta;
1790 cur_end += delta;
1791 cur_end = (char *)http_parse_reqline(msg, req->data,
1792 HTTP_MSG_RQMETH,
1793 msg->sol, cur_end + 1,
1794 NULL, NULL);
1795 if (unlikely(!cur_end))
1796 goto return_bad_req;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001797
Willy Tarreau59234e92008-11-30 23:51:27 +01001798 /* we have a full HTTP/1.0 request now and we know that
1799 * we have either a CR or an LF at <ptr>.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001800 */
Willy Tarreau59234e92008-11-30 23:51:27 +01001801 hdr_idx_set_start(&txn->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
1802 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001803
1804
Willy Tarreau59234e92008-11-30 23:51:27 +01001805 /* 5: we may need to capture headers */
1806 if (unlikely((s->logs.logwait & LW_REQHDR) && s->fe->req_cap))
1807 capture_headers(req->data + msg->som, &txn->hdr_idx,
1808 txn->req.cap, s->fe->req_cap);
Willy Tarreau11382812008-07-09 16:18:21 +02001809
Willy Tarreau59234e92008-11-30 23:51:27 +01001810 /*
1811 * 6: we will have to evaluate the filters.
1812 * As opposed to version 1.2, now they will be evaluated in the
1813 * filters order and not in the header order. This means that
1814 * each filter has to be validated among all headers.
1815 *
1816 * We can now check whether we want to switch to another
1817 * backend, in which case we will re-check the backend's
1818 * filters and various options. In order to support 3-level
1819 * switching, here's how we should proceed :
1820 *
1821 * a) run be.
1822 * if (switch) then switch ->be to the new backend.
1823 * b) run be if (be != fe).
1824 * There cannot be any switch from there, so ->be cannot be
1825 * changed anymore.
1826 *
1827 * => filters always apply to ->be, then ->be may change.
1828 *
1829 * The response path will be able to apply either ->be, or
1830 * ->be then ->fe filters in order to match the reverse of
1831 * the forward sequence.
1832 */
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001833
Willy Tarreau59234e92008-11-30 23:51:27 +01001834 do {
1835 struct acl_cond *cond;
1836 struct redirect_rule *rule;
1837 struct proxy *rule_set = s->be;
1838 cur_proxy = s->be;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001839
Willy Tarreau59234e92008-11-30 23:51:27 +01001840 /* first check whether we have some ACLs set to redirect this request */
1841 list_for_each_entry(rule, &cur_proxy->redirect_rules, list) {
1842 int ret = acl_exec_cond(rule->cond, cur_proxy, s, txn, ACL_DIR_REQ);
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001843
Willy Tarreau59234e92008-11-30 23:51:27 +01001844 ret = acl_pass(ret);
1845 if (rule->cond->pol == ACL_COND_UNLESS)
1846 ret = !ret;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001847
Willy Tarreau59234e92008-11-30 23:51:27 +01001848 if (ret) {
1849 struct chunk rdr = { trash, 0 };
1850 const char *msg_fmt;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001851
Willy Tarreau59234e92008-11-30 23:51:27 +01001852 /* build redirect message */
1853 switch(rule->code) {
1854 case 303:
1855 rdr.len = strlen(HTTP_303);
1856 msg_fmt = HTTP_303;
1857 break;
1858 case 301:
1859 rdr.len = strlen(HTTP_301);
1860 msg_fmt = HTTP_301;
1861 break;
1862 case 302:
1863 default:
1864 rdr.len = strlen(HTTP_302);
1865 msg_fmt = HTTP_302;
1866 break;
1867 }
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001868
Willy Tarreau59234e92008-11-30 23:51:27 +01001869 if (unlikely(rdr.len > sizeof(trash)))
1870 goto return_bad_req;
1871 memcpy(rdr.str, msg_fmt, rdr.len);
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001872
Willy Tarreau59234e92008-11-30 23:51:27 +01001873 switch(rule->type) {
1874 case REDIRECT_TYPE_PREFIX: {
1875 const char *path;
1876 int pathlen;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001877
Willy Tarreau59234e92008-11-30 23:51:27 +01001878 path = http_get_path(txn);
1879 /* build message using path */
1880 if (path) {
1881 pathlen = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
Willy Tarreau79da4692008-11-19 20:03:04 +01001882 if (rule->flags & REDIRECT_FLAG_DROP_QS) {
1883 int qs = 0;
1884 while (qs < pathlen) {
1885 if (path[qs] == '?') {
1886 pathlen = qs;
1887 break;
1888 }
1889 qs++;
1890 }
1891 }
Willy Tarreau59234e92008-11-30 23:51:27 +01001892 } else {
1893 path = "/";
1894 pathlen = 1;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001895 }
1896
Willy Tarreau59234e92008-11-30 23:51:27 +01001897 if (rdr.len + rule->rdr_len + pathlen > sizeof(trash) - 4)
1898 goto return_bad_req;
1899
Willy Tarreaufe651a52008-11-19 21:15:17 +01001900 /* add prefix. Note that if prefix == "/", we don't want to
1901 * add anything, otherwise it makes it hard for the user to
1902 * configure a self-redirection.
1903 */
1904 if (rule->rdr_len != 1 || *rule->rdr_str != '/') {
1905 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1906 rdr.len += rule->rdr_len;
1907 }
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001908
Willy Tarreau59234e92008-11-30 23:51:27 +01001909 /* add path */
1910 memcpy(rdr.str + rdr.len, path, pathlen);
1911 rdr.len += pathlen;
1912 break;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001913 }
Willy Tarreau59234e92008-11-30 23:51:27 +01001914 case REDIRECT_TYPE_LOCATION:
1915 default:
1916 if (rdr.len + rule->rdr_len > sizeof(trash) - 4)
1917 goto return_bad_req;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001918
Willy Tarreau59234e92008-11-30 23:51:27 +01001919 /* add location */
1920 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1921 rdr.len += rule->rdr_len;
1922 break;
1923 }
Willy Tarreau11382812008-07-09 16:18:21 +02001924
Willy Tarreau0140f252008-11-19 21:07:09 +01001925 if (rule->cookie_len) {
1926 memcpy(rdr.str + rdr.len, "\r\nSet-Cookie: ", 14);
1927 rdr.len += 14;
1928 memcpy(rdr.str + rdr.len, rule->cookie_str, rule->cookie_len);
1929 rdr.len += rule->cookie_len;
1930 memcpy(rdr.str + rdr.len, "\r\n", 2);
1931 rdr.len += 2;
1932 }
1933
Willy Tarreau59234e92008-11-30 23:51:27 +01001934 /* add end of headers */
1935 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
1936 rdr.len += 4;
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001937
Willy Tarreau59234e92008-11-30 23:51:27 +01001938 txn->status = rule->code;
1939 /* let's log the request time */
1940 s->logs.tv_request = now;
1941 stream_int_retnclose(req->prod, &rdr);
1942 goto return_prx_cond;
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001943 }
Willy Tarreau59234e92008-11-30 23:51:27 +01001944 }
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001945
Willy Tarreau59234e92008-11-30 23:51:27 +01001946 /* first check whether we have some ACLs set to block this request */
1947 list_for_each_entry(cond, &cur_proxy->block_cond, list) {
1948 int ret = acl_exec_cond(cond, cur_proxy, s, txn, ACL_DIR_REQ);
Willy Tarreau53b6c742006-12-17 13:37:46 +01001949
Willy Tarreau59234e92008-11-30 23:51:27 +01001950 ret = acl_pass(ret);
1951 if (cond->pol == ACL_COND_UNLESS)
1952 ret = !ret;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001953
Willy Tarreau59234e92008-11-30 23:51:27 +01001954 if (ret) {
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001955 txn->status = 403;
Willy Tarreau06619262006-12-17 08:37:22 +01001956 /* let's log the request time */
Willy Tarreau59234e92008-11-30 23:51:27 +01001957 s->logs.tv_request = now;
1958 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01001959 goto return_prx_cond;
1960 }
Willy Tarreau59234e92008-11-30 23:51:27 +01001961 }
1962
1963 /* try headers filters */
1964 if (rule_set->req_exp != NULL) {
1965 if (apply_filters_to_request(s, req, rule_set->req_exp) < 0)
1966 goto return_bad_req;
1967 }
1968
1969 if (!(s->flags & SN_BE_ASSIGNED) && (s->be != cur_proxy)) {
1970 /* to ensure correct connection accounting on
1971 * the backend, we count the connection for the
1972 * one managing the queue.
1973 */
1974 s->be->beconn++;
1975 if (s->be->beconn > s->be->beconn_max)
1976 s->be->beconn_max = s->be->beconn;
Willy Tarreau7f062c42009-03-05 18:43:00 +01001977 proxy_inc_be_ctr(s->be);
Willy Tarreau59234e92008-11-30 23:51:27 +01001978 s->flags |= SN_BE_ASSIGNED;
1979 }
Willy Tarreau06619262006-12-17 08:37:22 +01001980
Willy Tarreau59234e92008-11-30 23:51:27 +01001981 /* has the request been denied ? */
1982 if (txn->flags & TX_CLDENY) {
1983 /* no need to go further */
1984 txn->status = 403;
1985 /* let's log the request time */
1986 s->logs.tv_request = now;
1987 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_403));
1988 goto return_prx_cond;
1989 }
Willy Tarreau06619262006-12-17 08:37:22 +01001990
Willy Tarreau59234e92008-11-30 23:51:27 +01001991 /* We might have to check for "Connection:" */
1992 if (((s->fe->options | s->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
1993 !(s->flags & SN_CONN_CLOSED)) {
1994 char *cur_ptr, *cur_end, *cur_next;
1995 int cur_idx, old_idx, delta, val;
1996 struct hdr_idx_elem *cur_hdr;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001997
Willy Tarreau59234e92008-11-30 23:51:27 +01001998 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
1999 old_idx = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002000
Willy Tarreau59234e92008-11-30 23:51:27 +01002001 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
2002 cur_hdr = &txn->hdr_idx.v[cur_idx];
2003 cur_ptr = cur_next;
2004 cur_end = cur_ptr + cur_hdr->len;
2005 cur_next = cur_end + cur_hdr->cr + 1;
2006
2007 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
2008 if (val) {
2009 /* 3 possibilities :
2010 * - we have already set Connection: close,
2011 * so we remove this line.
2012 * - we have not yet set Connection: close,
2013 * but this line indicates close. We leave
2014 * it untouched and set the flag.
2015 * - we have not yet set Connection: close,
2016 * and this line indicates non-close. We
2017 * replace it.
2018 */
2019 if (s->flags & SN_CONN_CLOSED) {
2020 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
2021 txn->req.eoh += delta;
2022 cur_next += delta;
2023 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
2024 txn->hdr_idx.used--;
2025 cur_hdr->len = 0;
2026 } else {
2027 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
2028 delta = buffer_replace2(req, cur_ptr + val, cur_end,
2029 "close", 5);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002030 cur_next += delta;
Willy Tarreau59234e92008-11-30 23:51:27 +01002031 cur_hdr->len += delta;
2032 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002033 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002034 s->flags |= SN_CONN_CLOSED;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002035 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002036 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002037 old_idx = cur_idx;
Willy Tarreau06619262006-12-17 08:37:22 +01002038 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002039 }
2040 /* add request headers from the rule sets in the same order */
2041 for (cur_idx = 0; cur_idx < rule_set->nb_reqadd; cur_idx++) {
2042 if (unlikely(http_header_add_tail(req,
2043 &txn->req,
2044 &txn->hdr_idx,
2045 rule_set->req_add[cur_idx])) < 0)
2046 goto return_bad_req;
2047 }
Willy Tarreaub2513902006-12-17 14:52:38 +01002048
Willy Tarreau59234e92008-11-30 23:51:27 +01002049 /* check if stats URI was requested, and if an auth is needed */
2050 if (rule_set->uri_auth != NULL &&
2051 (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)) {
2052 /* we have to check the URI and auth for this request.
2053 * FIXME!!! that one is rather dangerous, we want to
2054 * make it follow standard rules (eg: clear req->analysers).
2055 */
2056 if (stats_check_uri_auth(s, rule_set)) {
2057 req->analysers = 0;
2058 return 0;
Willy Tarreaub2513902006-12-17 14:52:38 +01002059 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002060 }
Willy Tarreaub2513902006-12-17 14:52:38 +01002061
Willy Tarreau59234e92008-11-30 23:51:27 +01002062 /* now check whether we have some switching rules for this request */
2063 if (!(s->flags & SN_BE_ASSIGNED)) {
2064 struct switching_rule *rule;
Willy Tarreau55ea7572007-06-17 19:56:27 +02002065
Willy Tarreau59234e92008-11-30 23:51:27 +01002066 list_for_each_entry(rule, &cur_proxy->switching_rules, list) {
2067 int ret;
Willy Tarreau55ea7572007-06-17 19:56:27 +02002068
Willy Tarreau59234e92008-11-30 23:51:27 +01002069 ret = acl_exec_cond(rule->cond, cur_proxy, s, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02002070
Willy Tarreau59234e92008-11-30 23:51:27 +01002071 ret = acl_pass(ret);
2072 if (rule->cond->pol == ACL_COND_UNLESS)
2073 ret = !ret;
Willy Tarreau55ea7572007-06-17 19:56:27 +02002074
Willy Tarreau59234e92008-11-30 23:51:27 +01002075 if (ret) {
2076 s->be = rule->be.backend;
2077 s->be->beconn++;
2078 if (s->be->beconn > s->be->beconn_max)
2079 s->be->beconn_max = s->be->beconn;
Willy Tarreau7f062c42009-03-05 18:43:00 +01002080 proxy_inc_be_ctr(s->be);
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002081
Willy Tarreau59234e92008-11-30 23:51:27 +01002082 /* assign new parameters to the session from the new backend */
2083 s->rep->rto = s->req->wto = s->be->timeout.server;
2084 s->req->cto = s->be->timeout.connect;
2085 s->conn_retries = s->be->conn_retries;
Willy Tarreau32a4ec02009-04-02 11:35:18 +02002086 if (s->be->options2 & PR_O2_RSPBUG_OK)
2087 s->txn.rsp.err_pos = -1; /* let buggy responses pass */
Willy Tarreau59234e92008-11-30 23:51:27 +01002088 s->flags |= SN_BE_ASSIGNED;
2089 break;
Willy Tarreau55ea7572007-06-17 19:56:27 +02002090 }
2091 }
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002092 }
2093
Willy Tarreau59234e92008-11-30 23:51:27 +01002094 if (!(s->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
2095 /* No backend was set, but there was a default
2096 * backend set in the frontend, so we use it and
2097 * loop again.
2098 */
2099 s->be = cur_proxy->defbe.be;
2100 s->be->beconn++;
2101 if (s->be->beconn > s->be->beconn_max)
2102 s->be->beconn_max = s->be->beconn;
Willy Tarreau7f062c42009-03-05 18:43:00 +01002103 proxy_inc_be_ctr(s->be);
Willy Tarreau58f10d72006-12-04 02:26:12 +01002104
Willy Tarreau59234e92008-11-30 23:51:27 +01002105 /* assign new parameters to the session from the new backend */
2106 s->rep->rto = s->req->wto = s->be->timeout.server;
2107 s->req->cto = s->be->timeout.connect;
2108 s->conn_retries = s->be->conn_retries;
Willy Tarreau32a4ec02009-04-02 11:35:18 +02002109 if (s->be->options2 & PR_O2_RSPBUG_OK)
2110 s->txn.rsp.err_pos = -1; /* let buggy responses pass */
Willy Tarreau59234e92008-11-30 23:51:27 +01002111 s->flags |= SN_BE_ASSIGNED;
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01002112 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002113 } while (s->be != cur_proxy); /* we loop only if s->be has changed */
Willy Tarreau58f10d72006-12-04 02:26:12 +01002114
Willy Tarreau59234e92008-11-30 23:51:27 +01002115 if (!(s->flags & SN_BE_ASSIGNED)) {
2116 /* To ensure correct connection accounting on
2117 * the backend, we count the connection for the
2118 * one managing the queue.
Willy Tarreau06619262006-12-17 08:37:22 +01002119 */
Willy Tarreau59234e92008-11-30 23:51:27 +01002120 s->be->beconn++;
2121 if (s->be->beconn > s->be->beconn_max)
2122 s->be->beconn_max = s->be->beconn;
Willy Tarreau7f062c42009-03-05 18:43:00 +01002123 proxy_inc_be_ctr(s->be);
Willy Tarreau59234e92008-11-30 23:51:27 +01002124 s->flags |= SN_BE_ASSIGNED;
2125 }
Willy Tarreau06619262006-12-17 08:37:22 +01002126
Willy Tarreau59234e92008-11-30 23:51:27 +01002127 /*
2128 * Right now, we know that we have processed the entire headers
2129 * and that unwanted requests have been filtered out. We can do
2130 * whatever we want with the remaining request. Also, now we
2131 * may have separate values for ->fe, ->be.
2132 */
Willy Tarreau06619262006-12-17 08:37:22 +01002133
Willy Tarreau59234e92008-11-30 23:51:27 +01002134 /*
2135 * If HTTP PROXY is set we simply get remote server address
2136 * parsing incoming request.
2137 */
2138 if ((s->be->options & PR_O_HTTP_PROXY) && !(s->flags & SN_ADDR_SET)) {
2139 url2sa(req->data + msg->sl.rq.u, msg->sl.rq.u_l, &s->srv_addr);
2140 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002141
Willy Tarreau59234e92008-11-30 23:51:27 +01002142 /*
2143 * 7: the appsession cookie was looked up very early in 1.2,
2144 * so let's do the same now.
2145 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01002146
Willy Tarreau59234e92008-11-30 23:51:27 +01002147 /* It needs to look into the URI */
2148 if (s->be->appsession_name) {
2149 get_srv_from_appsession(s, &req->data[msg->som], msg->sl.rq.l);
2150 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01002151
Willy Tarreau59234e92008-11-30 23:51:27 +01002152 /*
2153 * 8: Now we can work with the cookies.
2154 * Note that doing so might move headers in the request, but
2155 * the fields will stay coherent and the URI will not move.
2156 * This should only be performed in the backend.
2157 */
Willy Tarreaufd39dda2008-10-17 12:01:58 +02002158 if ((s->be->cookie_name || s->be->appsession_name || s->fe->capture_name)
Willy Tarreau59234e92008-11-30 23:51:27 +01002159 && !(txn->flags & (TX_CLDENY|TX_CLTARPIT)))
2160 manage_client_side_cookies(s, req);
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002161
Willy Tarreau59234e92008-11-30 23:51:27 +01002162 /*
2163 * 9: add X-Forwarded-For if either the frontend or the backend
2164 * asks for it.
2165 */
2166 if ((s->fe->options | s->be->options) & PR_O_FWDFOR) {
2167 if (s->cli_addr.ss_family == AF_INET) {
2168 /* Add an X-Forwarded-For header unless the source IP is
2169 * in the 'except' network range.
2170 */
2171 if ((!s->fe->except_mask.s_addr ||
2172 (((struct sockaddr_in *)&s->cli_addr)->sin_addr.s_addr & s->fe->except_mask.s_addr)
2173 != s->fe->except_net.s_addr) &&
2174 (!s->be->except_mask.s_addr ||
2175 (((struct sockaddr_in *)&s->cli_addr)->sin_addr.s_addr & s->be->except_mask.s_addr)
2176 != s->be->except_net.s_addr)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002177 int len;
Willy Tarreau59234e92008-11-30 23:51:27 +01002178 unsigned char *pn;
2179 pn = (unsigned char *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr;
Ross Westaf72a1d2008-08-03 10:51:45 +02002180
2181 /* Note: we rely on the backend to get the header name to be used for
2182 * x-forwarded-for, because the header is really meant for the backends.
2183 * However, if the backend did not specify any option, we have to rely
2184 * on the frontend's header name.
2185 */
Willy Tarreau59234e92008-11-30 23:51:27 +01002186 if (s->be->fwdfor_hdr_len) {
2187 len = s->be->fwdfor_hdr_len;
2188 memcpy(trash, s->be->fwdfor_hdr_name, len);
Ross Westaf72a1d2008-08-03 10:51:45 +02002189 } else {
Willy Tarreau59234e92008-11-30 23:51:27 +01002190 len = s->fe->fwdfor_hdr_len;
2191 memcpy(trash, s->fe->fwdfor_hdr_name, len);
2192 }
2193 len += sprintf(trash + len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
Willy Tarreauedcf6682008-11-30 23:15:34 +01002194
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002195 if (unlikely(http_header_add_tail2(req, &txn->req,
2196 &txn->hdr_idx, trash, len)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002197 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01002198 }
2199 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002200 else if (s->cli_addr.ss_family == AF_INET6) {
2201 /* FIXME: for the sake of completeness, we should also support
2202 * 'except' here, although it is mostly useless in this case.
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002203 */
Willy Tarreau59234e92008-11-30 23:51:27 +01002204 int len;
2205 char pn[INET6_ADDRSTRLEN];
2206 inet_ntop(AF_INET6,
2207 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
2208 pn, sizeof(pn));
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002209
Willy Tarreau59234e92008-11-30 23:51:27 +01002210 /* Note: we rely on the backend to get the header name to be used for
2211 * x-forwarded-for, because the header is really meant for the backends.
2212 * However, if the backend did not specify any option, we have to rely
2213 * on the frontend's header name.
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002214 */
Willy Tarreau59234e92008-11-30 23:51:27 +01002215 if (s->be->fwdfor_hdr_len) {
2216 len = s->be->fwdfor_hdr_len;
2217 memcpy(trash, s->be->fwdfor_hdr_name, len);
2218 } else {
2219 len = s->fe->fwdfor_hdr_len;
2220 memcpy(trash, s->fe->fwdfor_hdr_name, len);
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002221 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002222 len += sprintf(trash + len, ": %s", pn);
Willy Tarreauadfb8562008-08-11 15:24:42 +02002223
Willy Tarreau59234e92008-11-30 23:51:27 +01002224 if (unlikely(http_header_add_tail2(req, &txn->req,
2225 &txn->hdr_idx, trash, len)) < 0)
2226 goto return_bad_req;
2227 }
2228 }
2229
2230 /*
Maik Broemme2850cb42009-04-17 18:53:21 +02002231 * 10: add X-Original-To if either the frontend or the backend
2232 * asks for it.
2233 */
2234 if ((s->fe->options | s->be->options) & PR_O_ORGTO) {
2235
2236 /* FIXME: don't know if IPv6 can handle that case too. */
2237 if (s->cli_addr.ss_family == AF_INET) {
2238 /* Add an X-Original-To header unless the destination IP is
2239 * in the 'except' network range.
2240 */
2241 if (!(s->flags & SN_FRT_ADDR_SET))
2242 get_frt_addr(s);
2243
2244 if ((!s->fe->except_mask_to.s_addr ||
2245 (((struct sockaddr_in *)&s->frt_addr)->sin_addr.s_addr & s->fe->except_mask_to.s_addr)
2246 != s->fe->except_to.s_addr) &&
2247 (!s->be->except_mask_to.s_addr ||
2248 (((struct sockaddr_in *)&s->frt_addr)->sin_addr.s_addr & s->be->except_mask_to.s_addr)
2249 != s->be->except_to.s_addr)) {
2250 int len;
2251 unsigned char *pn;
2252 pn = (unsigned char *)&((struct sockaddr_in *)&s->frt_addr)->sin_addr;
2253
2254 /* Note: we rely on the backend to get the header name to be used for
2255 * x-original-to, because the header is really meant for the backends.
2256 * However, if the backend did not specify any option, we have to rely
2257 * on the frontend's header name.
2258 */
2259 if (s->be->orgto_hdr_len) {
2260 len = s->be->orgto_hdr_len;
2261 memcpy(trash, s->be->orgto_hdr_name, len);
2262 } else {
2263 len = s->fe->orgto_hdr_len;
2264 memcpy(trash, s->fe->orgto_hdr_name, len);
2265 }
2266 len += sprintf(trash + len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
2267
2268 if (unlikely(http_header_add_tail2(req, &txn->req,
2269 &txn->hdr_idx, trash, len)) < 0)
2270 goto return_bad_req;
2271 }
2272 }
2273 }
2274
2275 /*
2276 * 11: add "Connection: close" if needed and not yet set.
Willy Tarreau59234e92008-11-30 23:51:27 +01002277 * Note that we do not need to add it in case of HTTP/1.0.
2278 */
2279 if (!(s->flags & SN_CONN_CLOSED) &&
2280 ((s->fe->options | s->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
2281 if ((unlikely(msg->sl.rq.v_l != 8) ||
2282 unlikely(req->data[msg->som + msg->sl.rq.v + 7] != '0')) &&
2283 unlikely(http_header_add_tail2(req, &txn->req, &txn->hdr_idx,
2284 "Connection: close", 17)) < 0)
2285 goto return_bad_req;
2286 s->flags |= SN_CONN_CLOSED;
2287 }
2288 /* Before we switch to data, was assignment set in manage_client_side_cookie?
2289 * If not assigned, perhaps we are balancing on url_param, but this is a
2290 * POST; and the parameters are in the body, maybe scan there to find our server.
2291 * (unless headers overflowed the buffer?)
2292 */
2293 if (!(s->flags & (SN_ASSIGNED|SN_DIRECT)) &&
2294 s->txn.meth == HTTP_METH_POST && s->be->url_param_name != NULL &&
2295 s->be->url_param_post_limit != 0 && !(req->flags & BF_FULL) &&
2296 memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) {
2297 /* are there enough bytes here? total == l || r || rlim ?
2298 * len is unsigned, but eoh is int,
2299 * how many bytes of body have we received?
2300 * eoh is the first empty line of the header
2301 */
2302 /* already established CRLF or LF at eoh, move to start of message, find message length in buffer */
2303 unsigned long len = req->l - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1);
2304
2305 /* If we have HTTP/1.1 and Expect: 100-continue, then abort.
2306 * We can't assume responsibility for the server's decision,
2307 * on this URI and header set. See rfc2616: 14.20, 8.2.3,
2308 * We also can't change our mind later, about which server to choose, so round robin.
2309 */
2310 if ((likely(msg->sl.rq.v_l == 8) && req->data[msg->som + msg->sl.rq.v + 7] == '1')) {
2311 struct hdr_ctx ctx;
2312 ctx.idx = 0;
2313 /* Expect is allowed in 1.1, look for it */
2314 http_find_header2("Expect", 6, msg->sol, &txn->hdr_idx, &ctx);
2315 if (ctx.idx != 0 &&
2316 unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val, "100-continue", 12) == 0))
2317 /* We can't reliablly stall and wait for data, because of
2318 * .NET clients that don't conform to rfc2616; so, no need for
2319 * the next block to check length expectations.
2320 * We could send 100 status back to the client, but then we need to
2321 * re-write headers, and send the message. And this isn't the right
2322 * place for that action.
2323 * TODO: support Expect elsewhere and delete this block.
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002324 */
Willy Tarreau59234e92008-11-30 23:51:27 +01002325 goto end_check_maybe_wait_for_body;
2326 }
2327
2328 if (likely(len > s->be->url_param_post_limit)) {
2329 /* nothing to do, we got enough */
2330 } else {
2331 /* limit implies we are supposed to need this many bytes
2332 * to find the parameter. Let's see how many bytes we can wait for.
2333 */
2334 long long hint = len;
2335 struct hdr_ctx ctx;
2336 ctx.idx = 0;
2337 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
2338 if (ctx.idx && ctx.vlen >= 7 && strncasecmp(ctx.line+ctx.val, "chunked", 7) == 0) {
2339 buffer_write_dis(req);
2340 req->analysers |= AN_REQ_HTTP_BODY;
2341 }
2342 else {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002343 ctx.idx = 0;
Willy Tarreau59234e92008-11-30 23:51:27 +01002344 http_find_header2("Content-Length", 14, msg->sol, &txn->hdr_idx, &ctx);
2345 /* now if we have a length, we'll take the hint */
2346 if (ctx.idx) {
2347 /* We have Content-Length */
2348 if (strl2llrc(ctx.line+ctx.val,ctx.vlen, &hint))
2349 hint = 0; /* parse failure, untrusted client */
2350 else {
2351 if (hint > 0)
2352 msg->hdr_content_len = hint;
2353 else
2354 hint = 0; /* bad client, sent negative length */
2355 }
2356 }
2357 /* but limited to what we care about, maybe we don't expect any entity data (hint == 0) */
2358 if (s->be->url_param_post_limit < hint)
2359 hint = s->be->url_param_post_limit;
2360 /* now do we really need to buffer more data? */
2361 if (len < hint) {
Willy Tarreau3da77c52008-08-29 09:58:42 +02002362 buffer_write_dis(req);
Willy Tarreau2df28e82008-08-17 15:20:19 +02002363 req->analysers |= AN_REQ_HTTP_BODY;
Willy Tarreau41f40ed2008-08-21 10:05:00 +02002364 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002365 /* else... There are no body bytes to wait for */
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002366 }
2367 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002368 }
2369 end_check_maybe_wait_for_body:
Willy Tarreaubaaee002006-06-26 02:48:02 +02002370
Willy Tarreau59234e92008-11-30 23:51:27 +01002371 /*************************************************************
2372 * OK, that's finished for the headers. We have done what we *
2373 * could. Let's switch to the DATA state. *
2374 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02002375
Willy Tarreau59234e92008-11-30 23:51:27 +01002376 buffer_set_rlim(req, BUFSIZE); /* no more rewrite needed */
2377 s->logs.tv_request = now;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002378
Willy Tarreau59234e92008-11-30 23:51:27 +01002379 /* When a connection is tarpitted, we use the tarpit timeout,
2380 * which may be the same as the connect timeout if unspecified.
2381 * If unset, then set it to zero because we really want it to
2382 * eventually expire. We build the tarpit as an analyser.
2383 */
2384 if (txn->flags & TX_CLTARPIT) {
Willy Tarreau6f0aa472009-03-08 20:33:29 +01002385 buffer_erase(s->req);
2386 /* wipe the request out so that we can drop the connection early
Willy Tarreau59234e92008-11-30 23:51:27 +01002387 * if the client closes first.
Willy Tarreau2a324282006-12-05 00:05:46 +01002388 */
Willy Tarreau59234e92008-11-30 23:51:27 +01002389 buffer_write_dis(req);
2390 req->analysers |= AN_REQ_HTTP_TARPIT;
2391 req->analyse_exp = tick_add_ifset(now_ms, s->be->timeout.tarpit);
2392 if (!req->analyse_exp)
Willy Tarreau2ab85e62009-03-29 10:24:15 +02002393 req->analyse_exp = tick_add(now_ms, 0);
Willy Tarreau59234e92008-11-30 23:51:27 +01002394 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002395
Willy Tarreau59234e92008-11-30 23:51:27 +01002396 /* OK let's go on with the BODY now */
2397 return 1;
Willy Tarreau06619262006-12-17 08:37:22 +01002398
Willy Tarreau59234e92008-11-30 23:51:27 +01002399 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau4076a152009-04-02 15:18:36 +02002400 if (unlikely(msg->msg_state == HTTP_MSG_ERROR) || msg->err_pos >= 0) {
Willy Tarreauf073a832009-03-01 23:21:47 +01002401 /* we detected a parsing error. We want to archive this request
2402 * in the dedicated proxy area for later troubleshooting.
2403 */
Willy Tarreau4076a152009-04-02 15:18:36 +02002404 http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
Willy Tarreauf073a832009-03-01 23:21:47 +01002405 }
Willy Tarreau4076a152009-04-02 15:18:36 +02002406
Willy Tarreau59234e92008-11-30 23:51:27 +01002407 txn->req.msg_state = HTTP_MSG_ERROR;
2408 txn->status = 400;
2409 req->analysers = 0;
2410 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
2411 s->fe->failed_req++;
Willy Tarreauadfb8562008-08-11 15:24:42 +02002412
Willy Tarreau59234e92008-11-30 23:51:27 +01002413 return_prx_cond:
2414 if (!(s->flags & SN_ERR_MASK))
2415 s->flags |= SN_ERR_PRXCOND;
2416 if (!(s->flags & SN_FINST_MASK))
2417 s->flags |= SN_FINST_R;
Willy Tarreaudafde432008-08-17 01:00:46 +02002418 return 0;
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02002419}
Willy Tarreauadfb8562008-08-11 15:24:42 +02002420
Willy Tarreau60b85b02008-11-30 23:28:40 +01002421/* This function is an analyser which processes the HTTP tarpit. It always
2422 * returns zero, at the beginning because it prevents any other processing
2423 * from occurring, and at the end because it terminates the request.
2424 */
2425int http_process_tarpit(struct session *s, struct buffer *req)
2426{
2427 struct http_txn *txn = &s->txn;
2428
2429 /* This connection is being tarpitted. The CLIENT side has
2430 * already set the connect expiration date to the right
2431 * timeout. We just have to check that the client is still
2432 * there and that the timeout has not expired.
2433 */
2434 if ((req->flags & (BF_SHUTR|BF_READ_ERROR)) == 0 &&
2435 !tick_is_expired(req->analyse_exp, now_ms))
2436 return 0;
2437
2438 /* We will set the queue timer to the time spent, just for
2439 * logging purposes. We fake a 500 server error, so that the
2440 * attacker will not suspect his connection has been tarpitted.
2441 * It will not cause trouble to the logs because we can exclude
2442 * the tarpitted connections by filtering on the 'PT' status flags.
2443 */
Willy Tarreau60b85b02008-11-30 23:28:40 +01002444 s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
2445
2446 txn->status = 500;
2447 if (req->flags != BF_READ_ERROR)
2448 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_500));
2449
2450 req->analysers = 0;
2451 req->analyse_exp = TICK_ETERNITY;
2452
2453 s->fe->failed_req++;
2454 if (!(s->flags & SN_ERR_MASK))
2455 s->flags |= SN_ERR_PRXCOND;
2456 if (!(s->flags & SN_FINST_MASK))
2457 s->flags |= SN_FINST_T;
2458 return 0;
2459}
2460
Willy Tarreaud34af782008-11-30 23:36:37 +01002461/* This function is an analyser which processes the HTTP request body. It looks
2462 * for parameters to be used for the load balancing algorithm (url_param). It
2463 * must only be called after the standard HTTP request processing has occurred,
2464 * because it expects the request to be parsed. It returns zero if it needs to
2465 * read more data, or 1 once it has completed its analysis.
2466 */
2467int http_process_request_body(struct session *s, struct buffer *req)
2468{
2469 struct http_msg *msg = &s->txn.req;
2470 unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1;
2471 long long limit = s->be->url_param_post_limit;
2472 struct hdr_ctx ctx;
2473
2474 /* We have to parse the HTTP request body to find any required data.
2475 * "balance url_param check_post" should have been the only way to get
2476 * into this. We were brought here after HTTP header analysis, so all
2477 * related structures are ready.
2478 */
2479
2480 ctx.idx = 0;
2481
2482 /* now if we have a length, we'll take the hint */
2483 http_find_header2("Transfer-Encoding", 17, msg->sol, &s->txn.hdr_idx, &ctx);
2484 if (ctx.idx && ctx.vlen >= 7 && strncasecmp(ctx.line+ctx.val, "chunked", 7) == 0) {
2485 unsigned int chunk = 0;
2486 while (body < req->l && !HTTP_IS_CRLF(msg->sol[body])) {
2487 char c = msg->sol[body];
2488 if (ishex(c)) {
2489 unsigned int hex = toupper(c) - '0';
2490 if (hex > 9)
2491 hex -= 'A' - '9' - 1;
2492 chunk = (chunk << 4) | hex;
2493 } else
2494 break;
2495 body++;
2496 }
2497 if (body + 2 >= req->l) /* we want CRLF too */
2498 goto http_body_end; /* end of buffer? data missing! */
2499
2500 if (memcmp(msg->sol+body, "\r\n", 2) != 0)
2501 goto http_body_end; /* chunked encoding len ends with CRLF, and we don't have it yet */
2502
2503 body += 2; // skip CRLF
2504
2505 /* if we support more then one chunk here, we have to do it again when assigning server
2506 * 1. how much entity data do we have? new var
2507 * 2. should save entity_start, entity_cursor, elen & rlen in req; so we don't repeat scanning here
2508 * 3. test if elen > limit, or set new limit to elen if 0 (end of entity found)
2509 */
2510
2511 if (chunk < limit)
2512 limit = chunk; /* only reading one chunk */
2513 } else {
2514 if (msg->hdr_content_len < limit)
2515 limit = msg->hdr_content_len;
2516 }
2517
2518 http_body_end:
2519 /* we leave once we know we have nothing left to do. This means that we have
2520 * enough bytes, or that we know we'll not get any more (buffer full, read
2521 * buffer closed).
2522 */
2523 if (req->l - body >= limit || /* enough bytes! */
2524 req->flags & (BF_FULL | BF_READ_ERROR | BF_SHUTR | BF_READ_TIMEOUT) ||
2525 tick_is_expired(req->analyse_exp, now_ms)) {
2526 /* The situation will not evolve, so let's give up on the analysis. */
2527 s->logs.tv_request = now; /* update the request timer to reflect full request */
2528 req->analysers &= ~AN_REQ_HTTP_BODY;
2529 req->analyse_exp = TICK_ETERNITY;
2530 return 1;
2531 }
2532 else {
2533 /* Not enough data. We'll re-use the http-request
2534 * timeout here. Ideally, we should set the timeout
2535 * relative to the accept() date. We just set the
2536 * request timeout once at the beginning of the
2537 * request.
2538 */
2539 buffer_write_dis(req);
2540 if (!tick_isset(req->analyse_exp))
2541 req->analyse_exp = tick_add_ifset(now_ms, s->fe->timeout.httpreq);
2542 return 0;
2543 }
2544}
2545
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002546/* This function performs all the processing enabled for the current response.
Willy Tarreaudafde432008-08-17 01:00:46 +02002547 * It normally returns zero, but may return 1 if it absolutely needs to be
2548 * called again after other functions. It relies on buffers flags, and updates
Willy Tarreau2df28e82008-08-17 15:20:19 +02002549 * t->rep->analysers. It might make sense to explode it into several other
Willy Tarreau41f40ed2008-08-21 10:05:00 +02002550 * functions. It works like process_request (see indications above).
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02002551 */
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002552int process_response(struct session *t)
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02002553{
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002554 struct http_txn *txn = &t->txn;
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02002555 struct buffer *req = t->req;
2556 struct buffer *rep = t->rep;
Willy Tarreauadfb8562008-08-11 15:24:42 +02002557
Willy Tarreau3a16b2c2008-08-28 08:54:27 +02002558 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
Willy Tarreaufa7e1022008-10-19 07:30:41 +02002559 now_ms, __FUNCTION__,
Willy Tarreau3a16b2c2008-08-28 08:54:27 +02002560 t,
2561 rep,
2562 rep->rex, rep->wex,
2563 rep->flags,
2564 rep->l,
2565 rep->analysers);
Willy Tarreau67f0eea2008-08-10 22:55:22 +02002566
Willy Tarreau2df28e82008-08-17 15:20:19 +02002567 if (rep->analysers & AN_RTR_HTTP_HDR) { /* receiving server headers */
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002568 /*
2569 * Now parse the partial (or complete) lines.
2570 * We will check the response syntax, and also join multi-line
2571 * headers. An index of all the lines will be elaborated while
2572 * parsing.
2573 *
2574 * For the parsing, we use a 28 states FSM.
2575 *
2576 * Here is the information we currently have :
Willy Tarreaue393fe22008-08-16 22:18:07 +02002577 * rep->data + rep->som = beginning of response
2578 * rep->data + rep->eoh = end of processed headers / start of current one
2579 * rep->data + rep->eol = end of current header or line (LF or CRLF)
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002580 * rep->lr = first non-visited byte
2581 * rep->r = end of data
2582 */
Willy Tarreau7f875f62008-08-11 17:35:01 +02002583
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002584 int cur_idx;
2585 struct http_msg *msg = &txn->rsp;
2586 struct proxy *cur_proxy;
2587
2588 if (likely(rep->lr < rep->r))
2589 http_msg_analyzer(rep, msg, &txn->hdr_idx);
2590
2591 /* 1: we might have to print this header in debug mode */
2592 if (unlikely((global.mode & MODE_DEBUG) &&
2593 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
2594 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
2595 char *eol, *sol;
2596
2597 sol = rep->data + msg->som;
2598 eol = sol + msg->sl.rq.l;
2599 debug_hdr("srvrep", t, sol, eol);
2600
2601 sol += hdr_idx_first_pos(&txn->hdr_idx);
2602 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
2603
2604 while (cur_idx) {
2605 eol = sol + txn->hdr_idx.v[cur_idx].len;
2606 debug_hdr("srvhdr", t, sol, eol);
2607 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
2608 cur_idx = txn->hdr_idx.v[cur_idx].next;
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02002609 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002610 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002611
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002612 /*
2613 * Now we quickly check if we have found a full valid response.
2614 * If not so, we check the FD and buffer states before leaving.
2615 * A full response is indicated by the fact that we have seen
2616 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
2617 * responses are checked first.
2618 *
2619 * Depending on whether the client is still there or not, we
2620 * may send an error response back or not. Note that normally
2621 * we should only check for HTTP status there, and check I/O
2622 * errors somewhere else.
2623 */
2624
2625 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
Willy Tarreaucebf57e2008-08-15 18:16:37 +02002626 /* Invalid response */
2627 if (unlikely(msg->msg_state == HTTP_MSG_ERROR)) {
Willy Tarreauf073a832009-03-01 23:21:47 +01002628 /* we detected a parsing error. We want to archive this response
2629 * in the dedicated proxy area for later troubleshooting.
2630 */
Willy Tarreaucebf57e2008-08-15 18:16:37 +02002631 hdr_response_bad:
Willy Tarreau4076a152009-04-02 15:18:36 +02002632 if (msg->msg_state == HTTP_MSG_ERROR || msg->err_pos >= 0)
2633 http_capture_bad_message(&t->be->invalid_rep, t, rep, msg, t->fe);
2634
Willy Tarreaufa7e1022008-10-19 07:30:41 +02002635 buffer_shutr_now(rep);
2636 buffer_shutw_now(req);
Willy Tarreau8365f932009-03-15 23:11:49 +01002637 if (t->srv)
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002638 t->srv->failed_resp++;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002639 t->be->failed_resp++;
Willy Tarreau2df28e82008-08-17 15:20:19 +02002640 rep->analysers = 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002641 txn->status = 502;
Willy Tarreau81acfab2008-11-30 19:22:53 +01002642 stream_int_return(rep->cons, error_message(t, HTTP_ERR_502));
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002643 if (!(t->flags & SN_ERR_MASK))
Willy Tarreaucebf57e2008-08-15 18:16:37 +02002644 t->flags |= SN_ERR_PRXCOND;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002645 if (!(t->flags & SN_FINST_MASK))
2646 t->flags |= SN_FINST_H;
Willy Tarreau461f6622008-08-15 23:43:19 +02002647
Willy Tarreaudafde432008-08-17 01:00:46 +02002648 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002649 }
Willy Tarreauf9839bd2008-08-27 23:57:16 +02002650 /* too large response does not fit in buffer. */
2651 else if (rep->flags & BF_FULL) {
2652 goto hdr_response_bad;
2653 }
2654 /* read error */
2655 else if (rep->flags & BF_READ_ERROR) {
Willy Tarreau4076a152009-04-02 15:18:36 +02002656 if (msg->err_pos >= 0)
2657 http_capture_bad_message(&t->be->invalid_rep, t, rep, msg, t->fe);
Willy Tarreaufa7e1022008-10-19 07:30:41 +02002658 buffer_shutr_now(rep);
2659 buffer_shutw_now(req);
Willy Tarreau8365f932009-03-15 23:11:49 +01002660 if (t->srv)
2661 t->srv->failed_resp++;
2662 t->be->failed_resp++;
Willy Tarreau2df28e82008-08-17 15:20:19 +02002663 rep->analysers = 0;
Willy Tarreaucebf57e2008-08-15 18:16:37 +02002664 txn->status = 502;
Willy Tarreau81acfab2008-11-30 19:22:53 +01002665 stream_int_return(rep->cons, error_message(t, HTTP_ERR_502));
Willy Tarreaucebf57e2008-08-15 18:16:37 +02002666 if (!(t->flags & SN_ERR_MASK))
2667 t->flags |= SN_ERR_SRVCL;
2668 if (!(t->flags & SN_FINST_MASK))
2669 t->flags |= SN_FINST_H;
Willy Tarreaudafde432008-08-17 01:00:46 +02002670 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002671 }
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002672 /* read timeout : return a 504 to the client. */
Willy Tarreaucebf57e2008-08-15 18:16:37 +02002673 else if (rep->flags & BF_READ_TIMEOUT) {
Willy Tarreau4076a152009-04-02 15:18:36 +02002674 if (msg->err_pos >= 0)
2675 http_capture_bad_message(&t->be->invalid_rep, t, rep, msg, t->fe);
Willy Tarreaufa7e1022008-10-19 07:30:41 +02002676 buffer_shutr_now(rep);
2677 buffer_shutw_now(req);
Willy Tarreau8365f932009-03-15 23:11:49 +01002678 if (t->srv)
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002679 t->srv->failed_resp++;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002680 t->be->failed_resp++;
Willy Tarreau2df28e82008-08-17 15:20:19 +02002681 rep->analysers = 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002682 txn->status = 504;
Willy Tarreau81acfab2008-11-30 19:22:53 +01002683 stream_int_return(rep->cons, error_message(t, HTTP_ERR_504));
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002684 if (!(t->flags & SN_ERR_MASK))
2685 t->flags |= SN_ERR_SRVTO;
2686 if (!(t->flags & SN_FINST_MASK))
2687 t->flags |= SN_FINST_H;
Willy Tarreaudafde432008-08-17 01:00:46 +02002688 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002689 }
Willy Tarreau8365f932009-03-15 23:11:49 +01002690 /* close from server */
2691 else if (rep->flags & BF_SHUTR) {
Willy Tarreau4076a152009-04-02 15:18:36 +02002692 if (msg->err_pos >= 0)
2693 http_capture_bad_message(&t->be->invalid_rep, t, rep, msg, t->fe);
Willy Tarreauf9839bd2008-08-27 23:57:16 +02002694 buffer_shutw_now(req);
Willy Tarreau8365f932009-03-15 23:11:49 +01002695 if (t->srv)
Willy Tarreauf9839bd2008-08-27 23:57:16 +02002696 t->srv->failed_resp++;
Willy Tarreauf9839bd2008-08-27 23:57:16 +02002697 t->be->failed_resp++;
2698 rep->analysers = 0;
2699 txn->status = 502;
Willy Tarreau81acfab2008-11-30 19:22:53 +01002700 stream_int_return(rep->cons, error_message(t, HTTP_ERR_502));
Willy Tarreauf9839bd2008-08-27 23:57:16 +02002701 if (!(t->flags & SN_ERR_MASK))
2702 t->flags |= SN_ERR_SRVCL;
2703 if (!(t->flags & SN_FINST_MASK))
2704 t->flags |= SN_FINST_H;
Willy Tarreauf9839bd2008-08-27 23:57:16 +02002705 return 0;
2706 }
Willy Tarreau8365f932009-03-15 23:11:49 +01002707 /* write error to client (we don't send any message then) */
2708 else if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreau4076a152009-04-02 15:18:36 +02002709 if (msg->err_pos >= 0)
2710 http_capture_bad_message(&t->be->invalid_rep, t, rep, msg, t->fe);
Willy Tarreau8365f932009-03-15 23:11:49 +01002711 buffer_shutr_now(rep);
2712 t->be->failed_resp++;
2713 rep->analysers = 0;
2714 if (!(t->flags & SN_ERR_MASK))
2715 t->flags |= SN_ERR_CLICL;
2716 if (!(t->flags & SN_FINST_MASK))
2717 t->flags |= SN_FINST_H;
2718 return 0;
2719 }
Willy Tarreau3da77c52008-08-29 09:58:42 +02002720 buffer_write_dis(rep);
Willy Tarreaucebf57e2008-08-15 18:16:37 +02002721 return 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002722 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002723
Willy Tarreau21d2af32008-02-14 20:25:24 +01002724
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002725 /*****************************************************************
2726 * More interesting part now : we know that we have a complete *
2727 * response which at least looks like HTTP. We have an indicator *
2728 * of each header's length, so we can parse them quickly. *
2729 ****************************************************************/
Willy Tarreau21d2af32008-02-14 20:25:24 +01002730
Willy Tarreau4076a152009-04-02 15:18:36 +02002731 if (msg->err_pos >= 0)
2732 http_capture_bad_message(&t->be->invalid_rep, t, rep, msg, t->fe);
2733
Willy Tarreau2df28e82008-08-17 15:20:19 +02002734 rep->analysers &= ~AN_RTR_HTTP_HDR;
Willy Tarreaua7c52762008-08-16 18:40:18 +02002735
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002736 /* ensure we keep this pointer to the beginning of the message */
2737 msg->sol = rep->data + msg->som;
Willy Tarreau21d2af32008-02-14 20:25:24 +01002738
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002739 /*
2740 * 1: get the status code and check for cacheability.
2741 */
Willy Tarreau21d2af32008-02-14 20:25:24 +01002742
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002743 t->logs.logwait &= ~LW_RESP;
2744 txn->status = strl2ui(rep->data + msg->sl.st.c, msg->sl.st.c_l);
Willy Tarreau21d2af32008-02-14 20:25:24 +01002745
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002746 switch (txn->status) {
2747 case 200:
2748 case 203:
2749 case 206:
2750 case 300:
2751 case 301:
2752 case 410:
2753 /* RFC2616 @13.4:
2754 * "A response received with a status code of
2755 * 200, 203, 206, 300, 301 or 410 MAY be stored
2756 * by a cache (...) unless a cache-control
2757 * directive prohibits caching."
2758 *
2759 * RFC2616 @9.5: POST method :
2760 * "Responses to this method are not cacheable,
2761 * unless the response includes appropriate
2762 * Cache-Control or Expires header fields."
2763 */
2764 if (likely(txn->meth != HTTP_METH_POST) &&
2765 (t->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
2766 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
2767 break;
2768 default:
2769 break;
2770 }
Willy Tarreau21d2af32008-02-14 20:25:24 +01002771
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002772 /*
2773 * 2: we may need to capture headers
2774 */
2775 if (unlikely((t->logs.logwait & LW_RSPHDR) && t->fe->rsp_cap))
2776 capture_headers(rep->data + msg->som, &txn->hdr_idx,
2777 txn->rsp.cap, t->fe->rsp_cap);
2778
2779 /*
2780 * 3: we will have to evaluate the filters.
2781 * As opposed to version 1.2, now they will be evaluated in the
2782 * filters order and not in the header order. This means that
2783 * each filter has to be validated among all headers.
2784 *
2785 * Filters are tried with ->be first, then with ->fe if it is
2786 * different from ->be.
2787 */
2788
2789 t->flags &= ~SN_CONN_CLOSED; /* prepare for inspection */
2790
2791 cur_proxy = t->be;
2792 while (1) {
2793 struct proxy *rule_set = cur_proxy;
2794
2795 /* try headers filters */
2796 if (rule_set->rsp_exp != NULL) {
2797 if (apply_filters_to_response(t, rep, rule_set->rsp_exp) < 0) {
2798 return_bad_resp:
Willy Tarreau8365f932009-03-15 23:11:49 +01002799 if (t->srv)
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002800 t->srv->failed_resp++;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002801 cur_proxy->failed_resp++;
2802 return_srv_prx_502:
Willy Tarreaufa7e1022008-10-19 07:30:41 +02002803 buffer_shutr_now(rep);
2804 buffer_shutw_now(req);
Willy Tarreau2df28e82008-08-17 15:20:19 +02002805 rep->analysers = 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002806 txn->status = 502;
Willy Tarreau81acfab2008-11-30 19:22:53 +01002807 stream_int_return(rep->cons, error_message(t, HTTP_ERR_502));
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002808 if (!(t->flags & SN_ERR_MASK))
2809 t->flags |= SN_ERR_PRXCOND;
2810 if (!(t->flags & SN_FINST_MASK))
2811 t->flags |= SN_FINST_H;
Willy Tarreaudafde432008-08-17 01:00:46 +02002812 return 0;
Willy Tarreau21d2af32008-02-14 20:25:24 +01002813 }
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002814 }
Willy Tarreau21d2af32008-02-14 20:25:24 +01002815
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002816 /* has the response been denied ? */
2817 if (txn->flags & TX_SVDENY) {
Willy Tarreau8365f932009-03-15 23:11:49 +01002818 if (t->srv)
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002819 t->srv->failed_secu++;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002820 cur_proxy->denied_resp++;
2821 goto return_srv_prx_502;
Willy Tarreau51406232008-03-10 22:04:20 +01002822 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002823
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002824 /* We might have to check for "Connection:" */
2825 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
2826 !(t->flags & SN_CONN_CLOSED)) {
2827 char *cur_ptr, *cur_end, *cur_next;
2828 int cur_idx, old_idx, delta, val;
2829 struct hdr_idx_elem *cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002830
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002831 cur_next = rep->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
2832 old_idx = 0;
Willy Tarreau541b5c22008-01-06 23:34:21 +01002833
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002834 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
2835 cur_hdr = &txn->hdr_idx.v[cur_idx];
2836 cur_ptr = cur_next;
2837 cur_end = cur_ptr + cur_hdr->len;
2838 cur_next = cur_end + cur_hdr->cr + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002839
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002840 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
2841 if (val) {
2842 /* 3 possibilities :
2843 * - we have already set Connection: close,
2844 * so we remove this line.
2845 * - we have not yet set Connection: close,
2846 * but this line indicates close. We leave
2847 * it untouched and set the flag.
2848 * - we have not yet set Connection: close,
2849 * and this line indicates non-close. We
2850 * replace it.
2851 */
2852 if (t->flags & SN_CONN_CLOSED) {
2853 delta = buffer_replace2(rep, cur_ptr, cur_next, NULL, 0);
2854 txn->rsp.eoh += delta;
2855 cur_next += delta;
2856 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
2857 txn->hdr_idx.used--;
2858 cur_hdr->len = 0;
2859 } else {
2860 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
2861 delta = buffer_replace2(rep, cur_ptr + val, cur_end,
2862 "close", 5);
2863 cur_next += delta;
2864 cur_hdr->len += delta;
2865 txn->rsp.eoh += delta;
2866 }
2867 t->flags |= SN_CONN_CLOSED;
2868 }
2869 }
2870 old_idx = cur_idx;
Willy Tarreau541b5c22008-01-06 23:34:21 +01002871 }
2872 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002873
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002874 /* add response headers from the rule sets in the same order */
2875 for (cur_idx = 0; cur_idx < rule_set->nb_rspadd; cur_idx++) {
2876 if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx,
2877 rule_set->rsp_add[cur_idx])) < 0)
2878 goto return_bad_resp;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002879 }
2880
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002881 /* check whether we're already working on the frontend */
2882 if (cur_proxy == t->fe)
2883 break;
2884 cur_proxy = t->fe;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002885 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002886
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002887 /*
2888 * 4: check for server cookie.
2889 */
Willy Tarreaufd39dda2008-10-17 12:01:58 +02002890 if (t->be->cookie_name || t->be->appsession_name || t->fe->capture_name
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002891 || (t->be->options & PR_O_CHK_CACHE))
2892 manage_server_side_cookies(t, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002893
Willy Tarreaubaaee002006-06-26 02:48:02 +02002894
Willy Tarreaua15645d2007-03-18 16:22:39 +01002895 /*
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002896 * 5: check for cache-control or pragma headers if required.
Willy Tarreaua15645d2007-03-18 16:22:39 +01002897 */
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002898 if ((t->be->options & (PR_O_COOK_NOC | PR_O_CHK_CACHE)) != 0)
2899 check_response_for_cacheability(t, rep);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002900
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002901 /*
2902 * 6: add server cookie in the response if needed
2903 */
2904 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
2905 (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
2906 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002907
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002908 /* the server is known, it's not the one the client requested, we have to
2909 * insert a set-cookie here, except if we want to insert only on POST
2910 * requests and this one isn't. Note that servers which don't have cookies
2911 * (eg: some backup servers) will return a full cookie removal request.
2912 */
2913 len = sprintf(trash, "Set-Cookie: %s=%s; path=/",
2914 t->be->cookie_name,
2915 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002916
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002917 if (t->be->cookie_domain)
2918 len += sprintf(trash+len, "; domain=%s", t->be->cookie_domain);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002919
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002920 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
2921 trash, len)) < 0)
2922 goto return_bad_resp;
2923 txn->flags |= TX_SCK_INSERTED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002924
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002925 /* Here, we will tell an eventual cache on the client side that we don't
2926 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
2927 * Some caches understand the correct form: 'no-cache="set-cookie"', but
2928 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
2929 */
2930 if ((t->be->options & PR_O_COOK_NOC) && (txn->flags & TX_CACHEABLE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002931
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002932 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
2933
2934 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
2935 "Cache-control: private", 22)) < 0)
2936 goto return_bad_resp;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002937 }
2938 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002939
Willy Tarreaubaaee002006-06-26 02:48:02 +02002940
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002941 /*
2942 * 7: check if result will be cacheable with a cookie.
2943 * We'll block the response if security checks have caught
2944 * nasty things such as a cacheable cookie.
2945 */
2946 if (((txn->flags & (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) ==
2947 (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) &&
2948 (t->be->options & PR_O_CHK_CACHE)) {
2949
2950 /* we're in presence of a cacheable response containing
2951 * a set-cookie header. We'll block it as requested by
2952 * the 'checkcache' option, and send an alert.
Willy Tarreaua15645d2007-03-18 16:22:39 +01002953 */
Willy Tarreau8365f932009-03-15 23:11:49 +01002954 if (t->srv)
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002955 t->srv->failed_secu++;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002956 t->be->denied_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002957
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002958 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n",
2959 t->be->id, t->srv?t->srv->id:"<dispatch>");
2960 send_log(t->be, LOG_ALERT,
2961 "Blocking cacheable cookie in response from instance %s, server %s.\n",
2962 t->be->id, t->srv?t->srv->id:"<dispatch>");
2963 goto return_srv_prx_502;
2964 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01002965
2966 /*
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002967 * 8: add "Connection: close" if needed and not yet set.
2968 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01002969 */
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002970 if (!(t->flags & SN_CONN_CLOSED) &&
2971 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
2972 if ((unlikely(msg->sl.st.v_l != 8) ||
2973 unlikely(req->data[msg->som + 7] != '0')) &&
2974 unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
2975 "Connection: close", 17)) < 0)
2976 goto return_bad_resp;
2977 t->flags |= SN_CONN_CLOSED;
2978 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01002979
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002980 /*************************************************************
2981 * OK, that's finished for the headers. We have done what we *
2982 * could. Let's switch to the DATA state. *
2983 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02002984
Willy Tarreaue393fe22008-08-16 22:18:07 +02002985 buffer_set_rlim(rep, BUFSIZE); /* no more rewrite needed */
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002986 t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002987
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002988#ifdef CONFIG_HAP_TCPSPLICE
2989 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
2990 /* TCP splicing supported by both FE and BE */
Willy Tarreau3a16b2c2008-08-28 08:54:27 +02002991 tcp_splice_splicefd(rep->cons->fd, rep->prod->fd, 0);
Willy Tarreauf5483bf2008-08-14 18:35:40 +02002992 }
2993#endif
2994 /* if the user wants to log as soon as possible, without counting
2995 * bytes from the server, then this is the right moment. We have
2996 * to temporarily assign bytes_out to log what we currently have.
2997 */
2998 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
2999 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
3000 t->logs.bytes_out = txn->rsp.eoh;
Willy Tarreaua5555ec2008-11-30 19:02:32 +01003001 t->do_log(t);
Willy Tarreauf5483bf2008-08-14 18:35:40 +02003002 t->logs.bytes_out = 0;
3003 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003004
Willy Tarreauf5483bf2008-08-14 18:35:40 +02003005 /* Note: we must not try to cheat by jumping directly to DATA,
3006 * otherwise we would not let the client side wake up.
3007 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003008
Willy Tarreaudafde432008-08-17 01:00:46 +02003009 return 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02003010 }
Willy Tarreaudafde432008-08-17 01:00:46 +02003011
Willy Tarreau2df28e82008-08-17 15:20:19 +02003012 /* Note: eventhough nobody should set an unknown flag, clearing them right now will
3013 * probably reduce one day's debugging session.
3014 */
3015#ifdef DEBUG_DEV
3016 if (rep->analysers & ~(AN_RTR_HTTP_HDR)) {
3017 fprintf(stderr, "FIXME !!!! unknown analysers flags %s:%d = 0x%08X\n",
3018 __FILE__, __LINE__, rep->analysers);
3019 ABORT_NOW();
3020 }
3021#endif
3022 rep->analysers &= AN_RTR_HTTP_HDR;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02003023 return 0;
3024}
Willy Tarreaua15645d2007-03-18 16:22:39 +01003025
Willy Tarreaubaaee002006-06-26 02:48:02 +02003026/*
3027 * Produces data for the session <s> depending on its source. Expects to be
Willy Tarreau1ae3a052008-08-16 10:56:30 +02003028 * called with client socket shut down on input. Right now, only statistics can
Willy Tarreau72b179a2008-08-28 16:01:32 +02003029 * be produced. It stops by itself by unsetting the BF_HIJACK flag from the
3030 * buffer, which it uses to keep on being called when there is free space in
Willy Tarreau01bf8672008-12-07 18:03:29 +01003031 * the buffer, or simply by letting an empty buffer upon return.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003032 */
Willy Tarreau01bf8672008-12-07 18:03:29 +01003033void produce_content(struct session *s, struct buffer *rep)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003034{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003035 if (s->data_source == DATA_SRC_NONE) {
Willy Tarreau01bf8672008-12-07 18:03:29 +01003036 buffer_stop_hijack(rep);
3037 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003038 }
3039 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003040 /* dump server statistics */
Willy Tarreau0a464892008-12-07 18:30:00 +01003041 int ret = stats_dump_http(s, rep, s->be->uri_auth);
Willy Tarreau91861262007-10-17 17:06:05 +02003042 if (ret >= 0)
Willy Tarreau01bf8672008-12-07 18:03:29 +01003043 return;
Willy Tarreau91861262007-10-17 17:06:05 +02003044 /* -1 indicates an error */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003045 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003046
Willy Tarreau91861262007-10-17 17:06:05 +02003047 /* unknown data source or internal error */
3048 s->txn.status = 500;
Willy Tarreau01bf8672008-12-07 18:03:29 +01003049 stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_500));
Willy Tarreau91861262007-10-17 17:06:05 +02003050 if (!(s->flags & SN_ERR_MASK))
3051 s->flags |= SN_ERR_PRXCOND;
3052 if (!(s->flags & SN_FINST_MASK))
3053 s->flags |= SN_FINST_R;
Willy Tarreau01bf8672008-12-07 18:03:29 +01003054 buffer_stop_hijack(rep);
3055 return;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003056}
3057
3058
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003059/* Iterate the same filter through all request headers.
3060 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003061 * Since it can manage the switch to another backend, it updates the per-proxy
3062 * DENY stats.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003063 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003064int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003065{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003066 char term;
3067 char *cur_ptr, *cur_end, *cur_next;
3068 int cur_idx, old_idx, last_hdr;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003069 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003070 struct hdr_idx_elem *cur_hdr;
3071 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003072
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003073 last_hdr = 0;
3074
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003075 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003076 old_idx = 0;
3077
3078 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01003079 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003080 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003081 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003082 (exp->action == ACT_ALLOW ||
3083 exp->action == ACT_DENY ||
3084 exp->action == ACT_TARPIT))
3085 return 0;
3086
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003087 cur_idx = txn->hdr_idx.v[old_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003088 if (!cur_idx)
3089 break;
3090
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003091 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003092 cur_ptr = cur_next;
3093 cur_end = cur_ptr + cur_hdr->len;
3094 cur_next = cur_end + cur_hdr->cr + 1;
3095
3096 /* Now we have one header between cur_ptr and cur_end,
3097 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003098 */
3099
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003100 /* The annoying part is that pattern matching needs
3101 * that we modify the contents to null-terminate all
3102 * strings before testing them.
3103 */
3104
3105 term = *cur_end;
3106 *cur_end = '\0';
3107
3108 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3109 switch (exp->action) {
3110 case ACT_SETBE:
3111 /* It is not possible to jump a second time.
3112 * FIXME: should we return an HTTP/500 here so that
3113 * the admin knows there's a problem ?
3114 */
3115 if (t->be != t->fe)
3116 break;
3117
3118 /* Swithing Proxy */
3119 t->be = (struct proxy *) exp->replace;
3120
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003121 /* right now, the backend switch is not overly complicated
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003122 * because we have associated req_cap and rsp_cap to the
3123 * frontend, and the beconn will be updated later.
3124 */
3125
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003126 t->rep->rto = t->req->wto = t->be->timeout.server;
3127 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02003128 t->conn_retries = t->be->conn_retries;
Willy Tarreau32a4ec02009-04-02 11:35:18 +02003129 if (t->be->options2 & PR_O2_RSPBUG_OK)
3130 t->txn.rsp.err_pos = -1; /* let buggy responses pass */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003131 last_hdr = 1;
3132 break;
3133
3134 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003135 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003136 last_hdr = 1;
3137 break;
3138
3139 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003140 txn->flags |= TX_CLDENY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003141 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003142 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003143 break;
3144
3145 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003146 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003147 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003148 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003149 break;
3150
3151 case ACT_REPLACE:
3152 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3153 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3154 /* FIXME: if the user adds a newline in the replacement, the
3155 * index will not be recalculated for now, and the new line
3156 * will not be counted as a new header.
3157 */
3158
3159 cur_end += delta;
3160 cur_next += delta;
3161 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003162 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003163 break;
3164
3165 case ACT_REMOVE:
3166 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3167 cur_next += delta;
3168
3169 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003170 txn->req.eoh += delta;
3171 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3172 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003173 cur_hdr->len = 0;
3174 cur_end = NULL; /* null-term has been rewritten */
3175 break;
3176
3177 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01003178 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003179 if (cur_end)
3180 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003181
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003182 /* keep the link from this header to next one in case of later
3183 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003184 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003185 old_idx = cur_idx;
3186 }
3187 return 0;
3188}
3189
3190
3191/* Apply the filter to the request line.
3192 * Returns 0 if nothing has been done, 1 if the filter has been applied,
3193 * or -1 if a replacement resulted in an invalid request line.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003194 * Since it can manage the switch to another backend, it updates the per-proxy
3195 * DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003196 */
3197int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
3198{
3199 char term;
3200 char *cur_ptr, *cur_end;
3201 int done;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003202 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003203 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003204
Willy Tarreau58f10d72006-12-04 02:26:12 +01003205
Willy Tarreau3d300592007-03-18 18:34:41 +01003206 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003207 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003208 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003209 (exp->action == ACT_ALLOW ||
3210 exp->action == ACT_DENY ||
3211 exp->action == ACT_TARPIT))
3212 return 0;
3213 else if (exp->action == ACT_REMOVE)
3214 return 0;
3215
3216 done = 0;
3217
Willy Tarreau9cdde232007-05-02 20:58:19 +02003218 cur_ptr = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003219 cur_end = cur_ptr + txn->req.sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003220
3221 /* Now we have the request line between cur_ptr and cur_end */
3222
3223 /* The annoying part is that pattern matching needs
3224 * that we modify the contents to null-terminate all
3225 * strings before testing them.
3226 */
3227
3228 term = *cur_end;
3229 *cur_end = '\0';
3230
3231 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3232 switch (exp->action) {
3233 case ACT_SETBE:
3234 /* It is not possible to jump a second time.
3235 * FIXME: should we return an HTTP/500 here so that
3236 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01003237 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003238 if (t->be != t->fe)
3239 break;
3240
3241 /* Swithing Proxy */
3242 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003243
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003244 /* right now, the backend switch is not too much complicated
3245 * because we have associated req_cap and rsp_cap to the
3246 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003247 */
3248
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003249 t->rep->rto = t->req->wto = t->be->timeout.server;
3250 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02003251 t->conn_retries = t->be->conn_retries;
Willy Tarreau32a4ec02009-04-02 11:35:18 +02003252 if (t->be->options2 & PR_O2_RSPBUG_OK)
3253 t->txn.rsp.err_pos = -1; /* let buggy responses pass */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003254 done = 1;
3255 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003256
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003257 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003258 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003259 done = 1;
3260 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003261
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003262 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003263 txn->flags |= TX_CLDENY;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003264 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003265 done = 1;
3266 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003267
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003268 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003269 txn->flags |= TX_CLTARPIT;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003270 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003271 done = 1;
3272 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003273
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003274 case ACT_REPLACE:
3275 *cur_end = term; /* restore the string terminator */
3276 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3277 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3278 /* FIXME: if the user adds a newline in the replacement, the
3279 * index will not be recalculated for now, and the new line
3280 * will not be counted as a new header.
3281 */
Willy Tarreaua496b602006-12-17 23:15:24 +01003282
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003283 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003284 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01003285
Willy Tarreau9cdde232007-05-02 20:58:19 +02003286 txn->req.sol = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003287 cur_end = (char *)http_parse_reqline(&txn->req, req->data,
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003288 HTTP_MSG_RQMETH,
3289 cur_ptr, cur_end + 1,
3290 NULL, NULL);
3291 if (unlikely(!cur_end))
3292 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01003293
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003294 /* we have a full request and we know that we have either a CR
3295 * or an LF at <ptr>.
3296 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003297 txn->meth = find_http_meth(cur_ptr, txn->req.sl.rq.m_l);
3298 hdr_idx_set_start(&txn->hdr_idx, txn->req.sl.rq.l, *cur_end == '\r');
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003299 /* there is no point trying this regex on headers */
3300 return 1;
3301 }
3302 }
3303 *cur_end = term; /* restore the string terminator */
3304 return done;
3305}
Willy Tarreau97de6242006-12-27 17:18:38 +01003306
Willy Tarreau58f10d72006-12-04 02:26:12 +01003307
Willy Tarreau58f10d72006-12-04 02:26:12 +01003308
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003309/*
3310 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
3311 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
Willy Tarreaua15645d2007-03-18 16:22:39 +01003312 * unparsable request. Since it can manage the switch to another backend, it
3313 * updates the per-proxy DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003314 */
3315int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
3316{
Willy Tarreau3d300592007-03-18 18:34:41 +01003317 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003318 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01003319 while (exp && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003320 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003321
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003322 /*
3323 * The interleaving of transformations and verdicts
3324 * makes it difficult to decide to continue or stop
3325 * the evaluation.
3326 */
3327
Willy Tarreau3d300592007-03-18 18:34:41 +01003328 if ((txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003329 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
3330 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
3331 exp = exp->next;
3332 continue;
3333 }
3334
3335 /* Apply the filter to the request line. */
3336 ret = apply_filter_to_req_line(t, req, exp);
3337 if (unlikely(ret < 0))
3338 return -1;
3339
3340 if (likely(ret == 0)) {
3341 /* The filter did not match the request, it can be
3342 * iterated through all headers.
3343 */
3344 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003345 }
3346 exp = exp->next;
3347 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003348 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003349}
3350
3351
Willy Tarreaua15645d2007-03-18 16:22:39 +01003352
Willy Tarreau58f10d72006-12-04 02:26:12 +01003353/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01003354 * Manage client-side cookie. It can impact performance by about 2% so it is
3355 * desirable to call it only when needed.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003356 */
3357void manage_client_side_cookies(struct session *t, struct buffer *req)
3358{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003359 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003360 char *p1, *p2, *p3, *p4;
3361 char *del_colon, *del_cookie, *colon;
3362 int app_cookies;
3363
3364 appsess *asession_temp = NULL;
3365 appsess local_asession;
3366
3367 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003368 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003369
Willy Tarreau2a324282006-12-05 00:05:46 +01003370 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003371 * we start with the start line.
3372 */
Willy Tarreau83969f42007-01-22 08:55:47 +01003373 old_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003374 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003375
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003376 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003377 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003378 int val;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003379
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003380 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003381 cur_ptr = cur_next;
3382 cur_end = cur_ptr + cur_hdr->len;
3383 cur_next = cur_end + cur_hdr->cr + 1;
3384
3385 /* We have one full header between cur_ptr and cur_end, and the
3386 * next header starts at cur_next. We're only interested in
3387 * "Cookie:" headers.
3388 */
3389
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003390 val = http_header_match2(cur_ptr, cur_end, "Cookie", 6);
3391 if (!val) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003392 old_idx = cur_idx;
3393 continue;
3394 }
3395
3396 /* Now look for cookies. Conforming to RFC2109, we have to support
3397 * attributes whose name begin with a '$', and associate them with
3398 * the right cookie, if we want to delete this cookie.
3399 * So there are 3 cases for each cookie read :
3400 * 1) it's a special attribute, beginning with a '$' : ignore it.
3401 * 2) it's a server id cookie that we *MAY* want to delete : save
3402 * some pointers on it (last semi-colon, beginning of cookie...)
3403 * 3) it's an application cookie : we *MAY* have to delete a previous
3404 * "special" cookie.
3405 * At the end of loop, if a "special" cookie remains, we may have to
3406 * remove it. If no application cookie persists in the header, we
3407 * *MUST* delete it
3408 */
3409
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003410 colon = p1 = cur_ptr + val; /* first non-space char after 'Cookie:' */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003411
Willy Tarreau58f10d72006-12-04 02:26:12 +01003412 /* del_cookie == NULL => nothing to be deleted */
3413 del_colon = del_cookie = NULL;
3414 app_cookies = 0;
3415
3416 while (p1 < cur_end) {
3417 /* skip spaces and colons, but keep an eye on these ones */
3418 while (p1 < cur_end) {
3419 if (*p1 == ';' || *p1 == ',')
3420 colon = p1;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02003421 else if (!isspace((unsigned char)*p1))
Willy Tarreau58f10d72006-12-04 02:26:12 +01003422 break;
3423 p1++;
3424 }
3425
3426 if (p1 == cur_end)
3427 break;
3428
3429 /* p1 is at the beginning of the cookie name */
3430 p2 = p1;
3431 while (p2 < cur_end && *p2 != '=')
3432 p2++;
3433
3434 if (p2 == cur_end)
3435 break;
3436
3437 p3 = p2 + 1; /* skips the '=' sign */
3438 if (p3 == cur_end)
3439 break;
3440
3441 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02003442 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';' && *p4 != ',')
Willy Tarreau58f10d72006-12-04 02:26:12 +01003443 p4++;
3444
3445 /* here, we have the cookie name between p1 and p2,
3446 * and its value between p3 and p4.
3447 * we can process it :
3448 *
3449 * Cookie: NAME=VALUE;
3450 * | || || |
3451 * | || || +--> p4
3452 * | || |+-------> p3
3453 * | || +--------> p2
3454 * | |+------------> p1
3455 * | +-------------> colon
3456 * +--------------------> cur_ptr
3457 */
3458
3459 if (*p1 == '$') {
3460 /* skip this one */
3461 }
3462 else {
3463 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003464 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003465 txn->cli_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003466 (p4 - p1 >= t->fe->capture_namelen) &&
3467 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003468 int log_len = p4 - p1;
3469
Willy Tarreau086b3b42007-05-13 21:45:51 +02003470 if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003471 Alert("HTTP logging : out of memory.\n");
3472 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003473 if (log_len > t->fe->capture_len)
3474 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003475 memcpy(txn->cli_cookie, p1, log_len);
3476 txn->cli_cookie[log_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003477 }
3478 }
3479
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003480 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
3481 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003482 /* Cool... it's the right one */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003483 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003484 char *delim;
3485
3486 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3487 * have the server ID betweek p3 and delim, and the original cookie between
3488 * delim+1 and p4. Otherwise, delim==p4 :
3489 *
3490 * Cookie: NAME=SRV~VALUE;
3491 * | || || | |
3492 * | || || | +--> p4
3493 * | || || +--------> delim
3494 * | || |+-----------> p3
3495 * | || +------------> p2
3496 * | |+----------------> p1
3497 * | +-----------------> colon
3498 * +------------------------> cur_ptr
3499 */
3500
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003501 if (t->be->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003502 for (delim = p3; delim < p4; delim++)
3503 if (*delim == COOKIE_DELIM)
3504 break;
3505 }
3506 else
3507 delim = p4;
3508
3509
3510 /* Here, we'll look for the first running server which supports the cookie.
3511 * This allows to share a same cookie between several servers, for example
3512 * to dedicate backup servers to specific servers only.
3513 * However, to prevent clients from sticking to cookie-less backup server
3514 * when they have incidentely learned an empty cookie, we simply ignore
3515 * empty cookies and mark them as invalid.
3516 */
3517 if (delim == p3)
3518 srv = NULL;
3519
3520 while (srv) {
Willy Tarreau92f2ab12007-02-02 22:14:47 +01003521 if (srv->cookie && (srv->cklen == delim - p3) &&
3522 !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003523 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003524 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01003525 txn->flags &= ~TX_CK_MASK;
3526 txn->flags |= TX_CK_VALID;
3527 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003528 t->srv = srv;
3529 break;
3530 } else {
3531 /* we found a server, but it's down */
Willy Tarreau3d300592007-03-18 18:34:41 +01003532 txn->flags &= ~TX_CK_MASK;
3533 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003534 }
3535 }
3536 srv = srv->next;
3537 }
3538
Willy Tarreau3d300592007-03-18 18:34:41 +01003539 if (!srv && !(txn->flags & TX_CK_DOWN)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003540 /* no server matched this cookie */
Willy Tarreau3d300592007-03-18 18:34:41 +01003541 txn->flags &= ~TX_CK_MASK;
3542 txn->flags |= TX_CK_INVALID;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003543 }
3544
3545 /* depending on the cookie mode, we may have to either :
3546 * - delete the complete cookie if we're in insert+indirect mode, so that
3547 * the server never sees it ;
3548 * - remove the server id from the cookie value, and tag the cookie as an
3549 * application cookie so that it does not get accidentely removed later,
3550 * if we're in cookie prefix mode
3551 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003552 if ((t->be->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003553 int delta; /* negative */
3554
3555 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
3556 p4 += delta;
3557 cur_end += delta;
3558 cur_next += delta;
3559 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003560 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003561
3562 del_cookie = del_colon = NULL;
3563 app_cookies++; /* protect the header from deletion */
3564 }
3565 else if (del_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003566 (t->be->options & (PR_O_COOK_INS | PR_O_COOK_IND)) == (PR_O_COOK_INS | PR_O_COOK_IND)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003567 del_cookie = p1;
3568 del_colon = colon;
3569 }
3570 } else {
3571 /* now we know that we must keep this cookie since it's
3572 * not ours. But if we wanted to delete our cookie
3573 * earlier, we cannot remove the complete header, but we
3574 * can remove the previous block itself.
3575 */
3576 app_cookies++;
3577
3578 if (del_cookie != NULL) {
3579 int delta; /* negative */
3580
3581 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
3582 p4 += delta;
3583 cur_end += delta;
3584 cur_next += delta;
3585 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003586 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003587 del_cookie = del_colon = NULL;
3588 }
3589 }
3590
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003591 if ((t->be->appsession_name != NULL) &&
3592 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003593 /* first, let's see if the cookie is our appcookie*/
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02003594
Willy Tarreau58f10d72006-12-04 02:26:12 +01003595 /* Cool... it's the right one */
3596
3597 asession_temp = &local_asession;
3598
Willy Tarreau63963c62007-05-13 21:29:55 +02003599 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003600 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3601 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3602 return;
3603 }
3604
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003605 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
3606 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003607 asession_temp->serverid = NULL;
Willy Tarreau51041c72007-09-09 21:56:53 +02003608
Willy Tarreau58f10d72006-12-04 02:26:12 +01003609 /* only do insert, if lookup fails */
Willy Tarreau51041c72007-09-09 21:56:53 +02003610 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
3611 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02003612 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003613 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02003614 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003615 Alert("Not enough memory process_cli():asession:calloc().\n");
3616 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3617 return;
3618 }
3619
3620 asession_temp->sessid = local_asession.sessid;
3621 asession_temp->serverid = local_asession.serverid;
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02003622 asession_temp->request_count = 0;
Willy Tarreau51041c72007-09-09 21:56:53 +02003623 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003624 } else {
3625 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02003626 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003627 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01003628 if (asession_temp->serverid == NULL) {
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02003629 /* TODO redispatch request */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003630 Alert("Found Application Session without matching server.\n");
3631 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003632 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003633 while (srv) {
3634 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003635 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003636 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01003637 txn->flags &= ~TX_CK_MASK;
3638 txn->flags |= TX_CK_VALID;
3639 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003640 t->srv = srv;
3641 break;
3642 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01003643 txn->flags &= ~TX_CK_MASK;
3644 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003645 }
3646 }
3647 srv = srv->next;
3648 }/* end while(srv) */
3649 }/* end else if server == NULL */
3650
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003651 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02003652 asession_temp->request_count++;
3653#if defined(DEBUG_HASH)
3654 Alert("manage_client_side_cookies\n");
3655 appsession_hash_dump(&(t->be->htbl_proxy));
3656#endif
Willy Tarreau58f10d72006-12-04 02:26:12 +01003657 }/* end if ((t->proxy->appsession_name != NULL) ... */
3658 }
3659
3660 /* we'll have to look for another cookie ... */
3661 p1 = p4;
3662 } /* while (p1 < cur_end) */
3663
3664 /* There's no more cookie on this line.
3665 * We may have marked the last one(s) for deletion.
3666 * We must do this now in two ways :
3667 * - if there is no app cookie, we simply delete the header ;
3668 * - if there are app cookies, we must delete the end of the
3669 * string properly, including the colon/semi-colon before
3670 * the cookie name.
3671 */
3672 if (del_cookie != NULL) {
3673 int delta;
3674 if (app_cookies) {
3675 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
3676 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003677 cur_hdr->len += delta;
3678 } else {
3679 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003680
3681 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003682 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3683 txn->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003684 cur_hdr->len = 0;
3685 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01003686 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003687 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003688 }
3689
3690 /* keep the link from this header to next one */
3691 old_idx = cur_idx;
3692 } /* end of cookie processing on this header */
3693}
3694
3695
Willy Tarreaua15645d2007-03-18 16:22:39 +01003696/* Iterate the same filter through all response headers contained in <rtr>.
3697 * Returns 1 if this filter can be stopped upon return, otherwise 0.
3698 */
3699int apply_filter_to_resp_headers(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
3700{
3701 char term;
3702 char *cur_ptr, *cur_end, *cur_next;
3703 int cur_idx, old_idx, last_hdr;
3704 struct http_txn *txn = &t->txn;
3705 struct hdr_idx_elem *cur_hdr;
3706 int len, delta;
3707
3708 last_hdr = 0;
3709
3710 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
3711 old_idx = 0;
3712
3713 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01003714 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01003715 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003716 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01003717 (exp->action == ACT_ALLOW ||
3718 exp->action == ACT_DENY))
3719 return 0;
3720
3721 cur_idx = txn->hdr_idx.v[old_idx].next;
3722 if (!cur_idx)
3723 break;
3724
3725 cur_hdr = &txn->hdr_idx.v[cur_idx];
3726 cur_ptr = cur_next;
3727 cur_end = cur_ptr + cur_hdr->len;
3728 cur_next = cur_end + cur_hdr->cr + 1;
3729
3730 /* Now we have one header between cur_ptr and cur_end,
3731 * and the next header starts at cur_next.
3732 */
3733
3734 /* The annoying part is that pattern matching needs
3735 * that we modify the contents to null-terminate all
3736 * strings before testing them.
3737 */
3738
3739 term = *cur_end;
3740 *cur_end = '\0';
3741
3742 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3743 switch (exp->action) {
3744 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003745 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003746 last_hdr = 1;
3747 break;
3748
3749 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003750 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003751 last_hdr = 1;
3752 break;
3753
3754 case ACT_REPLACE:
3755 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3756 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
3757 /* FIXME: if the user adds a newline in the replacement, the
3758 * index will not be recalculated for now, and the new line
3759 * will not be counted as a new header.
3760 */
3761
3762 cur_end += delta;
3763 cur_next += delta;
3764 cur_hdr->len += delta;
3765 txn->rsp.eoh += delta;
3766 break;
3767
3768 case ACT_REMOVE:
3769 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
3770 cur_next += delta;
3771
3772 /* FIXME: this should be a separate function */
3773 txn->rsp.eoh += delta;
3774 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3775 txn->hdr_idx.used--;
3776 cur_hdr->len = 0;
3777 cur_end = NULL; /* null-term has been rewritten */
3778 break;
3779
3780 }
3781 }
3782 if (cur_end)
3783 *cur_end = term; /* restore the string terminator */
3784
3785 /* keep the link from this header to next one in case of later
3786 * removal of next header.
3787 */
3788 old_idx = cur_idx;
3789 }
3790 return 0;
3791}
3792
3793
3794/* Apply the filter to the status line in the response buffer <rtr>.
3795 * Returns 0 if nothing has been done, 1 if the filter has been applied,
3796 * or -1 if a replacement resulted in an invalid status line.
3797 */
3798int apply_filter_to_sts_line(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
3799{
3800 char term;
3801 char *cur_ptr, *cur_end;
3802 int done;
3803 struct http_txn *txn = &t->txn;
3804 int len, delta;
3805
3806
Willy Tarreau3d300592007-03-18 18:34:41 +01003807 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01003808 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003809 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01003810 (exp->action == ACT_ALLOW ||
3811 exp->action == ACT_DENY))
3812 return 0;
3813 else if (exp->action == ACT_REMOVE)
3814 return 0;
3815
3816 done = 0;
3817
Willy Tarreau9cdde232007-05-02 20:58:19 +02003818 cur_ptr = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003819 cur_end = cur_ptr + txn->rsp.sl.rq.l;
3820
3821 /* Now we have the status line between cur_ptr and cur_end */
3822
3823 /* The annoying part is that pattern matching needs
3824 * that we modify the contents to null-terminate all
3825 * strings before testing them.
3826 */
3827
3828 term = *cur_end;
3829 *cur_end = '\0';
3830
3831 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3832 switch (exp->action) {
3833 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003834 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003835 done = 1;
3836 break;
3837
3838 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003839 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003840 done = 1;
3841 break;
3842
3843 case ACT_REPLACE:
3844 *cur_end = term; /* restore the string terminator */
3845 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3846 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
3847 /* FIXME: if the user adds a newline in the replacement, the
3848 * index will not be recalculated for now, and the new line
3849 * will not be counted as a new header.
3850 */
3851
3852 txn->rsp.eoh += delta;
3853 cur_end += delta;
3854
Willy Tarreau9cdde232007-05-02 20:58:19 +02003855 txn->rsp.sol = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003856 cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data,
Willy Tarreau02785762007-04-03 14:45:44 +02003857 HTTP_MSG_RPVER,
Willy Tarreaua15645d2007-03-18 16:22:39 +01003858 cur_ptr, cur_end + 1,
3859 NULL, NULL);
3860 if (unlikely(!cur_end))
3861 return -1;
3862
3863 /* we have a full respnse and we know that we have either a CR
3864 * or an LF at <ptr>.
3865 */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003866 txn->status = strl2ui(rtr->data + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003867 hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.rq.l, *cur_end == '\r');
3868 /* there is no point trying this regex on headers */
3869 return 1;
3870 }
3871 }
3872 *cur_end = term; /* restore the string terminator */
3873 return done;
3874}
3875
3876
3877
3878/*
3879 * Apply all the resp filters <exp> to all headers in buffer <rtr> of session <t>.
3880 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
3881 * unparsable response.
3882 */
3883int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
3884{
Willy Tarreau3d300592007-03-18 18:34:41 +01003885 struct http_txn *txn = &t->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003886 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01003887 while (exp && !(txn->flags & TX_SVDENY)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003888 int ret;
3889
3890 /*
3891 * The interleaving of transformations and verdicts
3892 * makes it difficult to decide to continue or stop
3893 * the evaluation.
3894 */
3895
Willy Tarreau3d300592007-03-18 18:34:41 +01003896 if ((txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01003897 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
3898 exp->action == ACT_PASS)) {
3899 exp = exp->next;
3900 continue;
3901 }
3902
3903 /* Apply the filter to the status line. */
3904 ret = apply_filter_to_sts_line(t, rtr, exp);
3905 if (unlikely(ret < 0))
3906 return -1;
3907
3908 if (likely(ret == 0)) {
3909 /* The filter did not match the response, it can be
3910 * iterated through all headers.
3911 */
3912 apply_filter_to_resp_headers(t, rtr, exp);
3913 }
3914 exp = exp->next;
3915 }
3916 return 0;
3917}
3918
3919
3920
3921/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01003922 * Manage server-side cookies. It can impact performance by about 2% so it is
3923 * desirable to call it only when needed.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003924 */
3925void manage_server_side_cookies(struct session *t, struct buffer *rtr)
3926{
3927 struct http_txn *txn = &t->txn;
3928 char *p1, *p2, *p3, *p4;
3929
3930 appsess *asession_temp = NULL;
3931 appsess local_asession;
3932
3933 char *cur_ptr, *cur_end, *cur_next;
3934 int cur_idx, old_idx, delta;
3935
Willy Tarreaua15645d2007-03-18 16:22:39 +01003936 /* Iterate through the headers.
3937 * we start with the start line.
3938 */
3939 old_idx = 0;
3940 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
3941
3942 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
3943 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003944 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003945
3946 cur_hdr = &txn->hdr_idx.v[cur_idx];
3947 cur_ptr = cur_next;
3948 cur_end = cur_ptr + cur_hdr->len;
3949 cur_next = cur_end + cur_hdr->cr + 1;
3950
3951 /* We have one full header between cur_ptr and cur_end, and the
3952 * next header starts at cur_next. We're only interested in
3953 * "Cookie:" headers.
3954 */
3955
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003956 val = http_header_match2(cur_ptr, cur_end, "Set-Cookie", 10);
3957 if (!val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003958 old_idx = cur_idx;
3959 continue;
3960 }
3961
3962 /* OK, right now we know we have a set-cookie at cur_ptr */
Willy Tarreau3d300592007-03-18 18:34:41 +01003963 txn->flags |= TX_SCK_ANY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003964
3965
Willy Tarreaufd39dda2008-10-17 12:01:58 +02003966 /* maybe we only wanted to see if there was a set-cookie. Note that
3967 * the cookie capture is declared in the fronend.
3968 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003969 if (t->be->cookie_name == NULL &&
3970 t->be->appsession_name == NULL &&
Willy Tarreaufd39dda2008-10-17 12:01:58 +02003971 t->fe->capture_name == NULL)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003972 return;
3973
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003974 p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003975
3976 while (p1 < cur_end) { /* in fact, we'll break after the first cookie */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003977 if (p1 == cur_end || *p1 == ';') /* end of cookie */
3978 break;
3979
3980 /* p1 is at the beginning of the cookie name */
3981 p2 = p1;
3982
3983 while (p2 < cur_end && *p2 != '=' && *p2 != ';')
3984 p2++;
3985
3986 if (p2 == cur_end || *p2 == ';') /* next cookie */
3987 break;
3988
3989 p3 = p2 + 1; /* skip the '=' sign */
3990 if (p3 == cur_end)
3991 break;
3992
3993 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02003994 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';')
Willy Tarreaua15645d2007-03-18 16:22:39 +01003995 p4++;
3996
3997 /* here, we have the cookie name between p1 and p2,
3998 * and its value between p3 and p4.
3999 * we can process it.
4000 */
4001
4002 /* first, let's see if we want to capture it */
Willy Tarreaufd39dda2008-10-17 12:01:58 +02004003 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004004 txn->srv_cookie == NULL &&
Willy Tarreaufd39dda2008-10-17 12:01:58 +02004005 (p4 - p1 >= t->fe->capture_namelen) &&
4006 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004007 int log_len = p4 - p1;
4008
Willy Tarreau086b3b42007-05-13 21:45:51 +02004009 if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004010 Alert("HTTP logging : out of memory.\n");
4011 }
4012
Willy Tarreaufd39dda2008-10-17 12:01:58 +02004013 if (log_len > t->fe->capture_len)
4014 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004015 memcpy(txn->srv_cookie, p1, log_len);
4016 txn->srv_cookie[log_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004017 }
4018
4019 /* now check if we need to process it for persistence */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004020 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4021 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004022 /* Cool... it's the right one */
Willy Tarreau3d300592007-03-18 18:34:41 +01004023 txn->flags |= TX_SCK_SEEN;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004024
4025 /* If the cookie is in insert mode on a known server, we'll delete
4026 * this occurrence because we'll insert another one later.
4027 * We'll delete it too if the "indirect" option is set and we're in
4028 * a direct access. */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004029 if (((t->srv) && (t->be->options & PR_O_COOK_INS)) ||
4030 ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004031 /* this header must be deleted */
4032 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4033 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4034 txn->hdr_idx.used--;
4035 cur_hdr->len = 0;
4036 cur_next += delta;
4037 txn->rsp.eoh += delta;
4038
Willy Tarreau3d300592007-03-18 18:34:41 +01004039 txn->flags |= TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004040 }
4041 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004042 (t->be->options & PR_O_COOK_RW)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004043 /* replace bytes p3->p4 with the cookie name associated
4044 * with this server since we know it.
4045 */
4046 delta = buffer_replace2(rtr, p3, p4, t->srv->cookie, t->srv->cklen);
4047 cur_hdr->len += delta;
4048 cur_next += delta;
4049 txn->rsp.eoh += delta;
4050
Willy Tarreau3d300592007-03-18 18:34:41 +01004051 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004052 }
4053 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004054 (t->be->options & PR_O_COOK_PFX)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004055 /* insert the cookie name associated with this server
4056 * before existing cookie, and insert a delimitor between them..
4057 */
4058 delta = buffer_replace2(rtr, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4059 cur_hdr->len += delta;
4060 cur_next += delta;
4061 txn->rsp.eoh += delta;
4062
4063 p3[t->srv->cklen] = COOKIE_DELIM;
Willy Tarreau3d300592007-03-18 18:34:41 +01004064 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004065 }
4066 }
4067 /* next, let's see if the cookie is our appcookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004068 else if ((t->be->appsession_name != NULL) &&
4069 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004070
4071 /* Cool... it's the right one */
4072
4073 size_t server_id_len = strlen(t->srv->id) + 1;
4074 asession_temp = &local_asession;
4075
Willy Tarreau63963c62007-05-13 21:29:55 +02004076 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004077 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4078 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4079 return;
4080 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004081 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4082 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004083 asession_temp->serverid = NULL;
4084
4085 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01004086 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4087 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004088 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004089 Alert("Not enough Memory process_srv():asession:calloc().\n");
4090 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
4091 return;
4092 }
4093 asession_temp->sessid = local_asession.sessid;
4094 asession_temp->serverid = local_asession.serverid;
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004095 asession_temp->request_count = 0;
Willy Tarreau51041c72007-09-09 21:56:53 +02004096 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
4097 } else {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004098 /* free wasted memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004099 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau51041c72007-09-09 21:56:53 +02004100 }
4101
Willy Tarreaua15645d2007-03-18 16:22:39 +01004102 if (asession_temp->serverid == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004103 if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004104 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4105 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4106 return;
4107 }
4108 asession_temp->serverid[0] = '\0';
4109 }
4110
4111 if (asession_temp->serverid[0] == '\0')
4112 memcpy(asession_temp->serverid, t->srv->id, server_id_len);
4113
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004114 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004115 asession_temp->request_count++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004116#if defined(DEBUG_HASH)
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004117 Alert("manage_server_side_cookies\n");
Willy Tarreau51041c72007-09-09 21:56:53 +02004118 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreaua15645d2007-03-18 16:22:39 +01004119#endif
4120 }/* end if ((t->proxy->appsession_name != NULL) ... */
4121 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4122 } /* we're now at the end of the cookie value */
4123
4124 /* keep the link from this header to next one */
4125 old_idx = cur_idx;
4126 } /* end of cookie processing on this header */
4127}
4128
4129
4130
4131/*
4132 * Check if response is cacheable or not. Updates t->flags.
4133 */
4134void check_response_for_cacheability(struct session *t, struct buffer *rtr)
4135{
4136 struct http_txn *txn = &t->txn;
4137 char *p1, *p2;
4138
4139 char *cur_ptr, *cur_end, *cur_next;
4140 int cur_idx;
4141
Willy Tarreau5df51872007-11-25 16:20:08 +01004142 if (!(txn->flags & TX_CACHEABLE))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004143 return;
4144
4145 /* Iterate through the headers.
4146 * we start with the start line.
4147 */
4148 cur_idx = 0;
4149 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4150
4151 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
4152 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004153 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004154
4155 cur_hdr = &txn->hdr_idx.v[cur_idx];
4156 cur_ptr = cur_next;
4157 cur_end = cur_ptr + cur_hdr->len;
4158 cur_next = cur_end + cur_hdr->cr + 1;
4159
4160 /* We have one full header between cur_ptr and cur_end, and the
4161 * next header starts at cur_next. We're only interested in
4162 * "Cookie:" headers.
4163 */
4164
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004165 val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
4166 if (val) {
4167 if ((cur_end - (cur_ptr + val) >= 8) &&
4168 strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
4169 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
4170 return;
4171 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01004172 }
4173
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004174 val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
4175 if (!val)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004176 continue;
4177
4178 /* OK, right now we know we have a cache-control header at cur_ptr */
4179
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004180 p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004181
4182 if (p1 >= cur_end) /* no more info */
4183 continue;
4184
4185 /* p1 is at the beginning of the value */
4186 p2 = p1;
4187
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004188 while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((unsigned char)*p2))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004189 p2++;
4190
4191 /* we have a complete value between p1 and p2 */
4192 if (p2 < cur_end && *p2 == '=') {
4193 /* we have something of the form no-cache="set-cookie" */
4194 if ((cur_end - p1 >= 21) &&
4195 strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0
4196 && (p1[20] == '"' || p1[20] == ','))
Willy Tarreau3d300592007-03-18 18:34:41 +01004197 txn->flags &= ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004198 continue;
4199 }
4200
4201 /* OK, so we know that either p2 points to the end of string or to a comma */
4202 if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) ||
4203 ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) ||
4204 ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) ||
4205 ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004206 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004207 return;
4208 }
4209
4210 if ((p2 - p1 == 6) && strncasecmp(p1, "public", 6) == 0) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004211 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004212 continue;
4213 }
4214 }
4215}
4216
4217
Willy Tarreau58f10d72006-12-04 02:26:12 +01004218/*
4219 * Try to retrieve a known appsession in the URI, then the associated server.
4220 * If the server is found, it's assigned to the session.
4221 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004222void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004223{
Willy Tarreau3d300592007-03-18 18:34:41 +01004224 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004225 appsess *asession_temp = NULL;
4226 appsess local_asession;
4227 char *request_line;
4228
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004229 if (t->be->appsession_name == NULL ||
Willy Tarreaub326fcc2007-03-03 13:54:32 +01004230 (t->txn.meth != HTTP_METH_GET && t->txn.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004231 (request_line = memchr(begin, ';', len)) == NULL ||
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004232 ((1 + t->be->appsession_name_len + 1 + t->be->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004233 return;
4234
4235 /* skip ';' */
4236 request_line++;
4237
4238 /* look if we have a jsessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004239 if (strncasecmp(request_line, t->be->appsession_name, t->be->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004240 return;
4241
4242 /* skip jsessionid= */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004243 request_line += t->be->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004244
4245 /* First try if we already have an appsession */
4246 asession_temp = &local_asession;
4247
Willy Tarreau63963c62007-05-13 21:29:55 +02004248 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004249 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4250 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4251 return;
4252 }
4253
4254 /* Copy the sessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004255 memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
4256 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004257 asession_temp->serverid = NULL;
4258
4259 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01004260 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4261 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004262 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004263 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004264 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004265 Alert("Not enough memory process_cli():asession:calloc().\n");
4266 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4267 return;
4268 }
4269 asession_temp->sessid = local_asession.sessid;
4270 asession_temp->serverid = local_asession.serverid;
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004271 asession_temp->request_count=0;
Willy Tarreau51041c72007-09-09 21:56:53 +02004272 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004273 }
4274 else {
4275 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004276 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004277 }
Willy Tarreau51041c72007-09-09 21:56:53 +02004278
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004279 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004280 asession_temp->request_count++;
Willy Tarreau51041c72007-09-09 21:56:53 +02004281
Willy Tarreau58f10d72006-12-04 02:26:12 +01004282#if defined(DEBUG_HASH)
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004283 Alert("get_srv_from_appsession\n");
Willy Tarreau51041c72007-09-09 21:56:53 +02004284 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreau58f10d72006-12-04 02:26:12 +01004285#endif
4286 if (asession_temp->serverid == NULL) {
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004287 /* TODO redispatch request */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004288 Alert("Found Application Session without matching server.\n");
4289 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004290 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004291 while (srv) {
4292 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004293 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004294 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004295 txn->flags &= ~TX_CK_MASK;
4296 txn->flags |= TX_CK_VALID;
4297 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004298 t->srv = srv;
4299 break;
4300 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01004301 txn->flags &= ~TX_CK_MASK;
4302 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004303 }
4304 }
4305 srv = srv->next;
4306 }
4307 }
4308}
4309
4310
Willy Tarreaub2513902006-12-17 14:52:38 +01004311/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004312 * In a GET or HEAD request, check if the requested URI matches the stats uri
4313 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01004314 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004315 * It is assumed that the request is either a HEAD or GET and that the
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004316 * t->be->uri_auth field is valid. An HTTP/401 response may be sent, or
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004317 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01004318 *
4319 * Returns 1 if the session's state changes, otherwise 0.
4320 */
4321int stats_check_uri_auth(struct session *t, struct proxy *backend)
4322{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004323 struct http_txn *txn = &t->txn;
Willy Tarreaub2513902006-12-17 14:52:38 +01004324 struct uri_auth *uri_auth = backend->uri_auth;
4325 struct user_auth *user;
4326 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004327 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01004328
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01004329 memset(&t->data_ctx.stats, 0, sizeof(t->data_ctx.stats));
4330
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004331 /* check URI size */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004332 if (uri_auth->uri_len > txn->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01004333 return 0;
4334
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004335 h = t->req->data + txn->req.sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004336
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004337 /* the URI is in h */
4338 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01004339 return 0;
4340
Willy Tarreaue7150cd2007-07-25 14:43:32 +02004341 h += uri_auth->uri_len;
4342 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 3) {
4343 if (memcmp(h, ";up", 3) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01004344 t->data_ctx.stats.flags |= STAT_HIDE_DOWN;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02004345 break;
4346 }
4347 h++;
4348 }
4349
4350 if (uri_auth->refresh) {
4351 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
4352 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 10) {
4353 if (memcmp(h, ";norefresh", 10) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01004354 t->data_ctx.stats.flags |= STAT_NO_REFRESH;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02004355 break;
4356 }
4357 h++;
4358 }
4359 }
4360
Willy Tarreau55bb8452007-10-17 18:44:57 +02004361 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
4362 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 4) {
4363 if (memcmp(h, ";csv", 4) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01004364 t->data_ctx.stats.flags |= STAT_FMT_CSV;
Willy Tarreau55bb8452007-10-17 18:44:57 +02004365 break;
4366 }
4367 h++;
4368 }
4369
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01004370 t->data_ctx.stats.flags |= STAT_SHOW_STAT | STAT_SHOW_INFO;
4371
Willy Tarreaub2513902006-12-17 14:52:38 +01004372 /* we are in front of a interceptable URI. Let's check
4373 * if there's an authentication and if it's valid.
4374 */
4375 user = uri_auth->users;
4376 if (!user) {
4377 /* no user auth required, it's OK */
4378 authenticated = 1;
4379 } else {
4380 authenticated = 0;
4381
4382 /* a user list is defined, we have to check.
4383 * skip 21 chars for "Authorization: Basic ".
4384 */
4385
4386 /* FIXME: this should move to an earlier place */
4387 cur_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004388 h = t->req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
4389 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
4390 int len = txn->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01004391 if (len > 14 &&
4392 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004393 txn->auth_hdr.str = h;
4394 txn->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01004395 break;
4396 }
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004397 h += len + txn->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01004398 }
4399
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004400 if (txn->auth_hdr.len < 21 ||
4401 memcmp(txn->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01004402 user = NULL;
4403
4404 while (user) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004405 if ((txn->auth_hdr.len == user->user_len + 14 + 7)
4406 && !memcmp(txn->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01004407 user->user_pwd, user->user_len)) {
4408 authenticated = 1;
4409 break;
4410 }
4411 user = user->next;
4412 }
4413 }
4414
4415 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01004416 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01004417
4418 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01004419 msg.str = trash;
4420 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004421 txn->status = 401;
Willy Tarreaudded32d2008-11-30 19:48:07 +01004422 stream_int_retnclose(t->req->prod, &msg);
Willy Tarreau2df28e82008-08-17 15:20:19 +02004423 t->req->analysers = 0;
Willy Tarreaub2513902006-12-17 14:52:38 +01004424 if (!(t->flags & SN_ERR_MASK))
4425 t->flags |= SN_ERR_PRXCOND;
4426 if (!(t->flags & SN_FINST_MASK))
4427 t->flags |= SN_FINST_R;
4428 return 1;
4429 }
4430
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01004431 /* The request is valid, the user is authenticated. Let's start sending
Willy Tarreaub2513902006-12-17 14:52:38 +01004432 * data.
4433 */
Willy Tarreauefb453c2008-10-26 20:49:47 +01004434 buffer_write_dis(t->req);
Willy Tarreau72b179a2008-08-28 16:01:32 +02004435 buffer_shutw_now(t->req);
4436 buffer_shutr_now(t->rep);
Willy Tarreau70089872008-06-13 21:12:51 +02004437 t->logs.tv_request = now;
Willy Tarreaub2513902006-12-17 14:52:38 +01004438 t->data_source = DATA_SRC_STATS;
4439 t->data_state = DATA_ST_INIT;
Willy Tarreau91e99932008-06-30 07:51:00 +02004440 t->task->nice = -32; /* small boost for HTTP statistics */
Willy Tarreau01bf8672008-12-07 18:03:29 +01004441 buffer_install_hijacker(t, t->rep, produce_content);
Willy Tarreaub2513902006-12-17 14:52:38 +01004442 return 1;
4443}
4444
Willy Tarreau4076a152009-04-02 15:18:36 +02004445/*
4446 * Capture a bad request or response and archive it in the proxy's structure.
4447 */
4448void http_capture_bad_message(struct error_snapshot *es, struct session *s,
4449 struct buffer *buf, struct http_msg *msg,
4450 struct proxy *other_end)
4451{
Willy Tarreau2df8d712009-05-01 11:33:17 +02004452 es->len = buf->r - (buf->data + msg->som);
4453 memcpy(es->buf, buf->data + msg->som, MIN(es->len, sizeof(es->buf)));
Willy Tarreau4076a152009-04-02 15:18:36 +02004454 if (msg->err_pos >= 0)
Willy Tarreau2df8d712009-05-01 11:33:17 +02004455 es->pos = msg->err_pos - msg->som;
Willy Tarreau4076a152009-04-02 15:18:36 +02004456 else
Willy Tarreau2df8d712009-05-01 11:33:17 +02004457 es->pos = buf->lr - (buf->data + msg->som);
Willy Tarreau4076a152009-04-02 15:18:36 +02004458 es->when = date; // user-visible date
4459 es->sid = s->uniq_id;
4460 es->srv = s->srv;
4461 es->oe = other_end;
4462 es->src = s->cli_addr;
4463}
Willy Tarreaub2513902006-12-17 14:52:38 +01004464
Willy Tarreaubaaee002006-06-26 02:48:02 +02004465/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01004466 * Print a debug line with a header
4467 */
4468void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
4469{
4470 int len, max;
4471 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
Willy Tarreau3a16b2c2008-08-28 08:54:27 +02004472 dir, (unsigned short)t->req->prod->fd, (unsigned short)t->req->cons->fd);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004473 max = end - start;
4474 UBOUND(max, sizeof(trash) - len - 1);
4475 len += strlcpy2(trash + len, start, max + 1);
4476 trash[len++] = '\n';
4477 write(1, trash, len);
4478}
4479
4480
Willy Tarreau8797c062007-05-07 00:55:35 +02004481/************************************************************************/
4482/* The code below is dedicated to ACL parsing and matching */
4483/************************************************************************/
4484
4485
4486
4487
4488/* 1. Check on METHOD
4489 * We use the pre-parsed method if it is known, and store its number as an
4490 * integer. If it is unknown, we use the pointer and the length.
4491 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02004492static int acl_parse_meth(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02004493{
4494 int len, meth;
4495
Willy Tarreauae8b7962007-06-09 23:10:04 +02004496 len = strlen(*text);
4497 meth = find_http_meth(*text, len);
Willy Tarreau8797c062007-05-07 00:55:35 +02004498
4499 pattern->val.i = meth;
4500 if (meth == HTTP_METH_OTHER) {
Willy Tarreauae8b7962007-06-09 23:10:04 +02004501 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02004502 if (!pattern->ptr.str)
4503 return 0;
4504 pattern->len = len;
4505 }
4506 return 1;
4507}
4508
Willy Tarreaud41f8d82007-06-10 10:06:18 +02004509static int
Willy Tarreau97be1452007-06-10 11:47:14 +02004510acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
4511 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02004512{
4513 int meth;
4514 struct http_txn *txn = l7;
4515
Willy Tarreaub6866442008-07-14 23:54:42 +02004516 if (!txn)
4517 return 0;
4518
Willy Tarreauc11416f2007-06-17 16:58:38 +02004519 if (txn->req.msg_state != HTTP_MSG_BODY)
4520 return 0;
4521
Willy Tarreau8797c062007-05-07 00:55:35 +02004522 meth = txn->meth;
4523 test->i = meth;
4524 if (meth == HTTP_METH_OTHER) {
Willy Tarreauc11416f2007-06-17 16:58:38 +02004525 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
4526 /* ensure the indexes are not affected */
4527 return 0;
Willy Tarreau8797c062007-05-07 00:55:35 +02004528 test->len = txn->req.sl.rq.m_l;
4529 test->ptr = txn->req.sol;
4530 }
4531 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
4532 return 1;
4533}
4534
4535static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
4536{
Willy Tarreauc8d7c962007-06-17 08:20:33 +02004537 int icase;
4538
Willy Tarreau8797c062007-05-07 00:55:35 +02004539 if (test->i != pattern->val.i)
Willy Tarreau11382812008-07-09 16:18:21 +02004540 return ACL_PAT_FAIL;
Willy Tarreau8797c062007-05-07 00:55:35 +02004541
4542 if (test->i != HTTP_METH_OTHER)
Willy Tarreau11382812008-07-09 16:18:21 +02004543 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02004544
4545 /* Other method, we must compare the strings */
4546 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +02004547 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +02004548
4549 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
4550 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) != 0) ||
4551 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +02004552 return ACL_PAT_FAIL;
4553 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02004554}
4555
4556/* 2. Check on Request/Status Version
4557 * We simply compare strings here.
4558 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02004559static int acl_parse_ver(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02004560{
Willy Tarreauae8b7962007-06-09 23:10:04 +02004561 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02004562 if (!pattern->ptr.str)
4563 return 0;
Willy Tarreauae8b7962007-06-09 23:10:04 +02004564 pattern->len = strlen(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02004565 return 1;
4566}
4567
Willy Tarreaud41f8d82007-06-10 10:06:18 +02004568static int
Willy Tarreau97be1452007-06-10 11:47:14 +02004569acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
4570 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02004571{
4572 struct http_txn *txn = l7;
4573 char *ptr;
4574 int len;
4575
Willy Tarreaub6866442008-07-14 23:54:42 +02004576 if (!txn)
4577 return 0;
4578
Willy Tarreauc11416f2007-06-17 16:58:38 +02004579 if (txn->req.msg_state != HTTP_MSG_BODY)
4580 return 0;
4581
Willy Tarreau8797c062007-05-07 00:55:35 +02004582 len = txn->req.sl.rq.v_l;
4583 ptr = txn->req.sol + txn->req.sl.rq.v - txn->req.som;
4584
4585 while ((len-- > 0) && (*ptr++ != '/'));
4586 if (len <= 0)
4587 return 0;
4588
4589 test->ptr = ptr;
4590 test->len = len;
4591
4592 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
4593 return 1;
4594}
4595
Willy Tarreaud41f8d82007-06-10 10:06:18 +02004596static int
Willy Tarreau97be1452007-06-10 11:47:14 +02004597acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
4598 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02004599{
4600 struct http_txn *txn = l7;
4601 char *ptr;
4602 int len;
4603
Willy Tarreaub6866442008-07-14 23:54:42 +02004604 if (!txn)
4605 return 0;
4606
Willy Tarreauc11416f2007-06-17 16:58:38 +02004607 if (txn->rsp.msg_state != HTTP_MSG_BODY)
4608 return 0;
4609
Willy Tarreau8797c062007-05-07 00:55:35 +02004610 len = txn->rsp.sl.st.v_l;
4611 ptr = txn->rsp.sol;
4612
4613 while ((len-- > 0) && (*ptr++ != '/'));
4614 if (len <= 0)
4615 return 0;
4616
4617 test->ptr = ptr;
4618 test->len = len;
4619
4620 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
4621 return 1;
4622}
4623
4624/* 3. Check on Status Code. We manipulate integers here. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02004625static int
Willy Tarreau97be1452007-06-10 11:47:14 +02004626acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, int dir,
4627 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02004628{
4629 struct http_txn *txn = l7;
4630 char *ptr;
4631 int len;
4632
Willy Tarreaub6866442008-07-14 23:54:42 +02004633 if (!txn)
4634 return 0;
4635
Willy Tarreauc11416f2007-06-17 16:58:38 +02004636 if (txn->rsp.msg_state != HTTP_MSG_BODY)
4637 return 0;
4638
Willy Tarreau8797c062007-05-07 00:55:35 +02004639 len = txn->rsp.sl.st.c_l;
4640 ptr = txn->rsp.sol + txn->rsp.sl.st.c - txn->rsp.som;
4641
4642 test->i = __strl2ui(ptr, len);
4643 test->flags = ACL_TEST_F_VOL_1ST;
4644 return 1;
4645}
4646
4647/* 4. Check on URL/URI. A pointer to the URI is stored. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02004648static int
Willy Tarreau97be1452007-06-10 11:47:14 +02004649acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
4650 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02004651{
4652 struct http_txn *txn = l7;
4653
Willy Tarreaub6866442008-07-14 23:54:42 +02004654 if (!txn)
4655 return 0;
4656
Willy Tarreauc11416f2007-06-17 16:58:38 +02004657 if (txn->req.msg_state != HTTP_MSG_BODY)
4658 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02004659
Willy Tarreauc11416f2007-06-17 16:58:38 +02004660 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
4661 /* ensure the indexes are not affected */
4662 return 0;
4663
Willy Tarreau8797c062007-05-07 00:55:35 +02004664 test->len = txn->req.sl.rq.u_l;
4665 test->ptr = txn->req.sol + txn->req.sl.rq.u;
4666
Willy Tarreauf3d25982007-05-08 22:45:09 +02004667 /* we do not need to set READ_ONLY because the data is in a buffer */
4668 test->flags = ACL_TEST_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +02004669 return 1;
4670}
4671
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01004672static int
4673acl_fetch_url_ip(struct proxy *px, struct session *l4, void *l7, int dir,
4674 struct acl_expr *expr, struct acl_test *test)
4675{
4676 struct http_txn *txn = l7;
4677
Willy Tarreaub6866442008-07-14 23:54:42 +02004678 if (!txn)
4679 return 0;
4680
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01004681 if (txn->req.msg_state != HTTP_MSG_BODY)
4682 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02004683
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01004684 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
4685 /* ensure the indexes are not affected */
4686 return 0;
4687
4688 /* Parse HTTP request */
4689 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
4690 test->ptr = (void *)&((struct sockaddr_in *)&l4->srv_addr)->sin_addr;
4691 test->i = AF_INET;
4692
4693 /*
4694 * If we are parsing url in frontend space, we prepare backend stage
4695 * to not parse again the same url ! optimization lazyness...
4696 */
4697 if (px->options & PR_O_HTTP_PROXY)
4698 l4->flags |= SN_ADDR_SET;
4699
4700 test->flags = ACL_TEST_F_READ_ONLY;
4701 return 1;
4702}
4703
4704static int
4705acl_fetch_url_port(struct proxy *px, struct session *l4, void *l7, int dir,
4706 struct acl_expr *expr, struct acl_test *test)
4707{
4708 struct http_txn *txn = l7;
4709
Willy Tarreaub6866442008-07-14 23:54:42 +02004710 if (!txn)
4711 return 0;
4712
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01004713 if (txn->req.msg_state != HTTP_MSG_BODY)
4714 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02004715
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01004716 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
4717 /* ensure the indexes are not affected */
4718 return 0;
4719
4720 /* Same optimization as url_ip */
4721 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
4722 test->i = ntohs(((struct sockaddr_in *)&l4->srv_addr)->sin_port);
4723
4724 if (px->options & PR_O_HTTP_PROXY)
4725 l4->flags |= SN_ADDR_SET;
4726
4727 test->flags = ACL_TEST_F_READ_ONLY;
4728 return 1;
4729}
4730
Willy Tarreauc11416f2007-06-17 16:58:38 +02004731/* 5. Check on HTTP header. A pointer to the beginning of the value is returned.
4732 * This generic function is used by both acl_fetch_chdr() and acl_fetch_shdr().
4733 */
Willy Tarreau33a7e692007-06-10 19:45:56 +02004734static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02004735acl_fetch_hdr(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02004736 struct acl_expr *expr, struct acl_test *test)
4737{
4738 struct http_txn *txn = l7;
4739 struct hdr_idx *idx = &txn->hdr_idx;
4740 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02004741
Willy Tarreaub6866442008-07-14 23:54:42 +02004742 if (!txn)
4743 return 0;
4744
Willy Tarreau33a7e692007-06-10 19:45:56 +02004745 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
4746 /* search for header from the beginning */
4747 ctx->idx = 0;
4748
Willy Tarreau33a7e692007-06-10 19:45:56 +02004749 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
4750 test->flags |= ACL_TEST_F_FETCH_MORE;
4751 test->flags |= ACL_TEST_F_VOL_HDR;
4752 test->len = ctx->vlen;
4753 test->ptr = (char *)ctx->line + ctx->val;
4754 return 1;
4755 }
4756
4757 test->flags &= ~ACL_TEST_F_FETCH_MORE;
4758 test->flags |= ACL_TEST_F_VOL_HDR;
4759 return 0;
4760}
4761
Willy Tarreau33a7e692007-06-10 19:45:56 +02004762static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02004763acl_fetch_chdr(struct proxy *px, struct session *l4, void *l7, int dir,
4764 struct acl_expr *expr, struct acl_test *test)
4765{
4766 struct http_txn *txn = l7;
4767
Willy Tarreaub6866442008-07-14 23:54:42 +02004768 if (!txn)
4769 return 0;
4770
Willy Tarreauc11416f2007-06-17 16:58:38 +02004771 if (txn->req.msg_state != HTTP_MSG_BODY)
4772 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02004773
Willy Tarreauc11416f2007-06-17 16:58:38 +02004774 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
4775 /* ensure the indexes are not affected */
4776 return 0;
4777
4778 return acl_fetch_hdr(px, l4, txn, txn->req.sol, expr, test);
4779}
4780
4781static int
4782acl_fetch_shdr(struct proxy *px, struct session *l4, void *l7, int dir,
4783 struct acl_expr *expr, struct acl_test *test)
4784{
4785 struct http_txn *txn = l7;
4786
Willy Tarreaub6866442008-07-14 23:54:42 +02004787 if (!txn)
4788 return 0;
4789
Willy Tarreauc11416f2007-06-17 16:58:38 +02004790 if (txn->rsp.msg_state != HTTP_MSG_BODY)
4791 return 0;
4792
4793 return acl_fetch_hdr(px, l4, txn, txn->rsp.sol, expr, test);
4794}
4795
4796/* 6. Check on HTTP header count. The number of occurrences is returned.
4797 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
4798 */
4799static int
4800acl_fetch_hdr_cnt(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02004801 struct acl_expr *expr, struct acl_test *test)
4802{
4803 struct http_txn *txn = l7;
4804 struct hdr_idx *idx = &txn->hdr_idx;
4805 struct hdr_ctx ctx;
Willy Tarreau33a7e692007-06-10 19:45:56 +02004806 int cnt;
Willy Tarreau8797c062007-05-07 00:55:35 +02004807
Willy Tarreaub6866442008-07-14 23:54:42 +02004808 if (!txn)
4809 return 0;
4810
Willy Tarreau33a7e692007-06-10 19:45:56 +02004811 ctx.idx = 0;
4812 cnt = 0;
4813 while (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, &ctx))
4814 cnt++;
4815
4816 test->i = cnt;
4817 test->flags = ACL_TEST_F_VOL_HDR;
4818 return 1;
4819}
4820
Willy Tarreauc11416f2007-06-17 16:58:38 +02004821static int
4822acl_fetch_chdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
4823 struct acl_expr *expr, struct acl_test *test)
4824{
4825 struct http_txn *txn = l7;
4826
Willy Tarreaub6866442008-07-14 23:54:42 +02004827 if (!txn)
4828 return 0;
4829
Willy Tarreauc11416f2007-06-17 16:58:38 +02004830 if (txn->req.msg_state != HTTP_MSG_BODY)
4831 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02004832
Willy Tarreauc11416f2007-06-17 16:58:38 +02004833 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
4834 /* ensure the indexes are not affected */
4835 return 0;
4836
4837 return acl_fetch_hdr_cnt(px, l4, txn, txn->req.sol, expr, test);
4838}
4839
4840static int
4841acl_fetch_shdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
4842 struct acl_expr *expr, struct acl_test *test)
4843{
4844 struct http_txn *txn = l7;
4845
Willy Tarreaub6866442008-07-14 23:54:42 +02004846 if (!txn)
4847 return 0;
4848
Willy Tarreauc11416f2007-06-17 16:58:38 +02004849 if (txn->rsp.msg_state != HTTP_MSG_BODY)
4850 return 0;
4851
4852 return acl_fetch_hdr_cnt(px, l4, txn, txn->rsp.sol, expr, test);
4853}
4854
Willy Tarreau33a7e692007-06-10 19:45:56 +02004855/* 7. Check on HTTP header's integer value. The integer value is returned.
4856 * FIXME: the type is 'int', it may not be appropriate for everything.
Willy Tarreauc11416f2007-06-17 16:58:38 +02004857 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
Willy Tarreau33a7e692007-06-10 19:45:56 +02004858 */
4859static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02004860acl_fetch_hdr_val(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02004861 struct acl_expr *expr, struct acl_test *test)
4862{
4863 struct http_txn *txn = l7;
4864 struct hdr_idx *idx = &txn->hdr_idx;
4865 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02004866
Willy Tarreaub6866442008-07-14 23:54:42 +02004867 if (!txn)
4868 return 0;
4869
Willy Tarreau33a7e692007-06-10 19:45:56 +02004870 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
4871 /* search for header from the beginning */
4872 ctx->idx = 0;
4873
Willy Tarreau33a7e692007-06-10 19:45:56 +02004874 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
4875 test->flags |= ACL_TEST_F_FETCH_MORE;
4876 test->flags |= ACL_TEST_F_VOL_HDR;
4877 test->i = strl2ic((char *)ctx->line + ctx->val, ctx->vlen);
4878 return 1;
4879 }
4880
4881 test->flags &= ~ACL_TEST_F_FETCH_MORE;
4882 test->flags |= ACL_TEST_F_VOL_HDR;
4883 return 0;
4884}
4885
Willy Tarreauc11416f2007-06-17 16:58:38 +02004886static int
4887acl_fetch_chdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
4888 struct acl_expr *expr, struct acl_test *test)
4889{
4890 struct http_txn *txn = l7;
4891
Willy Tarreaub6866442008-07-14 23:54:42 +02004892 if (!txn)
4893 return 0;
4894
Willy Tarreauc11416f2007-06-17 16:58:38 +02004895 if (txn->req.msg_state != HTTP_MSG_BODY)
4896 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02004897
Willy Tarreauc11416f2007-06-17 16:58:38 +02004898 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
4899 /* ensure the indexes are not affected */
4900 return 0;
4901
4902 return acl_fetch_hdr_val(px, l4, txn, txn->req.sol, expr, test);
4903}
4904
4905static int
4906acl_fetch_shdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
4907 struct acl_expr *expr, struct acl_test *test)
4908{
4909 struct http_txn *txn = l7;
4910
Willy Tarreaub6866442008-07-14 23:54:42 +02004911 if (!txn)
4912 return 0;
4913
Willy Tarreauc11416f2007-06-17 16:58:38 +02004914 if (txn->rsp.msg_state != HTTP_MSG_BODY)
4915 return 0;
4916
4917 return acl_fetch_hdr_val(px, l4, txn, txn->rsp.sol, expr, test);
4918}
4919
Willy Tarreau737b0c12007-06-10 21:28:46 +02004920/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at
4921 * the first '/' after the possible hostname, and ends before the possible '?'.
4922 */
4923static int
4924acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
4925 struct acl_expr *expr, struct acl_test *test)
4926{
4927 struct http_txn *txn = l7;
4928 char *ptr, *end;
Willy Tarreau33a7e692007-06-10 19:45:56 +02004929
Willy Tarreaub6866442008-07-14 23:54:42 +02004930 if (!txn)
4931 return 0;
4932
Willy Tarreauc11416f2007-06-17 16:58:38 +02004933 if (txn->req.msg_state != HTTP_MSG_BODY)
4934 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02004935
Willy Tarreauc11416f2007-06-17 16:58:38 +02004936 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
4937 /* ensure the indexes are not affected */
4938 return 0;
4939
Willy Tarreau21d2af32008-02-14 20:25:24 +01004940 end = txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
4941 ptr = http_get_path(txn);
4942 if (!ptr)
Willy Tarreau737b0c12007-06-10 21:28:46 +02004943 return 0;
4944
4945 /* OK, we got the '/' ! */
4946 test->ptr = ptr;
4947
4948 while (ptr < end && *ptr != '?')
4949 ptr++;
4950
4951 test->len = ptr - test->ptr;
4952
4953 /* we do not need to set READ_ONLY because the data is in a buffer */
4954 test->flags = ACL_TEST_F_VOL_1ST;
4955 return 1;
4956}
4957
4958
Willy Tarreau8797c062007-05-07 00:55:35 +02004959
4960/************************************************************************/
4961/* All supported keywords must be declared here. */
4962/************************************************************************/
4963
4964/* Note: must not be declared <const> as its list will be overwritten */
4965static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02004966 { "method", acl_parse_meth, acl_fetch_meth, acl_match_meth, ACL_USE_L7REQ_PERMANENT },
4967 { "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str, ACL_USE_L7REQ_VOLATILE },
4968 { "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str, ACL_USE_L7RTR_VOLATILE },
4969 { "status", acl_parse_int, acl_fetch_stcode, acl_match_int, ACL_USE_L7RTR_PERMANENT },
Willy Tarreau8797c062007-05-07 00:55:35 +02004970
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02004971 { "url", acl_parse_str, acl_fetch_url, acl_match_str, ACL_USE_L7REQ_VOLATILE },
4972 { "url_beg", acl_parse_str, acl_fetch_url, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
4973 { "url_end", acl_parse_str, acl_fetch_url, acl_match_end, ACL_USE_L7REQ_VOLATILE },
4974 { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
4975 { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
4976 { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
4977 { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
4978 { "url_ip", acl_parse_ip, acl_fetch_url_ip, acl_match_ip, ACL_USE_L7REQ_VOLATILE },
4979 { "url_port", acl_parse_int, acl_fetch_url_port, acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau8797c062007-05-07 00:55:35 +02004980
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02004981 /* note: we should set hdr* to use ACL_USE_HDR_VOLATILE, and chdr* to use L7REQ_VOLATILE */
4982 { "hdr", acl_parse_str, acl_fetch_chdr, acl_match_str, ACL_USE_L7REQ_VOLATILE },
4983 { "hdr_reg", acl_parse_reg, acl_fetch_chdr, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
4984 { "hdr_beg", acl_parse_str, acl_fetch_chdr, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
4985 { "hdr_end", acl_parse_str, acl_fetch_chdr, acl_match_end, ACL_USE_L7REQ_VOLATILE },
4986 { "hdr_sub", acl_parse_str, acl_fetch_chdr, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
4987 { "hdr_dir", acl_parse_str, acl_fetch_chdr, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
4988 { "hdr_dom", acl_parse_str, acl_fetch_chdr, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
4989 { "hdr_cnt", acl_parse_int, acl_fetch_chdr_cnt,acl_match_int, ACL_USE_L7REQ_VOLATILE },
4990 { "hdr_val", acl_parse_int, acl_fetch_chdr_val,acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreauc11416f2007-06-17 16:58:38 +02004991
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02004992 { "shdr", acl_parse_str, acl_fetch_shdr, acl_match_str, ACL_USE_L7RTR_VOLATILE },
4993 { "shdr_reg", acl_parse_reg, acl_fetch_shdr, acl_match_reg, ACL_USE_L7RTR_VOLATILE },
4994 { "shdr_beg", acl_parse_str, acl_fetch_shdr, acl_match_beg, ACL_USE_L7RTR_VOLATILE },
4995 { "shdr_end", acl_parse_str, acl_fetch_shdr, acl_match_end, ACL_USE_L7RTR_VOLATILE },
4996 { "shdr_sub", acl_parse_str, acl_fetch_shdr, acl_match_sub, ACL_USE_L7RTR_VOLATILE },
4997 { "shdr_dir", acl_parse_str, acl_fetch_shdr, acl_match_dir, ACL_USE_L7RTR_VOLATILE },
4998 { "shdr_dom", acl_parse_str, acl_fetch_shdr, acl_match_dom, ACL_USE_L7RTR_VOLATILE },
4999 { "shdr_cnt", acl_parse_int, acl_fetch_shdr_cnt,acl_match_int, ACL_USE_L7RTR_VOLATILE },
5000 { "shdr_val", acl_parse_int, acl_fetch_shdr_val,acl_match_int, ACL_USE_L7RTR_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005001
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005002 { "path", acl_parse_str, acl_fetch_path, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5003 { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5004 { "path_beg", acl_parse_str, acl_fetch_path, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5005 { "path_end", acl_parse_str, acl_fetch_path, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5006 { "path_sub", acl_parse_str, acl_fetch_path, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5007 { "path_dir", acl_parse_str, acl_fetch_path, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5008 { "path_dom", acl_parse_str, acl_fetch_path, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005009
Willy Tarreauf3d25982007-05-08 22:45:09 +02005010 { NULL, NULL, NULL, NULL },
5011
5012#if 0
Willy Tarreau8797c062007-05-07 00:55:35 +02005013 { "line", acl_parse_str, acl_fetch_line, acl_match_str },
5014 { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg },
5015 { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg },
5016 { "line_end", acl_parse_str, acl_fetch_line, acl_match_end },
5017 { "line_sub", acl_parse_str, acl_fetch_line, acl_match_sub },
5018 { "line_dir", acl_parse_str, acl_fetch_line, acl_match_dir },
5019 { "line_dom", acl_parse_str, acl_fetch_line, acl_match_dom },
5020
Willy Tarreau8797c062007-05-07 00:55:35 +02005021 { "cook", acl_parse_str, acl_fetch_cook, acl_match_str },
5022 { "cook_reg", acl_parse_reg, acl_fetch_cook, acl_match_reg },
5023 { "cook_beg", acl_parse_str, acl_fetch_cook, acl_match_beg },
5024 { "cook_end", acl_parse_str, acl_fetch_cook, acl_match_end },
5025 { "cook_sub", acl_parse_str, acl_fetch_cook, acl_match_sub },
5026 { "cook_dir", acl_parse_str, acl_fetch_cook, acl_match_dir },
5027 { "cook_dom", acl_parse_str, acl_fetch_cook, acl_match_dom },
5028 { "cook_pst", acl_parse_none, acl_fetch_cook, acl_match_pst },
5029
5030 { "auth_user", acl_parse_str, acl_fetch_user, acl_match_str },
5031 { "auth_regex", acl_parse_reg, acl_fetch_user, acl_match_reg },
5032 { "auth_clear", acl_parse_str, acl_fetch_auth, acl_match_str },
5033 { "auth_md5", acl_parse_str, acl_fetch_auth, acl_match_md5 },
5034 { NULL, NULL, NULL, NULL },
5035#endif
5036}};
5037
5038
5039__attribute__((constructor))
5040static void __http_protocol_init(void)
5041{
5042 acl_register_keywords(&acl_kws);
5043}
5044
5045
Willy Tarreau58f10d72006-12-04 02:26:12 +01005046/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02005047 * Local variables:
5048 * c-indent-level: 8
5049 * c-basic-offset: 8
5050 * End:
5051 */