blob: 3a8ab9aa70e5b830d71227f1ba1ac6f3ae21f9a3 [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
Willy Tarreau8797c062007-05-07 00:55:35 +020038#include <types/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020039#include <types/capture.h>
40#include <types/client.h>
41#include <types/global.h>
42#include <types/httperr.h>
43#include <types/polling.h>
44#include <types/proxy.h>
45#include <types/server.h>
46
Willy Tarreau8797c062007-05-07 00:55:35 +020047#include <proto/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020048#include <proto/backend.h>
49#include <proto/buffers.h>
Willy Tarreau91861262007-10-17 17:06:05 +020050#include <proto/dumpstats.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020051#include <proto/fd.h>
52#include <proto/log.h>
Willy Tarreau58f10d72006-12-04 02:26:12 +010053#include <proto/hdr_idx.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020054#include <proto/proto_http.h>
55#include <proto/queue.h>
Willy Tarreau91861262007-10-17 17:06:05 +020056#include <proto/senddata.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020057#include <proto/session.h>
58#include <proto/task.h>
59
Willy Tarreau6d1a9882007-01-07 02:03:04 +010060#ifdef CONFIG_HAP_TCPSPLICE
61#include <libtcpsplice.h>
62#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020063
Willy Tarreau58f10d72006-12-04 02:26:12 +010064#define DEBUG_PARSE_NO_SPEEDUP
65#undef DEBUG_PARSE_NO_SPEEDUP
66
Willy Tarreau976f1ee2006-12-17 10:06:03 +010067/* This is used to perform a quick jump as an alternative to a break/continue
68 * instruction. The first argument is the label for normal operation, and the
69 * second one is the break/continue instruction in the no_speedup mode.
70 */
71
72#ifdef DEBUG_PARSE_NO_SPEEDUP
73#define QUICK_JUMP(x,y) y
74#else
75#define QUICK_JUMP(x,y) goto x
76#endif
77
Willy Tarreau1c47f852006-07-09 08:22:27 +020078/* This is used by remote monitoring */
Willy Tarreau0f772532006-12-23 20:51:41 +010079const char HTTP_200[] =
Willy Tarreau1c47f852006-07-09 08:22:27 +020080 "HTTP/1.0 200 OK\r\n"
81 "Cache-Control: no-cache\r\n"
82 "Connection: close\r\n"
83 "Content-Type: text/html\r\n"
84 "\r\n"
85 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
86
Willy Tarreau0f772532006-12-23 20:51:41 +010087const struct chunk http_200_chunk = {
88 .str = (char *)&HTTP_200,
89 .len = sizeof(HTTP_200)-1
90};
91
Willy Tarreaub463dfb2008-06-07 23:08:56 +020092const char *HTTP_301 =
93 "HTTP/1.0 301 Moved Permantenly\r\n"
94 "Cache-Control: no-cache\r\n"
95 "Connection: close\r\n"
96 "Location: "; /* not terminated since it will be concatenated with the URL */
97
Willy Tarreau0f772532006-12-23 20:51:41 +010098const char *HTTP_302 =
99 "HTTP/1.0 302 Found\r\n"
100 "Cache-Control: no-cache\r\n"
101 "Connection: close\r\n"
102 "Location: "; /* not terminated since it will be concatenated with the URL */
103
104/* same as 302 except that the browser MUST retry with the GET method */
105const char *HTTP_303 =
106 "HTTP/1.0 303 See Other\r\n"
107 "Cache-Control: no-cache\r\n"
108 "Connection: close\r\n"
109 "Location: "; /* not terminated since it will be concatenated with the URL */
110
Willy Tarreaubaaee002006-06-26 02:48:02 +0200111/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
112const char *HTTP_401_fmt =
113 "HTTP/1.0 401 Unauthorized\r\n"
114 "Cache-Control: no-cache\r\n"
115 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +0200116 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200117 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
118 "\r\n"
119 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
120
Willy Tarreau0f772532006-12-23 20:51:41 +0100121
122const int http_err_codes[HTTP_ERR_SIZE] = {
123 [HTTP_ERR_400] = 400,
124 [HTTP_ERR_403] = 403,
125 [HTTP_ERR_408] = 408,
126 [HTTP_ERR_500] = 500,
127 [HTTP_ERR_502] = 502,
128 [HTTP_ERR_503] = 503,
129 [HTTP_ERR_504] = 504,
130};
131
Willy Tarreau80587432006-12-24 17:47:20 +0100132static const char *http_err_msgs[HTTP_ERR_SIZE] = {
Willy Tarreau0f772532006-12-23 20:51:41 +0100133 [HTTP_ERR_400] =
Willy Tarreau80587432006-12-24 17:47:20 +0100134 "HTTP/1.0 400 Bad request\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +0100135 "Cache-Control: no-cache\r\n"
136 "Connection: close\r\n"
137 "Content-Type: text/html\r\n"
138 "\r\n"
139 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
140
141 [HTTP_ERR_403] =
142 "HTTP/1.0 403 Forbidden\r\n"
143 "Cache-Control: no-cache\r\n"
144 "Connection: close\r\n"
145 "Content-Type: text/html\r\n"
146 "\r\n"
147 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
148
149 [HTTP_ERR_408] =
150 "HTTP/1.0 408 Request Time-out\r\n"
151 "Cache-Control: no-cache\r\n"
152 "Connection: close\r\n"
153 "Content-Type: text/html\r\n"
154 "\r\n"
155 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
156
157 [HTTP_ERR_500] =
158 "HTTP/1.0 500 Server Error\r\n"
159 "Cache-Control: no-cache\r\n"
160 "Connection: close\r\n"
161 "Content-Type: text/html\r\n"
162 "\r\n"
163 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n",
164
165 [HTTP_ERR_502] =
166 "HTTP/1.0 502 Bad Gateway\r\n"
167 "Cache-Control: no-cache\r\n"
168 "Connection: close\r\n"
169 "Content-Type: text/html\r\n"
170 "\r\n"
171 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n",
172
173 [HTTP_ERR_503] =
174 "HTTP/1.0 503 Service Unavailable\r\n"
175 "Cache-Control: no-cache\r\n"
176 "Connection: close\r\n"
177 "Content-Type: text/html\r\n"
178 "\r\n"
179 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n",
180
181 [HTTP_ERR_504] =
182 "HTTP/1.0 504 Gateway Time-out\r\n"
183 "Cache-Control: no-cache\r\n"
184 "Connection: close\r\n"
185 "Content-Type: text/html\r\n"
186 "\r\n"
187 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n",
188
189};
190
Willy Tarreau80587432006-12-24 17:47:20 +0100191/* We must put the messages here since GCC cannot initialize consts depending
192 * on strlen().
193 */
194struct chunk http_err_chunks[HTTP_ERR_SIZE];
195
Willy Tarreau42250582007-04-01 01:30:43 +0200196#define FD_SETS_ARE_BITFIELDS
197#ifdef FD_SETS_ARE_BITFIELDS
198/*
199 * This map is used with all the FD_* macros to check whether a particular bit
200 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
201 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
202 * byte should be encoded. Be careful to always pass bytes from 0 to 255
203 * exclusively to the macros.
204 */
205fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
206fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
207
208#else
209#error "Check if your OS uses bitfields for fd_sets"
210#endif
211
Willy Tarreau80587432006-12-24 17:47:20 +0100212void init_proto_http()
213{
Willy Tarreau42250582007-04-01 01:30:43 +0200214 int i;
215 char *tmp;
Willy Tarreau80587432006-12-24 17:47:20 +0100216 int msg;
Willy Tarreau42250582007-04-01 01:30:43 +0200217
Willy Tarreau80587432006-12-24 17:47:20 +0100218 for (msg = 0; msg < HTTP_ERR_SIZE; msg++) {
219 if (!http_err_msgs[msg]) {
220 Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n", msg);
221 abort();
222 }
223
224 http_err_chunks[msg].str = (char *)http_err_msgs[msg];
225 http_err_chunks[msg].len = strlen(http_err_msgs[msg]);
226 }
Willy Tarreau42250582007-04-01 01:30:43 +0200227
228 /* initialize the log header encoding map : '{|}"#' should be encoded with
229 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
230 * URL encoding only requires '"', '#' to be encoded as well as non-
231 * printable characters above.
232 */
233 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
234 memset(url_encode_map, 0, sizeof(url_encode_map));
235 for (i = 0; i < 32; i++) {
236 FD_SET(i, hdr_encode_map);
237 FD_SET(i, url_encode_map);
238 }
239 for (i = 127; i < 256; i++) {
240 FD_SET(i, hdr_encode_map);
241 FD_SET(i, url_encode_map);
242 }
243
244 tmp = "\"#{|}";
245 while (*tmp) {
246 FD_SET(*tmp, hdr_encode_map);
247 tmp++;
248 }
249
250 tmp = "\"#";
251 while (*tmp) {
252 FD_SET(*tmp, url_encode_map);
253 tmp++;
254 }
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200255
256 /* memory allocations */
257 pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED);
Willy Tarreau086b3b42007-05-13 21:45:51 +0200258 pool2_capture = create_pool("capture", CAPTURE_LEN, MEM_F_SHARED);
Willy Tarreau80587432006-12-24 17:47:20 +0100259}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200260
Willy Tarreau53b6c742006-12-17 13:37:46 +0100261/*
262 * We have 26 list of methods (1 per first letter), each of which can have
263 * up to 3 entries (2 valid, 1 null).
264 */
265struct http_method_desc {
266 http_meth_t meth;
267 int len;
268 const char text[8];
269};
270
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100271const struct http_method_desc http_methods[26][3] = {
Willy Tarreau53b6c742006-12-17 13:37:46 +0100272 ['C' - 'A'] = {
273 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
274 },
275 ['D' - 'A'] = {
276 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
277 },
278 ['G' - 'A'] = {
279 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
280 },
281 ['H' - 'A'] = {
282 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
283 },
284 ['P' - 'A'] = {
285 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
286 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
287 },
288 ['T' - 'A'] = {
289 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
290 },
291 /* rest is empty like this :
292 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
293 */
294};
295
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100296/* It is about twice as fast on recent architectures to lookup a byte in a
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +0200297 * table than to perform a boolean AND or OR between two tests. Refer to
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100298 * RFC2616 for those chars.
299 */
300
301const char http_is_spht[256] = {
302 [' '] = 1, ['\t'] = 1,
303};
304
305const char http_is_crlf[256] = {
306 ['\r'] = 1, ['\n'] = 1,
307};
308
309const char http_is_lws[256] = {
310 [' '] = 1, ['\t'] = 1,
311 ['\r'] = 1, ['\n'] = 1,
312};
313
314const char http_is_sep[256] = {
315 ['('] = 1, [')'] = 1, ['<'] = 1, ['>'] = 1,
316 ['@'] = 1, [','] = 1, [';'] = 1, [':'] = 1,
317 ['"'] = 1, ['/'] = 1, ['['] = 1, [']'] = 1,
318 ['{'] = 1, ['}'] = 1, ['?'] = 1, ['='] = 1,
319 [' '] = 1, ['\t'] = 1, ['\\'] = 1,
320};
321
322const char http_is_ctl[256] = {
323 [0 ... 31] = 1,
324 [127] = 1,
325};
326
327/*
328 * A token is any ASCII char that is neither a separator nor a CTL char.
329 * Do not overwrite values in assignment since gcc-2.95 will not handle
330 * them correctly. Instead, define every non-CTL char's status.
331 */
332const char http_is_token[256] = {
333 [' '] = 0, ['!'] = 1, ['"'] = 0, ['#'] = 1,
334 ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1,
335 ['('] = 0, [')'] = 0, ['*'] = 1, ['+'] = 1,
336 [','] = 0, ['-'] = 1, ['.'] = 1, ['/'] = 0,
337 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1,
338 ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1,
339 ['8'] = 1, ['9'] = 1, [':'] = 0, [';'] = 0,
340 ['<'] = 0, ['='] = 0, ['>'] = 0, ['?'] = 0,
341 ['@'] = 0, ['A'] = 1, ['B'] = 1, ['C'] = 1,
342 ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1,
343 ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1,
344 ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1,
345 ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1,
346 ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1,
347 ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 0,
348 ['\\'] = 0, [']'] = 0, ['^'] = 1, ['_'] = 1,
349 ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1,
350 ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1,
351 ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1,
352 ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1,
353 ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1,
354 ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1,
355 ['x'] = 1, ['y'] = 1, ['z'] = 1, ['{'] = 0,
356 ['|'] = 1, ['}'] = 0, ['~'] = 1,
357};
358
359
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100360/*
361 * An http ver_token is any ASCII which can be found in an HTTP version,
362 * which includes 'H', 'T', 'P', '/', '.' and any digit.
363 */
364const char http_is_ver_token[256] = {
365 ['.'] = 1, ['/'] = 1,
366 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1,
367 ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1,
368 ['H'] = 1, ['P'] = 1, ['T'] = 1,
369};
370
371
Willy Tarreaubaaee002006-06-26 02:48:02 +0200372#ifdef DEBUG_FULL
373static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
374static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
375#endif
376
Willy Tarreau42250582007-04-01 01:30:43 +0200377static void http_sess_log(struct session *s);
378
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100379/*
380 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
381 * CRLF. Text length is measured first, so it cannot be NULL.
382 * The header is also automatically added to the index <hdr_idx>, and the end
383 * of headers is automatically adjusted. The number of bytes added is returned
384 * on success, otherwise <0 is returned indicating an error.
385 */
386int http_header_add_tail(struct buffer *b, struct http_msg *msg,
387 struct hdr_idx *hdr_idx, const char *text)
388{
389 int bytes, len;
390
391 len = strlen(text);
392 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
393 if (!bytes)
394 return -1;
395 msg->eoh += bytes;
396 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
397}
398
399/*
400 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
401 * CRLF. <len> bytes are copied, not counting the CRLF. If <text> is NULL, then
402 * the buffer is only opened and the space reserved, but nothing is copied.
403 * The header is also automatically added to the index <hdr_idx>, and the end
404 * of headers is automatically adjusted. The number of bytes added is returned
405 * on success, otherwise <0 is returned indicating an error.
406 */
407int http_header_add_tail2(struct buffer *b, struct http_msg *msg,
408 struct hdr_idx *hdr_idx, const char *text, int len)
409{
410 int bytes;
411
412 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
413 if (!bytes)
414 return -1;
415 msg->eoh += bytes;
416 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
417}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200418
419/*
Willy Tarreauaa9dce32007-03-18 23:50:16 +0100420 * Checks if <hdr> is exactly <name> for <len> chars, and ends with a colon.
421 * If so, returns the position of the first non-space character relative to
422 * <hdr>, or <end>-<hdr> if not found before. If no value is found, it tries
423 * to return a pointer to the place after the first space. Returns 0 if the
424 * header name does not match. Checks are case-insensitive.
425 */
426int http_header_match2(const char *hdr, const char *end,
427 const char *name, int len)
428{
429 const char *val;
430
431 if (hdr + len >= end)
432 return 0;
433 if (hdr[len] != ':')
434 return 0;
435 if (strncasecmp(hdr, name, len) != 0)
436 return 0;
437 val = hdr + len + 1;
438 while (val < end && HTTP_IS_SPHT(*val))
439 val++;
440 if ((val >= end) && (len + 2 <= end - hdr))
441 return len + 2; /* we may replace starting from second space */
442 return val - hdr;
443}
444
Willy Tarreau33a7e692007-06-10 19:45:56 +0200445/* Find the end of the header value contained between <s> and <e>.
446 * See RFC2616, par 2.2 for more information. Note that it requires
447 * a valid header to return a valid result.
448 */
449const char *find_hdr_value_end(const char *s, const char *e)
450{
451 int quoted, qdpair;
452
453 quoted = qdpair = 0;
454 for (; s < e; s++) {
455 if (qdpair) qdpair = 0;
456 else if (quoted && *s == '\\') qdpair = 1;
457 else if (quoted && *s == '"') quoted = 0;
458 else if (*s == '"') quoted = 1;
459 else if (*s == ',') return s;
460 }
461 return s;
462}
463
464/* Find the first or next occurrence of header <name> in message buffer <sol>
465 * using headers index <idx>, and return it in the <ctx> structure. This
466 * structure holds everything necessary to use the header and find next
467 * occurrence. If its <idx> member is 0, the header is searched from the
468 * beginning. Otherwise, the next occurrence is returned. The function returns
469 * 1 when it finds a value, and 0 when there is no more.
470 */
471int http_find_header2(const char *name, int len,
472 const char *sol, struct hdr_idx *idx,
473 struct hdr_ctx *ctx)
474{
475 __label__ return_hdr, next_hdr;
476 const char *eol, *sov;
477 int cur_idx;
478
479 if (ctx->idx) {
480 /* We have previously returned a value, let's search
481 * another one on the same line.
482 */
483 cur_idx = ctx->idx;
484 sol = ctx->line;
485 sov = sol + ctx->val + ctx->vlen;
486 eol = sol + idx->v[cur_idx].len;
487
488 if (sov >= eol)
489 /* no more values in this header */
490 goto next_hdr;
491
492 /* values remaining for this header, skip the comma */
493 sov++;
494 while (sov < eol && http_is_lws[(unsigned char)*sov])
495 sov++;
496
497 goto return_hdr;
498 }
499
500 /* first request for this header */
501 sol += hdr_idx_first_pos(idx);
502 cur_idx = hdr_idx_first_idx(idx);
503
504 while (cur_idx) {
505 eol = sol + idx->v[cur_idx].len;
506
Willy Tarreau1ad7c6d2007-06-10 21:42:55 +0200507 if (len == 0) {
508 /* No argument was passed, we want any header.
509 * To achieve this, we simply build a fake request. */
510 while (sol + len < eol && sol[len] != ':')
511 len++;
512 name = sol;
513 }
514
Willy Tarreau33a7e692007-06-10 19:45:56 +0200515 if ((len < eol - sol) &&
516 (sol[len] == ':') &&
517 (strncasecmp(sol, name, len) == 0)) {
518
519 sov = sol + len + 1;
520 while (sov < eol && http_is_lws[(unsigned char)*sov])
521 sov++;
522 return_hdr:
523 ctx->line = sol;
524 ctx->idx = cur_idx;
525 ctx->val = sov - sol;
526
527 eol = find_hdr_value_end(sov, eol);
528 ctx->vlen = eol - sov;
529 return 1;
530 }
531 next_hdr:
532 sol = eol + idx->v[cur_idx].cr + 1;
533 cur_idx = idx->v[cur_idx].next;
534 }
535 return 0;
536}
537
538int http_find_header(const char *name,
539 const char *sol, struct hdr_idx *idx,
540 struct hdr_ctx *ctx)
541{
542 return http_find_header2(name, strlen(name), sol, idx, ctx);
543}
544
Willy Tarreaubaaee002006-06-26 02:48:02 +0200545/* This function turns the server state into the SV_STCLOSE, and sets
Willy Tarreau0f772532006-12-23 20:51:41 +0100546 * indicators accordingly. Note that if <status> is 0, or if the message
547 * pointer is NULL, then no message is returned.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200548 */
549void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreau0f772532006-12-23 20:51:41 +0100550 int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200551{
552 t->srv_state = SV_STCLOSE;
Willy Tarreau0f772532006-12-23 20:51:41 +0100553 if (status > 0 && msg) {
Willy Tarreau3bac9ff2007-03-18 17:31:28 +0100554 t->txn.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100555 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100556 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200557 }
558 if (!(t->flags & SN_ERR_MASK))
559 t->flags |= err;
560 if (!(t->flags & SN_FINST_MASK))
561 t->flags |= finst;
562}
563
Willy Tarreau80587432006-12-24 17:47:20 +0100564/* This function returns the appropriate error location for the given session
565 * and message.
566 */
567
568struct chunk *error_message(struct session *s, int msgnum)
569{
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200570 if (s->be->errmsg[msgnum].str)
571 return &s->be->errmsg[msgnum];
Willy Tarreau80587432006-12-24 17:47:20 +0100572 else if (s->fe->errmsg[msgnum].str)
573 return &s->fe->errmsg[msgnum];
574 else
575 return &http_err_chunks[msgnum];
576}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200577
Willy Tarreau53b6c742006-12-17 13:37:46 +0100578/*
579 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
580 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
581 */
582static http_meth_t find_http_meth(const char *str, const int len)
583{
584 unsigned char m;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100585 const struct http_method_desc *h;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100586
587 m = ((unsigned)*str - 'A');
588
589 if (m < 26) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100590 for (h = http_methods[m]; h->len > 0; h++) {
591 if (unlikely(h->len != len))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100592 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100593 if (likely(memcmp(str, h->text, h->len) == 0))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100594 return h->meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100595 };
596 return HTTP_METH_OTHER;
597 }
598 return HTTP_METH_NONE;
599
600}
601
Willy Tarreau21d2af32008-02-14 20:25:24 +0100602/* Parse the URI from the given transaction (which is assumed to be in request
603 * phase) and look for the "/" beginning the PATH. If not found, return NULL.
604 * It is returned otherwise.
605 */
606static char *
607http_get_path(struct http_txn *txn)
608{
609 char *ptr, *end;
610
611 ptr = txn->req.sol + txn->req.sl.rq.u;
612 end = ptr + txn->req.sl.rq.u_l;
613
614 if (ptr >= end)
615 return NULL;
616
617 /* RFC2616, par. 5.1.2 :
618 * Request-URI = "*" | absuri | abspath | authority
619 */
620
621 if (*ptr == '*')
622 return NULL;
623
624 if (isalpha((unsigned char)*ptr)) {
625 /* this is a scheme as described by RFC3986, par. 3.1 */
626 ptr++;
627 while (ptr < end &&
628 (isalnum((unsigned char)*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.'))
629 ptr++;
630 /* skip '://' */
631 if (ptr == end || *ptr++ != ':')
632 return NULL;
633 if (ptr == end || *ptr++ != '/')
634 return NULL;
635 if (ptr == end || *ptr++ != '/')
636 return NULL;
637 }
638 /* skip [user[:passwd]@]host[:[port]] */
639
640 while (ptr < end && *ptr != '/')
641 ptr++;
642
643 if (ptr == end)
644 return NULL;
645
646 /* OK, we got the '/' ! */
647 return ptr;
648}
649
Willy Tarreaubaaee002006-06-26 02:48:02 +0200650/* Processes the client and server jobs of a session task, then
651 * puts it back to the wait queue in a clean state, or
652 * cleans up its resources if it must be deleted. Returns
653 * the time the task accepts to wait, or TIME_ETERNITY for
654 * infinity.
655 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200656void process_session(struct task *t, int *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200657{
658 struct session *s = t->context;
659 int fsm_resync = 0;
660
661 do {
662 fsm_resync = 0;
663 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
664 fsm_resync |= process_cli(s);
665 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
666 fsm_resync |= process_srv(s);
667 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
668 } while (fsm_resync);
669
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200670 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100671
672 if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
673 session_process_counters(s);
674
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200675 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
676 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200677
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200678 t->expire = tick_first(tick_first(s->req->rex, s->req->wex),
679 tick_first(s->rep->rex, s->rep->wex));
680 t->expire = tick_first(t->expire, s->req->cex);
Willy Tarreau036fae02008-01-06 13:24:40 +0100681 if (s->cli_state == CL_STHEADERS)
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200682 t->expire = tick_first(t->expire, s->txn.exp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200683
684 /* restore t to its place in the task list */
685 task_queue(t);
686
Willy Tarreaud825eef2007-05-12 22:35:00 +0200687 *next = t->expire;
688 return; /* nothing more to do */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200689 }
690
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100691 s->fe->feconn--;
692 if (s->flags & SN_BE_ASSIGNED)
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200693 s->be->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200694 actconn--;
695
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200696 if (unlikely((global.mode & MODE_DEBUG) &&
697 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200698 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100699 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200700 s->uniq_id, s->be->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100701 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200702 write(1, trash, len);
703 }
704
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200705 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100706 session_process_counters(s);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200707
708 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200709 if (s->logs.logwait &&
710 !(s->flags & SN_MONITOR) &&
Willy Tarreau42250582007-04-01 01:30:43 +0200711 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total)) {
712 if (s->fe->to_log & LW_REQ)
713 http_sess_log(s);
714 else
715 tcp_sess_log(s);
716 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200717
718 /* the task MUST not be in the run queue anymore */
719 task_delete(t);
720 session_free(s);
721 task_free(t);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200722 *next = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200723}
724
725
Willy Tarreau42250582007-04-01 01:30:43 +0200726extern const char sess_term_cond[8];
727extern const char sess_fin_state[8];
728extern const char *monthname[12];
729const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
730const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
731 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
732 unknown, Set-cookie Rewritten */
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200733struct pool_head *pool2_requri;
Willy Tarreau086b3b42007-05-13 21:45:51 +0200734struct pool_head *pool2_capture;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100735
Willy Tarreau42250582007-04-01 01:30:43 +0200736/*
737 * send a log for the session when we have enough info about it.
738 * Will not log if the frontend has no log defined.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100739 */
Willy Tarreau42250582007-04-01 01:30:43 +0200740static void http_sess_log(struct session *s)
741{
742 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
743 struct proxy *fe = s->fe;
744 struct proxy *be = s->be;
745 struct proxy *prx_log;
746 struct http_txn *txn = &s->txn;
747 int tolog;
748 char *uri, *h;
749 char *svid;
Willy Tarreaufe944602007-10-25 10:34:16 +0200750 struct tm tm;
Willy Tarreau42250582007-04-01 01:30:43 +0200751 static char tmpline[MAX_SYSLOG_LEN];
Willy Tarreau70089872008-06-13 21:12:51 +0200752 int t_request;
Willy Tarreau42250582007-04-01 01:30:43 +0200753 int hdr;
754
755 if (fe->logfac1 < 0 && fe->logfac2 < 0)
756 return;
757 prx_log = fe;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100758
Willy Tarreau42250582007-04-01 01:30:43 +0200759 if (s->cli_addr.ss_family == AF_INET)
760 inet_ntop(AF_INET,
761 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
762 pn, sizeof(pn));
763 else
764 inet_ntop(AF_INET6,
765 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
766 pn, sizeof(pn));
767
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200768 get_localtime(s->logs.accept_date.tv_sec, &tm);
Willy Tarreau42250582007-04-01 01:30:43 +0200769
770 /* FIXME: let's limit ourselves to frontend logging for now. */
771 tolog = fe->to_log;
772
773 h = tmpline;
774 if (fe->to_log & LW_REQHDR &&
775 txn->req.cap &&
776 (h < tmpline + sizeof(tmpline) - 10)) {
777 *(h++) = ' ';
778 *(h++) = '{';
779 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
780 if (hdr)
781 *(h++) = '|';
782 if (txn->req.cap[hdr] != NULL)
783 h = encode_string(h, tmpline + sizeof(tmpline) - 7,
784 '#', hdr_encode_map, txn->req.cap[hdr]);
785 }
786 *(h++) = '}';
787 }
788
789 if (fe->to_log & LW_RSPHDR &&
790 txn->rsp.cap &&
791 (h < tmpline + sizeof(tmpline) - 7)) {
792 *(h++) = ' ';
793 *(h++) = '{';
794 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
795 if (hdr)
796 *(h++) = '|';
797 if (txn->rsp.cap[hdr] != NULL)
798 h = encode_string(h, tmpline + sizeof(tmpline) - 4,
799 '#', hdr_encode_map, txn->rsp.cap[hdr]);
800 }
801 *(h++) = '}';
802 }
803
804 if (h < tmpline + sizeof(tmpline) - 4) {
805 *(h++) = ' ';
806 *(h++) = '"';
807 uri = txn->uri ? txn->uri : "<BADREQ>";
808 h = encode_string(h, tmpline + sizeof(tmpline) - 1,
809 '#', url_encode_map, uri);
810 *(h++) = '"';
811 }
812 *h = '\0';
813
814 svid = (tolog & LW_SVID) ?
815 (s->data_source != DATA_SRC_STATS) ?
816 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
817
Willy Tarreau70089872008-06-13 21:12:51 +0200818 t_request = -1;
819 if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
820 t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
821
Willy Tarreau42250582007-04-01 01:30:43 +0200822 send_log(prx_log, LOG_INFO,
823 "%s:%d [%02d/%s/%04d:%02d:%02d:%02d.%03d]"
824 " %s %s/%s %d/%d/%d/%d/%s%d %d %s%lld"
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100825 " %s %s %c%c%c%c %d/%d/%d/%d/%s%u %d/%d%s\n",
Willy Tarreau42250582007-04-01 01:30:43 +0200826 pn,
827 (s->cli_addr.ss_family == AF_INET) ?
828 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
829 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
Willy Tarreaufe944602007-10-25 10:34:16 +0200830 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200831 tm.tm_hour, tm.tm_min, tm.tm_sec, s->logs.accept_date.tv_usec/1000,
Willy Tarreau42250582007-04-01 01:30:43 +0200832 fe->id, be->id, svid,
Willy Tarreau70089872008-06-13 21:12:51 +0200833 t_request,
834 (s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1,
Willy Tarreau42250582007-04-01 01:30:43 +0200835 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
836 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
837 (tolog & LW_BYTES) ? "" : "+", s->logs.t_close,
838 txn->status,
Willy Tarreau8b3977f2008-01-18 11:16:32 +0100839 (tolog & LW_BYTES) ? "" : "+", s->logs.bytes_out,
Willy Tarreau42250582007-04-01 01:30:43 +0200840 txn->cli_cookie ? txn->cli_cookie : "-",
841 txn->srv_cookie ? txn->srv_cookie : "-",
842 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
843 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
844 (be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-',
845 (be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-',
846 actconn, fe->feconn, be->beconn, s->srv ? s->srv->cur_sess : 0,
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100847 (s->flags & SN_REDISP)?"+":"",
848 (s->conn_retries>0)?(be->conn_retries - s->conn_retries):be->conn_retries,
Willy Tarreau42250582007-04-01 01:30:43 +0200849 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
850
851 s->logs.logwait = 0;
852}
853
Willy Tarreau117f59e2007-03-04 18:17:17 +0100854
855/*
856 * Capture headers from message starting at <som> according to header list
857 * <cap_hdr>, and fill the <idx> structure appropriately.
858 */
859void capture_headers(char *som, struct hdr_idx *idx,
860 char **cap, struct cap_hdr *cap_hdr)
861{
862 char *eol, *sol, *col, *sov;
863 int cur_idx;
864 struct cap_hdr *h;
865 int len;
866
867 sol = som + hdr_idx_first_pos(idx);
868 cur_idx = hdr_idx_first_idx(idx);
869
870 while (cur_idx) {
871 eol = sol + idx->v[cur_idx].len;
872
873 col = sol;
874 while (col < eol && *col != ':')
875 col++;
876
877 sov = col + 1;
878 while (sov < eol && http_is_lws[(unsigned char)*sov])
879 sov++;
880
881 for (h = cap_hdr; h; h = h->next) {
882 if ((h->namelen == col - sol) &&
883 (strncasecmp(sol, h->name, h->namelen) == 0)) {
884 if (cap[h->index] == NULL)
885 cap[h->index] =
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200886 pool_alloc2(h->pool);
Willy Tarreau117f59e2007-03-04 18:17:17 +0100887
888 if (cap[h->index] == NULL) {
889 Alert("HTTP capture : out of memory.\n");
890 continue;
891 }
892
893 len = eol - sov;
894 if (len > h->len)
895 len = h->len;
896
897 memcpy(cap[h->index], sov, len);
898 cap[h->index][len]=0;
899 }
900 }
901 sol = eol + idx->v[cur_idx].cr + 1;
902 cur_idx = idx->v[cur_idx].next;
903 }
904}
905
906
Willy Tarreau42250582007-04-01 01:30:43 +0200907/* either we find an LF at <ptr> or we jump to <bad>.
908 */
909#define EXPECT_LF_HERE(ptr, bad) do { if (unlikely(*(ptr) != '\n')) goto bad; } while (0)
910
911/* plays with variables <ptr>, <end> and <state>. Jumps to <good> if OK,
912 * otherwise to <http_msg_ood> with <state> set to <st>.
913 */
914#define EAT_AND_JUMP_OR_RETURN(good, st) do { \
915 ptr++; \
916 if (likely(ptr < end)) \
917 goto good; \
918 else { \
919 state = (st); \
920 goto http_msg_ood; \
921 } \
922 } while (0)
923
924
Willy Tarreaubaaee002006-06-26 02:48:02 +0200925/*
Willy Tarreaua15645d2007-03-18 16:22:39 +0100926 * This function parses a status line between <ptr> and <end>, starting with
Willy Tarreau8973c702007-01-21 23:58:29 +0100927 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
928 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
929 * will give undefined results.
930 * Note that it is upon the caller's responsibility to ensure that ptr < end,
931 * and that msg->sol points to the beginning of the response.
932 * If a complete line is found (which implies that at least one CR or LF is
933 * found before <end>, the updated <ptr> is returned, otherwise NULL is
934 * returned indicating an incomplete line (which does not mean that parts have
935 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
936 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
937 * upon next call.
938 *
Willy Tarreau9cdde232007-05-02 20:58:19 +0200939 * This function was intentionally designed to be called from
Willy Tarreau8973c702007-01-21 23:58:29 +0100940 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
941 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +0200942 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreau8973c702007-01-21 23:58:29 +0100943 */
Willy Tarreaue69eada2008-01-27 00:34:10 +0100944const char *http_parse_stsline(struct http_msg *msg, const char *msg_buf,
945 unsigned int state, const char *ptr, const char *end,
946 char **ret_ptr, unsigned int *ret_state)
Willy Tarreau8973c702007-01-21 23:58:29 +0100947{
948 __label__
949 http_msg_rpver,
950 http_msg_rpver_sp,
951 http_msg_rpcode,
952 http_msg_rpcode_sp,
953 http_msg_rpreason,
954 http_msg_rpline_eol,
955 http_msg_ood, /* out of data */
956 http_msg_invalid;
957
958 switch (state) {
959 http_msg_rpver:
960 case HTTP_MSG_RPVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100961 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8973c702007-01-21 23:58:29 +0100962 EAT_AND_JUMP_OR_RETURN(http_msg_rpver, HTTP_MSG_RPVER);
963
964 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +0100965 msg->sl.st.v_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +0100966 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
967 }
968 goto http_msg_invalid;
969
970 http_msg_rpver_sp:
971 case HTTP_MSG_RPVER_SP:
972 if (likely(!HTTP_IS_LWS(*ptr))) {
973 msg->sl.st.c = ptr - msg_buf;
974 goto http_msg_rpcode;
975 }
976 if (likely(HTTP_IS_SPHT(*ptr)))
977 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
978 /* so it's a CR/LF, this is invalid */
979 goto http_msg_invalid;
980
981 http_msg_rpcode:
982 case HTTP_MSG_RPCODE:
983 if (likely(!HTTP_IS_LWS(*ptr)))
984 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode, HTTP_MSG_RPCODE);
985
986 if (likely(HTTP_IS_SPHT(*ptr))) {
987 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
988 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
989 }
990
991 /* so it's a CR/LF, so there is no reason phrase */
992 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
993 http_msg_rsp_reason:
994 /* FIXME: should we support HTTP responses without any reason phrase ? */
995 msg->sl.st.r = ptr - msg_buf;
996 msg->sl.st.r_l = 0;
997 goto http_msg_rpline_eol;
998
999 http_msg_rpcode_sp:
1000 case HTTP_MSG_RPCODE_SP:
1001 if (likely(!HTTP_IS_LWS(*ptr))) {
1002 msg->sl.st.r = ptr - msg_buf;
1003 goto http_msg_rpreason;
1004 }
1005 if (likely(HTTP_IS_SPHT(*ptr)))
1006 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1007 /* so it's a CR/LF, so there is no reason phrase */
1008 goto http_msg_rsp_reason;
1009
1010 http_msg_rpreason:
1011 case HTTP_MSG_RPREASON:
1012 if (likely(!HTTP_IS_CRLF(*ptr)))
1013 EAT_AND_JUMP_OR_RETURN(http_msg_rpreason, HTTP_MSG_RPREASON);
1014 msg->sl.st.r_l = (ptr - msg_buf) - msg->sl.st.r;
1015 http_msg_rpline_eol:
1016 /* We have seen the end of line. Note that we do not
1017 * necessarily have the \n yet, but at least we know that we
1018 * have EITHER \r OR \n, otherwise the response would not be
1019 * complete. We can then record the response length and return
1020 * to the caller which will be able to register it.
1021 */
1022 msg->sl.st.l = ptr - msg->sol;
1023 return ptr;
1024
1025#ifdef DEBUG_FULL
1026 default:
1027 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1028 exit(1);
1029#endif
1030 }
1031
1032 http_msg_ood:
1033 /* out of data */
1034 if (ret_state)
1035 *ret_state = state;
1036 if (ret_ptr)
1037 *ret_ptr = (char *)ptr;
1038 return NULL;
1039
1040 http_msg_invalid:
1041 /* invalid message */
1042 if (ret_state)
1043 *ret_state = HTTP_MSG_ERROR;
1044 return NULL;
1045}
1046
1047
1048/*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001049 * This function parses a request line between <ptr> and <end>, starting with
1050 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
1051 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
1052 * will give undefined results.
1053 * Note that it is upon the caller's responsibility to ensure that ptr < end,
1054 * and that msg->sol points to the beginning of the request.
1055 * If a complete line is found (which implies that at least one CR or LF is
1056 * found before <end>, the updated <ptr> is returned, otherwise NULL is
1057 * returned indicating an incomplete line (which does not mean that parts have
1058 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
1059 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
1060 * upon next call.
1061 *
Willy Tarreau9cdde232007-05-02 20:58:19 +02001062 * This function was intentionally designed to be called from
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001063 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
1064 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +02001065 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001066 */
Willy Tarreaue69eada2008-01-27 00:34:10 +01001067const char *http_parse_reqline(struct http_msg *msg, const char *msg_buf,
1068 unsigned int state, const char *ptr, const char *end,
1069 char **ret_ptr, unsigned int *ret_state)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001070{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001071 __label__
1072 http_msg_rqmeth,
1073 http_msg_rqmeth_sp,
1074 http_msg_rquri,
1075 http_msg_rquri_sp,
1076 http_msg_rqver,
1077 http_msg_rqline_eol,
1078 http_msg_ood, /* out of data */
1079 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001080
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001081 switch (state) {
1082 http_msg_rqmeth:
1083 case HTTP_MSG_RQMETH:
1084 if (likely(HTTP_IS_TOKEN(*ptr)))
1085 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth, HTTP_MSG_RQMETH);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001086
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001087 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001088 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001089 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1090 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001091
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001092 if (likely(HTTP_IS_CRLF(*ptr))) {
1093 /* HTTP 0.9 request */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001094 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001095 http_msg_req09_uri:
1096 msg->sl.rq.u = ptr - msg_buf;
1097 http_msg_req09_uri_e:
1098 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1099 http_msg_req09_ver:
1100 msg->sl.rq.v = ptr - msg_buf;
1101 msg->sl.rq.v_l = 0;
1102 goto http_msg_rqline_eol;
1103 }
1104 goto http_msg_invalid;
1105
1106 http_msg_rqmeth_sp:
1107 case HTTP_MSG_RQMETH_SP:
1108 if (likely(!HTTP_IS_LWS(*ptr))) {
1109 msg->sl.rq.u = ptr - msg_buf;
1110 goto http_msg_rquri;
1111 }
1112 if (likely(HTTP_IS_SPHT(*ptr)))
1113 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1114 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1115 goto http_msg_req09_uri;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001116
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001117 http_msg_rquri:
1118 case HTTP_MSG_RQURI:
1119 if (likely(!HTTP_IS_LWS(*ptr)))
1120 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001121
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001122 if (likely(HTTP_IS_SPHT(*ptr))) {
1123 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1124 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1125 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001126
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001127 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1128 goto http_msg_req09_uri_e;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001129
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001130 http_msg_rquri_sp:
1131 case HTTP_MSG_RQURI_SP:
1132 if (likely(!HTTP_IS_LWS(*ptr))) {
1133 msg->sl.rq.v = ptr - msg_buf;
1134 goto http_msg_rqver;
1135 }
1136 if (likely(HTTP_IS_SPHT(*ptr)))
1137 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1138 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1139 goto http_msg_req09_ver;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001140
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001141 http_msg_rqver:
1142 case HTTP_MSG_RQVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001143 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001144 EAT_AND_JUMP_OR_RETURN(http_msg_rqver, HTTP_MSG_RQVER);
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001145
1146 if (likely(HTTP_IS_CRLF(*ptr))) {
1147 msg->sl.rq.v_l = (ptr - msg_buf) - msg->sl.rq.v;
1148 http_msg_rqline_eol:
1149 /* We have seen the end of line. Note that we do not
1150 * necessarily have the \n yet, but at least we know that we
1151 * have EITHER \r OR \n, otherwise the request would not be
1152 * complete. We can then record the request length and return
1153 * to the caller which will be able to register it.
1154 */
1155 msg->sl.rq.l = ptr - msg->sol;
1156 return ptr;
1157 }
1158
1159 /* neither an HTTP_VER token nor a CRLF */
1160 goto http_msg_invalid;
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:
1170 /* out of data */
1171 if (ret_state)
1172 *ret_state = state;
1173 if (ret_ptr)
1174 *ret_ptr = (char *)ptr;
1175 return NULL;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001176
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001177 http_msg_invalid:
1178 /* invalid message */
1179 if (ret_state)
1180 *ret_state = HTTP_MSG_ERROR;
1181 return NULL;
1182}
Willy Tarreau58f10d72006-12-04 02:26:12 +01001183
1184
Willy Tarreau8973c702007-01-21 23:58:29 +01001185/*
1186 * This function parses an HTTP message, either a request or a response,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001187 * depending on the initial msg->msg_state. It can be preempted everywhere
Willy Tarreau8973c702007-01-21 23:58:29 +01001188 * when data are missing and recalled at the exact same location with no
1189 * information loss. The header index is re-initialized when switching from
Willy Tarreau9cdde232007-05-02 20:58:19 +02001190 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH. It modifies msg->sol among other
1191 * fields.
Willy Tarreau8973c702007-01-21 23:58:29 +01001192 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001193void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx *idx)
1194{
1195 __label__
1196 http_msg_rqbefore,
1197 http_msg_rqbefore_cr,
1198 http_msg_rqmeth,
1199 http_msg_rqline_end,
1200 http_msg_hdr_first,
1201 http_msg_hdr_name,
1202 http_msg_hdr_l1_sp,
1203 http_msg_hdr_l1_lf,
1204 http_msg_hdr_l1_lws,
1205 http_msg_hdr_val,
1206 http_msg_hdr_l2_lf,
1207 http_msg_hdr_l2_lws,
1208 http_msg_complete_header,
1209 http_msg_last_lf,
1210 http_msg_ood, /* out of data */
1211 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001212
Willy Tarreaue69eada2008-01-27 00:34:10 +01001213 unsigned int state; /* updated only when leaving the FSM */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001214 register char *ptr, *end; /* request pointers, to avoid dereferences */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001215
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001216 state = msg->msg_state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001217 ptr = buf->lr;
1218 end = buf->r;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001219
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001220 if (unlikely(ptr >= end))
1221 goto http_msg_ood;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001222
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001223 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +01001224 /*
1225 * First, states that are specific to the response only.
1226 * We check them first so that request and headers are
1227 * closer to each other (accessed more often).
1228 */
1229 http_msg_rpbefore:
1230 case HTTP_MSG_RPBEFORE:
1231 if (likely(HTTP_IS_TOKEN(*ptr))) {
1232 if (likely(ptr == buf->data)) {
1233 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001234 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001235 } else {
1236#if PARSE_PRESERVE_EMPTY_LINES
1237 /* only skip empty leading lines, don't remove them */
1238 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001239 msg->som = ptr - buf->data;
Willy Tarreau8973c702007-01-21 23:58:29 +01001240#else
1241 /* Remove empty leading lines, as recommended by
1242 * RFC2616. This takes a lot of time because we
1243 * must move all the buffer backwards, but this
1244 * is rarely needed. The method above will be
1245 * cleaner when we'll be able to start sending
1246 * the request from any place in the buffer.
1247 */
1248 buf->lr = ptr;
1249 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001250 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001251 msg->sol = buf->data;
1252 ptr = buf->data;
1253 end = buf->r;
1254#endif
1255 }
1256 hdr_idx_init(idx);
1257 state = HTTP_MSG_RPVER;
1258 goto http_msg_rpver;
1259 }
1260
1261 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1262 goto http_msg_invalid;
1263
1264 if (unlikely(*ptr == '\n'))
1265 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1266 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore_cr, HTTP_MSG_RPBEFORE_CR);
1267 /* stop here */
1268
1269 http_msg_rpbefore_cr:
1270 case HTTP_MSG_RPBEFORE_CR:
1271 EXPECT_LF_HERE(ptr, http_msg_invalid);
1272 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1273 /* stop here */
1274
1275 http_msg_rpver:
1276 case HTTP_MSG_RPVER:
1277 case HTTP_MSG_RPVER_SP:
1278 case HTTP_MSG_RPCODE:
1279 case HTTP_MSG_RPCODE_SP:
1280 case HTTP_MSG_RPREASON:
Willy Tarreaua15645d2007-03-18 16:22:39 +01001281 ptr = (char *)http_parse_stsline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001282 &buf->lr, &msg->msg_state);
Willy Tarreau8973c702007-01-21 23:58:29 +01001283 if (unlikely(!ptr))
1284 return;
1285
1286 /* we have a full response and we know that we have either a CR
1287 * or an LF at <ptr>.
1288 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001289 //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 +01001290 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
1291
1292 msg->sol = ptr;
1293 if (likely(*ptr == '\r'))
1294 EAT_AND_JUMP_OR_RETURN(http_msg_rpline_end, HTTP_MSG_RPLINE_END);
1295 goto http_msg_rpline_end;
1296
1297 http_msg_rpline_end:
1298 case HTTP_MSG_RPLINE_END:
1299 /* msg->sol must point to the first of CR or LF. */
1300 EXPECT_LF_HERE(ptr, http_msg_invalid);
1301 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
1302 /* stop here */
1303
1304 /*
1305 * Second, states that are specific to the request only
1306 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001307 http_msg_rqbefore:
1308 case HTTP_MSG_RQBEFORE:
1309 if (likely(HTTP_IS_TOKEN(*ptr))) {
1310 if (likely(ptr == buf->data)) {
1311 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001312 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001313 } else {
1314#if PARSE_PRESERVE_EMPTY_LINES
1315 /* only skip empty leading lines, don't remove them */
1316 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001317 msg->som = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001318#else
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001319 /* Remove empty leading lines, as recommended by
1320 * RFC2616. This takes a lot of time because we
1321 * must move all the buffer backwards, but this
1322 * is rarely needed. The method above will be
1323 * cleaner when we'll be able to start sending
1324 * the request from any place in the buffer.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001325 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001326 buf->lr = ptr;
1327 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001328 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001329 msg->sol = buf->data;
1330 ptr = buf->data;
1331 end = buf->r;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001332#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001333 }
Willy Tarreauf0d058e2007-01-25 12:03:42 +01001334 /* we will need this when keep-alive will be supported
1335 hdr_idx_init(idx);
1336 */
Willy Tarreau8973c702007-01-21 23:58:29 +01001337 state = HTTP_MSG_RQMETH;
1338 goto http_msg_rqmeth;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001339 }
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001340
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001341 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1342 goto http_msg_invalid;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001343
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001344 if (unlikely(*ptr == '\n'))
1345 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
1346 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore_cr, HTTP_MSG_RQBEFORE_CR);
Willy Tarreau8973c702007-01-21 23:58:29 +01001347 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001348
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001349 http_msg_rqbefore_cr:
1350 case HTTP_MSG_RQBEFORE_CR:
1351 EXPECT_LF_HERE(ptr, http_msg_invalid);
1352 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
Willy Tarreau8973c702007-01-21 23:58:29 +01001353 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001354
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001355 http_msg_rqmeth:
1356 case HTTP_MSG_RQMETH:
1357 case HTTP_MSG_RQMETH_SP:
1358 case HTTP_MSG_RQURI:
1359 case HTTP_MSG_RQURI_SP:
1360 case HTTP_MSG_RQVER:
1361 ptr = (char *)http_parse_reqline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001362 &buf->lr, &msg->msg_state);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001363 if (unlikely(!ptr))
1364 return;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001365
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001366 /* we have a full request and we know that we have either a CR
1367 * or an LF at <ptr>.
1368 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001369 //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 +01001370 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001371
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001372 msg->sol = ptr;
1373 if (likely(*ptr == '\r'))
1374 EAT_AND_JUMP_OR_RETURN(http_msg_rqline_end, HTTP_MSG_RQLINE_END);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001375 goto http_msg_rqline_end;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001376
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001377 http_msg_rqline_end:
1378 case HTTP_MSG_RQLINE_END:
1379 /* check for HTTP/0.9 request : no version information available.
1380 * msg->sol must point to the first of CR or LF.
1381 */
1382 if (unlikely(msg->sl.rq.v_l == 0))
1383 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001384
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001385 EXPECT_LF_HERE(ptr, http_msg_invalid);
1386 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
Willy Tarreau8973c702007-01-21 23:58:29 +01001387 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001388
Willy Tarreau8973c702007-01-21 23:58:29 +01001389 /*
1390 * Common states below
1391 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001392 http_msg_hdr_first:
1393 case HTTP_MSG_HDR_FIRST:
1394 msg->sol = ptr;
1395 if (likely(!HTTP_IS_CRLF(*ptr))) {
1396 goto http_msg_hdr_name;
1397 }
1398
1399 if (likely(*ptr == '\r'))
1400 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1401 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001402
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001403 http_msg_hdr_name:
1404 case HTTP_MSG_HDR_NAME:
1405 /* assumes msg->sol points to the first char */
1406 if (likely(HTTP_IS_TOKEN(*ptr)))
1407 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001408
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001409 if (likely(*ptr == ':')) {
1410 msg->col = ptr - buf->data;
1411 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
1412 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001413
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001414 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001415
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001416 http_msg_hdr_l1_sp:
1417 case HTTP_MSG_HDR_L1_SP:
1418 /* assumes msg->sol points to the first char and msg->col to the colon */
1419 if (likely(HTTP_IS_SPHT(*ptr)))
1420 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001421
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001422 /* header value can be basically anything except CR/LF */
1423 msg->sov = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001424
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001425 if (likely(!HTTP_IS_CRLF(*ptr))) {
1426 goto http_msg_hdr_val;
1427 }
1428
1429 if (likely(*ptr == '\r'))
1430 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lf, HTTP_MSG_HDR_L1_LF);
1431 goto http_msg_hdr_l1_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001432
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001433 http_msg_hdr_l1_lf:
1434 case HTTP_MSG_HDR_L1_LF:
1435 EXPECT_LF_HERE(ptr, http_msg_invalid);
1436 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lws, HTTP_MSG_HDR_L1_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001437
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001438 http_msg_hdr_l1_lws:
1439 case HTTP_MSG_HDR_L1_LWS:
1440 if (likely(HTTP_IS_SPHT(*ptr))) {
1441 /* replace HT,CR,LF with spaces */
1442 for (; buf->data+msg->sov < ptr; msg->sov++)
1443 buf->data[msg->sov] = ' ';
1444 goto http_msg_hdr_l1_sp;
1445 }
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001446 /* we had a header consisting only in spaces ! */
1447 msg->eol = buf->data + msg->sov;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001448 goto http_msg_complete_header;
1449
1450 http_msg_hdr_val:
1451 case HTTP_MSG_HDR_VAL:
1452 /* assumes msg->sol points to the first char, msg->col to the
1453 * colon, and msg->sov points to the first character of the
1454 * value.
1455 */
1456 if (likely(!HTTP_IS_CRLF(*ptr)))
1457 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001458
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001459 msg->eol = ptr;
1460 /* Note: we could also copy eol into ->eoh so that we have the
1461 * real header end in case it ends with lots of LWS, but is this
1462 * really needed ?
1463 */
1464 if (likely(*ptr == '\r'))
1465 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1466 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001467
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001468 http_msg_hdr_l2_lf:
1469 case HTTP_MSG_HDR_L2_LF:
1470 EXPECT_LF_HERE(ptr, http_msg_invalid);
1471 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001472
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001473 http_msg_hdr_l2_lws:
1474 case HTTP_MSG_HDR_L2_LWS:
1475 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1476 /* LWS: replace HT,CR,LF with spaces */
1477 for (; msg->eol < ptr; msg->eol++)
1478 *msg->eol = ' ';
1479 goto http_msg_hdr_val;
1480 }
1481 http_msg_complete_header:
1482 /*
1483 * It was a new header, so the last one is finished.
1484 * Assumes msg->sol points to the first char, msg->col to the
1485 * colon, msg->sov points to the first character of the value
1486 * and msg->eol to the first CR or LF so we know how the line
1487 * ends. We insert last header into the index.
1488 */
1489 /*
1490 fprintf(stderr,"registering %-2d bytes : ", msg->eol - msg->sol);
1491 write(2, msg->sol, msg->eol-msg->sol);
1492 fprintf(stderr,"\n");
1493 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001494
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001495 if (unlikely(hdr_idx_add(msg->eol - msg->sol, *msg->eol == '\r',
1496 idx, idx->tail) < 0))
1497 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001498
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001499 msg->sol = ptr;
1500 if (likely(!HTTP_IS_CRLF(*ptr))) {
1501 goto http_msg_hdr_name;
1502 }
1503
1504 if (likely(*ptr == '\r'))
1505 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1506 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001507
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001508 http_msg_last_lf:
1509 case HTTP_MSG_LAST_LF:
1510 /* Assumes msg->sol points to the first of either CR or LF */
1511 EXPECT_LF_HERE(ptr, http_msg_invalid);
1512 ptr++;
1513 buf->lr = ptr;
1514 msg->eoh = msg->sol - buf->data;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001515 msg->msg_state = HTTP_MSG_BODY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001516 return;
1517#ifdef DEBUG_FULL
1518 default:
1519 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1520 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001521#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001522 }
1523 http_msg_ood:
1524 /* out of data */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001525 msg->msg_state = state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001526 buf->lr = ptr;
1527 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001528
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001529 http_msg_invalid:
1530 /* invalid message */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001531 msg->msg_state = HTTP_MSG_ERROR;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001532 return;
1533}
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001534
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001535/*
1536 * manages the client FSM and its socket. BTW, it also tries to handle the
1537 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1538 * 0 else.
1539 */
1540int process_cli(struct session *t)
1541{
1542 int s = t->srv_state;
1543 int c = t->cli_state;
1544 struct buffer *req = t->req;
1545 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001546
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001547 DPRINTF(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
1548 cli_stnames[c], srv_stnames[s],
Willy Tarreauf161a342007-04-08 16:59:42 +02001549 EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001550 req->rex.tv_sec, req->rex.tv_usec,
1551 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001552
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001553 if (c == CL_STHEADERS) {
1554 /*
1555 * Now parse the partial (or complete) lines.
1556 * We will check the request syntax, and also join multi-line
1557 * headers. An index of all the lines will be elaborated while
1558 * parsing.
1559 *
Willy Tarreau8973c702007-01-21 23:58:29 +01001560 * For the parsing, we use a 28 states FSM.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001561 *
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001562 * Here is the information we currently have :
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001563 * req->data + req->som = beginning of request
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001564 * req->data + req->eoh = end of processed headers / start of current one
1565 * req->data + req->eol = end of current header or line (LF or CRLF)
1566 * req->lr = first non-visited byte
1567 * req->r = end of data
1568 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001569
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001570 int cur_idx;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001571 struct http_txn *txn = &t->txn;
1572 struct http_msg *msg = &txn->req;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001573 struct proxy *cur_proxy;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001574
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001575 if (likely(req->lr < req->r))
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001576 http_msg_analyzer(req, msg, &txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001577
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001578 /* 1: we might have to print this header in debug mode */
1579 if (unlikely((global.mode & MODE_DEBUG) &&
1580 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001581 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001582 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001583
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001584 sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001585 eol = sol + msg->sl.rq.l;
1586 debug_hdr("clireq", t, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001587
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001588 sol += hdr_idx_first_pos(&txn->hdr_idx);
1589 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001590
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001591 while (cur_idx) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001592 eol = sol + txn->hdr_idx.v[cur_idx].len;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001593 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001594 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
1595 cur_idx = txn->hdr_idx.v[cur_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001596 }
1597 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001598
Willy Tarreau58f10d72006-12-04 02:26:12 +01001599
1600 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001601 * Now we quickly check if we have found a full valid request.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001602 * If not so, we check the FD and buffer states before leaving.
1603 * A full request is indicated by the fact that we have seen
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001604 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
1605 * requests are checked first.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001606 *
1607 */
1608
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001609 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001610 /*
1611 * First, let's catch bad requests.
1612 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001613 if (unlikely(msg->msg_state == HTTP_MSG_ERROR))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001614 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001615
1616 /* 1: Since we are in header mode, if there's no space
1617 * left for headers, we won't be able to free more
1618 * later, so the session will never terminate. We
1619 * must terminate it now.
1620 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001621 if (unlikely(req->l >= req->rlim - req->data)) {
1622 /* FIXME: check if URI is set and return Status
1623 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001624 */
Willy Tarreau06619262006-12-17 08:37:22 +01001625 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001626 }
1627
1628 /* 2: have we encountered a read error or a close ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001629 else if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1630 /* read error, or last read : give up. */
Willy Tarreaufa645582007-06-03 15:59:52 +02001631 buffer_shutr(req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001632 fd_delete(t->cli_fd);
1633 t->cli_state = CL_STCLOSE;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001634 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001635 if (!(t->flags & SN_ERR_MASK))
1636 t->flags |= SN_ERR_CLICL;
1637 if (!(t->flags & SN_FINST_MASK))
1638 t->flags |= SN_FINST_R;
1639 return 1;
1640 }
1641
1642 /* 3: has the read timeout expired ? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001643 else if (unlikely(tick_is_expired(req->rex, now_ms) ||
1644 tick_is_expired(txn->exp, now_ms))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001645 /* read timeout : give up with an error message. */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001646 txn->status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +01001647 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001648 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001649 if (!(t->flags & SN_ERR_MASK))
1650 t->flags |= SN_ERR_CLITO;
1651 if (!(t->flags & SN_FINST_MASK))
1652 t->flags |= SN_FINST_R;
1653 return 1;
1654 }
1655
1656 /* 4: do we need to re-enable the read socket ? */
Willy Tarreau66319382007-04-08 17:17:37 +02001657 else if (unlikely(EV_FD_COND_S(t->cli_fd, DIR_RD))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02001658 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreau58f10d72006-12-04 02:26:12 +01001659 * full. We cannot loop here since stream_sock_read will disable it only if
1660 * req->l == rlim-data
1661 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001662 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001663 }
1664 return t->cli_state != CL_STHEADERS;
1665 }
1666
1667
1668 /****************************************************************
1669 * More interesting part now : we know that we have a complete *
1670 * request which at least looks like HTTP. We have an indicator *
1671 * of each header's length, so we can parse them quickly. *
1672 ****************************************************************/
1673
Willy Tarreau9cdde232007-05-02 20:58:19 +02001674 /* ensure we keep this pointer to the beginning of the message */
1675 msg->sol = req->data + msg->som;
1676
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001677 /*
1678 * 1: identify the method
1679 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001680 txn->meth = find_http_meth(&req->data[msg->som], msg->sl.rq.m_l);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001681
1682 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001683 * 2: check if the URI matches the monitor_uri.
Willy Tarreau06619262006-12-17 08:37:22 +01001684 * We have to do this for every request which gets in, because
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001685 * the monitor-uri is defined by the frontend.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001686 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001687 if (unlikely((t->fe->monitor_uri_len != 0) &&
1688 (t->fe->monitor_uri_len == msg->sl.rq.u_l) &&
1689 !memcmp(&req->data[msg->sl.rq.u],
1690 t->fe->monitor_uri,
1691 t->fe->monitor_uri_len))) {
1692 /*
1693 * We have found the monitor URI
1694 */
Willy Tarreaub80c2302007-11-30 20:51:32 +01001695 struct acl_cond *cond;
1696 cur_proxy = t->fe;
1697
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001698 t->flags |= SN_MONITOR;
Willy Tarreaub80c2302007-11-30 20:51:32 +01001699
1700 /* Check if we want to fail this monitor request or not */
1701 list_for_each_entry(cond, &cur_proxy->mon_fail_cond, list) {
1702 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001703
1704 ret = acl_pass(ret);
Willy Tarreaub80c2302007-11-30 20:51:32 +01001705 if (cond->pol == ACL_COND_UNLESS)
1706 ret = !ret;
1707
1708 if (ret) {
1709 /* we fail this request, let's return 503 service unavail */
1710 txn->status = 503;
1711 client_retnclose(t, error_message(t, HTTP_ERR_503));
1712 goto return_prx_cond;
1713 }
1714 }
1715
1716 /* nothing to fail, let's reply normaly */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001717 txn->status = 200;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001718 client_retnclose(t, &http_200_chunk);
1719 goto return_prx_cond;
1720 }
1721
1722 /*
1723 * 3: Maybe we have to copy the original REQURI for the logs ?
1724 * Note: we cannot log anymore if the request has been
1725 * classified as invalid.
1726 */
1727 if (unlikely(t->logs.logwait & LW_REQ)) {
1728 /* we have a complete HTTP request that we must log */
Willy Tarreau332f8bf2007-05-13 21:36:56 +02001729 if ((txn->uri = pool_alloc2(pool2_requri)) != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001730 int urilen = msg->sl.rq.l;
1731
1732 if (urilen >= REQURI_LEN)
1733 urilen = REQURI_LEN - 1;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001734 memcpy(txn->uri, &req->data[msg->som], urilen);
1735 txn->uri[urilen] = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001736
1737 if (!(t->logs.logwait &= ~LW_REQ))
Willy Tarreau42250582007-04-01 01:30:43 +02001738 http_sess_log(t);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001739 } else {
1740 Alert("HTTP logging : out of memory.\n");
1741 }
1742 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001743
Willy Tarreau06619262006-12-17 08:37:22 +01001744
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001745 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
1746 if (unlikely(msg->sl.rq.v_l == 0)) {
1747 int delta;
1748 char *cur_end;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001749 msg->sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001750 cur_end = msg->sol + msg->sl.rq.l;
1751 delta = 0;
Willy Tarreau06619262006-12-17 08:37:22 +01001752
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001753 if (msg->sl.rq.u_l == 0) {
1754 /* if no URI was set, add "/" */
1755 delta = buffer_replace2(req, cur_end, cur_end, " /", 2);
1756 cur_end += delta;
1757 msg->eoh += delta;
Willy Tarreau06619262006-12-17 08:37:22 +01001758 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001759 /* add HTTP version */
1760 delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
1761 msg->eoh += delta;
1762 cur_end += delta;
1763 cur_end = (char *)http_parse_reqline(msg, req->data,
1764 HTTP_MSG_RQMETH,
1765 msg->sol, cur_end + 1,
1766 NULL, NULL);
1767 if (unlikely(!cur_end))
1768 goto return_bad_req;
1769
1770 /* we have a full HTTP/1.0 request now and we know that
1771 * we have either a CR or an LF at <ptr>.
1772 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001773 hdr_idx_set_start(&txn->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
Willy Tarreau58f10d72006-12-04 02:26:12 +01001774 }
1775
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001776
1777 /* 5: we may need to capture headers */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001778 if (unlikely((t->logs.logwait & LW_REQHDR) && t->fe->req_cap))
Willy Tarreau117f59e2007-03-04 18:17:17 +01001779 capture_headers(req->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001780 txn->req.cap, t->fe->req_cap);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001781
1782 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001783 * 6: we will have to evaluate the filters.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001784 * As opposed to version 1.2, now they will be evaluated in the
1785 * filters order and not in the header order. This means that
1786 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001787 *
1788 * We can now check whether we want to switch to another
1789 * backend, in which case we will re-check the backend's
1790 * filters and various options. In order to support 3-level
1791 * switching, here's how we should proceed :
1792 *
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001793 * a) run be.
Willy Tarreau830ff452006-12-17 19:31:23 +01001794 * if (switch) then switch ->be to the new backend.
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001795 * b) run be if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001796 * There cannot be any switch from there, so ->be cannot be
1797 * changed anymore.
1798 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001799 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001800 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001801 * The response path will be able to apply either ->be, or
1802 * ->be then ->fe filters in order to match the reverse of
1803 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001804 */
1805
Willy Tarreau06619262006-12-17 08:37:22 +01001806 do {
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001807 struct acl_cond *cond;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001808 struct redirect_rule *rule;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001809 struct proxy *rule_set = t->be;
Willy Tarreau830ff452006-12-17 19:31:23 +01001810 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001811
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001812 /* first check whether we have some ACLs set to redirect this request */
1813 list_for_each_entry(rule, &cur_proxy->redirect_rules, list) {
1814 int ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001815
1816 ret = acl_pass(ret);
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001817 if (rule->cond->pol == ACL_COND_UNLESS)
1818 ret = !ret;
1819
1820 if (ret) {
1821 struct chunk rdr = { trash, 0 };
1822 const char *msg_fmt;
1823
1824 /* build redirect message */
1825 switch(rule->code) {
1826 case 303:
1827 rdr.len = strlen(HTTP_303);
1828 msg_fmt = HTTP_303;
1829 break;
1830 case 301:
1831 rdr.len = strlen(HTTP_301);
1832 msg_fmt = HTTP_301;
1833 break;
1834 case 302:
1835 default:
1836 rdr.len = strlen(HTTP_302);
1837 msg_fmt = HTTP_302;
1838 break;
1839 }
1840
1841 if (unlikely(rdr.len > sizeof(trash)))
1842 goto return_bad_req;
1843 memcpy(rdr.str, msg_fmt, rdr.len);
1844
1845 switch(rule->type) {
1846 case REDIRECT_TYPE_PREFIX: {
1847 const char *path;
1848 int pathlen;
1849
1850 path = http_get_path(txn);
1851 /* build message using path */
1852 if (path) {
1853 pathlen = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
1854 } else {
1855 path = "/";
1856 pathlen = 1;
1857 }
1858
1859 if (rdr.len + rule->rdr_len + pathlen > sizeof(trash) - 4)
1860 goto return_bad_req;
1861
1862 /* add prefix */
1863 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1864 rdr.len += rule->rdr_len;
1865
1866 /* add path */
1867 memcpy(rdr.str + rdr.len, path, pathlen);
1868 rdr.len += pathlen;
1869 break;
1870 }
1871 case REDIRECT_TYPE_LOCATION:
1872 default:
1873 if (rdr.len + rule->rdr_len > sizeof(trash) - 4)
1874 goto return_bad_req;
1875
1876 /* add location */
1877 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1878 rdr.len += rule->rdr_len;
1879 break;
1880 }
1881
1882 /* add end of headers */
1883 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
1884 rdr.len += 4;
1885
1886 txn->status = rule->code;
1887 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02001888 t->logs.tv_request = now;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001889 client_retnclose(t, &rdr);
1890 goto return_prx_cond;
1891 }
1892 }
1893
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001894 /* first check whether we have some ACLs set to block this request */
1895 list_for_each_entry(cond, &cur_proxy->block_cond, list) {
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001896 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001897
1898 ret = acl_pass(ret);
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001899 if (cond->pol == ACL_COND_UNLESS)
1900 ret = !ret;
1901
1902 if (ret) {
1903 txn->status = 403;
1904 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02001905 t->logs.tv_request = now;
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001906 client_retnclose(t, error_message(t, HTTP_ERR_403));
1907 goto return_prx_cond;
1908 }
1909 }
1910
Willy Tarreau06619262006-12-17 08:37:22 +01001911 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01001912 if (rule_set->req_exp != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001913 if (apply_filters_to_request(t, req, rule_set->req_exp) < 0)
1914 goto return_bad_req;
Willy Tarreau53b6c742006-12-17 13:37:46 +01001915 }
1916
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001917 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
1918 /* to ensure correct connection accounting on
1919 * the backend, we count the connection for the
1920 * one managing the queue.
1921 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001922 t->be->beconn++;
1923 if (t->be->beconn > t->be->beconn_max)
1924 t->be->beconn_max = t->be->beconn;
1925 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001926 t->flags |= SN_BE_ASSIGNED;
1927 }
1928
Willy Tarreau06619262006-12-17 08:37:22 +01001929 /* has the request been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01001930 if (txn->flags & TX_CLDENY) {
Willy Tarreau06619262006-12-17 08:37:22 +01001931 /* no need to go further */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001932 txn->status = 403;
Willy Tarreau06619262006-12-17 08:37:22 +01001933 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02001934 t->logs.tv_request = now;
Willy Tarreau80587432006-12-24 17:47:20 +01001935 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01001936 goto return_prx_cond;
1937 }
1938
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001939 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01001940 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001941 !(t->flags & SN_CONN_CLOSED)) {
1942 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001943 int cur_idx, old_idx, delta, val;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001944 struct hdr_idx_elem *cur_hdr;
Willy Tarreau06619262006-12-17 08:37:22 +01001945
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001946 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001947 old_idx = 0;
1948
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001949 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
1950 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001951 cur_ptr = cur_next;
1952 cur_end = cur_ptr + cur_hdr->len;
1953 cur_next = cur_end + cur_hdr->cr + 1;
1954
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001955 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
1956 if (val) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001957 /* 3 possibilities :
1958 * - we have already set Connection: close,
1959 * so we remove this line.
1960 * - we have not yet set Connection: close,
1961 * but this line indicates close. We leave
1962 * it untouched and set the flag.
1963 * - we have not yet set Connection: close,
1964 * and this line indicates non-close. We
1965 * replace it.
1966 */
1967 if (t->flags & SN_CONN_CLOSED) {
1968 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001969 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001970 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001971 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
1972 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001973 cur_hdr->len = 0;
1974 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001975 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
1976 delta = buffer_replace2(req, cur_ptr + val, cur_end,
1977 "close", 5);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001978 cur_next += delta;
1979 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001980 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001981 }
1982 t->flags |= SN_CONN_CLOSED;
1983 }
1984 }
1985 old_idx = cur_idx;
1986 }
Willy Tarreauf2f0ee82007-03-30 12:02:43 +02001987 }
1988 /* add request headers from the rule sets in the same order */
1989 for (cur_idx = 0; cur_idx < rule_set->nb_reqadd; cur_idx++) {
1990 if (unlikely(http_header_add_tail(req,
1991 &txn->req,
1992 &txn->hdr_idx,
1993 rule_set->req_add[cur_idx])) < 0)
1994 goto return_bad_req;
Willy Tarreau06619262006-12-17 08:37:22 +01001995 }
Willy Tarreaub2513902006-12-17 14:52:38 +01001996
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001997 /* check if stats URI was requested, and if an auth is needed */
Willy Tarreau0214c3a2007-01-07 13:47:30 +01001998 if (rule_set->uri_auth != NULL &&
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001999 (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)) {
Willy Tarreaub2513902006-12-17 14:52:38 +01002000 /* we have to check the URI and auth for this request */
2001 if (stats_check_uri_auth(t, rule_set))
2002 return 1;
2003 }
2004
Willy Tarreau55ea7572007-06-17 19:56:27 +02002005 /* now check whether we have some switching rules for this request */
2006 if (!(t->flags & SN_BE_ASSIGNED)) {
2007 struct switching_rule *rule;
2008
2009 list_for_each_entry(rule, &cur_proxy->switching_rules, list) {
2010 int ret;
2011
2012 ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02002013
2014 ret = acl_pass(ret);
Willy Tarreaua8cfa342008-07-09 11:23:31 +02002015 if (rule->cond->pol == ACL_COND_UNLESS)
Willy Tarreau55ea7572007-06-17 19:56:27 +02002016 ret = !ret;
2017
2018 if (ret) {
2019 t->be = rule->be.backend;
2020 t->be->beconn++;
2021 if (t->be->beconn > t->be->beconn_max)
2022 t->be->beconn_max = t->be->beconn;
2023 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002024
2025 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002026 t->rep->rto = t->req->wto = t->be->timeout.server;
2027 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002028 t->conn_retries = t->be->conn_retries;
Willy Tarreau55ea7572007-06-17 19:56:27 +02002029 t->flags |= SN_BE_ASSIGNED;
2030 break;
2031 }
2032 }
2033 }
2034
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002035 if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
2036 /* No backend was set, but there was a default
2037 * backend set in the frontend, so we use it and
2038 * loop again.
2039 */
2040 t->be = cur_proxy->defbe.be;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002041 t->be->beconn++;
2042 if (t->be->beconn > t->be->beconn_max)
2043 t->be->beconn_max = t->be->beconn;
2044 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002045
2046 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002047 t->rep->rto = t->req->wto = t->be->timeout.server;
2048 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002049 t->conn_retries = t->be->conn_retries;
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002050 t->flags |= SN_BE_ASSIGNED;
2051 }
2052 } while (t->be != cur_proxy); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01002053
Willy Tarreau58f10d72006-12-04 02:26:12 +01002054
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002055 if (!(t->flags & SN_BE_ASSIGNED)) {
2056 /* To ensure correct connection accounting on
2057 * the backend, we count the connection for the
2058 * one managing the queue.
2059 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002060 t->be->beconn++;
2061 if (t->be->beconn > t->be->beconn_max)
2062 t->be->beconn_max = t->be->beconn;
2063 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002064 t->flags |= SN_BE_ASSIGNED;
2065 }
2066
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002067 /*
2068 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01002069 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002070 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01002071 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01002072 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01002073
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01002074 /*
2075 * If HTTP PROXY is set we simply get remote server address
2076 * parsing incoming request.
2077 */
2078 if ((t->be->options & PR_O_HTTP_PROXY) && !(t->flags & SN_ADDR_SET)) {
2079 url2sa(req->data + msg->sl.rq.u, msg->sl.rq.u_l, &t->srv_addr);
2080 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002081
Willy Tarreau2a324282006-12-05 00:05:46 +01002082 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002083 * 7: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01002084 * so let's do the same now.
2085 */
2086
2087 /* It needs to look into the URI */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002088 if (t->be->appsession_name) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01002089 get_srv_from_appsession(t, &req->data[msg->som], msg->sl.rq.l);
Willy Tarreau06619262006-12-17 08:37:22 +01002090 }
2091
2092
2093 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002094 * 8: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01002095 * Note that doing so might move headers in the request, but
2096 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01002097 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01002098 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01002099 if ((t->be->cookie_name || t->be->appsession_name || t->be->capture_name)
2100 && !(txn->flags & (TX_CLDENY|TX_CLTARPIT)))
Willy Tarreau2a324282006-12-05 00:05:46 +01002101 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01002102
Willy Tarreau58f10d72006-12-04 02:26:12 +01002103
Willy Tarreau2a324282006-12-05 00:05:46 +01002104 /*
Willy Tarreaubb046ac2007-03-03 19:17:03 +01002105 * 9: add X-Forwarded-For if either the frontend or the backend
2106 * asks for it.
Willy Tarreau2a324282006-12-05 00:05:46 +01002107 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002108 if ((t->fe->options | t->be->options) & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002109 if (t->cli_addr.ss_family == AF_INET) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002110 /* Add an X-Forwarded-For header unless the source IP is
2111 * in the 'except' network range.
2112 */
2113 if ((!t->fe->except_mask.s_addr ||
2114 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->fe->except_mask.s_addr)
2115 != t->fe->except_net.s_addr) &&
2116 (!t->be->except_mask.s_addr ||
2117 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->be->except_mask.s_addr)
2118 != t->be->except_net.s_addr)) {
2119 int len;
2120 unsigned char *pn;
2121 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
Willy Tarreau45e73e32006-12-17 00:05:15 +01002122
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002123 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d",
2124 pn[0], pn[1], pn[2], pn[3]);
2125
2126 if (unlikely(http_header_add_tail2(req, &txn->req,
2127 &txn->hdr_idx, trash, len)) < 0)
2128 goto return_bad_req;
2129 }
Willy Tarreau2a324282006-12-05 00:05:46 +01002130 }
2131 else if (t->cli_addr.ss_family == AF_INET6) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002132 /* FIXME: for the sake of completeness, we should also support
2133 * 'except' here, although it is mostly useless in this case.
2134 */
Willy Tarreau2a324282006-12-05 00:05:46 +01002135 int len;
2136 char pn[INET6_ADDRSTRLEN];
2137 inet_ntop(AF_INET6,
2138 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2139 pn, sizeof(pn));
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002140 len = sprintf(trash, "X-Forwarded-For: %s", pn);
2141 if (unlikely(http_header_add_tail2(req, &txn->req,
2142 &txn->hdr_idx, trash, len)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002143 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01002144 }
2145 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002146
Willy Tarreau2a324282006-12-05 00:05:46 +01002147 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002148 * 10: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02002149 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaub2513902006-12-17 14:52:38 +01002150 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02002151 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002152 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02002153 if ((unlikely(msg->sl.rq.v_l != 8) ||
2154 unlikely(req->data[msg->som + msg->sl.rq.v + 7] != '0')) &&
2155 unlikely(http_header_add_tail2(req, &txn->req, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002156 "Connection: close", 17)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002157 goto return_bad_req;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002158 t->flags |= SN_CONN_CLOSED;
Willy Tarreaue15d9132006-12-14 22:26:42 +01002159 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002160 /* Before we switch to data, was assignment set in manage_client_side_cookie?
2161 * If not assigned, perhaps we are balancing on url_param, but this is a
2162 * POST; and the parameters are in the body, maybe scan there to find our server.
2163 * (unless headers overflowed the buffer?)
2164 */
2165 if (!(t->flags & (SN_ASSIGNED|SN_DIRECT)) &&
2166 t->txn.meth == HTTP_METH_POST && t->be->url_param_name != NULL &&
2167 t->be->url_param_post_limit != 0 && req->total < BUFSIZE &&
2168 memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) {
2169 /* are there enough bytes here? total == l || r || rlim ?
2170 * len is unsigned, but eoh is int,
2171 * how many bytes of body have we received?
2172 * eoh is the first empty line of the header
2173 */
2174 /* already established CRLF or LF at eoh, move to start of message, find message length in buffer */
2175 unsigned long len = req->total - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1);
2176
2177 /* If we have HTTP/1.1 and Expect: 100-continue, then abort.
2178 * We can't assume responsibility for the server's decision,
2179 * on this URI and header set. See rfc2616: 14.20, 8.2.3,
2180 * We also can't change our mind later, about which server to choose, so round robin.
2181 */
2182 if ((likely(msg->sl.rq.v_l == 8) && req->data[msg->som + msg->sl.rq.v + 7] == '1')) {
2183 struct hdr_ctx ctx;
2184 ctx.idx = 0;
2185 /* Expect is allowed in 1.1, look for it */
2186 http_find_header2("Expect", 6, msg->sol, &txn->hdr_idx, &ctx);
2187 if (ctx.idx != 0 &&
2188 unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val,"100-continue",12)==0))
2189 /* We can't reliablly stall and wait for data, because of
2190 * .NET clients that don't conform to rfc2616; so, no need for
2191 * the next block to check length expectations.
2192 * We could send 100 status back to the client, but then we need to
2193 * re-write headers, and send the message. And this isn't the right
2194 * place for that action.
2195 * TODO: support Expect elsewhere and delete this block.
2196 */
2197 goto end_check_maybe_wait_for_body;
2198 }
2199 if ( likely(len > t->be->url_param_post_limit) ) {
2200 /* nothing to do, we got enough */
2201 } else {
2202 /* limit implies we are supposed to need this many bytes
2203 * to find the parameter. Let's see how many bytes we can wait for.
2204 */
2205 long long hint = len;
2206 struct hdr_ctx ctx;
2207 ctx.idx = 0;
2208 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
2209 if (unlikely(ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",7)==0)) {
2210 t->srv_state = SV_STANALYZE;
2211 } else {
2212 ctx.idx = 0;
2213 http_find_header2("Content-Length", 14, msg->sol, &txn->hdr_idx, &ctx);
2214 /* now if we have a length, we'll take the hint */
2215 if ( ctx.idx ) {
2216 /* We have Content-Length */
2217 if ( strl2llrc(ctx.line+ctx.val,ctx.vlen, &hint) )
2218 hint = 0; /* parse failure, untrusted client */
2219 else {
2220 if ( hint > 0 )
2221 msg->hdr_content_len = hint;
2222 else
2223 hint = 0; /* bad client, sent negative length */
2224 }
2225 }
2226 /* but limited to what we care about, maybe we don't expect any entity data (hint == 0) */
2227 if ( t->be->url_param_post_limit < hint )
2228 hint = t->be->url_param_post_limit;
2229 /* now do we really need to buffer more data? */
2230 if ( len < hint )
2231 t->srv_state = SV_STANALYZE;
2232 /* else... There are no body bytes to wait for */
2233 }
2234 }
2235 }
2236 end_check_maybe_wait_for_body:
Willy Tarreaubaaee002006-06-26 02:48:02 +02002237
Willy Tarreau2a324282006-12-05 00:05:46 +01002238 /*************************************************************
2239 * OK, that's finished for the headers. We have done what we *
2240 * could. Let's switch to the DATA state. *
2241 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02002242
Willy Tarreau2a324282006-12-05 00:05:46 +01002243 t->cli_state = CL_STDATA;
2244 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002245
Willy Tarreau70089872008-06-13 21:12:51 +02002246 t->logs.tv_request = now;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002247
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002248 if (!t->fe->timeout.client ||
2249 (t->srv_state < SV_STDATA && t->be->timeout.server)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002250 /* If the client has no timeout, or if the server is not ready yet,
2251 * and we know for sure that it can expire, then it's cleaner to
2252 * disable the timeout on the client side so that too low values
2253 * cannot make the sessions abort too early.
2254 *
2255 * FIXME-20050705: the server needs a way to re-enable this time-out
2256 * when it switches its state, otherwise a client can stay connected
2257 * indefinitely. This now seems to be OK.
2258 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002259 req->rex = TICK_ETERNITY;
Willy Tarreau2a324282006-12-05 00:05:46 +01002260 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002261
Willy Tarreau1fa31262007-12-03 00:36:16 +01002262 /* When a connection is tarpitted, we use the tarpit timeout,
2263 * which may be the same as the connect timeout if unspecified.
2264 * If unset, then set it to zero because we really want it to
2265 * eventually expire.
Willy Tarreau2a324282006-12-05 00:05:46 +01002266 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002267 if (txn->flags & TX_CLTARPIT) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002268 t->req->l = 0;
2269 /* flush the request so that we can drop the connection early
2270 * if the client closes first.
2271 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002272 req->cex = tick_add_ifset(now_ms, t->be->timeout.tarpit);
2273 if (!req->cex)
2274 req->cex = now_ms;
Willy Tarreau2a324282006-12-05 00:05:46 +01002275 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002276
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002277 /* OK let's go on with the BODY now */
Willy Tarreau06619262006-12-17 08:37:22 +01002278 goto process_data;
2279
2280 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002281 txn->req.msg_state = HTTP_MSG_ERROR;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002282 txn->status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01002283 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002284 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01002285 return_prx_cond:
2286 if (!(t->flags & SN_ERR_MASK))
2287 t->flags |= SN_ERR_PRXCOND;
2288 if (!(t->flags & SN_FINST_MASK))
2289 t->flags |= SN_FINST_R;
2290 return 1;
2291
Willy Tarreaubaaee002006-06-26 02:48:02 +02002292 }
2293 else if (c == CL_STDATA) {
2294 process_data:
2295 /* FIXME: this error handling is partly buggy because we always report
2296 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
2297 * or HEADER phase. BTW, it's not logical to expire the client while
2298 * we're waiting for the server to connect.
2299 */
2300 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002301 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002302 buffer_shutr(req);
2303 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002304 fd_delete(t->cli_fd);
2305 t->cli_state = CL_STCLOSE;
2306 if (!(t->flags & SN_ERR_MASK))
2307 t->flags |= SN_ERR_CLICL;
2308 if (!(t->flags & SN_FINST_MASK)) {
2309 if (t->pend_pos)
2310 t->flags |= SN_FINST_Q;
2311 else if (s == SV_STCONN)
2312 t->flags |= SN_FINST_C;
2313 else
2314 t->flags |= SN_FINST_D;
2315 }
2316 return 1;
2317 }
2318 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002319 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002320 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002321 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002322 t->cli_state = CL_STSHUTR;
2323 return 1;
2324 }
2325 /* last server read and buffer empty */
2326 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002327 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02002328 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002329 shutdown(t->cli_fd, SHUT_WR);
2330 /* We must ensure that the read part is still alive when switching
2331 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002332 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002333 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002334 t->cli_state = CL_STSHUTW;
2335 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2336 return 1;
2337 }
2338 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002339 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002340 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002341 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002342 t->cli_state = CL_STSHUTR;
2343 if (!(t->flags & SN_ERR_MASK))
2344 t->flags |= SN_ERR_CLITO;
2345 if (!(t->flags & SN_FINST_MASK)) {
2346 if (t->pend_pos)
2347 t->flags |= SN_FINST_Q;
2348 else if (s == SV_STCONN)
2349 t->flags |= SN_FINST_C;
2350 else
2351 t->flags |= SN_FINST_D;
2352 }
2353 return 1;
2354 }
2355 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002356 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002357 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02002358 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002359 shutdown(t->cli_fd, SHUT_WR);
2360 /* We must ensure that the read part is still alive when switching
2361 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002362 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002363 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002364
2365 t->cli_state = CL_STSHUTW;
2366 if (!(t->flags & SN_ERR_MASK))
2367 t->flags |= SN_ERR_CLITO;
2368 if (!(t->flags & SN_FINST_MASK)) {
2369 if (t->pend_pos)
2370 t->flags |= SN_FINST_Q;
2371 else if (s == SV_STCONN)
2372 t->flags |= SN_FINST_C;
2373 else
2374 t->flags |= SN_FINST_D;
2375 }
2376 return 1;
2377 }
2378
2379 if (req->l >= req->rlim - req->data) {
2380 /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02002381 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002382 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002383 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002384 }
2385 } else {
2386 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002387 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002388 if (!t->fe->timeout.client ||
2389 (t->srv_state < SV_STDATA && t->be->timeout.server))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002390 /* If the client has no timeout, or if the server not ready yet, and we
2391 * know for sure that it can expire, then it's cleaner to disable the
2392 * timeout on the client side so that too low values cannot make the
2393 * sessions abort too early.
2394 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002395 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002396 else
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002397 req->rex = tick_add(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002398 }
2399 }
2400
2401 if ((rep->l == 0) ||
2402 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002403 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2404 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002405 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002406 }
2407 } else {
2408 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002409 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2410 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002411 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
2412 if (rep->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002413 /* FIXME: to prevent the client from expiring read timeouts during writes,
2414 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002415 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002416 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002417 }
2418 }
2419 return 0; /* other cases change nothing */
2420 }
2421 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002422 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002423 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002424 fd_delete(t->cli_fd);
2425 t->cli_state = CL_STCLOSE;
2426 if (!(t->flags & SN_ERR_MASK))
2427 t->flags |= SN_ERR_CLICL;
2428 if (!(t->flags & SN_FINST_MASK)) {
2429 if (t->pend_pos)
2430 t->flags |= SN_FINST_Q;
2431 else if (s == SV_STCONN)
2432 t->flags |= SN_FINST_C;
2433 else
2434 t->flags |= SN_FINST_D;
2435 }
2436 return 1;
2437 }
2438 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
2439 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002440 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002441 fd_delete(t->cli_fd);
2442 t->cli_state = CL_STCLOSE;
2443 return 1;
2444 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002445 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002446 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002447 fd_delete(t->cli_fd);
2448 t->cli_state = CL_STCLOSE;
2449 if (!(t->flags & SN_ERR_MASK))
2450 t->flags |= SN_ERR_CLITO;
2451 if (!(t->flags & SN_FINST_MASK)) {
2452 if (t->pend_pos)
2453 t->flags |= SN_FINST_Q;
2454 else if (s == SV_STCONN)
2455 t->flags |= SN_FINST_C;
2456 else
2457 t->flags |= SN_FINST_D;
2458 }
2459 return 1;
2460 }
2461
2462 if (t->flags & SN_SELF_GEN) {
2463 produce_content(t);
2464 if (rep->l == 0) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002465 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002466 fd_delete(t->cli_fd);
2467 t->cli_state = CL_STCLOSE;
2468 return 1;
2469 }
2470 }
2471
2472 if ((rep->l == 0)
2473 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002474 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2475 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002476 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002477 }
2478 } else {
2479 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002480 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2481 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002482 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002483 }
2484 }
2485 return 0;
2486 }
2487 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002488 if (req->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002489 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002490 fd_delete(t->cli_fd);
2491 t->cli_state = CL_STCLOSE;
2492 if (!(t->flags & SN_ERR_MASK))
2493 t->flags |= SN_ERR_CLICL;
2494 if (!(t->flags & SN_FINST_MASK)) {
2495 if (t->pend_pos)
2496 t->flags |= SN_FINST_Q;
2497 else if (s == SV_STCONN)
2498 t->flags |= SN_FINST_C;
2499 else
2500 t->flags |= SN_FINST_D;
2501 }
2502 return 1;
2503 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002504 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002505 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002506 fd_delete(t->cli_fd);
2507 t->cli_state = CL_STCLOSE;
2508 return 1;
2509 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002510 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002511 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002512 fd_delete(t->cli_fd);
2513 t->cli_state = CL_STCLOSE;
2514 if (!(t->flags & SN_ERR_MASK))
2515 t->flags |= SN_ERR_CLITO;
2516 if (!(t->flags & SN_FINST_MASK)) {
2517 if (t->pend_pos)
2518 t->flags |= SN_FINST_Q;
2519 else if (s == SV_STCONN)
2520 t->flags |= SN_FINST_C;
2521 else
2522 t->flags |= SN_FINST_D;
2523 }
2524 return 1;
2525 }
2526 else if (req->l >= req->rlim - req->data) {
2527 /* no room to read more data */
2528
2529 /* FIXME-20050705: is it possible for a client to maintain a session
2530 * after the timeout by sending more data after it receives a close ?
2531 */
2532
Willy Tarreau66319382007-04-08 17:17:37 +02002533 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002534 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002535 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002536 }
2537 } else {
2538 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002539 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002540 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002541 }
2542 }
2543 return 0;
2544 }
2545 else { /* CL_STCLOSE: nothing to do */
2546 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2547 int len;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002548 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002549 write(1, trash, len);
2550 }
2551 return 0;
2552 }
2553 return 0;
2554}
2555
2556
2557/*
2558 * manages the server FSM and its socket. It returns 1 if a state has changed
2559 * (and a resync may be needed), 0 else.
2560 */
2561int process_srv(struct session *t)
2562{
2563 int s = t->srv_state;
2564 int c = t->cli_state;
Willy Tarreau3d300592007-03-18 18:34:41 +01002565 struct http_txn *txn = &t->txn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002566 struct buffer *req = t->req;
2567 struct buffer *rep = t->rep;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002568 int conn_err;
2569
2570#ifdef DEBUG_FULL
2571 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2572#endif
Willy Tarreauee991362007-05-14 14:37:50 +02002573
2574#if 0
2575 fprintf(stderr,"%s:%d fe->clito=%d.%d, fe->conto=%d.%d, fe->srvto=%d.%d\n",
2576 __FUNCTION__, __LINE__,
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002577 t->fe->timeout.client.tv_sec, t->fe->timeout.client.tv_usec,
2578 t->fe->timeout.connect.tv_sec, t->fe->timeout.connect.tv_usec,
2579 t->fe->timeout.server.tv_sec, t->fe->timeout.server.tv_usec);
Willy Tarreauee991362007-05-14 14:37:50 +02002580 fprintf(stderr,"%s:%d be->clito=%d.%d, be->conto=%d.%d, be->srvto=%d.%d\n",
2581 __FUNCTION__, __LINE__,
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002582 t->be->timeout.client.tv_sec, t->be->timeout.client.tv_usec,
2583 t->be->timeout.connect.tv_sec, t->be->timeout.connect.tv_usec,
2584 t->be->timeout.server.tv_sec, t->be->timeout.server.tv_usec);
Willy Tarreauee991362007-05-14 14:37:50 +02002585
2586 fprintf(stderr,"%s:%d req->cto=%d.%d, req->rto=%d.%d, req->wto=%d.%d\n",
2587 __FUNCTION__, __LINE__,
2588 req->cto.tv_sec, req->cto.tv_usec,
2589 req->rto.tv_sec, req->rto.tv_usec,
2590 req->wto.tv_sec, req->wto.tv_usec);
2591
2592 fprintf(stderr,"%s:%d rep->cto=%d.%d, rep->rto=%d.%d, rep->wto=%d.%d\n",
2593 __FUNCTION__, __LINE__,
2594 rep->cto.tv_sec, rep->cto.tv_usec,
2595 rep->rto.tv_sec, rep->rto.tv_usec,
2596 rep->wto.tv_sec, rep->wto.tv_usec);
2597#endif
2598
Willy Tarreaubaaee002006-06-26 02:48:02 +02002599 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
Willy Tarreauf161a342007-04-08 16:59:42 +02002600 //EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
2601 //EV_FD_ISSET(t->srv_fd, DIR_RD), EV_FD_ISSET(t->srv_fd, DIR_WR)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002602 //);
2603 if (s == SV_STIDLE) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002604 /* NOTE: The client processor may switch to SV_STANALYZE, which switches back SV_STIDLE.
2605 * This is logcially after CL_STHEADERS completed, CL_STDATA has started, but
2606 * we need to defer server selection until more data arrives, if possible.
2607 * This is rare, and only if balancing on parameter hash with values in the entity of a POST
2608 */
2609 if (c == CL_STHEADERS )
Willy Tarreaubaaee002006-06-26 02:48:02 +02002610 return 0; /* stay in idle, waiting for data to reach the client side */
2611 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
2612 (c == CL_STSHUTR &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002613 (t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002614 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002615 if (t->pend_pos)
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002616 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002617 /* note that this must not return any error because it would be able to
2618 * overwrite the client_retnclose() output.
2619 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002620 if (txn->flags & TX_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01002621 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02002622 else
Willy Tarreau0f772532006-12-23 20:51:41 +01002623 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002624
2625 return 1;
2626 }
2627 else {
Willy Tarreau3d300592007-03-18 18:34:41 +01002628 if (txn->flags & TX_CLTARPIT) {
Willy Tarreaub8750a82006-09-03 09:56:00 +02002629 /* This connection is being tarpitted. The CLIENT side has
2630 * already set the connect expiration date to the right
2631 * timeout. We just have to check that it has not expired.
2632 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002633 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreaub8750a82006-09-03 09:56:00 +02002634 return 0;
2635
2636 /* We will set the queue timer to the time spent, just for
2637 * logging purposes. We fake a 500 server error, so that the
2638 * attacker will not suspect his connection has been tarpitted.
2639 * It will not cause trouble to the logs because we can exclude
2640 * the tarpitted connections by filtering on the 'PT' status flags.
2641 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002642 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002643 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaub8750a82006-09-03 09:56:00 +02002644 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01002645 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02002646 return 1;
2647 }
2648
Willy Tarreaubaaee002006-06-26 02:48:02 +02002649 /* Right now, we will need to create a connection to the server.
2650 * We might already have tried, and got a connection pending, in
2651 * which case we will not do anything till it's pending. It's up
2652 * to any other session to release it and wake us up again.
2653 */
2654 if (t->pend_pos) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002655 if (!tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002656 return 0;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002657 } else {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002658 /* we've been waiting too long here */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002659 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002660 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002661 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01002662 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002663 if (t->srv)
2664 t->srv->failed_conns++;
Willy Tarreau50fd1e12007-12-10 15:25:35 +01002665 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002666 return 1;
2667 }
2668 }
2669
2670 do {
2671 /* first, get a connection */
Willy Tarreau21d2af32008-02-14 20:25:24 +01002672 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
2673 t->flags |= SN_REDIRECTABLE;
2674
Willy Tarreaubaaee002006-06-26 02:48:02 +02002675 if (srv_redispatch_connect(t))
2676 return t->srv_state != SV_STIDLE;
2677
Willy Tarreau21d2af32008-02-14 20:25:24 +01002678 if ((t->flags & SN_REDIRECTABLE) && t->srv && t->srv->rdr_len) {
2679 /* Server supporting redirection and it is possible.
2680 * Invalid requests are reported as such. It concerns all
2681 * the largest ones.
2682 */
2683 struct chunk rdr;
2684 char *path;
2685 int len;
2686
2687 /* 1: create the response header */
2688 rdr.len = strlen(HTTP_302);
2689 rdr.str = trash;
2690 memcpy(rdr.str, HTTP_302, rdr.len);
2691
2692 /* 2: add the server's prefix */
2693 if (rdr.len + t->srv->rdr_len > sizeof(trash))
2694 goto cancel_redir;
2695
2696 memcpy(rdr.str + rdr.len, t->srv->rdr_pfx, t->srv->rdr_len);
2697 rdr.len += t->srv->rdr_len;
2698
2699 /* 3: add the request URI */
2700 path = http_get_path(txn);
2701 if (!path)
2702 goto cancel_redir;
2703 len = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
2704 if (rdr.len + len > sizeof(trash) - 4) /* 4 for CRLF-CRLF */
2705 goto cancel_redir;
2706
2707 memcpy(rdr.str + rdr.len, path, len);
2708 rdr.len += len;
2709 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
2710 rdr.len += 4;
2711
2712 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C, 302, &rdr);
2713 /* FIXME: we should increase a counter of redirects per server and per backend. */
2714 if (t->srv)
2715 t->srv->cum_sess++;
2716 return 1;
2717 cancel_redir:
2718 txn->status = 400;
2719 t->fe->failed_req++;
2720 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C,
2721 400, error_message(t, HTTP_ERR_400));
2722 return 1;
2723 }
2724
Willy Tarreaubaaee002006-06-26 02:48:02 +02002725 /* try to (re-)connect to the server, and fail if we expire the
2726 * number of retries.
2727 */
2728 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002729 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002730 return t->srv_state != SV_STIDLE;
2731 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002732 } while (1);
2733 }
2734 }
2735 else if (s == SV_STCONN) { /* connection in progress */
2736 if (c == CL_STCLOSE || c == CL_STSHUTW ||
2737 (c == CL_STSHUTR &&
Willy Tarreauc9b654b2007-05-08 14:46:53 +02002738 ((t->req->l == 0 && !(req->flags & BF_WRITE_STATUS)) ||
2739 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002740 req->cex = TICK_ETERNITY;
Willy Tarreauf899b942008-03-28 18:09:38 +01002741 if (!(t->flags & SN_CONN_TAR)) {
2742 /* if we are in turn-around, we have already closed the FD */
2743 fd_delete(t->srv_fd);
2744 if (t->srv) {
2745 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002746 sess_change_server(t, NULL);
Willy Tarreauf899b942008-03-28 18:09:38 +01002747 }
Willy Tarreau51406232008-03-10 22:04:20 +01002748 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002749
2750 /* note that this must not return any error because it would be able to
2751 * overwrite the client_retnclose() output.
2752 */
Willy Tarreau0f772532006-12-23 20:51:41 +01002753 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002754 return 1;
2755 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002756 if (!(req->flags & BF_WRITE_STATUS) && !tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002757 return 0; /* nothing changed */
2758 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002759 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002760 /* timeout, asynchronous connect error or first write error */
2761 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2762
Willy Tarreau541b5c22008-01-06 23:34:21 +01002763 if (t->flags & SN_CONN_TAR) {
2764 /* We are doing a turn-around waiting for a new connection attempt. */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002765 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreau541b5c22008-01-06 23:34:21 +01002766 return 0;
2767 t->flags &= ~SN_CONN_TAR;
2768 }
2769 else {
2770 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01002771 if (t->srv) {
Willy Tarreau541b5c22008-01-06 23:34:21 +01002772 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002773 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01002774 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002775
Willy Tarreau541b5c22008-01-06 23:34:21 +01002776 if (!(req->flags & BF_WRITE_STATUS))
2777 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
2778 else
2779 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
2780
2781 /* ensure that we have enough retries left */
2782 if (srv_count_retry_down(t, conn_err))
2783 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002784
Willy Tarreau541b5c22008-01-06 23:34:21 +01002785 if (req->flags & BF_WRITE_ERROR) {
2786 /* we encountered an immediate connection error, and we
2787 * will have to retry connecting to the same server, most
2788 * likely leading to the same result. To avoid this, we
2789 * fake a connection timeout to retry after a turn-around
2790 * time of 1 second. We will wait in the previous if block.
2791 */
2792 t->flags |= SN_CONN_TAR;
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002793 req->cex = tick_add(now_ms, MS_TO_TICKS(1000));
Willy Tarreau541b5c22008-01-06 23:34:21 +01002794 return 0;
2795 }
2796 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002797
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002798 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002799 /* We're on our last chance, and the REDISP option was specified.
2800 * We will ignore cookie and force to balance or use the dispatcher.
2801 */
2802 /* let's try to offer this slot to anybody */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002803 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02002804 process_srv_queue(t->srv);
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002805
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01002806 /* it's left to the dispatcher to choose a server */
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002807 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
Willy Tarreau7c669d72008-06-20 15:04:11 +02002808 t->prev_srv = t->srv;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002809
2810 /* first, get a connection */
2811 if (srv_redispatch_connect(t))
Willy Tarreau00559e72008-01-06 23:46:19 +01002812 return t->srv_state != SV_STCONN;
Krzysztof Piotr Oledzki626a19b2008-02-04 02:10:09 +01002813 } else {
2814 if (t->srv)
2815 t->srv->retries++;
2816 t->be->retries++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002817 }
2818
Willy Tarreaubaaee002006-06-26 02:48:02 +02002819 do {
2820 /* Now we will try to either reconnect to the same server or
2821 * connect to another server. If the connection gets queued
2822 * because all servers are saturated, then we will go back to
2823 * the SV_STIDLE state.
2824 */
2825 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002826 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002827 return t->srv_state != SV_STCONN;
2828 }
2829
2830 /* we need to redispatch the connection to another server */
2831 if (srv_redispatch_connect(t))
2832 return t->srv_state != SV_STCONN;
2833 } while (1);
2834 }
2835 else { /* no error or write 0 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002836 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002837
2838 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2839 if (req->l == 0) /* nothing to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002840 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002841 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002842 } else /* need the right to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002843 EV_FD_SET(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002844 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
2845 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002846 /* FIXME: to prevent the server from expiring read timeouts during writes,
2847 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002848 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002849 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002850 }
2851
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002852 if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreauf161a342007-04-08 16:59:42 +02002853 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002854 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002855 t->srv_state = SV_STDATA;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002856 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
2857
2858 /* if the user wants to log as soon as possible, without counting
2859 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002860 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002861 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
Willy Tarreau42250582007-04-01 01:30:43 +02002862 tcp_sess_log(t);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002863 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002864#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002865 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002866 /* TCP splicing supported by both FE and BE */
2867 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2868 }
2869#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002870 }
2871 else {
2872 t->srv_state = SV_STHEADERS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002873 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002874 t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
2875 /* reset hdr_idx which was already initialized by the request.
2876 * right now, the http parser does it.
2877 * hdr_idx_init(&t->txn.hdr_idx);
2878 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002879 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002880 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002881 return 1;
2882 }
2883 }
2884 else if (s == SV_STHEADERS) { /* receiving server headers */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002885 /*
2886 * Now parse the partial (or complete) lines.
2887 * We will check the response syntax, and also join multi-line
2888 * headers. An index of all the lines will be elaborated while
2889 * parsing.
2890 *
2891 * For the parsing, we use a 28 states FSM.
2892 *
2893 * Here is the information we currently have :
2894 * rep->data + req->som = beginning of response
2895 * rep->data + req->eoh = end of processed headers / start of current one
2896 * rep->data + req->eol = end of current header or line (LF or CRLF)
2897 * rep->lr = first non-visited byte
2898 * rep->r = end of data
2899 */
2900
2901 int cur_idx;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002902 struct http_msg *msg = &txn->rsp;
2903 struct proxy *cur_proxy;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002904
Willy Tarreaua15645d2007-03-18 16:22:39 +01002905 if (likely(rep->lr < rep->r))
2906 http_msg_analyzer(rep, msg, &txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002907
Willy Tarreaua15645d2007-03-18 16:22:39 +01002908 /* 1: we might have to print this header in debug mode */
2909 if (unlikely((global.mode & MODE_DEBUG) &&
2910 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
2911 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
2912 char *eol, *sol;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002913
Willy Tarreaua15645d2007-03-18 16:22:39 +01002914 sol = rep->data + msg->som;
2915 eol = sol + msg->sl.rq.l;
2916 debug_hdr("srvrep", t, sol, eol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002917
Willy Tarreaua15645d2007-03-18 16:22:39 +01002918 sol += hdr_idx_first_pos(&txn->hdr_idx);
2919 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002920
Willy Tarreaua15645d2007-03-18 16:22:39 +01002921 while (cur_idx) {
2922 eol = sol + txn->hdr_idx.v[cur_idx].len;
2923 debug_hdr("srvhdr", t, sol, eol);
2924 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
2925 cur_idx = txn->hdr_idx.v[cur_idx].next;
2926 }
2927 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002928
Willy Tarreaubaaee002006-06-26 02:48:02 +02002929
Willy Tarreau66319382007-04-08 17:17:37 +02002930 if ((rep->l < rep->rlim - rep->data) && EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002931 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreaua15645d2007-03-18 16:22:39 +01002932 * full. We cannot loop here since stream_sock_read will disable it only if
2933 * rep->l == rlim-data
2934 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002935 req->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002936 }
2937
2938
2939 /*
2940 * Now we quickly check if we have found a full valid response.
2941 * If not so, we check the FD and buffer states before leaving.
2942 * A full response is indicated by the fact that we have seen
2943 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
2944 * responses are checked first.
2945 *
2946 * Depending on whether the client is still there or not, we
2947 * may send an error response back or not. Note that normally
2948 * we should only check for HTTP status there, and check I/O
2949 * errors somewhere else.
2950 */
2951
2952 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
2953
2954 /* Invalid response, or read error or write error */
2955 if (unlikely((msg->msg_state == HTTP_MSG_ERROR) ||
2956 (req->flags & BF_WRITE_ERROR) ||
2957 (rep->flags & BF_READ_ERROR))) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002958 buffer_shutr(rep);
2959 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002960 fd_delete(t->srv_fd);
2961 if (t->srv) {
2962 t->srv->cur_sess--;
2963 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002964 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002965 }
2966 t->be->failed_resp++;
2967 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002968 txn->status = 502;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002969 client_return(t, error_message(t, HTTP_ERR_502));
2970 if (!(t->flags & SN_ERR_MASK))
2971 t->flags |= SN_ERR_SRVCL;
2972 if (!(t->flags & SN_FINST_MASK))
2973 t->flags |= SN_FINST_H;
2974 /* We used to have a free connection slot. Since we'll never use it,
2975 * we have to inform the server that it may be used by another session.
2976 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002977 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02002978 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002979
Willy Tarreaua15645d2007-03-18 16:22:39 +01002980 return 1;
2981 }
2982
2983 /* end of client write or end of server read.
2984 * since we are in header mode, if there's no space left for headers, we
2985 * won't be able to free more later, so the session will never terminate.
2986 */
2987 else if (unlikely(rep->flags & BF_READ_NULL ||
2988 c == CL_STSHUTW || c == CL_STCLOSE ||
2989 rep->l >= rep->rlim - rep->data)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002990 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002991 buffer_shutr(rep);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002992 t->srv_state = SV_STSHUTR;
2993 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2994 return 1;
2995 }
2996
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002997 /* read timeout : return a 504 to the client. */
Willy Tarreauf161a342007-04-08 16:59:42 +02002998 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_RD) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002999 tick_is_expired(rep->rex, now_ms))) {
Willy Tarreaufa645582007-06-03 15:59:52 +02003000 buffer_shutr(rep);
3001 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003002 fd_delete(t->srv_fd);
3003 if (t->srv) {
3004 t->srv->cur_sess--;
3005 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003006 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003007 }
3008 t->be->failed_resp++;
3009 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003010 txn->status = 504;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003011 client_return(t, error_message(t, HTTP_ERR_504));
3012 if (!(t->flags & SN_ERR_MASK))
3013 t->flags |= SN_ERR_SRVTO;
3014 if (!(t->flags & SN_FINST_MASK))
3015 t->flags |= SN_FINST_H;
3016 /* We used to have a free connection slot. Since we'll never use it,
3017 * we have to inform the server that it may be used by another session.
3018 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003019 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003020 process_srv_queue(t->srv);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003021 return 1;
3022 }
3023
3024 /* last client read and buffer empty */
3025 /* FIXME!!! here, we don't want to switch to SHUTW if the
3026 * client shuts read too early, because we may still have
3027 * some work to do on the headers.
3028 * The side-effect is that if the client completely closes its
3029 * connection during SV_STHEADER, the connection to the server
3030 * is kept until a response comes back or the timeout is reached.
3031 */
3032 else if (unlikely((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) &&
3033 (req->l == 0))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003034 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003035 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003036
3037 /* We must ensure that the read part is still
3038 * alive when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003039 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003040 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003041
3042 shutdown(t->srv_fd, SHUT_WR);
3043 t->srv_state = SV_STSHUTW;
3044 return 1;
3045 }
3046
3047 /* write timeout */
3048 /* FIXME!!! here, we don't want to switch to SHUTW if the
3049 * client shuts read too early, because we may still have
3050 * some work to do on the headers.
3051 */
Willy Tarreauf161a342007-04-08 16:59:42 +02003052 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_WR) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003053 tick_is_expired(req->wex, now_ms))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003054 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003055 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003056 shutdown(t->srv_fd, SHUT_WR);
3057 /* We must ensure that the read part is still alive
3058 * when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003059 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003060 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003061
3062 t->srv_state = SV_STSHUTW;
3063 if (!(t->flags & SN_ERR_MASK))
3064 t->flags |= SN_ERR_SRVTO;
3065 if (!(t->flags & SN_FINST_MASK))
3066 t->flags |= SN_FINST_H;
3067 return 1;
3068 }
3069
3070 /*
3071 * And now the non-error cases.
3072 */
3073
3074 /* Data remaining in the request buffer.
3075 * This happens during the first pass here, and during
3076 * long posts.
3077 */
3078 else if (likely(req->l)) {
Willy Tarreau66319382007-04-08 17:17:37 +02003079 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3080 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003081 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3082 if (req->wex) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003083 /* FIXME: to prevent the server from expiring read timeouts during writes,
3084 * we refresh it. */
3085 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003086 }
3087 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003088 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003089
Willy Tarreaua15645d2007-03-18 16:22:39 +01003090 /* nothing left in the request buffer */
3091 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003092 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3093 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003094 req->wex = TICK_ETERNITY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003095 }
3096 }
3097
3098 return t->srv_state != SV_STHEADERS;
3099 }
3100
3101
3102 /*****************************************************************
3103 * More interesting part now : we know that we have a complete *
3104 * response which at least looks like HTTP. We have an indicator *
3105 * of each header's length, so we can parse them quickly. *
3106 ****************************************************************/
3107
Willy Tarreau9cdde232007-05-02 20:58:19 +02003108 /* ensure we keep this pointer to the beginning of the message */
3109 msg->sol = rep->data + msg->som;
3110
Willy Tarreaua15645d2007-03-18 16:22:39 +01003111 /*
3112 * 1: get the status code and check for cacheability.
3113 */
3114
3115 t->logs.logwait &= ~LW_RESP;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003116 txn->status = strl2ui(rep->data + msg->sl.st.c, msg->sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003117
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003118 switch (txn->status) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003119 case 200:
3120 case 203:
3121 case 206:
3122 case 300:
3123 case 301:
3124 case 410:
3125 /* RFC2616 @13.4:
3126 * "A response received with a status code of
3127 * 200, 203, 206, 300, 301 or 410 MAY be stored
3128 * by a cache (...) unless a cache-control
3129 * directive prohibits caching."
3130 *
3131 * RFC2616 @9.5: POST method :
3132 * "Responses to this method are not cacheable,
3133 * unless the response includes appropriate
3134 * Cache-Control or Expires header fields."
3135 */
3136 if (likely(txn->meth != HTTP_METH_POST) &&
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003137 (t->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
Willy Tarreau3d300592007-03-18 18:34:41 +01003138 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003139 break;
3140 default:
3141 break;
3142 }
3143
3144 /*
3145 * 2: we may need to capture headers
3146 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003147 if (unlikely((t->logs.logwait & LW_RSPHDR) && t->fe->rsp_cap))
Willy Tarreaua15645d2007-03-18 16:22:39 +01003148 capture_headers(rep->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003149 txn->rsp.cap, t->fe->rsp_cap);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003150
3151 /*
3152 * 3: we will have to evaluate the filters.
3153 * As opposed to version 1.2, now they will be evaluated in the
3154 * filters order and not in the header order. This means that
3155 * each filter has to be validated among all headers.
3156 *
3157 * Filters are tried with ->be first, then with ->fe if it is
3158 * different from ->be.
3159 */
3160
3161 t->flags &= ~SN_CONN_CLOSED; /* prepare for inspection */
3162
3163 cur_proxy = t->be;
3164 while (1) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003165 struct proxy *rule_set = cur_proxy;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003166
3167 /* try headers filters */
3168 if (rule_set->rsp_exp != NULL) {
3169 if (apply_filters_to_response(t, rep, rule_set->rsp_exp) < 0) {
3170 return_bad_resp:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003171 if (t->srv) {
3172 t->srv->cur_sess--;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003173 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003174 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003175 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003176 cur_proxy->failed_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003177 return_srv_prx_502:
Willy Tarreaufa645582007-06-03 15:59:52 +02003178 buffer_shutr(rep);
3179 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003180 fd_delete(t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003181 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003182 txn->status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01003183 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003184 if (!(t->flags & SN_ERR_MASK))
3185 t->flags |= SN_ERR_PRXCOND;
3186 if (!(t->flags & SN_FINST_MASK))
3187 t->flags |= SN_FINST_H;
3188 /* We used to have a free connection slot. Since we'll never use it,
3189 * we have to inform the server that it may be used by another session.
3190 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003191 if (t->srv && may_dequeue_tasks(t->srv, cur_proxy))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003192 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003193 return 1;
3194 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003195 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003196
Willy Tarreaua15645d2007-03-18 16:22:39 +01003197 /* has the response been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01003198 if (txn->flags & TX_SVDENY) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003199 if (t->srv) {
3200 t->srv->cur_sess--;
3201 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003202 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003203 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003204 cur_proxy->denied_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003205 goto return_srv_prx_502;
3206 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003207
Willy Tarreaua15645d2007-03-18 16:22:39 +01003208 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003209 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01003210 !(t->flags & SN_CONN_CLOSED)) {
3211 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003212 int cur_idx, old_idx, delta, val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003213 struct hdr_idx_elem *cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003214
Willy Tarreaua15645d2007-03-18 16:22:39 +01003215 cur_next = rep->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
3216 old_idx = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003217
Willy Tarreaua15645d2007-03-18 16:22:39 +01003218 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
3219 cur_hdr = &txn->hdr_idx.v[cur_idx];
3220 cur_ptr = cur_next;
3221 cur_end = cur_ptr + cur_hdr->len;
3222 cur_next = cur_end + cur_hdr->cr + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003223
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003224 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
3225 if (val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003226 /* 3 possibilities :
3227 * - we have already set Connection: close,
3228 * so we remove this line.
3229 * - we have not yet set Connection: close,
3230 * but this line indicates close. We leave
3231 * it untouched and set the flag.
3232 * - we have not yet set Connection: close,
3233 * and this line indicates non-close. We
3234 * replace it.
3235 */
3236 if (t->flags & SN_CONN_CLOSED) {
3237 delta = buffer_replace2(rep, cur_ptr, cur_next, NULL, 0);
3238 txn->rsp.eoh += delta;
3239 cur_next += delta;
3240 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3241 txn->hdr_idx.used--;
3242 cur_hdr->len = 0;
3243 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003244 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
3245 delta = buffer_replace2(rep, cur_ptr + val, cur_end,
3246 "close", 5);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003247 cur_next += delta;
3248 cur_hdr->len += delta;
3249 txn->rsp.eoh += delta;
3250 }
3251 t->flags |= SN_CONN_CLOSED;
3252 }
3253 }
3254 old_idx = cur_idx;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003255 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003256 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003257
Willy Tarreaua15645d2007-03-18 16:22:39 +01003258 /* add response headers from the rule sets in the same order */
3259 for (cur_idx = 0; cur_idx < rule_set->nb_rspadd; cur_idx++) {
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003260 if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx,
3261 rule_set->rsp_add[cur_idx])) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003262 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003263 }
3264
Willy Tarreaua15645d2007-03-18 16:22:39 +01003265 /* check whether we're already working on the frontend */
3266 if (cur_proxy == t->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003267 break;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003268 cur_proxy = t->fe;
3269 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003270
Willy Tarreaua15645d2007-03-18 16:22:39 +01003271 /*
3272 * 4: check for server cookie.
3273 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003274 if (t->be->cookie_name || t->be->appsession_name || t->be->capture_name
3275 || (t->be->options & PR_O_CHK_CACHE))
3276 manage_server_side_cookies(t, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003277
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003278
Willy Tarreaua15645d2007-03-18 16:22:39 +01003279 /*
Willy Tarreau396d2c62007-11-04 19:30:00 +01003280 * 5: check for cache-control or pragma headers if required.
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003281 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003282 if ((t->be->options & (PR_O_COOK_NOC | PR_O_CHK_CACHE)) != 0)
3283 check_response_for_cacheability(t, rep);
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003284
3285 /*
3286 * 6: add server cookie in the response if needed
Willy Tarreaua15645d2007-03-18 16:22:39 +01003287 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003288 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
3289 (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003290 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003291
Willy Tarreaua15645d2007-03-18 16:22:39 +01003292 /* the server is known, it's not the one the client requested, we have to
3293 * insert a set-cookie here, except if we want to insert only on POST
3294 * requests and this one isn't. Note that servers which don't have cookies
3295 * (eg: some backup servers) will return a full cookie removal request.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003296 */
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003297 len = sprintf(trash, "Set-Cookie: %s=%s; path=/",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003298 t->be->cookie_name,
Willy Tarreaua15645d2007-03-18 16:22:39 +01003299 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003300
Krzysztof Piotr Oledzki1acf2172008-05-29 23:03:34 +02003301 if (t->be->cookie_domain)
3302 len += sprintf(trash+len, "; domain=%s", t->be->cookie_domain);
Krzysztof Piotr Oledzkiefe3b6f2008-05-23 23:49:32 +02003303
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003304 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3305 trash, len)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003306 goto return_bad_resp;
Willy Tarreau3d300592007-03-18 18:34:41 +01003307 txn->flags |= TX_SCK_INSERTED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003308
Willy Tarreaua15645d2007-03-18 16:22:39 +01003309 /* Here, we will tell an eventual cache on the client side that we don't
3310 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3311 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3312 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3313 */
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003314 if ((t->be->options & PR_O_COOK_NOC) && (txn->flags & TX_CACHEABLE)) {
3315
3316 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
3317
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003318 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3319 "Cache-control: private", 22)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003320 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003321 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003322 }
3323
3324
3325 /*
Willy Tarreaua15645d2007-03-18 16:22:39 +01003326 * 7: check if result will be cacheable with a cookie.
3327 * We'll block the response if security checks have caught
3328 * nasty things such as a cacheable cookie.
3329 */
Willy Tarreau3d300592007-03-18 18:34:41 +01003330 if (((txn->flags & (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) ==
3331 (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003332 (t->be->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003333
Willy Tarreaua15645d2007-03-18 16:22:39 +01003334 /* we're in presence of a cacheable response containing
3335 * a set-cookie header. We'll block it as requested by
3336 * the 'checkcache' option, and send an alert.
3337 */
3338 if (t->srv) {
3339 t->srv->cur_sess--;
3340 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003341 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003342 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003343 t->be->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003344
Willy Tarreaua15645d2007-03-18 16:22:39 +01003345 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003346 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003347 send_log(t->be, LOG_ALERT,
3348 "Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003349 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003350 goto return_srv_prx_502;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003351 }
3352
Willy Tarreaua15645d2007-03-18 16:22:39 +01003353 /*
3354 * 8: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02003355 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003356 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02003357 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003358 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02003359 if ((unlikely(msg->sl.st.v_l != 8) ||
3360 unlikely(req->data[msg->som + 7] != '0')) &&
3361 unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003362 "Connection: close", 17)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003363 goto return_bad_resp;
3364 t->flags |= SN_CONN_CLOSED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003365 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003366
Willy Tarreaubaaee002006-06-26 02:48:02 +02003367
Willy Tarreaua15645d2007-03-18 16:22:39 +01003368 /*************************************************************
3369 * OK, that's finished for the headers. We have done what we *
3370 * could. Let's switch to the DATA state. *
3371 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02003372
Willy Tarreaua15645d2007-03-18 16:22:39 +01003373 t->srv_state = SV_STDATA;
3374 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02003375 t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003376
3377 /* client connection already closed or option 'forceclose' required :
3378 * we close the server's outgoing connection right now.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003379 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003380 if ((req->l == 0) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003381 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->options & PR_O_FORCE_CLO)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003382 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003383 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003384
3385 /* We must ensure that the read part is still alive when switching
3386 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003387 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003388 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003389
Willy Tarreaua15645d2007-03-18 16:22:39 +01003390 shutdown(t->srv_fd, SHUT_WR);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003391 t->srv_state = SV_STSHUTW;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003392 }
3393
Willy Tarreaua15645d2007-03-18 16:22:39 +01003394#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003395 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003396 /* TCP splicing supported by both FE and BE */
3397 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003398 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003399#endif
3400 /* if the user wants to log as soon as possible, without counting
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003401 * bytes from the server, then this is the right moment. We have
3402 * to temporarily assign bytes_out to log what we currently have.
3403 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003404 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
3405 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreau8b3977f2008-01-18 11:16:32 +01003406 t->logs.bytes_out = txn->rsp.eoh;
Willy Tarreau42250582007-04-01 01:30:43 +02003407 if (t->fe->to_log & LW_REQ)
3408 http_sess_log(t);
3409 else
3410 tcp_sess_log(t);
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003411 t->logs.bytes_out = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003412 }
3413
Willy Tarreaua15645d2007-03-18 16:22:39 +01003414 /* Note: we must not try to cheat by jumping directly to DATA,
3415 * otherwise we would not let the client side wake up.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003416 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003417
3418 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003419 }
3420 else if (s == SV_STDATA) {
3421 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003422 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02003423 buffer_shutr(rep);
3424 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003425 fd_delete(t->srv_fd);
3426 if (t->srv) {
3427 t->srv->cur_sess--;
3428 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003429 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003430 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003431 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003432 t->srv_state = SV_STCLOSE;
3433 if (!(t->flags & SN_ERR_MASK))
3434 t->flags |= SN_ERR_SRVCL;
3435 if (!(t->flags & SN_FINST_MASK))
3436 t->flags |= SN_FINST_D;
3437 /* We used to have a free connection slot. Since we'll never use it,
3438 * we have to inform the server that it may be used by another session.
3439 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003440 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003441 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003442
3443 return 1;
3444 }
3445 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003446 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003447 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003448 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003449 t->srv_state = SV_STSHUTR;
3450 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3451 return 1;
3452 }
3453 /* end of client read and no more data to send */
3454 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003455 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003456 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003457 shutdown(t->srv_fd, SHUT_WR);
3458 /* We must ensure that the read part is still alive when switching
3459 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003460 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003461 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003462
3463 t->srv_state = SV_STSHUTW;
3464 return 1;
3465 }
3466 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003467 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003468 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003469 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003470 t->srv_state = SV_STSHUTR;
3471 if (!(t->flags & SN_ERR_MASK))
3472 t->flags |= SN_ERR_SRVTO;
3473 if (!(t->flags & SN_FINST_MASK))
3474 t->flags |= SN_FINST_D;
3475 return 1;
3476 }
3477 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003478 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003479 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003480 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003481 shutdown(t->srv_fd, SHUT_WR);
3482 /* We must ensure that the read part is still alive when switching
3483 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003484 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003485 rep->cex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003486 t->srv_state = SV_STSHUTW;
3487 if (!(t->flags & SN_ERR_MASK))
3488 t->flags |= SN_ERR_SRVTO;
3489 if (!(t->flags & SN_FINST_MASK))
3490 t->flags |= SN_FINST_D;
3491 return 1;
3492 }
3493
3494 /* recompute request time-outs */
3495 if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003496 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3497 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003498 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003499 }
3500 }
3501 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau66319382007-04-08 17:17:37 +02003502 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3503 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003504 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3505 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003506 /* FIXME: to prevent the server from expiring read timeouts during writes,
3507 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02003508 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003509 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003510 }
3511 }
3512
3513 /* recompute response time-outs */
3514 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003515 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003516 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003517 }
3518 }
3519 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003520 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003521 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003522 }
3523 }
3524
3525 return 0; /* other cases change nothing */
3526 }
3527 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003528 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003529 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003530 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003531 fd_delete(t->srv_fd);
3532 if (t->srv) {
3533 t->srv->cur_sess--;
3534 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003535 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003536 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003537 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003538 //close(t->srv_fd);
3539 t->srv_state = SV_STCLOSE;
3540 if (!(t->flags & SN_ERR_MASK))
3541 t->flags |= SN_ERR_SRVCL;
3542 if (!(t->flags & SN_FINST_MASK))
3543 t->flags |= SN_FINST_D;
3544 /* We used to have a free connection slot. Since we'll never use it,
3545 * we have to inform the server that it may be used by another session.
3546 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003547 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003548 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003549
3550 return 1;
3551 }
3552 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003553 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003554 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003555 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003556 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003557 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003558 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003559 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003560 //close(t->srv_fd);
3561 t->srv_state = SV_STCLOSE;
3562 /* We used to have a free connection slot. Since we'll never use it,
3563 * we have to inform the server that it may be used by another session.
3564 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003565 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003566 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003567
3568 return 1;
3569 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003570 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003571 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003572 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003573 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003574 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003575 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003576 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003577 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003578 //close(t->srv_fd);
3579 t->srv_state = SV_STCLOSE;
3580 if (!(t->flags & SN_ERR_MASK))
3581 t->flags |= SN_ERR_SRVTO;
3582 if (!(t->flags & SN_FINST_MASK))
3583 t->flags |= SN_FINST_D;
3584 /* We used to have a free connection slot. Since we'll never use it,
3585 * we have to inform the server that it may be used by another session.
3586 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003587 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003588 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003589
3590 return 1;
3591 }
3592 else if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003593 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3594 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003595 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003596 }
3597 }
3598 else { /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02003599 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3600 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003601 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003602 }
3603 }
3604 return 0;
3605 }
3606 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003607 if (rep->flags & BF_READ_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003608 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003609 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003610 fd_delete(t->srv_fd);
3611 if (t->srv) {
3612 t->srv->cur_sess--;
3613 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003614 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003615 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003616 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003617 //close(t->srv_fd);
3618 t->srv_state = SV_STCLOSE;
3619 if (!(t->flags & SN_ERR_MASK))
3620 t->flags |= SN_ERR_SRVCL;
3621 if (!(t->flags & SN_FINST_MASK))
3622 t->flags |= SN_FINST_D;
3623 /* We used to have a free connection slot. Since we'll never use it,
3624 * we have to inform the server that it may be used by another session.
3625 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003626 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003627 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003628
3629 return 1;
3630 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003631 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003632 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003633 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003634 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003635 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003636 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003637 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003638 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003639 //close(t->srv_fd);
3640 t->srv_state = SV_STCLOSE;
3641 /* We used to have a free connection slot. Since we'll never use it,
3642 * we have to inform the server that it may be used by another session.
3643 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003644 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003645 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003646
3647 return 1;
3648 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003649 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003650 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003651 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003652 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003653 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003654 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003655 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003656 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003657 //close(t->srv_fd);
3658 t->srv_state = SV_STCLOSE;
3659 if (!(t->flags & SN_ERR_MASK))
3660 t->flags |= SN_ERR_SRVTO;
3661 if (!(t->flags & SN_FINST_MASK))
3662 t->flags |= SN_FINST_D;
3663 /* We used to have a free connection slot. Since we'll never use it,
3664 * we have to inform the server that it may be used by another session.
3665 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003666 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003667 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003668
3669 return 1;
3670 }
3671 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003672 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003673 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003674 }
3675 }
3676 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003677 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003678 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003679 }
3680 }
3681 return 0;
3682 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003683 else if (s == SV_STANALYZE){
3684 /* this server state is set by the client to study the body for server assignment */
3685
3686 /* Have we been through this long enough to timeout? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003687 if (!tick_is_expired(req->rex, now_ms)) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003688 /* balance url_param check_post should have been the only to get into this.
3689 * just wait for data, check to compare how much
3690 */
3691 struct http_msg * msg = &t->txn.req;
3692 unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 :msg->eoh + 1;
3693 unsigned long len = req->total - body;
3694 long long limit = t->be->url_param_post_limit;
3695 struct hdr_ctx ctx;
3696 ctx.idx = 0;
3697 /* now if we have a length, we'll take the hint */
3698 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
3699 if ( ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",ctx.vlen)==0) {
3700 unsigned int chunk = 0;
3701 while ( body < req->total && !HTTP_IS_CRLF(msg->sol[body])) {
3702 char c = msg->sol[body];
3703 if (ishex(c)) {
3704 unsigned int hex = toupper(c) - '0';
3705 if ( hex > 9 )
3706 hex -= 'A' - '9' - 1;
3707 chunk = (chunk << 4) | hex;
3708 }
3709 else break;
3710 body++;
3711 len--;
3712 }
3713 if ( body == req->total )
3714 return 0; /* end of buffer? data missing! */
3715
3716 if ( memcmp(msg->sol+body, "\r\n", 2) != 0 )
3717 return 0; /* chunked encoding len ends with CRLF, and we don't have it yet */
3718
3719 /* if we support more then one chunk here, we have to do it again when assigning server
3720 1. how much entity data do we have? new var
3721 2. should save entity_start, entity_cursor, elen & rlen in req; so we don't repeat scanning here
3722 3. test if elen > limit, or set new limit to elen if 0 (end of entity found)
3723 */
3724
3725 if ( chunk < limit )
3726 limit = chunk; /* only reading one chunk */
3727 } else {
3728 if ( msg->hdr_content_len < limit )
3729 limit = msg->hdr_content_len;
3730 }
3731 if ( len < limit )
3732 return 0;
3733 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003734 t->srv_state = SV_STIDLE;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003735 return 1;
3736 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003737 else { /* SV_STCLOSE : nothing to do */
3738 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
3739 int len;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003740 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003741 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003742 write(1, trash, len);
3743 }
3744 return 0;
3745 }
3746 return 0;
3747}
3748
3749
3750/*
3751 * Produces data for the session <s> depending on its source. Expects to be
3752 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3753 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3754 * session, which it uses to keep on being called when there is free space in
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003755 * the buffer, or simply by letting an empty buffer upon return. It returns 1
Willy Tarreaubaaee002006-06-26 02:48:02 +02003756 * if it changes the session state from CL_STSHUTR, otherwise 0.
3757 */
3758int produce_content(struct session *s)
3759{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003760 if (s->data_source == DATA_SRC_NONE) {
3761 s->flags &= ~SN_SELF_GEN;
3762 return 1;
3763 }
3764 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003765 /* dump server statistics */
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01003766 int ret = stats_dump_http(s, s->be->uri_auth);
Willy Tarreau91861262007-10-17 17:06:05 +02003767 if (ret >= 0)
3768 return ret;
3769 /* -1 indicates an error */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003770 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003771
Willy Tarreau91861262007-10-17 17:06:05 +02003772 /* unknown data source or internal error */
3773 s->txn.status = 500;
3774 client_retnclose(s, error_message(s, HTTP_ERR_500));
3775 if (!(s->flags & SN_ERR_MASK))
3776 s->flags |= SN_ERR_PRXCOND;
3777 if (!(s->flags & SN_FINST_MASK))
3778 s->flags |= SN_FINST_R;
3779 s->flags &= ~SN_SELF_GEN;
3780 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003781}
3782
3783
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003784/* Iterate the same filter through all request headers.
3785 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003786 * Since it can manage the switch to another backend, it updates the per-proxy
3787 * DENY stats.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003788 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003789int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003790{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003791 char term;
3792 char *cur_ptr, *cur_end, *cur_next;
3793 int cur_idx, old_idx, last_hdr;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003794 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003795 struct hdr_idx_elem *cur_hdr;
3796 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003797
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003798 last_hdr = 0;
3799
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003800 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003801 old_idx = 0;
3802
3803 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01003804 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003805 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003806 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003807 (exp->action == ACT_ALLOW ||
3808 exp->action == ACT_DENY ||
3809 exp->action == ACT_TARPIT))
3810 return 0;
3811
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003812 cur_idx = txn->hdr_idx.v[old_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003813 if (!cur_idx)
3814 break;
3815
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003816 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003817 cur_ptr = cur_next;
3818 cur_end = cur_ptr + cur_hdr->len;
3819 cur_next = cur_end + cur_hdr->cr + 1;
3820
3821 /* Now we have one header between cur_ptr and cur_end,
3822 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003823 */
3824
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003825 /* The annoying part is that pattern matching needs
3826 * that we modify the contents to null-terminate all
3827 * strings before testing them.
3828 */
3829
3830 term = *cur_end;
3831 *cur_end = '\0';
3832
3833 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3834 switch (exp->action) {
3835 case ACT_SETBE:
3836 /* It is not possible to jump a second time.
3837 * FIXME: should we return an HTTP/500 here so that
3838 * the admin knows there's a problem ?
3839 */
3840 if (t->be != t->fe)
3841 break;
3842
3843 /* Swithing Proxy */
3844 t->be = (struct proxy *) exp->replace;
3845
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003846 /* right now, the backend switch is not overly complicated
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003847 * because we have associated req_cap and rsp_cap to the
3848 * frontend, and the beconn will be updated later.
3849 */
3850
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003851 t->rep->rto = t->req->wto = t->be->timeout.server;
3852 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02003853 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003854 last_hdr = 1;
3855 break;
3856
3857 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003858 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003859 last_hdr = 1;
3860 break;
3861
3862 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003863 txn->flags |= TX_CLDENY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003864 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003865 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003866 break;
3867
3868 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003869 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003870 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003871 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003872 break;
3873
3874 case ACT_REPLACE:
3875 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3876 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3877 /* FIXME: if the user adds a newline in the replacement, the
3878 * index will not be recalculated for now, and the new line
3879 * will not be counted as a new header.
3880 */
3881
3882 cur_end += delta;
3883 cur_next += delta;
3884 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003885 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003886 break;
3887
3888 case ACT_REMOVE:
3889 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3890 cur_next += delta;
3891
3892 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003893 txn->req.eoh += delta;
3894 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3895 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003896 cur_hdr->len = 0;
3897 cur_end = NULL; /* null-term has been rewritten */
3898 break;
3899
3900 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01003901 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003902 if (cur_end)
3903 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003904
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003905 /* keep the link from this header to next one in case of later
3906 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003907 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003908 old_idx = cur_idx;
3909 }
3910 return 0;
3911}
3912
3913
3914/* Apply the filter to the request line.
3915 * Returns 0 if nothing has been done, 1 if the filter has been applied,
3916 * or -1 if a replacement resulted in an invalid request line.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003917 * Since it can manage the switch to another backend, it updates the per-proxy
3918 * DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003919 */
3920int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
3921{
3922 char term;
3923 char *cur_ptr, *cur_end;
3924 int done;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003925 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003926 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003927
Willy Tarreau58f10d72006-12-04 02:26:12 +01003928
Willy Tarreau3d300592007-03-18 18:34:41 +01003929 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003930 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003931 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003932 (exp->action == ACT_ALLOW ||
3933 exp->action == ACT_DENY ||
3934 exp->action == ACT_TARPIT))
3935 return 0;
3936 else if (exp->action == ACT_REMOVE)
3937 return 0;
3938
3939 done = 0;
3940
Willy Tarreau9cdde232007-05-02 20:58:19 +02003941 cur_ptr = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003942 cur_end = cur_ptr + txn->req.sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003943
3944 /* Now we have the request line between cur_ptr and cur_end */
3945
3946 /* The annoying part is that pattern matching needs
3947 * that we modify the contents to null-terminate all
3948 * strings before testing them.
3949 */
3950
3951 term = *cur_end;
3952 *cur_end = '\0';
3953
3954 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3955 switch (exp->action) {
3956 case ACT_SETBE:
3957 /* It is not possible to jump a second time.
3958 * FIXME: should we return an HTTP/500 here so that
3959 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01003960 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003961 if (t->be != t->fe)
3962 break;
3963
3964 /* Swithing Proxy */
3965 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003966
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003967 /* right now, the backend switch is not too much complicated
3968 * because we have associated req_cap and rsp_cap to the
3969 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003970 */
3971
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003972 t->rep->rto = t->req->wto = t->be->timeout.server;
3973 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02003974 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003975 done = 1;
3976 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003977
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003978 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003979 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003980 done = 1;
3981 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003982
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003983 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003984 txn->flags |= TX_CLDENY;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003985 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003986 done = 1;
3987 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003988
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003989 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003990 txn->flags |= TX_CLTARPIT;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003991 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003992 done = 1;
3993 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003994
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003995 case ACT_REPLACE:
3996 *cur_end = term; /* restore the string terminator */
3997 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3998 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3999 /* FIXME: if the user adds a newline in the replacement, the
4000 * index will not be recalculated for now, and the new line
4001 * will not be counted as a new header.
4002 */
Willy Tarreaua496b602006-12-17 23:15:24 +01004003
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004004 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004005 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01004006
Willy Tarreau9cdde232007-05-02 20:58:19 +02004007 txn->req.sol = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004008 cur_end = (char *)http_parse_reqline(&txn->req, req->data,
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004009 HTTP_MSG_RQMETH,
4010 cur_ptr, cur_end + 1,
4011 NULL, NULL);
4012 if (unlikely(!cur_end))
4013 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01004014
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004015 /* we have a full request and we know that we have either a CR
4016 * or an LF at <ptr>.
4017 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004018 txn->meth = find_http_meth(cur_ptr, txn->req.sl.rq.m_l);
4019 hdr_idx_set_start(&txn->hdr_idx, txn->req.sl.rq.l, *cur_end == '\r');
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004020 /* there is no point trying this regex on headers */
4021 return 1;
4022 }
4023 }
4024 *cur_end = term; /* restore the string terminator */
4025 return done;
4026}
Willy Tarreau97de6242006-12-27 17:18:38 +01004027
Willy Tarreau58f10d72006-12-04 02:26:12 +01004028
Willy Tarreau58f10d72006-12-04 02:26:12 +01004029
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004030/*
4031 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
4032 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
Willy Tarreaua15645d2007-03-18 16:22:39 +01004033 * unparsable request. Since it can manage the switch to another backend, it
4034 * updates the per-proxy DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004035 */
4036int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
4037{
Willy Tarreau3d300592007-03-18 18:34:41 +01004038 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004039 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004040 while (exp && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004041 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004042
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004043 /*
4044 * The interleaving of transformations and verdicts
4045 * makes it difficult to decide to continue or stop
4046 * the evaluation.
4047 */
4048
Willy Tarreau3d300592007-03-18 18:34:41 +01004049 if ((txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004050 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4051 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
4052 exp = exp->next;
4053 continue;
4054 }
4055
4056 /* Apply the filter to the request line. */
4057 ret = apply_filter_to_req_line(t, req, exp);
4058 if (unlikely(ret < 0))
4059 return -1;
4060
4061 if (likely(ret == 0)) {
4062 /* The filter did not match the request, it can be
4063 * iterated through all headers.
4064 */
4065 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004066 }
4067 exp = exp->next;
4068 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004069 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004070}
4071
4072
Willy Tarreaua15645d2007-03-18 16:22:39 +01004073
Willy Tarreau58f10d72006-12-04 02:26:12 +01004074/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004075 * Manage client-side cookie. It can impact performance by about 2% so it is
4076 * desirable to call it only when needed.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004077 */
4078void manage_client_side_cookies(struct session *t, struct buffer *req)
4079{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004080 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004081 char *p1, *p2, *p3, *p4;
4082 char *del_colon, *del_cookie, *colon;
4083 int app_cookies;
4084
4085 appsess *asession_temp = NULL;
4086 appsess local_asession;
4087
4088 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004089 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004090
Willy Tarreau2a324282006-12-05 00:05:46 +01004091 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004092 * we start with the start line.
4093 */
Willy Tarreau83969f42007-01-22 08:55:47 +01004094 old_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004095 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004096
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004097 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004098 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004099 int val;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004100
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004101 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01004102 cur_ptr = cur_next;
4103 cur_end = cur_ptr + cur_hdr->len;
4104 cur_next = cur_end + cur_hdr->cr + 1;
4105
4106 /* We have one full header between cur_ptr and cur_end, and the
4107 * next header starts at cur_next. We're only interested in
4108 * "Cookie:" headers.
4109 */
4110
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004111 val = http_header_match2(cur_ptr, cur_end, "Cookie", 6);
4112 if (!val) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004113 old_idx = cur_idx;
4114 continue;
4115 }
4116
4117 /* Now look for cookies. Conforming to RFC2109, we have to support
4118 * attributes whose name begin with a '$', and associate them with
4119 * the right cookie, if we want to delete this cookie.
4120 * So there are 3 cases for each cookie read :
4121 * 1) it's a special attribute, beginning with a '$' : ignore it.
4122 * 2) it's a server id cookie that we *MAY* want to delete : save
4123 * some pointers on it (last semi-colon, beginning of cookie...)
4124 * 3) it's an application cookie : we *MAY* have to delete a previous
4125 * "special" cookie.
4126 * At the end of loop, if a "special" cookie remains, we may have to
4127 * remove it. If no application cookie persists in the header, we
4128 * *MUST* delete it
4129 */
4130
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004131 colon = p1 = cur_ptr + val; /* first non-space char after 'Cookie:' */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004132
Willy Tarreau58f10d72006-12-04 02:26:12 +01004133 /* del_cookie == NULL => nothing to be deleted */
4134 del_colon = del_cookie = NULL;
4135 app_cookies = 0;
4136
4137 while (p1 < cur_end) {
4138 /* skip spaces and colons, but keep an eye on these ones */
4139 while (p1 < cur_end) {
4140 if (*p1 == ';' || *p1 == ',')
4141 colon = p1;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004142 else if (!isspace((unsigned char)*p1))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004143 break;
4144 p1++;
4145 }
4146
4147 if (p1 == cur_end)
4148 break;
4149
4150 /* p1 is at the beginning of the cookie name */
4151 p2 = p1;
4152 while (p2 < cur_end && *p2 != '=')
4153 p2++;
4154
4155 if (p2 == cur_end)
4156 break;
4157
4158 p3 = p2 + 1; /* skips the '=' sign */
4159 if (p3 == cur_end)
4160 break;
4161
4162 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004163 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';' && *p4 != ',')
Willy Tarreau58f10d72006-12-04 02:26:12 +01004164 p4++;
4165
4166 /* here, we have the cookie name between p1 and p2,
4167 * and its value between p3 and p4.
4168 * we can process it :
4169 *
4170 * Cookie: NAME=VALUE;
4171 * | || || |
4172 * | || || +--> p4
4173 * | || |+-------> p3
4174 * | || +--------> p2
4175 * | |+------------> p1
4176 * | +-------------> colon
4177 * +--------------------> cur_ptr
4178 */
4179
4180 if (*p1 == '$') {
4181 /* skip this one */
4182 }
4183 else {
4184 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004185 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004186 txn->cli_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004187 (p4 - p1 >= t->fe->capture_namelen) &&
4188 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004189 int log_len = p4 - p1;
4190
Willy Tarreau086b3b42007-05-13 21:45:51 +02004191 if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004192 Alert("HTTP logging : out of memory.\n");
4193 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004194 if (log_len > t->fe->capture_len)
4195 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004196 memcpy(txn->cli_cookie, p1, log_len);
4197 txn->cli_cookie[log_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004198 }
4199 }
4200
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004201 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4202 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004203 /* Cool... it's the right one */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004204 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004205 char *delim;
4206
4207 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4208 * have the server ID betweek p3 and delim, and the original cookie between
4209 * delim+1 and p4. Otherwise, delim==p4 :
4210 *
4211 * Cookie: NAME=SRV~VALUE;
4212 * | || || | |
4213 * | || || | +--> p4
4214 * | || || +--------> delim
4215 * | || |+-----------> p3
4216 * | || +------------> p2
4217 * | |+----------------> p1
4218 * | +-----------------> colon
4219 * +------------------------> cur_ptr
4220 */
4221
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004222 if (t->be->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004223 for (delim = p3; delim < p4; delim++)
4224 if (*delim == COOKIE_DELIM)
4225 break;
4226 }
4227 else
4228 delim = p4;
4229
4230
4231 /* Here, we'll look for the first running server which supports the cookie.
4232 * This allows to share a same cookie between several servers, for example
4233 * to dedicate backup servers to specific servers only.
4234 * However, to prevent clients from sticking to cookie-less backup server
4235 * when they have incidentely learned an empty cookie, we simply ignore
4236 * empty cookies and mark them as invalid.
4237 */
4238 if (delim == p3)
4239 srv = NULL;
4240
4241 while (srv) {
Willy Tarreau92f2ab12007-02-02 22:14:47 +01004242 if (srv->cookie && (srv->cklen == delim - p3) &&
4243 !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004244 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004245 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004246 txn->flags &= ~TX_CK_MASK;
4247 txn->flags |= TX_CK_VALID;
4248 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004249 t->srv = srv;
4250 break;
4251 } else {
4252 /* we found a server, but it's down */
Willy Tarreau3d300592007-03-18 18:34:41 +01004253 txn->flags &= ~TX_CK_MASK;
4254 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004255 }
4256 }
4257 srv = srv->next;
4258 }
4259
Willy Tarreau3d300592007-03-18 18:34:41 +01004260 if (!srv && !(txn->flags & TX_CK_DOWN)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004261 /* no server matched this cookie */
Willy Tarreau3d300592007-03-18 18:34:41 +01004262 txn->flags &= ~TX_CK_MASK;
4263 txn->flags |= TX_CK_INVALID;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004264 }
4265
4266 /* depending on the cookie mode, we may have to either :
4267 * - delete the complete cookie if we're in insert+indirect mode, so that
4268 * the server never sees it ;
4269 * - remove the server id from the cookie value, and tag the cookie as an
4270 * application cookie so that it does not get accidentely removed later,
4271 * if we're in cookie prefix mode
4272 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004273 if ((t->be->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004274 int delta; /* negative */
4275
4276 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
4277 p4 += delta;
4278 cur_end += delta;
4279 cur_next += delta;
4280 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004281 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004282
4283 del_cookie = del_colon = NULL;
4284 app_cookies++; /* protect the header from deletion */
4285 }
4286 else if (del_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004287 (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 +01004288 del_cookie = p1;
4289 del_colon = colon;
4290 }
4291 } else {
4292 /* now we know that we must keep this cookie since it's
4293 * not ours. But if we wanted to delete our cookie
4294 * earlier, we cannot remove the complete header, but we
4295 * can remove the previous block itself.
4296 */
4297 app_cookies++;
4298
4299 if (del_cookie != NULL) {
4300 int delta; /* negative */
4301
4302 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
4303 p4 += delta;
4304 cur_end += delta;
4305 cur_next += delta;
4306 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004307 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004308 del_cookie = del_colon = NULL;
4309 }
4310 }
4311
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004312 if ((t->be->appsession_name != NULL) &&
4313 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004314 /* first, let's see if the cookie is our appcookie*/
4315
4316 /* Cool... it's the right one */
4317
4318 asession_temp = &local_asession;
4319
Willy Tarreau63963c62007-05-13 21:29:55 +02004320 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004321 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4322 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4323 return;
4324 }
4325
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004326 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4327 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004328 asession_temp->serverid = NULL;
Willy Tarreau51041c72007-09-09 21:56:53 +02004329
Willy Tarreau58f10d72006-12-04 02:26:12 +01004330 /* only do insert, if lookup fails */
Willy Tarreau51041c72007-09-09 21:56:53 +02004331 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4332 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004333 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004334 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004335 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004336 Alert("Not enough memory process_cli():asession:calloc().\n");
4337 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4338 return;
4339 }
4340
4341 asession_temp->sessid = local_asession.sessid;
4342 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004343 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004344 } else {
4345 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004346 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004347 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004348 if (asession_temp->serverid == NULL) {
4349 Alert("Found Application Session without matching server.\n");
4350 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004351 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004352 while (srv) {
4353 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004354 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004355 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004356 txn->flags &= ~TX_CK_MASK;
4357 txn->flags |= TX_CK_VALID;
4358 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004359 t->srv = srv;
4360 break;
4361 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01004362 txn->flags &= ~TX_CK_MASK;
4363 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004364 }
4365 }
4366 srv = srv->next;
4367 }/* end while(srv) */
4368 }/* end else if server == NULL */
4369
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004370 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004371 }/* end if ((t->proxy->appsession_name != NULL) ... */
4372 }
4373
4374 /* we'll have to look for another cookie ... */
4375 p1 = p4;
4376 } /* while (p1 < cur_end) */
4377
4378 /* There's no more cookie on this line.
4379 * We may have marked the last one(s) for deletion.
4380 * We must do this now in two ways :
4381 * - if there is no app cookie, we simply delete the header ;
4382 * - if there are app cookies, we must delete the end of the
4383 * string properly, including the colon/semi-colon before
4384 * the cookie name.
4385 */
4386 if (del_cookie != NULL) {
4387 int delta;
4388 if (app_cookies) {
4389 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
4390 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004391 cur_hdr->len += delta;
4392 } else {
4393 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004394
4395 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004396 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4397 txn->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004398 cur_hdr->len = 0;
4399 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01004400 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004401 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004402 }
4403
4404 /* keep the link from this header to next one */
4405 old_idx = cur_idx;
4406 } /* end of cookie processing on this header */
4407}
4408
4409
Willy Tarreaua15645d2007-03-18 16:22:39 +01004410/* Iterate the same filter through all response headers contained in <rtr>.
4411 * Returns 1 if this filter can be stopped upon return, otherwise 0.
4412 */
4413int apply_filter_to_resp_headers(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4414{
4415 char term;
4416 char *cur_ptr, *cur_end, *cur_next;
4417 int cur_idx, old_idx, last_hdr;
4418 struct http_txn *txn = &t->txn;
4419 struct hdr_idx_elem *cur_hdr;
4420 int len, delta;
4421
4422 last_hdr = 0;
4423
4424 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4425 old_idx = 0;
4426
4427 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004428 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004429 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004430 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004431 (exp->action == ACT_ALLOW ||
4432 exp->action == ACT_DENY))
4433 return 0;
4434
4435 cur_idx = txn->hdr_idx.v[old_idx].next;
4436 if (!cur_idx)
4437 break;
4438
4439 cur_hdr = &txn->hdr_idx.v[cur_idx];
4440 cur_ptr = cur_next;
4441 cur_end = cur_ptr + cur_hdr->len;
4442 cur_next = cur_end + cur_hdr->cr + 1;
4443
4444 /* Now we have one header between cur_ptr and cur_end,
4445 * and the next header starts at cur_next.
4446 */
4447
4448 /* The annoying part is that pattern matching needs
4449 * that we modify the contents to null-terminate all
4450 * strings before testing them.
4451 */
4452
4453 term = *cur_end;
4454 *cur_end = '\0';
4455
4456 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4457 switch (exp->action) {
4458 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004459 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004460 last_hdr = 1;
4461 break;
4462
4463 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004464 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004465 last_hdr = 1;
4466 break;
4467
4468 case ACT_REPLACE:
4469 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4470 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4471 /* FIXME: if the user adds a newline in the replacement, the
4472 * index will not be recalculated for now, and the new line
4473 * will not be counted as a new header.
4474 */
4475
4476 cur_end += delta;
4477 cur_next += delta;
4478 cur_hdr->len += delta;
4479 txn->rsp.eoh += delta;
4480 break;
4481
4482 case ACT_REMOVE:
4483 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4484 cur_next += delta;
4485
4486 /* FIXME: this should be a separate function */
4487 txn->rsp.eoh += delta;
4488 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4489 txn->hdr_idx.used--;
4490 cur_hdr->len = 0;
4491 cur_end = NULL; /* null-term has been rewritten */
4492 break;
4493
4494 }
4495 }
4496 if (cur_end)
4497 *cur_end = term; /* restore the string terminator */
4498
4499 /* keep the link from this header to next one in case of later
4500 * removal of next header.
4501 */
4502 old_idx = cur_idx;
4503 }
4504 return 0;
4505}
4506
4507
4508/* Apply the filter to the status line in the response buffer <rtr>.
4509 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4510 * or -1 if a replacement resulted in an invalid status line.
4511 */
4512int apply_filter_to_sts_line(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4513{
4514 char term;
4515 char *cur_ptr, *cur_end;
4516 int done;
4517 struct http_txn *txn = &t->txn;
4518 int len, delta;
4519
4520
Willy Tarreau3d300592007-03-18 18:34:41 +01004521 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004522 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004523 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004524 (exp->action == ACT_ALLOW ||
4525 exp->action == ACT_DENY))
4526 return 0;
4527 else if (exp->action == ACT_REMOVE)
4528 return 0;
4529
4530 done = 0;
4531
Willy Tarreau9cdde232007-05-02 20:58:19 +02004532 cur_ptr = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004533 cur_end = cur_ptr + txn->rsp.sl.rq.l;
4534
4535 /* Now we have the status line between cur_ptr and cur_end */
4536
4537 /* The annoying part is that pattern matching needs
4538 * that we modify the contents to null-terminate all
4539 * strings before testing them.
4540 */
4541
4542 term = *cur_end;
4543 *cur_end = '\0';
4544
4545 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4546 switch (exp->action) {
4547 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004548 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004549 done = 1;
4550 break;
4551
4552 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004553 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004554 done = 1;
4555 break;
4556
4557 case ACT_REPLACE:
4558 *cur_end = term; /* restore the string terminator */
4559 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4560 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4561 /* FIXME: if the user adds a newline in the replacement, the
4562 * index will not be recalculated for now, and the new line
4563 * will not be counted as a new header.
4564 */
4565
4566 txn->rsp.eoh += delta;
4567 cur_end += delta;
4568
Willy Tarreau9cdde232007-05-02 20:58:19 +02004569 txn->rsp.sol = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004570 cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data,
Willy Tarreau02785762007-04-03 14:45:44 +02004571 HTTP_MSG_RPVER,
Willy Tarreaua15645d2007-03-18 16:22:39 +01004572 cur_ptr, cur_end + 1,
4573 NULL, NULL);
4574 if (unlikely(!cur_end))
4575 return -1;
4576
4577 /* we have a full respnse and we know that we have either a CR
4578 * or an LF at <ptr>.
4579 */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004580 txn->status = strl2ui(rtr->data + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004581 hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.rq.l, *cur_end == '\r');
4582 /* there is no point trying this regex on headers */
4583 return 1;
4584 }
4585 }
4586 *cur_end = term; /* restore the string terminator */
4587 return done;
4588}
4589
4590
4591
4592/*
4593 * Apply all the resp filters <exp> to all headers in buffer <rtr> of session <t>.
4594 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
4595 * unparsable response.
4596 */
4597int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4598{
Willy Tarreau3d300592007-03-18 18:34:41 +01004599 struct http_txn *txn = &t->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004600 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004601 while (exp && !(txn->flags & TX_SVDENY)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004602 int ret;
4603
4604 /*
4605 * The interleaving of transformations and verdicts
4606 * makes it difficult to decide to continue or stop
4607 * the evaluation.
4608 */
4609
Willy Tarreau3d300592007-03-18 18:34:41 +01004610 if ((txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004611 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4612 exp->action == ACT_PASS)) {
4613 exp = exp->next;
4614 continue;
4615 }
4616
4617 /* Apply the filter to the status line. */
4618 ret = apply_filter_to_sts_line(t, rtr, exp);
4619 if (unlikely(ret < 0))
4620 return -1;
4621
4622 if (likely(ret == 0)) {
4623 /* The filter did not match the response, it can be
4624 * iterated through all headers.
4625 */
4626 apply_filter_to_resp_headers(t, rtr, exp);
4627 }
4628 exp = exp->next;
4629 }
4630 return 0;
4631}
4632
4633
4634
4635/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004636 * Manage server-side cookies. It can impact performance by about 2% so it is
4637 * desirable to call it only when needed.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004638 */
4639void manage_server_side_cookies(struct session *t, struct buffer *rtr)
4640{
4641 struct http_txn *txn = &t->txn;
4642 char *p1, *p2, *p3, *p4;
4643
4644 appsess *asession_temp = NULL;
4645 appsess local_asession;
4646
4647 char *cur_ptr, *cur_end, *cur_next;
4648 int cur_idx, old_idx, delta;
4649
Willy Tarreaua15645d2007-03-18 16:22:39 +01004650 /* Iterate through the headers.
4651 * we start with the start line.
4652 */
4653 old_idx = 0;
4654 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4655
4656 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
4657 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004658 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004659
4660 cur_hdr = &txn->hdr_idx.v[cur_idx];
4661 cur_ptr = cur_next;
4662 cur_end = cur_ptr + cur_hdr->len;
4663 cur_next = cur_end + cur_hdr->cr + 1;
4664
4665 /* We have one full header between cur_ptr and cur_end, and the
4666 * next header starts at cur_next. We're only interested in
4667 * "Cookie:" headers.
4668 */
4669
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004670 val = http_header_match2(cur_ptr, cur_end, "Set-Cookie", 10);
4671 if (!val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004672 old_idx = cur_idx;
4673 continue;
4674 }
4675
4676 /* OK, right now we know we have a set-cookie at cur_ptr */
Willy Tarreau3d300592007-03-18 18:34:41 +01004677 txn->flags |= TX_SCK_ANY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004678
4679
4680 /* maybe we only wanted to see if there was a set-cookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004681 if (t->be->cookie_name == NULL &&
4682 t->be->appsession_name == NULL &&
4683 t->be->capture_name == NULL)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004684 return;
4685
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004686 p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004687
4688 while (p1 < cur_end) { /* in fact, we'll break after the first cookie */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004689 if (p1 == cur_end || *p1 == ';') /* end of cookie */
4690 break;
4691
4692 /* p1 is at the beginning of the cookie name */
4693 p2 = p1;
4694
4695 while (p2 < cur_end && *p2 != '=' && *p2 != ';')
4696 p2++;
4697
4698 if (p2 == cur_end || *p2 == ';') /* next cookie */
4699 break;
4700
4701 p3 = p2 + 1; /* skip the '=' sign */
4702 if (p3 == cur_end)
4703 break;
4704
4705 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004706 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';')
Willy Tarreaua15645d2007-03-18 16:22:39 +01004707 p4++;
4708
4709 /* here, we have the cookie name between p1 and p2,
4710 * and its value between p3 and p4.
4711 * we can process it.
4712 */
4713
4714 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004715 if (t->be->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004716 txn->srv_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004717 (p4 - p1 >= t->be->capture_namelen) &&
4718 memcmp(p1, t->be->capture_name, t->be->capture_namelen) == 0) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004719 int log_len = p4 - p1;
4720
Willy Tarreau086b3b42007-05-13 21:45:51 +02004721 if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004722 Alert("HTTP logging : out of memory.\n");
4723 }
4724
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004725 if (log_len > t->be->capture_len)
4726 log_len = t->be->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004727 memcpy(txn->srv_cookie, p1, log_len);
4728 txn->srv_cookie[log_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004729 }
4730
4731 /* now check if we need to process it for persistence */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004732 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4733 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004734 /* Cool... it's the right one */
Willy Tarreau3d300592007-03-18 18:34:41 +01004735 txn->flags |= TX_SCK_SEEN;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004736
4737 /* If the cookie is in insert mode on a known server, we'll delete
4738 * this occurrence because we'll insert another one later.
4739 * We'll delete it too if the "indirect" option is set and we're in
4740 * a direct access. */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004741 if (((t->srv) && (t->be->options & PR_O_COOK_INS)) ||
4742 ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004743 /* this header must be deleted */
4744 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4745 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4746 txn->hdr_idx.used--;
4747 cur_hdr->len = 0;
4748 cur_next += delta;
4749 txn->rsp.eoh += delta;
4750
Willy Tarreau3d300592007-03-18 18:34:41 +01004751 txn->flags |= TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004752 }
4753 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004754 (t->be->options & PR_O_COOK_RW)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004755 /* replace bytes p3->p4 with the cookie name associated
4756 * with this server since we know it.
4757 */
4758 delta = buffer_replace2(rtr, p3, p4, t->srv->cookie, t->srv->cklen);
4759 cur_hdr->len += delta;
4760 cur_next += delta;
4761 txn->rsp.eoh += delta;
4762
Willy Tarreau3d300592007-03-18 18:34:41 +01004763 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004764 }
4765 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004766 (t->be->options & PR_O_COOK_PFX)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004767 /* insert the cookie name associated with this server
4768 * before existing cookie, and insert a delimitor between them..
4769 */
4770 delta = buffer_replace2(rtr, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4771 cur_hdr->len += delta;
4772 cur_next += delta;
4773 txn->rsp.eoh += delta;
4774
4775 p3[t->srv->cklen] = COOKIE_DELIM;
Willy Tarreau3d300592007-03-18 18:34:41 +01004776 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004777 }
4778 }
4779 /* next, let's see if the cookie is our appcookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004780 else if ((t->be->appsession_name != NULL) &&
4781 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004782
4783 /* Cool... it's the right one */
4784
4785 size_t server_id_len = strlen(t->srv->id) + 1;
4786 asession_temp = &local_asession;
4787
Willy Tarreau63963c62007-05-13 21:29:55 +02004788 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004789 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4790 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4791 return;
4792 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004793 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4794 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004795 asession_temp->serverid = NULL;
4796
4797 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01004798 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4799 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004800 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004801 Alert("Not enough Memory process_srv():asession:calloc().\n");
4802 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
4803 return;
4804 }
4805 asession_temp->sessid = local_asession.sessid;
4806 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004807 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
4808 } else {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004809 /* free wasted memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004810 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau51041c72007-09-09 21:56:53 +02004811 }
4812
Willy Tarreaua15645d2007-03-18 16:22:39 +01004813 if (asession_temp->serverid == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004814 if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004815 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4816 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4817 return;
4818 }
4819 asession_temp->serverid[0] = '\0';
4820 }
4821
4822 if (asession_temp->serverid[0] == '\0')
4823 memcpy(asession_temp->serverid, t->srv->id, server_id_len);
4824
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004825 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004826
4827#if defined(DEBUG_HASH)
Willy Tarreau51041c72007-09-09 21:56:53 +02004828 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreaua15645d2007-03-18 16:22:39 +01004829#endif
4830 }/* end if ((t->proxy->appsession_name != NULL) ... */
4831 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4832 } /* we're now at the end of the cookie value */
4833
4834 /* keep the link from this header to next one */
4835 old_idx = cur_idx;
4836 } /* end of cookie processing on this header */
4837}
4838
4839
4840
4841/*
4842 * Check if response is cacheable or not. Updates t->flags.
4843 */
4844void check_response_for_cacheability(struct session *t, struct buffer *rtr)
4845{
4846 struct http_txn *txn = &t->txn;
4847 char *p1, *p2;
4848
4849 char *cur_ptr, *cur_end, *cur_next;
4850 int cur_idx;
4851
Willy Tarreau5df51872007-11-25 16:20:08 +01004852 if (!(txn->flags & TX_CACHEABLE))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004853 return;
4854
4855 /* Iterate through the headers.
4856 * we start with the start line.
4857 */
4858 cur_idx = 0;
4859 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4860
4861 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
4862 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004863 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004864
4865 cur_hdr = &txn->hdr_idx.v[cur_idx];
4866 cur_ptr = cur_next;
4867 cur_end = cur_ptr + cur_hdr->len;
4868 cur_next = cur_end + cur_hdr->cr + 1;
4869
4870 /* We have one full header between cur_ptr and cur_end, and the
4871 * next header starts at cur_next. We're only interested in
4872 * "Cookie:" headers.
4873 */
4874
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004875 val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
4876 if (val) {
4877 if ((cur_end - (cur_ptr + val) >= 8) &&
4878 strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
4879 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
4880 return;
4881 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01004882 }
4883
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004884 val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
4885 if (!val)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004886 continue;
4887
4888 /* OK, right now we know we have a cache-control header at cur_ptr */
4889
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004890 p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004891
4892 if (p1 >= cur_end) /* no more info */
4893 continue;
4894
4895 /* p1 is at the beginning of the value */
4896 p2 = p1;
4897
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004898 while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((unsigned char)*p2))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004899 p2++;
4900
4901 /* we have a complete value between p1 and p2 */
4902 if (p2 < cur_end && *p2 == '=') {
4903 /* we have something of the form no-cache="set-cookie" */
4904 if ((cur_end - p1 >= 21) &&
4905 strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0
4906 && (p1[20] == '"' || p1[20] == ','))
Willy Tarreau3d300592007-03-18 18:34:41 +01004907 txn->flags &= ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004908 continue;
4909 }
4910
4911 /* OK, so we know that either p2 points to the end of string or to a comma */
4912 if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) ||
4913 ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) ||
4914 ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) ||
4915 ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004916 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004917 return;
4918 }
4919
4920 if ((p2 - p1 == 6) && strncasecmp(p1, "public", 6) == 0) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004921 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004922 continue;
4923 }
4924 }
4925}
4926
4927
Willy Tarreau58f10d72006-12-04 02:26:12 +01004928/*
4929 * Try to retrieve a known appsession in the URI, then the associated server.
4930 * If the server is found, it's assigned to the session.
4931 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004932void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004933{
Willy Tarreau3d300592007-03-18 18:34:41 +01004934 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004935 appsess *asession_temp = NULL;
4936 appsess local_asession;
4937 char *request_line;
4938
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004939 if (t->be->appsession_name == NULL ||
Willy Tarreaub326fcc2007-03-03 13:54:32 +01004940 (t->txn.meth != HTTP_METH_GET && t->txn.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004941 (request_line = memchr(begin, ';', len)) == NULL ||
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004942 ((1 + t->be->appsession_name_len + 1 + t->be->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004943 return;
4944
4945 /* skip ';' */
4946 request_line++;
4947
4948 /* look if we have a jsessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004949 if (strncasecmp(request_line, t->be->appsession_name, t->be->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004950 return;
4951
4952 /* skip jsessionid= */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004953 request_line += t->be->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004954
4955 /* First try if we already have an appsession */
4956 asession_temp = &local_asession;
4957
Willy Tarreau63963c62007-05-13 21:29:55 +02004958 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004959 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4960 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4961 return;
4962 }
4963
4964 /* Copy the sessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004965 memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
4966 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004967 asession_temp->serverid = NULL;
4968
4969 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01004970 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4971 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004972 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004973 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004974 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004975 Alert("Not enough memory process_cli():asession:calloc().\n");
4976 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4977 return;
4978 }
4979 asession_temp->sessid = local_asession.sessid;
4980 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004981 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004982 }
4983 else {
4984 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004985 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004986 }
Willy Tarreau51041c72007-09-09 21:56:53 +02004987
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004988 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004989 asession_temp->request_count++;
Willy Tarreau51041c72007-09-09 21:56:53 +02004990
Willy Tarreau58f10d72006-12-04 02:26:12 +01004991#if defined(DEBUG_HASH)
Willy Tarreau51041c72007-09-09 21:56:53 +02004992 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreau58f10d72006-12-04 02:26:12 +01004993#endif
4994 if (asession_temp->serverid == NULL) {
4995 Alert("Found Application Session without matching server.\n");
4996 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004997 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004998 while (srv) {
4999 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005000 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005001 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01005002 txn->flags &= ~TX_CK_MASK;
5003 txn->flags |= TX_CK_VALID;
5004 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005005 t->srv = srv;
5006 break;
5007 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01005008 txn->flags &= ~TX_CK_MASK;
5009 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005010 }
5011 }
5012 srv = srv->next;
5013 }
5014 }
5015}
5016
5017
Willy Tarreaub2513902006-12-17 14:52:38 +01005018/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005019 * In a GET or HEAD request, check if the requested URI matches the stats uri
5020 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01005021 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005022 * It is assumed that the request is either a HEAD or GET and that the
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005023 * t->be->uri_auth field is valid. An HTTP/401 response may be sent, or
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005024 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01005025 *
5026 * Returns 1 if the session's state changes, otherwise 0.
5027 */
5028int stats_check_uri_auth(struct session *t, struct proxy *backend)
5029{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005030 struct http_txn *txn = &t->txn;
Willy Tarreaub2513902006-12-17 14:52:38 +01005031 struct uri_auth *uri_auth = backend->uri_auth;
5032 struct user_auth *user;
5033 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005034 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01005035
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005036 memset(&t->data_ctx.stats, 0, sizeof(t->data_ctx.stats));
5037
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005038 /* check URI size */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005039 if (uri_auth->uri_len > txn->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01005040 return 0;
5041
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005042 h = t->req->data + txn->req.sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005043
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005044 /* the URI is in h */
5045 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01005046 return 0;
5047
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005048 h += uri_auth->uri_len;
5049 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 3) {
5050 if (memcmp(h, ";up", 3) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005051 t->data_ctx.stats.flags |= STAT_HIDE_DOWN;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005052 break;
5053 }
5054 h++;
5055 }
5056
5057 if (uri_auth->refresh) {
5058 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5059 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 10) {
5060 if (memcmp(h, ";norefresh", 10) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005061 t->data_ctx.stats.flags |= STAT_NO_REFRESH;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005062 break;
5063 }
5064 h++;
5065 }
5066 }
5067
Willy Tarreau55bb8452007-10-17 18:44:57 +02005068 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5069 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 4) {
5070 if (memcmp(h, ";csv", 4) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005071 t->data_ctx.stats.flags |= STAT_FMT_CSV;
Willy Tarreau55bb8452007-10-17 18:44:57 +02005072 break;
5073 }
5074 h++;
5075 }
5076
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005077 t->data_ctx.stats.flags |= STAT_SHOW_STAT | STAT_SHOW_INFO;
5078
Willy Tarreaub2513902006-12-17 14:52:38 +01005079 /* we are in front of a interceptable URI. Let's check
5080 * if there's an authentication and if it's valid.
5081 */
5082 user = uri_auth->users;
5083 if (!user) {
5084 /* no user auth required, it's OK */
5085 authenticated = 1;
5086 } else {
5087 authenticated = 0;
5088
5089 /* a user list is defined, we have to check.
5090 * skip 21 chars for "Authorization: Basic ".
5091 */
5092
5093 /* FIXME: this should move to an earlier place */
5094 cur_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005095 h = t->req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
5096 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
5097 int len = txn->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005098 if (len > 14 &&
5099 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005100 txn->auth_hdr.str = h;
5101 txn->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005102 break;
5103 }
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005104 h += len + txn->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01005105 }
5106
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005107 if (txn->auth_hdr.len < 21 ||
5108 memcmp(txn->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01005109 user = NULL;
5110
5111 while (user) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005112 if ((txn->auth_hdr.len == user->user_len + 14 + 7)
5113 && !memcmp(txn->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01005114 user->user_pwd, user->user_len)) {
5115 authenticated = 1;
5116 break;
5117 }
5118 user = user->next;
5119 }
5120 }
5121
5122 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01005123 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01005124
5125 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01005126 msg.str = trash;
5127 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005128 txn->status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01005129 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01005130 if (!(t->flags & SN_ERR_MASK))
5131 t->flags |= SN_ERR_PRXCOND;
5132 if (!(t->flags & SN_FINST_MASK))
5133 t->flags |= SN_FINST_R;
5134 return 1;
5135 }
5136
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005137 /* The request is valid, the user is authenticated. Let's start sending
Willy Tarreaub2513902006-12-17 14:52:38 +01005138 * data.
5139 */
Willy Tarreau284c7b32008-06-29 16:38:43 +02005140 EV_FD_CLR(t->cli_fd, DIR_RD);
5141 buffer_shutr(t->req);
5142 buffer_shutr(t->rep);
Willy Tarreaub2513902006-12-17 14:52:38 +01005143 t->cli_state = CL_STSHUTR;
5144 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau70089872008-06-13 21:12:51 +02005145 t->logs.tv_request = now;
Willy Tarreaub2513902006-12-17 14:52:38 +01005146 t->data_source = DATA_SRC_STATS;
5147 t->data_state = DATA_ST_INIT;
Willy Tarreau91e99932008-06-30 07:51:00 +02005148 t->task->nice = -32; /* small boost for HTTP statistics */
Willy Tarreaub2513902006-12-17 14:52:38 +01005149 produce_content(t);
5150 return 1;
5151}
5152
5153
Willy Tarreaubaaee002006-06-26 02:48:02 +02005154/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01005155 * Print a debug line with a header
5156 */
5157void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
5158{
5159 int len, max;
5160 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
5161 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
5162 max = end - start;
5163 UBOUND(max, sizeof(trash) - len - 1);
5164 len += strlcpy2(trash + len, start, max + 1);
5165 trash[len++] = '\n';
5166 write(1, trash, len);
5167}
5168
5169
Willy Tarreau8797c062007-05-07 00:55:35 +02005170/************************************************************************/
5171/* The code below is dedicated to ACL parsing and matching */
5172/************************************************************************/
5173
5174
5175
5176
5177/* 1. Check on METHOD
5178 * We use the pre-parsed method if it is known, and store its number as an
5179 * integer. If it is unknown, we use the pointer and the length.
5180 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005181static int acl_parse_meth(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005182{
5183 int len, meth;
5184
Willy Tarreauae8b7962007-06-09 23:10:04 +02005185 len = strlen(*text);
5186 meth = find_http_meth(*text, len);
Willy Tarreau8797c062007-05-07 00:55:35 +02005187
5188 pattern->val.i = meth;
5189 if (meth == HTTP_METH_OTHER) {
Willy Tarreauae8b7962007-06-09 23:10:04 +02005190 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005191 if (!pattern->ptr.str)
5192 return 0;
5193 pattern->len = len;
5194 }
5195 return 1;
5196}
5197
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005198static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005199acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
5200 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005201{
5202 int meth;
5203 struct http_txn *txn = l7;
5204
Willy Tarreauc11416f2007-06-17 16:58:38 +02005205 if (txn->req.msg_state != HTTP_MSG_BODY)
5206 return 0;
5207
Willy Tarreau8797c062007-05-07 00:55:35 +02005208 meth = txn->meth;
5209 test->i = meth;
5210 if (meth == HTTP_METH_OTHER) {
Willy Tarreauc11416f2007-06-17 16:58:38 +02005211 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5212 /* ensure the indexes are not affected */
5213 return 0;
Willy Tarreau8797c062007-05-07 00:55:35 +02005214 test->len = txn->req.sl.rq.m_l;
5215 test->ptr = txn->req.sol;
5216 }
5217 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5218 return 1;
5219}
5220
5221static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
5222{
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005223 int icase;
5224
Willy Tarreau8797c062007-05-07 00:55:35 +02005225 if (test->i != pattern->val.i)
Willy Tarreau11382812008-07-09 16:18:21 +02005226 return ACL_PAT_FAIL;
Willy Tarreau8797c062007-05-07 00:55:35 +02005227
5228 if (test->i != HTTP_METH_OTHER)
Willy Tarreau11382812008-07-09 16:18:21 +02005229 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005230
5231 /* Other method, we must compare the strings */
5232 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +02005233 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005234
5235 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
5236 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) != 0) ||
5237 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +02005238 return ACL_PAT_FAIL;
5239 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005240}
5241
5242/* 2. Check on Request/Status Version
5243 * We simply compare strings here.
5244 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005245static int acl_parse_ver(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005246{
Willy Tarreauae8b7962007-06-09 23:10:04 +02005247 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005248 if (!pattern->ptr.str)
5249 return 0;
Willy Tarreauae8b7962007-06-09 23:10:04 +02005250 pattern->len = strlen(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005251 return 1;
5252}
5253
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005254static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005255acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
5256 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005257{
5258 struct http_txn *txn = l7;
5259 char *ptr;
5260 int len;
5261
Willy Tarreauc11416f2007-06-17 16:58:38 +02005262 if (txn->req.msg_state != HTTP_MSG_BODY)
5263 return 0;
5264
Willy Tarreau8797c062007-05-07 00:55:35 +02005265 len = txn->req.sl.rq.v_l;
5266 ptr = txn->req.sol + txn->req.sl.rq.v - txn->req.som;
5267
5268 while ((len-- > 0) && (*ptr++ != '/'));
5269 if (len <= 0)
5270 return 0;
5271
5272 test->ptr = ptr;
5273 test->len = len;
5274
5275 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5276 return 1;
5277}
5278
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005279static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005280acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
5281 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005282{
5283 struct http_txn *txn = l7;
5284 char *ptr;
5285 int len;
5286
Willy Tarreauc11416f2007-06-17 16:58:38 +02005287 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5288 return 0;
5289
Willy Tarreau8797c062007-05-07 00:55:35 +02005290 len = txn->rsp.sl.st.v_l;
5291 ptr = txn->rsp.sol;
5292
5293 while ((len-- > 0) && (*ptr++ != '/'));
5294 if (len <= 0)
5295 return 0;
5296
5297 test->ptr = ptr;
5298 test->len = len;
5299
5300 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5301 return 1;
5302}
5303
5304/* 3. Check on Status Code. We manipulate integers here. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005305static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005306acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, int dir,
5307 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005308{
5309 struct http_txn *txn = l7;
5310 char *ptr;
5311 int len;
5312
Willy Tarreauc11416f2007-06-17 16:58:38 +02005313 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5314 return 0;
5315
Willy Tarreau8797c062007-05-07 00:55:35 +02005316 len = txn->rsp.sl.st.c_l;
5317 ptr = txn->rsp.sol + txn->rsp.sl.st.c - txn->rsp.som;
5318
5319 test->i = __strl2ui(ptr, len);
5320 test->flags = ACL_TEST_F_VOL_1ST;
5321 return 1;
5322}
5323
5324/* 4. Check on URL/URI. A pointer to the URI is stored. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005325static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005326acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
5327 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005328{
5329 struct http_txn *txn = l7;
5330
Willy Tarreauc11416f2007-06-17 16:58:38 +02005331 if (txn->req.msg_state != HTTP_MSG_BODY)
5332 return 0;
5333 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5334 /* ensure the indexes are not affected */
5335 return 0;
5336
Willy Tarreau8797c062007-05-07 00:55:35 +02005337 test->len = txn->req.sl.rq.u_l;
5338 test->ptr = txn->req.sol + txn->req.sl.rq.u;
5339
Willy Tarreauf3d25982007-05-08 22:45:09 +02005340 /* we do not need to set READ_ONLY because the data is in a buffer */
5341 test->flags = ACL_TEST_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +02005342 return 1;
5343}
5344
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005345static int
5346acl_fetch_url_ip(struct proxy *px, struct session *l4, void *l7, int dir,
5347 struct acl_expr *expr, struct acl_test *test)
5348{
5349 struct http_txn *txn = l7;
5350
5351 if (txn->req.msg_state != HTTP_MSG_BODY)
5352 return 0;
5353 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5354 /* ensure the indexes are not affected */
5355 return 0;
5356
5357 /* Parse HTTP request */
5358 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5359 test->ptr = (void *)&((struct sockaddr_in *)&l4->srv_addr)->sin_addr;
5360 test->i = AF_INET;
5361
5362 /*
5363 * If we are parsing url in frontend space, we prepare backend stage
5364 * to not parse again the same url ! optimization lazyness...
5365 */
5366 if (px->options & PR_O_HTTP_PROXY)
5367 l4->flags |= SN_ADDR_SET;
5368
5369 test->flags = ACL_TEST_F_READ_ONLY;
5370 return 1;
5371}
5372
5373static int
5374acl_fetch_url_port(struct proxy *px, struct session *l4, void *l7, int dir,
5375 struct acl_expr *expr, struct acl_test *test)
5376{
5377 struct http_txn *txn = l7;
5378
5379 if (txn->req.msg_state != HTTP_MSG_BODY)
5380 return 0;
5381 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5382 /* ensure the indexes are not affected */
5383 return 0;
5384
5385 /* Same optimization as url_ip */
5386 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5387 test->i = ntohs(((struct sockaddr_in *)&l4->srv_addr)->sin_port);
5388
5389 if (px->options & PR_O_HTTP_PROXY)
5390 l4->flags |= SN_ADDR_SET;
5391
5392 test->flags = ACL_TEST_F_READ_ONLY;
5393 return 1;
5394}
5395
Willy Tarreauc11416f2007-06-17 16:58:38 +02005396/* 5. Check on HTTP header. A pointer to the beginning of the value is returned.
5397 * This generic function is used by both acl_fetch_chdr() and acl_fetch_shdr().
5398 */
Willy Tarreau33a7e692007-06-10 19:45:56 +02005399static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005400acl_fetch_hdr(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005401 struct acl_expr *expr, struct acl_test *test)
5402{
5403 struct http_txn *txn = l7;
5404 struct hdr_idx *idx = &txn->hdr_idx;
5405 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005406
5407 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5408 /* search for header from the beginning */
5409 ctx->idx = 0;
5410
Willy Tarreau33a7e692007-06-10 19:45:56 +02005411 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5412 test->flags |= ACL_TEST_F_FETCH_MORE;
5413 test->flags |= ACL_TEST_F_VOL_HDR;
5414 test->len = ctx->vlen;
5415 test->ptr = (char *)ctx->line + ctx->val;
5416 return 1;
5417 }
5418
5419 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5420 test->flags |= ACL_TEST_F_VOL_HDR;
5421 return 0;
5422}
5423
Willy Tarreau33a7e692007-06-10 19:45:56 +02005424static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005425acl_fetch_chdr(struct proxy *px, struct session *l4, void *l7, int dir,
5426 struct acl_expr *expr, struct acl_test *test)
5427{
5428 struct http_txn *txn = l7;
5429
5430 if (txn->req.msg_state != HTTP_MSG_BODY)
5431 return 0;
5432 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5433 /* ensure the indexes are not affected */
5434 return 0;
5435
5436 return acl_fetch_hdr(px, l4, txn, txn->req.sol, expr, test);
5437}
5438
5439static int
5440acl_fetch_shdr(struct proxy *px, struct session *l4, void *l7, int dir,
5441 struct acl_expr *expr, struct acl_test *test)
5442{
5443 struct http_txn *txn = l7;
5444
5445 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5446 return 0;
5447
5448 return acl_fetch_hdr(px, l4, txn, txn->rsp.sol, expr, test);
5449}
5450
5451/* 6. Check on HTTP header count. The number of occurrences is returned.
5452 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
5453 */
5454static int
5455acl_fetch_hdr_cnt(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005456 struct acl_expr *expr, struct acl_test *test)
5457{
5458 struct http_txn *txn = l7;
5459 struct hdr_idx *idx = &txn->hdr_idx;
5460 struct hdr_ctx ctx;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005461 int cnt;
Willy Tarreau8797c062007-05-07 00:55:35 +02005462
Willy Tarreau33a7e692007-06-10 19:45:56 +02005463 ctx.idx = 0;
5464 cnt = 0;
5465 while (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, &ctx))
5466 cnt++;
5467
5468 test->i = cnt;
5469 test->flags = ACL_TEST_F_VOL_HDR;
5470 return 1;
5471}
5472
Willy Tarreauc11416f2007-06-17 16:58:38 +02005473static int
5474acl_fetch_chdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5475 struct acl_expr *expr, struct acl_test *test)
5476{
5477 struct http_txn *txn = l7;
5478
5479 if (txn->req.msg_state != HTTP_MSG_BODY)
5480 return 0;
5481 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5482 /* ensure the indexes are not affected */
5483 return 0;
5484
5485 return acl_fetch_hdr_cnt(px, l4, txn, txn->req.sol, expr, test);
5486}
5487
5488static int
5489acl_fetch_shdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5490 struct acl_expr *expr, struct acl_test *test)
5491{
5492 struct http_txn *txn = l7;
5493
5494 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5495 return 0;
5496
5497 return acl_fetch_hdr_cnt(px, l4, txn, txn->rsp.sol, expr, test);
5498}
5499
Willy Tarreau33a7e692007-06-10 19:45:56 +02005500/* 7. Check on HTTP header's integer value. The integer value is returned.
5501 * FIXME: the type is 'int', it may not be appropriate for everything.
Willy Tarreauc11416f2007-06-17 16:58:38 +02005502 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
Willy Tarreau33a7e692007-06-10 19:45:56 +02005503 */
5504static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005505acl_fetch_hdr_val(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005506 struct acl_expr *expr, struct acl_test *test)
5507{
5508 struct http_txn *txn = l7;
5509 struct hdr_idx *idx = &txn->hdr_idx;
5510 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005511
5512 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5513 /* search for header from the beginning */
5514 ctx->idx = 0;
5515
Willy Tarreau33a7e692007-06-10 19:45:56 +02005516 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5517 test->flags |= ACL_TEST_F_FETCH_MORE;
5518 test->flags |= ACL_TEST_F_VOL_HDR;
5519 test->i = strl2ic((char *)ctx->line + ctx->val, ctx->vlen);
5520 return 1;
5521 }
5522
5523 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5524 test->flags |= ACL_TEST_F_VOL_HDR;
5525 return 0;
5526}
5527
Willy Tarreauc11416f2007-06-17 16:58:38 +02005528static int
5529acl_fetch_chdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5530 struct acl_expr *expr, struct acl_test *test)
5531{
5532 struct http_txn *txn = l7;
5533
5534 if (txn->req.msg_state != HTTP_MSG_BODY)
5535 return 0;
5536 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5537 /* ensure the indexes are not affected */
5538 return 0;
5539
5540 return acl_fetch_hdr_val(px, l4, txn, txn->req.sol, expr, test);
5541}
5542
5543static int
5544acl_fetch_shdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5545 struct acl_expr *expr, struct acl_test *test)
5546{
5547 struct http_txn *txn = l7;
5548
5549 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5550 return 0;
5551
5552 return acl_fetch_hdr_val(px, l4, txn, txn->rsp.sol, expr, test);
5553}
5554
Willy Tarreau737b0c12007-06-10 21:28:46 +02005555/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at
5556 * the first '/' after the possible hostname, and ends before the possible '?'.
5557 */
5558static int
5559acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
5560 struct acl_expr *expr, struct acl_test *test)
5561{
5562 struct http_txn *txn = l7;
5563 char *ptr, *end;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005564
Willy Tarreauc11416f2007-06-17 16:58:38 +02005565 if (txn->req.msg_state != HTTP_MSG_BODY)
5566 return 0;
5567 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5568 /* ensure the indexes are not affected */
5569 return 0;
5570
Willy Tarreau21d2af32008-02-14 20:25:24 +01005571 end = txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
5572 ptr = http_get_path(txn);
5573 if (!ptr)
Willy Tarreau737b0c12007-06-10 21:28:46 +02005574 return 0;
5575
5576 /* OK, we got the '/' ! */
5577 test->ptr = ptr;
5578
5579 while (ptr < end && *ptr != '?')
5580 ptr++;
5581
5582 test->len = ptr - test->ptr;
5583
5584 /* we do not need to set READ_ONLY because the data is in a buffer */
5585 test->flags = ACL_TEST_F_VOL_1ST;
5586 return 1;
5587}
5588
5589
Willy Tarreau8797c062007-05-07 00:55:35 +02005590
5591/************************************************************************/
5592/* All supported keywords must be declared here. */
5593/************************************************************************/
5594
5595/* Note: must not be declared <const> as its list will be overwritten */
5596static struct acl_kw_list acl_kws = {{ },{
5597 { "method", acl_parse_meth, acl_fetch_meth, acl_match_meth },
5598 { "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str },
5599 { "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str },
Willy Tarreauae8b7962007-06-09 23:10:04 +02005600 { "status", acl_parse_int, acl_fetch_stcode, acl_match_int },
Willy Tarreau8797c062007-05-07 00:55:35 +02005601
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005602 { "url", acl_parse_str, acl_fetch_url, acl_match_str },
5603 { "url_beg", acl_parse_str, acl_fetch_url, acl_match_beg },
5604 { "url_end", acl_parse_str, acl_fetch_url, acl_match_end },
5605 { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub },
5606 { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir },
5607 { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom },
5608 { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg },
5609 { "url_ip", acl_parse_ip, acl_fetch_url_ip, acl_match_ip },
5610 { "url_port", acl_parse_int, acl_fetch_url_port, acl_match_int },
Willy Tarreau8797c062007-05-07 00:55:35 +02005611
Willy Tarreauc11416f2007-06-17 16:58:38 +02005612 { "hdr", acl_parse_str, acl_fetch_chdr, acl_match_str },
5613 { "hdr_reg", acl_parse_reg, acl_fetch_chdr, acl_match_reg },
5614 { "hdr_beg", acl_parse_str, acl_fetch_chdr, acl_match_beg },
5615 { "hdr_end", acl_parse_str, acl_fetch_chdr, acl_match_end },
5616 { "hdr_sub", acl_parse_str, acl_fetch_chdr, acl_match_sub },
5617 { "hdr_dir", acl_parse_str, acl_fetch_chdr, acl_match_dir },
5618 { "hdr_dom", acl_parse_str, acl_fetch_chdr, acl_match_dom },
5619 { "hdr_cnt", acl_parse_int, acl_fetch_chdr_cnt,acl_match_int },
5620 { "hdr_val", acl_parse_int, acl_fetch_chdr_val,acl_match_int },
5621
5622 { "shdr", acl_parse_str, acl_fetch_shdr, acl_match_str },
5623 { "shdr_reg", acl_parse_reg, acl_fetch_shdr, acl_match_reg },
5624 { "shdr_beg", acl_parse_str, acl_fetch_shdr, acl_match_beg },
5625 { "shdr_end", acl_parse_str, acl_fetch_shdr, acl_match_end },
5626 { "shdr_sub", acl_parse_str, acl_fetch_shdr, acl_match_sub },
5627 { "shdr_dir", acl_parse_str, acl_fetch_shdr, acl_match_dir },
5628 { "shdr_dom", acl_parse_str, acl_fetch_shdr, acl_match_dom },
5629 { "shdr_cnt", acl_parse_int, acl_fetch_shdr_cnt,acl_match_int },
5630 { "shdr_val", acl_parse_int, acl_fetch_shdr_val,acl_match_int },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005631
5632 { "path", acl_parse_str, acl_fetch_path, acl_match_str },
5633 { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg },
5634 { "path_beg", acl_parse_str, acl_fetch_path, acl_match_beg },
5635 { "path_end", acl_parse_str, acl_fetch_path, acl_match_end },
5636 { "path_sub", acl_parse_str, acl_fetch_path, acl_match_sub },
5637 { "path_dir", acl_parse_str, acl_fetch_path, acl_match_dir },
5638 { "path_dom", acl_parse_str, acl_fetch_path, acl_match_dom },
5639
Willy Tarreauf3d25982007-05-08 22:45:09 +02005640 { NULL, NULL, NULL, NULL },
5641
5642#if 0
Willy Tarreau8797c062007-05-07 00:55:35 +02005643 { "line", acl_parse_str, acl_fetch_line, acl_match_str },
5644 { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg },
5645 { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg },
5646 { "line_end", acl_parse_str, acl_fetch_line, acl_match_end },
5647 { "line_sub", acl_parse_str, acl_fetch_line, acl_match_sub },
5648 { "line_dir", acl_parse_str, acl_fetch_line, acl_match_dir },
5649 { "line_dom", acl_parse_str, acl_fetch_line, acl_match_dom },
5650
Willy Tarreau8797c062007-05-07 00:55:35 +02005651 { "cook", acl_parse_str, acl_fetch_cook, acl_match_str },
5652 { "cook_reg", acl_parse_reg, acl_fetch_cook, acl_match_reg },
5653 { "cook_beg", acl_parse_str, acl_fetch_cook, acl_match_beg },
5654 { "cook_end", acl_parse_str, acl_fetch_cook, acl_match_end },
5655 { "cook_sub", acl_parse_str, acl_fetch_cook, acl_match_sub },
5656 { "cook_dir", acl_parse_str, acl_fetch_cook, acl_match_dir },
5657 { "cook_dom", acl_parse_str, acl_fetch_cook, acl_match_dom },
5658 { "cook_pst", acl_parse_none, acl_fetch_cook, acl_match_pst },
5659
5660 { "auth_user", acl_parse_str, acl_fetch_user, acl_match_str },
5661 { "auth_regex", acl_parse_reg, acl_fetch_user, acl_match_reg },
5662 { "auth_clear", acl_parse_str, acl_fetch_auth, acl_match_str },
5663 { "auth_md5", acl_parse_str, acl_fetch_auth, acl_match_md5 },
5664 { NULL, NULL, NULL, NULL },
5665#endif
5666}};
5667
5668
5669__attribute__((constructor))
5670static void __http_protocol_init(void)
5671{
5672 acl_register_keywords(&acl_kws);
5673}
5674
5675
Willy Tarreau58f10d72006-12-04 02:26:12 +01005676/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02005677 * Local variables:
5678 * c-indent-level: 8
5679 * c-basic-offset: 8
5680 * End:
5681 */