blob: ea199d9b9a47d4ae5d08ba24e6f4c41df15a9f71 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * HTTP protocol analyzer
3 *
Willy Tarreaua15645d2007-03-18 16:22:39 +01004 * Copyright 2000-2007 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>
33#include <common/time.h>
34#include <common/uri_auth.h>
35#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020036
Willy Tarreau8797c062007-05-07 00:55:35 +020037#include <types/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020038#include <types/capture.h>
39#include <types/client.h>
40#include <types/global.h>
41#include <types/httperr.h>
42#include <types/polling.h>
43#include <types/proxy.h>
44#include <types/server.h>
45
Willy Tarreau8797c062007-05-07 00:55:35 +020046#include <proto/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020047#include <proto/backend.h>
48#include <proto/buffers.h>
49#include <proto/fd.h>
50#include <proto/log.h>
Willy Tarreau58f10d72006-12-04 02:26:12 +010051#include <proto/hdr_idx.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020052#include <proto/proto_http.h>
53#include <proto/queue.h>
54#include <proto/session.h>
55#include <proto/task.h>
56
Willy Tarreau6d1a9882007-01-07 02:03:04 +010057#ifdef CONFIG_HAP_TCPSPLICE
58#include <libtcpsplice.h>
59#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020060
Willy Tarreau58f10d72006-12-04 02:26:12 +010061#define DEBUG_PARSE_NO_SPEEDUP
62#undef DEBUG_PARSE_NO_SPEEDUP
63
Willy Tarreau976f1ee2006-12-17 10:06:03 +010064/* This is used to perform a quick jump as an alternative to a break/continue
65 * instruction. The first argument is the label for normal operation, and the
66 * second one is the break/continue instruction in the no_speedup mode.
67 */
68
69#ifdef DEBUG_PARSE_NO_SPEEDUP
70#define QUICK_JUMP(x,y) y
71#else
72#define QUICK_JUMP(x,y) goto x
73#endif
74
Willy Tarreau1c47f852006-07-09 08:22:27 +020075/* This is used by remote monitoring */
Willy Tarreau0f772532006-12-23 20:51:41 +010076const char HTTP_200[] =
Willy Tarreau1c47f852006-07-09 08:22:27 +020077 "HTTP/1.0 200 OK\r\n"
78 "Cache-Control: no-cache\r\n"
79 "Connection: close\r\n"
80 "Content-Type: text/html\r\n"
81 "\r\n"
82 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
83
Willy Tarreau0f772532006-12-23 20:51:41 +010084const struct chunk http_200_chunk = {
85 .str = (char *)&HTTP_200,
86 .len = sizeof(HTTP_200)-1
87};
88
89const char *HTTP_302 =
90 "HTTP/1.0 302 Found\r\n"
91 "Cache-Control: no-cache\r\n"
92 "Connection: close\r\n"
93 "Location: "; /* not terminated since it will be concatenated with the URL */
94
95/* same as 302 except that the browser MUST retry with the GET method */
96const char *HTTP_303 =
97 "HTTP/1.0 303 See Other\r\n"
98 "Cache-Control: no-cache\r\n"
99 "Connection: close\r\n"
100 "Location: "; /* not terminated since it will be concatenated with the URL */
101
Willy Tarreaubaaee002006-06-26 02:48:02 +0200102/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
103const char *HTTP_401_fmt =
104 "HTTP/1.0 401 Unauthorized\r\n"
105 "Cache-Control: no-cache\r\n"
106 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +0200107 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200108 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
109 "\r\n"
110 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
111
Willy Tarreau0f772532006-12-23 20:51:41 +0100112
113const int http_err_codes[HTTP_ERR_SIZE] = {
114 [HTTP_ERR_400] = 400,
115 [HTTP_ERR_403] = 403,
116 [HTTP_ERR_408] = 408,
117 [HTTP_ERR_500] = 500,
118 [HTTP_ERR_502] = 502,
119 [HTTP_ERR_503] = 503,
120 [HTTP_ERR_504] = 504,
121};
122
Willy Tarreau80587432006-12-24 17:47:20 +0100123static const char *http_err_msgs[HTTP_ERR_SIZE] = {
Willy Tarreau0f772532006-12-23 20:51:41 +0100124 [HTTP_ERR_400] =
Willy Tarreau80587432006-12-24 17:47:20 +0100125 "HTTP/1.0 400 Bad request\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +0100126 "Cache-Control: no-cache\r\n"
127 "Connection: close\r\n"
128 "Content-Type: text/html\r\n"
129 "\r\n"
130 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
131
132 [HTTP_ERR_403] =
133 "HTTP/1.0 403 Forbidden\r\n"
134 "Cache-Control: no-cache\r\n"
135 "Connection: close\r\n"
136 "Content-Type: text/html\r\n"
137 "\r\n"
138 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
139
140 [HTTP_ERR_408] =
141 "HTTP/1.0 408 Request Time-out\r\n"
142 "Cache-Control: no-cache\r\n"
143 "Connection: close\r\n"
144 "Content-Type: text/html\r\n"
145 "\r\n"
146 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
147
148 [HTTP_ERR_500] =
149 "HTTP/1.0 500 Server Error\r\n"
150 "Cache-Control: no-cache\r\n"
151 "Connection: close\r\n"
152 "Content-Type: text/html\r\n"
153 "\r\n"
154 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n",
155
156 [HTTP_ERR_502] =
157 "HTTP/1.0 502 Bad Gateway\r\n"
158 "Cache-Control: no-cache\r\n"
159 "Connection: close\r\n"
160 "Content-Type: text/html\r\n"
161 "\r\n"
162 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n",
163
164 [HTTP_ERR_503] =
165 "HTTP/1.0 503 Service Unavailable\r\n"
166 "Cache-Control: no-cache\r\n"
167 "Connection: close\r\n"
168 "Content-Type: text/html\r\n"
169 "\r\n"
170 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n",
171
172 [HTTP_ERR_504] =
173 "HTTP/1.0 504 Gateway Time-out\r\n"
174 "Cache-Control: no-cache\r\n"
175 "Connection: close\r\n"
176 "Content-Type: text/html\r\n"
177 "\r\n"
178 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n",
179
180};
181
Willy Tarreau80587432006-12-24 17:47:20 +0100182/* We must put the messages here since GCC cannot initialize consts depending
183 * on strlen().
184 */
185struct chunk http_err_chunks[HTTP_ERR_SIZE];
186
Willy Tarreau42250582007-04-01 01:30:43 +0200187#define FD_SETS_ARE_BITFIELDS
188#ifdef FD_SETS_ARE_BITFIELDS
189/*
190 * This map is used with all the FD_* macros to check whether a particular bit
191 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
192 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
193 * byte should be encoded. Be careful to always pass bytes from 0 to 255
194 * exclusively to the macros.
195 */
196fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
197fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
198
199#else
200#error "Check if your OS uses bitfields for fd_sets"
201#endif
202
Willy Tarreau80587432006-12-24 17:47:20 +0100203void init_proto_http()
204{
Willy Tarreau42250582007-04-01 01:30:43 +0200205 int i;
206 char *tmp;
Willy Tarreau80587432006-12-24 17:47:20 +0100207 int msg;
Willy Tarreau42250582007-04-01 01:30:43 +0200208
Willy Tarreau80587432006-12-24 17:47:20 +0100209 for (msg = 0; msg < HTTP_ERR_SIZE; msg++) {
210 if (!http_err_msgs[msg]) {
211 Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n", msg);
212 abort();
213 }
214
215 http_err_chunks[msg].str = (char *)http_err_msgs[msg];
216 http_err_chunks[msg].len = strlen(http_err_msgs[msg]);
217 }
Willy Tarreau42250582007-04-01 01:30:43 +0200218
219 /* initialize the log header encoding map : '{|}"#' should be encoded with
220 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
221 * URL encoding only requires '"', '#' to be encoded as well as non-
222 * printable characters above.
223 */
224 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
225 memset(url_encode_map, 0, sizeof(url_encode_map));
226 for (i = 0; i < 32; i++) {
227 FD_SET(i, hdr_encode_map);
228 FD_SET(i, url_encode_map);
229 }
230 for (i = 127; i < 256; i++) {
231 FD_SET(i, hdr_encode_map);
232 FD_SET(i, url_encode_map);
233 }
234
235 tmp = "\"#{|}";
236 while (*tmp) {
237 FD_SET(*tmp, hdr_encode_map);
238 tmp++;
239 }
240
241 tmp = "\"#";
242 while (*tmp) {
243 FD_SET(*tmp, url_encode_map);
244 tmp++;
245 }
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200246
247 /* memory allocations */
248 pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED);
Willy Tarreau086b3b42007-05-13 21:45:51 +0200249 pool2_capture = create_pool("capture", CAPTURE_LEN, MEM_F_SHARED);
Willy Tarreau80587432006-12-24 17:47:20 +0100250}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200251
Willy Tarreau53b6c742006-12-17 13:37:46 +0100252/*
253 * We have 26 list of methods (1 per first letter), each of which can have
254 * up to 3 entries (2 valid, 1 null).
255 */
256struct http_method_desc {
257 http_meth_t meth;
258 int len;
259 const char text[8];
260};
261
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100262const struct http_method_desc http_methods[26][3] = {
Willy Tarreau53b6c742006-12-17 13:37:46 +0100263 ['C' - 'A'] = {
264 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
265 },
266 ['D' - 'A'] = {
267 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
268 },
269 ['G' - 'A'] = {
270 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
271 },
272 ['H' - 'A'] = {
273 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
274 },
275 ['P' - 'A'] = {
276 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
277 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
278 },
279 ['T' - 'A'] = {
280 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
281 },
282 /* rest is empty like this :
283 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
284 */
285};
286
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100287/* It is about twice as fast on recent architectures to lookup a byte in a
288 * table than two perform a boolean AND or OR between two tests. Refer to
289 * RFC2616 for those chars.
290 */
291
292const char http_is_spht[256] = {
293 [' '] = 1, ['\t'] = 1,
294};
295
296const char http_is_crlf[256] = {
297 ['\r'] = 1, ['\n'] = 1,
298};
299
300const char http_is_lws[256] = {
301 [' '] = 1, ['\t'] = 1,
302 ['\r'] = 1, ['\n'] = 1,
303};
304
305const char http_is_sep[256] = {
306 ['('] = 1, [')'] = 1, ['<'] = 1, ['>'] = 1,
307 ['@'] = 1, [','] = 1, [';'] = 1, [':'] = 1,
308 ['"'] = 1, ['/'] = 1, ['['] = 1, [']'] = 1,
309 ['{'] = 1, ['}'] = 1, ['?'] = 1, ['='] = 1,
310 [' '] = 1, ['\t'] = 1, ['\\'] = 1,
311};
312
313const char http_is_ctl[256] = {
314 [0 ... 31] = 1,
315 [127] = 1,
316};
317
318/*
319 * A token is any ASCII char that is neither a separator nor a CTL char.
320 * Do not overwrite values in assignment since gcc-2.95 will not handle
321 * them correctly. Instead, define every non-CTL char's status.
322 */
323const char http_is_token[256] = {
324 [' '] = 0, ['!'] = 1, ['"'] = 0, ['#'] = 1,
325 ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1,
326 ['('] = 0, [')'] = 0, ['*'] = 1, ['+'] = 1,
327 [','] = 0, ['-'] = 1, ['.'] = 1, ['/'] = 0,
328 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1,
329 ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1,
330 ['8'] = 1, ['9'] = 1, [':'] = 0, [';'] = 0,
331 ['<'] = 0, ['='] = 0, ['>'] = 0, ['?'] = 0,
332 ['@'] = 0, ['A'] = 1, ['B'] = 1, ['C'] = 1,
333 ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1,
334 ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1,
335 ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1,
336 ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1,
337 ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1,
338 ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 0,
339 ['\\'] = 0, [']'] = 0, ['^'] = 1, ['_'] = 1,
340 ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1,
341 ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1,
342 ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1,
343 ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1,
344 ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1,
345 ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1,
346 ['x'] = 1, ['y'] = 1, ['z'] = 1, ['{'] = 0,
347 ['|'] = 1, ['}'] = 0, ['~'] = 1,
348};
349
350
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100351/*
352 * An http ver_token is any ASCII which can be found in an HTTP version,
353 * which includes 'H', 'T', 'P', '/', '.' and any digit.
354 */
355const char http_is_ver_token[256] = {
356 ['.'] = 1, ['/'] = 1,
357 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1,
358 ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1,
359 ['H'] = 1, ['P'] = 1, ['T'] = 1,
360};
361
362
Willy Tarreaubaaee002006-06-26 02:48:02 +0200363#ifdef DEBUG_FULL
364static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
365static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
366#endif
367
Willy Tarreau42250582007-04-01 01:30:43 +0200368static void http_sess_log(struct session *s);
369
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100370/*
371 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
372 * CRLF. Text length is measured first, so it cannot be NULL.
373 * The header is also automatically added to the index <hdr_idx>, and the end
374 * of headers is automatically adjusted. The number of bytes added is returned
375 * on success, otherwise <0 is returned indicating an error.
376 */
377int http_header_add_tail(struct buffer *b, struct http_msg *msg,
378 struct hdr_idx *hdr_idx, const char *text)
379{
380 int bytes, len;
381
382 len = strlen(text);
383 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
384 if (!bytes)
385 return -1;
386 msg->eoh += bytes;
387 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
388}
389
390/*
391 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
392 * CRLF. <len> bytes are copied, not counting the CRLF. If <text> is NULL, then
393 * the buffer is only opened and the space reserved, but nothing is copied.
394 * The header is also automatically added to the index <hdr_idx>, and the end
395 * of headers is automatically adjusted. The number of bytes added is returned
396 * on success, otherwise <0 is returned indicating an error.
397 */
398int http_header_add_tail2(struct buffer *b, struct http_msg *msg,
399 struct hdr_idx *hdr_idx, const char *text, int len)
400{
401 int bytes;
402
403 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
404 if (!bytes)
405 return -1;
406 msg->eoh += bytes;
407 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
408}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200409
410/*
Willy Tarreauaa9dce32007-03-18 23:50:16 +0100411 * Checks if <hdr> is exactly <name> for <len> chars, and ends with a colon.
412 * If so, returns the position of the first non-space character relative to
413 * <hdr>, or <end>-<hdr> if not found before. If no value is found, it tries
414 * to return a pointer to the place after the first space. Returns 0 if the
415 * header name does not match. Checks are case-insensitive.
416 */
417int http_header_match2(const char *hdr, const char *end,
418 const char *name, int len)
419{
420 const char *val;
421
422 if (hdr + len >= end)
423 return 0;
424 if (hdr[len] != ':')
425 return 0;
426 if (strncasecmp(hdr, name, len) != 0)
427 return 0;
428 val = hdr + len + 1;
429 while (val < end && HTTP_IS_SPHT(*val))
430 val++;
431 if ((val >= end) && (len + 2 <= end - hdr))
432 return len + 2; /* we may replace starting from second space */
433 return val - hdr;
434}
435
436/*
Willy Tarreaubaaee002006-06-26 02:48:02 +0200437 * returns a message to the client ; the connection is shut down for read,
438 * and the request is cleared so that no server connection can be initiated.
439 * The client must be in a valid state for this (HEADER, DATA ...).
Willy Tarreau0f772532006-12-23 20:51:41 +0100440 * Nothing is performed on the server side. The message is contained in a
441 * "chunk". If it is null, then an empty message is used.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200442 * The reply buffer doesn't need to be empty before this.
443 */
Willy Tarreau0f772532006-12-23 20:51:41 +0100444void client_retnclose(struct session *s, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200445{
Willy Tarreauf161a342007-04-08 16:59:42 +0200446 EV_FD_CLR(s->cli_fd, DIR_RD);
447 EV_FD_SET(s->cli_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +0200448 buffer_shutr(s->req);
Willy Tarreaua8b55e32007-05-13 16:08:19 +0200449 if (!tv_add_ifset(&s->rep->wex, &now, &s->fe->clitimeout))
Willy Tarreaud7971282006-07-29 18:36:34 +0200450 tv_eternity(&s->rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200451 s->cli_state = CL_STSHUTR;
452 buffer_flush(s->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100453 if (msg->len)
454 buffer_write(s->rep, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200455 s->req->l = 0;
456}
457
458
459/*
460 * returns a message into the rep buffer, and flushes the req buffer.
Willy Tarreau0f772532006-12-23 20:51:41 +0100461 * The reply buffer doesn't need to be empty before this. The message
462 * is contained in a "chunk". If it is null, then an empty message is
463 * used.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200464 */
Willy Tarreau0f772532006-12-23 20:51:41 +0100465void client_return(struct session *s, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200466{
467 buffer_flush(s->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100468 if (msg->len)
469 buffer_write(s->rep, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200470 s->req->l = 0;
471}
472
473
474/* This function turns the server state into the SV_STCLOSE, and sets
Willy Tarreau0f772532006-12-23 20:51:41 +0100475 * indicators accordingly. Note that if <status> is 0, or if the message
476 * pointer is NULL, then no message is returned.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200477 */
478void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreau0f772532006-12-23 20:51:41 +0100479 int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200480{
481 t->srv_state = SV_STCLOSE;
Willy Tarreau0f772532006-12-23 20:51:41 +0100482 if (status > 0 && msg) {
Willy Tarreau3bac9ff2007-03-18 17:31:28 +0100483 t->txn.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100484 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100485 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200486 }
487 if (!(t->flags & SN_ERR_MASK))
488 t->flags |= err;
489 if (!(t->flags & SN_FINST_MASK))
490 t->flags |= finst;
491}
492
Willy Tarreau80587432006-12-24 17:47:20 +0100493/* This function returns the appropriate error location for the given session
494 * and message.
495 */
496
497struct chunk *error_message(struct session *s, int msgnum)
498{
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200499 if (s->be->errmsg[msgnum].str)
500 return &s->be->errmsg[msgnum];
Willy Tarreau80587432006-12-24 17:47:20 +0100501 else if (s->fe->errmsg[msgnum].str)
502 return &s->fe->errmsg[msgnum];
503 else
504 return &http_err_chunks[msgnum];
505}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200506
Willy Tarreau53b6c742006-12-17 13:37:46 +0100507/*
508 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
509 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
510 */
511static http_meth_t find_http_meth(const char *str, const int len)
512{
513 unsigned char m;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100514 const struct http_method_desc *h;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100515
516 m = ((unsigned)*str - 'A');
517
518 if (m < 26) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100519 for (h = http_methods[m]; h->len > 0; h++) {
520 if (unlikely(h->len != len))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100521 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100522 if (likely(memcmp(str, h->text, h->len) == 0))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100523 return h->meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100524 };
525 return HTTP_METH_OTHER;
526 }
527 return HTTP_METH_NONE;
528
529}
530
Willy Tarreaubaaee002006-06-26 02:48:02 +0200531/* Processes the client and server jobs of a session task, then
532 * puts it back to the wait queue in a clean state, or
533 * cleans up its resources if it must be deleted. Returns
534 * the time the task accepts to wait, or TIME_ETERNITY for
535 * infinity.
536 */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200537void process_session(struct task *t, struct timeval *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200538{
539 struct session *s = t->context;
540 int fsm_resync = 0;
541
542 do {
543 fsm_resync = 0;
544 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
545 fsm_resync |= process_cli(s);
546 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
547 fsm_resync |= process_srv(s);
548 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
549 } while (fsm_resync);
550
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200551 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200552 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
553 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200554
Willy Tarreaua6a6a932007-04-28 22:40:08 +0200555 t->expire = s->req->rex;
556 tv_min(&t->expire, &s->req->rex, &s->req->wex);
557 tv_bound(&t->expire, &s->req->cex);
558 tv_bound(&t->expire, &s->rep->rex);
559 tv_bound(&t->expire, &s->rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200560
561 /* restore t to its place in the task list */
562 task_queue(t);
563
564#ifdef DEBUG_FULL
565 /* DEBUG code : this should never ever happen, otherwise it indicates
566 * that a task still has something to do and will provoke a quick loop.
567 */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200568 if (tv_remain2(&now, &t->expire) <= 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200569 exit(100);
570#endif
Willy Tarreaud825eef2007-05-12 22:35:00 +0200571 *next = t->expire;
572 return; /* nothing more to do */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200573 }
574
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100575 s->fe->feconn--;
576 if (s->flags & SN_BE_ASSIGNED)
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200577 s->be->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200578 actconn--;
579
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200580 if (unlikely((global.mode & MODE_DEBUG) &&
581 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200582 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100583 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200584 s->uniq_id, s->be->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100585 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200586 write(1, trash, len);
587 }
588
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200589 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Willy Tarreau35d66b02007-01-02 00:28:21 +0100590 if (s->req != NULL)
591 s->logs.bytes_in = s->req->total;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200592 if (s->rep != NULL)
Willy Tarreau35d66b02007-01-02 00:28:21 +0100593 s->logs.bytes_out = s->rep->total;
594
595 s->fe->bytes_in += s->logs.bytes_in;
596 s->fe->bytes_out += s->logs.bytes_out;
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200597 if (s->be != s->fe) {
598 s->be->bytes_in += s->logs.bytes_in;
599 s->be->bytes_out += s->logs.bytes_out;
Willy Tarreau35d66b02007-01-02 00:28:21 +0100600 }
601 if (s->srv) {
602 s->srv->bytes_in += s->logs.bytes_in;
603 s->srv->bytes_out += s->logs.bytes_out;
604 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200605
606 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200607 if (s->logs.logwait &&
608 !(s->flags & SN_MONITOR) &&
Willy Tarreau42250582007-04-01 01:30:43 +0200609 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total)) {
610 if (s->fe->to_log & LW_REQ)
611 http_sess_log(s);
612 else
613 tcp_sess_log(s);
614 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200615
616 /* the task MUST not be in the run queue anymore */
617 task_delete(t);
618 session_free(s);
619 task_free(t);
Willy Tarreaud825eef2007-05-12 22:35:00 +0200620 tv_eternity(next);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200621}
622
623
Willy Tarreau42250582007-04-01 01:30:43 +0200624extern const char sess_term_cond[8];
625extern const char sess_fin_state[8];
626extern const char *monthname[12];
627const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
628const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
629 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
630 unknown, Set-cookie Rewritten */
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200631struct pool_head *pool2_requri;
Willy Tarreau086b3b42007-05-13 21:45:51 +0200632struct pool_head *pool2_capture;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100633
Willy Tarreau42250582007-04-01 01:30:43 +0200634/*
635 * send a log for the session when we have enough info about it.
636 * Will not log if the frontend has no log defined.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100637 */
Willy Tarreau42250582007-04-01 01:30:43 +0200638static void http_sess_log(struct session *s)
639{
640 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
641 struct proxy *fe = s->fe;
642 struct proxy *be = s->be;
643 struct proxy *prx_log;
644 struct http_txn *txn = &s->txn;
645 int tolog;
646 char *uri, *h;
647 char *svid;
648 struct tm *tm;
649 static char tmpline[MAX_SYSLOG_LEN];
650 int hdr;
651
652 if (fe->logfac1 < 0 && fe->logfac2 < 0)
653 return;
654 prx_log = fe;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100655
Willy Tarreau42250582007-04-01 01:30:43 +0200656 if (s->cli_addr.ss_family == AF_INET)
657 inet_ntop(AF_INET,
658 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
659 pn, sizeof(pn));
660 else
661 inet_ntop(AF_INET6,
662 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
663 pn, sizeof(pn));
664
665 tm = localtime((time_t *)&s->logs.tv_accept.tv_sec);
666
667
668 /* FIXME: let's limit ourselves to frontend logging for now. */
669 tolog = fe->to_log;
670
671 h = tmpline;
672 if (fe->to_log & LW_REQHDR &&
673 txn->req.cap &&
674 (h < tmpline + sizeof(tmpline) - 10)) {
675 *(h++) = ' ';
676 *(h++) = '{';
677 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
678 if (hdr)
679 *(h++) = '|';
680 if (txn->req.cap[hdr] != NULL)
681 h = encode_string(h, tmpline + sizeof(tmpline) - 7,
682 '#', hdr_encode_map, txn->req.cap[hdr]);
683 }
684 *(h++) = '}';
685 }
686
687 if (fe->to_log & LW_RSPHDR &&
688 txn->rsp.cap &&
689 (h < tmpline + sizeof(tmpline) - 7)) {
690 *(h++) = ' ';
691 *(h++) = '{';
692 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
693 if (hdr)
694 *(h++) = '|';
695 if (txn->rsp.cap[hdr] != NULL)
696 h = encode_string(h, tmpline + sizeof(tmpline) - 4,
697 '#', hdr_encode_map, txn->rsp.cap[hdr]);
698 }
699 *(h++) = '}';
700 }
701
702 if (h < tmpline + sizeof(tmpline) - 4) {
703 *(h++) = ' ';
704 *(h++) = '"';
705 uri = txn->uri ? txn->uri : "<BADREQ>";
706 h = encode_string(h, tmpline + sizeof(tmpline) - 1,
707 '#', url_encode_map, uri);
708 *(h++) = '"';
709 }
710 *h = '\0';
711
712 svid = (tolog & LW_SVID) ?
713 (s->data_source != DATA_SRC_STATS) ?
714 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
715
716 send_log(prx_log, LOG_INFO,
717 "%s:%d [%02d/%s/%04d:%02d:%02d:%02d.%03d]"
718 " %s %s/%s %d/%d/%d/%d/%s%d %d %s%lld"
719 " %s %s %c%c%c%c %d/%d/%d/%d %d/%d%s\n",
720 pn,
721 (s->cli_addr.ss_family == AF_INET) ?
722 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
723 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
724 tm->tm_mday, monthname[tm->tm_mon], tm->tm_year+1900,
725 tm->tm_hour, tm->tm_min, tm->tm_sec, s->logs.tv_accept.tv_usec/1000,
726 fe->id, be->id, svid,
727 s->logs.t_request,
728 (s->logs.t_queue >= 0) ? s->logs.t_queue - s->logs.t_request : -1,
729 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
730 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
731 (tolog & LW_BYTES) ? "" : "+", s->logs.t_close,
732 txn->status,
733 (tolog & LW_BYTES) ? "" : "+", s->logs.bytes_in,
734 txn->cli_cookie ? txn->cli_cookie : "-",
735 txn->srv_cookie ? txn->srv_cookie : "-",
736 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
737 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
738 (be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-',
739 (be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-',
740 actconn, fe->feconn, be->beconn, s->srv ? s->srv->cur_sess : 0,
741 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
742
743 s->logs.logwait = 0;
744}
745
Willy Tarreau117f59e2007-03-04 18:17:17 +0100746
747/*
748 * Capture headers from message starting at <som> according to header list
749 * <cap_hdr>, and fill the <idx> structure appropriately.
750 */
751void capture_headers(char *som, struct hdr_idx *idx,
752 char **cap, struct cap_hdr *cap_hdr)
753{
754 char *eol, *sol, *col, *sov;
755 int cur_idx;
756 struct cap_hdr *h;
757 int len;
758
759 sol = som + hdr_idx_first_pos(idx);
760 cur_idx = hdr_idx_first_idx(idx);
761
762 while (cur_idx) {
763 eol = sol + idx->v[cur_idx].len;
764
765 col = sol;
766 while (col < eol && *col != ':')
767 col++;
768
769 sov = col + 1;
770 while (sov < eol && http_is_lws[(unsigned char)*sov])
771 sov++;
772
773 for (h = cap_hdr; h; h = h->next) {
774 if ((h->namelen == col - sol) &&
775 (strncasecmp(sol, h->name, h->namelen) == 0)) {
776 if (cap[h->index] == NULL)
777 cap[h->index] =
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200778 pool_alloc2(h->pool);
Willy Tarreau117f59e2007-03-04 18:17:17 +0100779
780 if (cap[h->index] == NULL) {
781 Alert("HTTP capture : out of memory.\n");
782 continue;
783 }
784
785 len = eol - sov;
786 if (len > h->len)
787 len = h->len;
788
789 memcpy(cap[h->index], sov, len);
790 cap[h->index][len]=0;
791 }
792 }
793 sol = eol + idx->v[cur_idx].cr + 1;
794 cur_idx = idx->v[cur_idx].next;
795 }
796}
797
798
Willy Tarreau42250582007-04-01 01:30:43 +0200799/* either we find an LF at <ptr> or we jump to <bad>.
800 */
801#define EXPECT_LF_HERE(ptr, bad) do { if (unlikely(*(ptr) != '\n')) goto bad; } while (0)
802
803/* plays with variables <ptr>, <end> and <state>. Jumps to <good> if OK,
804 * otherwise to <http_msg_ood> with <state> set to <st>.
805 */
806#define EAT_AND_JUMP_OR_RETURN(good, st) do { \
807 ptr++; \
808 if (likely(ptr < end)) \
809 goto good; \
810 else { \
811 state = (st); \
812 goto http_msg_ood; \
813 } \
814 } while (0)
815
816
Willy Tarreaubaaee002006-06-26 02:48:02 +0200817/*
Willy Tarreaua15645d2007-03-18 16:22:39 +0100818 * This function parses a status line between <ptr> and <end>, starting with
Willy Tarreau8973c702007-01-21 23:58:29 +0100819 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
820 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
821 * will give undefined results.
822 * Note that it is upon the caller's responsibility to ensure that ptr < end,
823 * and that msg->sol points to the beginning of the response.
824 * If a complete line is found (which implies that at least one CR or LF is
825 * found before <end>, the updated <ptr> is returned, otherwise NULL is
826 * returned indicating an incomplete line (which does not mean that parts have
827 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
828 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
829 * upon next call.
830 *
Willy Tarreau9cdde232007-05-02 20:58:19 +0200831 * This function was intentionally designed to be called from
Willy Tarreau8973c702007-01-21 23:58:29 +0100832 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
833 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +0200834 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreau8973c702007-01-21 23:58:29 +0100835 */
Willy Tarreaua15645d2007-03-18 16:22:39 +0100836const char *http_parse_stsline(struct http_msg *msg, const char *msg_buf, int state,
Willy Tarreau8973c702007-01-21 23:58:29 +0100837 const char *ptr, const char *end,
838 char **ret_ptr, int *ret_state)
839{
840 __label__
841 http_msg_rpver,
842 http_msg_rpver_sp,
843 http_msg_rpcode,
844 http_msg_rpcode_sp,
845 http_msg_rpreason,
846 http_msg_rpline_eol,
847 http_msg_ood, /* out of data */
848 http_msg_invalid;
849
850 switch (state) {
851 http_msg_rpver:
852 case HTTP_MSG_RPVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100853 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8973c702007-01-21 23:58:29 +0100854 EAT_AND_JUMP_OR_RETURN(http_msg_rpver, HTTP_MSG_RPVER);
855
856 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +0100857 msg->sl.st.v_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +0100858 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
859 }
860 goto http_msg_invalid;
861
862 http_msg_rpver_sp:
863 case HTTP_MSG_RPVER_SP:
864 if (likely(!HTTP_IS_LWS(*ptr))) {
865 msg->sl.st.c = ptr - msg_buf;
866 goto http_msg_rpcode;
867 }
868 if (likely(HTTP_IS_SPHT(*ptr)))
869 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
870 /* so it's a CR/LF, this is invalid */
871 goto http_msg_invalid;
872
873 http_msg_rpcode:
874 case HTTP_MSG_RPCODE:
875 if (likely(!HTTP_IS_LWS(*ptr)))
876 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode, HTTP_MSG_RPCODE);
877
878 if (likely(HTTP_IS_SPHT(*ptr))) {
879 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
880 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
881 }
882
883 /* so it's a CR/LF, so there is no reason phrase */
884 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
885 http_msg_rsp_reason:
886 /* FIXME: should we support HTTP responses without any reason phrase ? */
887 msg->sl.st.r = ptr - msg_buf;
888 msg->sl.st.r_l = 0;
889 goto http_msg_rpline_eol;
890
891 http_msg_rpcode_sp:
892 case HTTP_MSG_RPCODE_SP:
893 if (likely(!HTTP_IS_LWS(*ptr))) {
894 msg->sl.st.r = ptr - msg_buf;
895 goto http_msg_rpreason;
896 }
897 if (likely(HTTP_IS_SPHT(*ptr)))
898 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
899 /* so it's a CR/LF, so there is no reason phrase */
900 goto http_msg_rsp_reason;
901
902 http_msg_rpreason:
903 case HTTP_MSG_RPREASON:
904 if (likely(!HTTP_IS_CRLF(*ptr)))
905 EAT_AND_JUMP_OR_RETURN(http_msg_rpreason, HTTP_MSG_RPREASON);
906 msg->sl.st.r_l = (ptr - msg_buf) - msg->sl.st.r;
907 http_msg_rpline_eol:
908 /* We have seen the end of line. Note that we do not
909 * necessarily have the \n yet, but at least we know that we
910 * have EITHER \r OR \n, otherwise the response would not be
911 * complete. We can then record the response length and return
912 * to the caller which will be able to register it.
913 */
914 msg->sl.st.l = ptr - msg->sol;
915 return ptr;
916
917#ifdef DEBUG_FULL
918 default:
919 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
920 exit(1);
921#endif
922 }
923
924 http_msg_ood:
925 /* out of data */
926 if (ret_state)
927 *ret_state = state;
928 if (ret_ptr)
929 *ret_ptr = (char *)ptr;
930 return NULL;
931
932 http_msg_invalid:
933 /* invalid message */
934 if (ret_state)
935 *ret_state = HTTP_MSG_ERROR;
936 return NULL;
937}
938
939
940/*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100941 * This function parses a request line between <ptr> and <end>, starting with
942 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
943 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
944 * will give undefined results.
945 * Note that it is upon the caller's responsibility to ensure that ptr < end,
946 * and that msg->sol points to the beginning of the request.
947 * If a complete line is found (which implies that at least one CR or LF is
948 * found before <end>, the updated <ptr> is returned, otherwise NULL is
949 * returned indicating an incomplete line (which does not mean that parts have
950 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
951 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
952 * upon next call.
953 *
Willy Tarreau9cdde232007-05-02 20:58:19 +0200954 * This function was intentionally designed to be called from
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100955 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
956 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +0200957 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200958 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100959const char *http_parse_reqline(struct http_msg *msg, const char *msg_buf, int state,
Willy Tarreau8973c702007-01-21 23:58:29 +0100960 const char *ptr, const char *end,
961 char **ret_ptr, int *ret_state)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200962{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100963 __label__
964 http_msg_rqmeth,
965 http_msg_rqmeth_sp,
966 http_msg_rquri,
967 http_msg_rquri_sp,
968 http_msg_rqver,
969 http_msg_rqline_eol,
970 http_msg_ood, /* out of data */
971 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100972
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100973 switch (state) {
974 http_msg_rqmeth:
975 case HTTP_MSG_RQMETH:
976 if (likely(HTTP_IS_TOKEN(*ptr)))
977 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth, HTTP_MSG_RQMETH);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100978
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100979 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +0100980 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100981 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
982 }
Willy Tarreau58f10d72006-12-04 02:26:12 +0100983
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100984 if (likely(HTTP_IS_CRLF(*ptr))) {
985 /* HTTP 0.9 request */
Willy Tarreaub326fcc2007-03-03 13:54:32 +0100986 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100987 http_msg_req09_uri:
988 msg->sl.rq.u = ptr - msg_buf;
989 http_msg_req09_uri_e:
990 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
991 http_msg_req09_ver:
992 msg->sl.rq.v = ptr - msg_buf;
993 msg->sl.rq.v_l = 0;
994 goto http_msg_rqline_eol;
995 }
996 goto http_msg_invalid;
997
998 http_msg_rqmeth_sp:
999 case HTTP_MSG_RQMETH_SP:
1000 if (likely(!HTTP_IS_LWS(*ptr))) {
1001 msg->sl.rq.u = ptr - msg_buf;
1002 goto http_msg_rquri;
1003 }
1004 if (likely(HTTP_IS_SPHT(*ptr)))
1005 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1006 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1007 goto http_msg_req09_uri;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001008
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001009 http_msg_rquri:
1010 case HTTP_MSG_RQURI:
1011 if (likely(!HTTP_IS_LWS(*ptr)))
1012 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001013
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001014 if (likely(HTTP_IS_SPHT(*ptr))) {
1015 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1016 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1017 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001018
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001019 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1020 goto http_msg_req09_uri_e;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001021
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001022 http_msg_rquri_sp:
1023 case HTTP_MSG_RQURI_SP:
1024 if (likely(!HTTP_IS_LWS(*ptr))) {
1025 msg->sl.rq.v = ptr - msg_buf;
1026 goto http_msg_rqver;
1027 }
1028 if (likely(HTTP_IS_SPHT(*ptr)))
1029 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1030 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1031 goto http_msg_req09_ver;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001032
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001033 http_msg_rqver:
1034 case HTTP_MSG_RQVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001035 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001036 EAT_AND_JUMP_OR_RETURN(http_msg_rqver, HTTP_MSG_RQVER);
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001037
1038 if (likely(HTTP_IS_CRLF(*ptr))) {
1039 msg->sl.rq.v_l = (ptr - msg_buf) - msg->sl.rq.v;
1040 http_msg_rqline_eol:
1041 /* We have seen the end of line. Note that we do not
1042 * necessarily have the \n yet, but at least we know that we
1043 * have EITHER \r OR \n, otherwise the request would not be
1044 * complete. We can then record the request length and return
1045 * to the caller which will be able to register it.
1046 */
1047 msg->sl.rq.l = ptr - msg->sol;
1048 return ptr;
1049 }
1050
1051 /* neither an HTTP_VER token nor a CRLF */
1052 goto http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001053
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001054#ifdef DEBUG_FULL
1055 default:
1056 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1057 exit(1);
1058#endif
1059 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001060
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001061 http_msg_ood:
1062 /* out of data */
1063 if (ret_state)
1064 *ret_state = state;
1065 if (ret_ptr)
1066 *ret_ptr = (char *)ptr;
1067 return NULL;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001068
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001069 http_msg_invalid:
1070 /* invalid message */
1071 if (ret_state)
1072 *ret_state = HTTP_MSG_ERROR;
1073 return NULL;
1074}
Willy Tarreau58f10d72006-12-04 02:26:12 +01001075
1076
Willy Tarreau8973c702007-01-21 23:58:29 +01001077/*
1078 * This function parses an HTTP message, either a request or a response,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001079 * depending on the initial msg->msg_state. It can be preempted everywhere
Willy Tarreau8973c702007-01-21 23:58:29 +01001080 * when data are missing and recalled at the exact same location with no
1081 * information loss. The header index is re-initialized when switching from
Willy Tarreau9cdde232007-05-02 20:58:19 +02001082 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH. It modifies msg->sol among other
1083 * fields.
Willy Tarreau8973c702007-01-21 23:58:29 +01001084 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001085void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx *idx)
1086{
1087 __label__
1088 http_msg_rqbefore,
1089 http_msg_rqbefore_cr,
1090 http_msg_rqmeth,
1091 http_msg_rqline_end,
1092 http_msg_hdr_first,
1093 http_msg_hdr_name,
1094 http_msg_hdr_l1_sp,
1095 http_msg_hdr_l1_lf,
1096 http_msg_hdr_l1_lws,
1097 http_msg_hdr_val,
1098 http_msg_hdr_l2_lf,
1099 http_msg_hdr_l2_lws,
1100 http_msg_complete_header,
1101 http_msg_last_lf,
1102 http_msg_ood, /* out of data */
1103 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001104
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001105 int state; /* updated only when leaving the FSM */
1106 register char *ptr, *end; /* request pointers, to avoid dereferences */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001107
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001108 state = msg->msg_state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001109 ptr = buf->lr;
1110 end = buf->r;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001111
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001112 if (unlikely(ptr >= end))
1113 goto http_msg_ood;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001114
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001115 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +01001116 /*
1117 * First, states that are specific to the response only.
1118 * We check them first so that request and headers are
1119 * closer to each other (accessed more often).
1120 */
1121 http_msg_rpbefore:
1122 case HTTP_MSG_RPBEFORE:
1123 if (likely(HTTP_IS_TOKEN(*ptr))) {
1124 if (likely(ptr == buf->data)) {
1125 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001126 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001127 } else {
1128#if PARSE_PRESERVE_EMPTY_LINES
1129 /* only skip empty leading lines, don't remove them */
1130 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001131 msg->som = ptr - buf->data;
Willy Tarreau8973c702007-01-21 23:58:29 +01001132#else
1133 /* Remove empty leading lines, as recommended by
1134 * RFC2616. This takes a lot of time because we
1135 * must move all the buffer backwards, but this
1136 * is rarely needed. The method above will be
1137 * cleaner when we'll be able to start sending
1138 * the request from any place in the buffer.
1139 */
1140 buf->lr = ptr;
1141 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001142 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001143 msg->sol = buf->data;
1144 ptr = buf->data;
1145 end = buf->r;
1146#endif
1147 }
1148 hdr_idx_init(idx);
1149 state = HTTP_MSG_RPVER;
1150 goto http_msg_rpver;
1151 }
1152
1153 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1154 goto http_msg_invalid;
1155
1156 if (unlikely(*ptr == '\n'))
1157 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1158 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore_cr, HTTP_MSG_RPBEFORE_CR);
1159 /* stop here */
1160
1161 http_msg_rpbefore_cr:
1162 case HTTP_MSG_RPBEFORE_CR:
1163 EXPECT_LF_HERE(ptr, http_msg_invalid);
1164 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1165 /* stop here */
1166
1167 http_msg_rpver:
1168 case HTTP_MSG_RPVER:
1169 case HTTP_MSG_RPVER_SP:
1170 case HTTP_MSG_RPCODE:
1171 case HTTP_MSG_RPCODE_SP:
1172 case HTTP_MSG_RPREASON:
Willy Tarreaua15645d2007-03-18 16:22:39 +01001173 ptr = (char *)http_parse_stsline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001174 &buf->lr, &msg->msg_state);
Willy Tarreau8973c702007-01-21 23:58:29 +01001175 if (unlikely(!ptr))
1176 return;
1177
1178 /* we have a full response and we know that we have either a CR
1179 * or an LF at <ptr>.
1180 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001181 //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 +01001182 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
1183
1184 msg->sol = ptr;
1185 if (likely(*ptr == '\r'))
1186 EAT_AND_JUMP_OR_RETURN(http_msg_rpline_end, HTTP_MSG_RPLINE_END);
1187 goto http_msg_rpline_end;
1188
1189 http_msg_rpline_end:
1190 case HTTP_MSG_RPLINE_END:
1191 /* msg->sol must point to the first of CR or LF. */
1192 EXPECT_LF_HERE(ptr, http_msg_invalid);
1193 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
1194 /* stop here */
1195
1196 /*
1197 * Second, states that are specific to the request only
1198 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001199 http_msg_rqbefore:
1200 case HTTP_MSG_RQBEFORE:
1201 if (likely(HTTP_IS_TOKEN(*ptr))) {
1202 if (likely(ptr == buf->data)) {
1203 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001204 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001205 } else {
1206#if PARSE_PRESERVE_EMPTY_LINES
1207 /* only skip empty leading lines, don't remove them */
1208 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001209 msg->som = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001210#else
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001211 /* Remove empty leading lines, as recommended by
1212 * RFC2616. This takes a lot of time because we
1213 * must move all the buffer backwards, but this
1214 * is rarely needed. The method above will be
1215 * cleaner when we'll be able to start sending
1216 * the request from any place in the buffer.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001217 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001218 buf->lr = ptr;
1219 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001220 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001221 msg->sol = buf->data;
1222 ptr = buf->data;
1223 end = buf->r;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001224#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001225 }
Willy Tarreauf0d058e2007-01-25 12:03:42 +01001226 /* we will need this when keep-alive will be supported
1227 hdr_idx_init(idx);
1228 */
Willy Tarreau8973c702007-01-21 23:58:29 +01001229 state = HTTP_MSG_RQMETH;
1230 goto http_msg_rqmeth;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001231 }
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001232
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001233 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1234 goto http_msg_invalid;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001235
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001236 if (unlikely(*ptr == '\n'))
1237 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
1238 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore_cr, HTTP_MSG_RQBEFORE_CR);
Willy Tarreau8973c702007-01-21 23:58:29 +01001239 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001240
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001241 http_msg_rqbefore_cr:
1242 case HTTP_MSG_RQBEFORE_CR:
1243 EXPECT_LF_HERE(ptr, http_msg_invalid);
1244 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
Willy Tarreau8973c702007-01-21 23:58:29 +01001245 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001246
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001247 http_msg_rqmeth:
1248 case HTTP_MSG_RQMETH:
1249 case HTTP_MSG_RQMETH_SP:
1250 case HTTP_MSG_RQURI:
1251 case HTTP_MSG_RQURI_SP:
1252 case HTTP_MSG_RQVER:
1253 ptr = (char *)http_parse_reqline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001254 &buf->lr, &msg->msg_state);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001255 if (unlikely(!ptr))
1256 return;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001257
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001258 /* we have a full request and we know that we have either a CR
1259 * or an LF at <ptr>.
1260 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001261 //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 +01001262 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001263
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001264 msg->sol = ptr;
1265 if (likely(*ptr == '\r'))
1266 EAT_AND_JUMP_OR_RETURN(http_msg_rqline_end, HTTP_MSG_RQLINE_END);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001267 goto http_msg_rqline_end;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001268
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001269 http_msg_rqline_end:
1270 case HTTP_MSG_RQLINE_END:
1271 /* check for HTTP/0.9 request : no version information available.
1272 * msg->sol must point to the first of CR or LF.
1273 */
1274 if (unlikely(msg->sl.rq.v_l == 0))
1275 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001276
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001277 EXPECT_LF_HERE(ptr, http_msg_invalid);
1278 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
Willy Tarreau8973c702007-01-21 23:58:29 +01001279 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001280
Willy Tarreau8973c702007-01-21 23:58:29 +01001281 /*
1282 * Common states below
1283 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001284 http_msg_hdr_first:
1285 case HTTP_MSG_HDR_FIRST:
1286 msg->sol = ptr;
1287 if (likely(!HTTP_IS_CRLF(*ptr))) {
1288 goto http_msg_hdr_name;
1289 }
1290
1291 if (likely(*ptr == '\r'))
1292 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1293 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001294
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001295 http_msg_hdr_name:
1296 case HTTP_MSG_HDR_NAME:
1297 /* assumes msg->sol points to the first char */
1298 if (likely(HTTP_IS_TOKEN(*ptr)))
1299 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001300
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001301 if (likely(*ptr == ':')) {
1302 msg->col = ptr - buf->data;
1303 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
1304 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001305
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001306 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001307
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001308 http_msg_hdr_l1_sp:
1309 case HTTP_MSG_HDR_L1_SP:
1310 /* assumes msg->sol points to the first char and msg->col to the colon */
1311 if (likely(HTTP_IS_SPHT(*ptr)))
1312 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001313
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001314 /* header value can be basically anything except CR/LF */
1315 msg->sov = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001316
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001317 if (likely(!HTTP_IS_CRLF(*ptr))) {
1318 goto http_msg_hdr_val;
1319 }
1320
1321 if (likely(*ptr == '\r'))
1322 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lf, HTTP_MSG_HDR_L1_LF);
1323 goto http_msg_hdr_l1_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001324
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001325 http_msg_hdr_l1_lf:
1326 case HTTP_MSG_HDR_L1_LF:
1327 EXPECT_LF_HERE(ptr, http_msg_invalid);
1328 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lws, HTTP_MSG_HDR_L1_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001329
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001330 http_msg_hdr_l1_lws:
1331 case HTTP_MSG_HDR_L1_LWS:
1332 if (likely(HTTP_IS_SPHT(*ptr))) {
1333 /* replace HT,CR,LF with spaces */
1334 for (; buf->data+msg->sov < ptr; msg->sov++)
1335 buf->data[msg->sov] = ' ';
1336 goto http_msg_hdr_l1_sp;
1337 }
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001338 /* we had a header consisting only in spaces ! */
1339 msg->eol = buf->data + msg->sov;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001340 goto http_msg_complete_header;
1341
1342 http_msg_hdr_val:
1343 case HTTP_MSG_HDR_VAL:
1344 /* assumes msg->sol points to the first char, msg->col to the
1345 * colon, and msg->sov points to the first character of the
1346 * value.
1347 */
1348 if (likely(!HTTP_IS_CRLF(*ptr)))
1349 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001350
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001351 msg->eol = ptr;
1352 /* Note: we could also copy eol into ->eoh so that we have the
1353 * real header end in case it ends with lots of LWS, but is this
1354 * really needed ?
1355 */
1356 if (likely(*ptr == '\r'))
1357 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1358 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001359
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001360 http_msg_hdr_l2_lf:
1361 case HTTP_MSG_HDR_L2_LF:
1362 EXPECT_LF_HERE(ptr, http_msg_invalid);
1363 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001364
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001365 http_msg_hdr_l2_lws:
1366 case HTTP_MSG_HDR_L2_LWS:
1367 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1368 /* LWS: replace HT,CR,LF with spaces */
1369 for (; msg->eol < ptr; msg->eol++)
1370 *msg->eol = ' ';
1371 goto http_msg_hdr_val;
1372 }
1373 http_msg_complete_header:
1374 /*
1375 * It was a new header, so the last one is finished.
1376 * Assumes msg->sol points to the first char, msg->col to the
1377 * colon, msg->sov points to the first character of the value
1378 * and msg->eol to the first CR or LF so we know how the line
1379 * ends. We insert last header into the index.
1380 */
1381 /*
1382 fprintf(stderr,"registering %-2d bytes : ", msg->eol - msg->sol);
1383 write(2, msg->sol, msg->eol-msg->sol);
1384 fprintf(stderr,"\n");
1385 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001386
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001387 if (unlikely(hdr_idx_add(msg->eol - msg->sol, *msg->eol == '\r',
1388 idx, idx->tail) < 0))
1389 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001390
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001391 msg->sol = ptr;
1392 if (likely(!HTTP_IS_CRLF(*ptr))) {
1393 goto http_msg_hdr_name;
1394 }
1395
1396 if (likely(*ptr == '\r'))
1397 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1398 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001399
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001400 http_msg_last_lf:
1401 case HTTP_MSG_LAST_LF:
1402 /* Assumes msg->sol points to the first of either CR or LF */
1403 EXPECT_LF_HERE(ptr, http_msg_invalid);
1404 ptr++;
1405 buf->lr = ptr;
1406 msg->eoh = msg->sol - buf->data;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001407 msg->msg_state = HTTP_MSG_BODY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001408 return;
1409#ifdef DEBUG_FULL
1410 default:
1411 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1412 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001413#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001414 }
1415 http_msg_ood:
1416 /* out of data */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001417 msg->msg_state = state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001418 buf->lr = ptr;
1419 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001420
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001421 http_msg_invalid:
1422 /* invalid message */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001423 msg->msg_state = HTTP_MSG_ERROR;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001424 return;
1425}
1426
1427/*
1428 * manages the client FSM and its socket. BTW, it also tries to handle the
1429 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1430 * 0 else.
1431 */
1432int process_cli(struct session *t)
1433{
1434 int s = t->srv_state;
1435 int c = t->cli_state;
1436 struct buffer *req = t->req;
1437 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001438
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001439 DPRINTF(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
1440 cli_stnames[c], srv_stnames[s],
Willy Tarreauf161a342007-04-08 16:59:42 +02001441 EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001442 req->rex.tv_sec, req->rex.tv_usec,
1443 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001444
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001445 if (c == CL_STHEADERS) {
1446 /*
1447 * Now parse the partial (or complete) lines.
1448 * We will check the request syntax, and also join multi-line
1449 * headers. An index of all the lines will be elaborated while
1450 * parsing.
1451 *
Willy Tarreau8973c702007-01-21 23:58:29 +01001452 * For the parsing, we use a 28 states FSM.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001453 *
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001454 * Here is the information we currently have :
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001455 * req->data + req->som = beginning of request
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001456 * req->data + req->eoh = end of processed headers / start of current one
1457 * req->data + req->eol = end of current header or line (LF or CRLF)
1458 * req->lr = first non-visited byte
1459 * req->r = end of data
1460 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001461
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001462 int cur_idx;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001463 struct http_txn *txn = &t->txn;
1464 struct http_msg *msg = &txn->req;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001465 struct proxy *cur_proxy;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001466
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001467 if (likely(req->lr < req->r))
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001468 http_msg_analyzer(req, msg, &txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001469
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001470 /* 1: we might have to print this header in debug mode */
1471 if (unlikely((global.mode & MODE_DEBUG) &&
1472 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001473 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001474 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001475
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001476 sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001477 eol = sol + msg->sl.rq.l;
1478 debug_hdr("clireq", t, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001479
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001480 sol += hdr_idx_first_pos(&txn->hdr_idx);
1481 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001482
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001483 while (cur_idx) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001484 eol = sol + txn->hdr_idx.v[cur_idx].len;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001485 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001486 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
1487 cur_idx = txn->hdr_idx.v[cur_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001488 }
1489 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001490
Willy Tarreau58f10d72006-12-04 02:26:12 +01001491
1492 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001493 * Now we quickly check if we have found a full valid request.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001494 * If not so, we check the FD and buffer states before leaving.
1495 * A full request is indicated by the fact that we have seen
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001496 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
1497 * requests are checked first.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001498 *
1499 */
1500
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001501 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001502 /*
1503 * First, let's catch bad requests.
1504 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001505 if (unlikely(msg->msg_state == HTTP_MSG_ERROR))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001506 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001507
1508 /* 1: Since we are in header mode, if there's no space
1509 * left for headers, we won't be able to free more
1510 * later, so the session will never terminate. We
1511 * must terminate it now.
1512 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001513 if (unlikely(req->l >= req->rlim - req->data)) {
1514 /* FIXME: check if URI is set and return Status
1515 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001516 */
Willy Tarreau06619262006-12-17 08:37:22 +01001517 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001518 }
1519
1520 /* 2: have we encountered a read error or a close ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001521 else if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1522 /* read error, or last read : give up. */
Willy Tarreaufa645582007-06-03 15:59:52 +02001523 buffer_shutr(req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001524 fd_delete(t->cli_fd);
1525 t->cli_state = CL_STCLOSE;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001526 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001527 if (!(t->flags & SN_ERR_MASK))
1528 t->flags |= SN_ERR_CLICL;
1529 if (!(t->flags & SN_FINST_MASK))
1530 t->flags |= SN_FINST_R;
1531 return 1;
1532 }
1533
1534 /* 3: has the read timeout expired ? */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02001535 else if (unlikely(tv_isle(&req->rex, &now))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001536 /* read timeout : give up with an error message. */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001537 txn->status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +01001538 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001539 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001540 if (!(t->flags & SN_ERR_MASK))
1541 t->flags |= SN_ERR_CLITO;
1542 if (!(t->flags & SN_FINST_MASK))
1543 t->flags |= SN_FINST_R;
1544 return 1;
1545 }
1546
1547 /* 4: do we need to re-enable the read socket ? */
Willy Tarreau66319382007-04-08 17:17:37 +02001548 else if (unlikely(EV_FD_COND_S(t->cli_fd, DIR_RD))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02001549 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreau58f10d72006-12-04 02:26:12 +01001550 * full. We cannot loop here since stream_sock_read will disable it only if
1551 * req->l == rlim-data
1552 */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02001553 if (!tv_add_ifset(&req->rex, &now, &t->fe->clitimeout))
Willy Tarreau58f10d72006-12-04 02:26:12 +01001554 tv_eternity(&req->rex);
1555 }
1556 return t->cli_state != CL_STHEADERS;
1557 }
1558
1559
1560 /****************************************************************
1561 * More interesting part now : we know that we have a complete *
1562 * request which at least looks like HTTP. We have an indicator *
1563 * of each header's length, so we can parse them quickly. *
1564 ****************************************************************/
1565
Willy Tarreau9cdde232007-05-02 20:58:19 +02001566 /* ensure we keep this pointer to the beginning of the message */
1567 msg->sol = req->data + msg->som;
1568
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001569 /*
1570 * 1: identify the method
1571 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001572 txn->meth = find_http_meth(&req->data[msg->som], msg->sl.rq.m_l);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001573
1574 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001575 * 2: check if the URI matches the monitor_uri.
Willy Tarreau06619262006-12-17 08:37:22 +01001576 * We have to do this for every request which gets in, because
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001577 * the monitor-uri is defined by the frontend.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001578 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001579 if (unlikely((t->fe->monitor_uri_len != 0) &&
1580 (t->fe->monitor_uri_len == msg->sl.rq.u_l) &&
1581 !memcmp(&req->data[msg->sl.rq.u],
1582 t->fe->monitor_uri,
1583 t->fe->monitor_uri_len))) {
1584 /*
1585 * We have found the monitor URI
1586 */
1587 t->flags |= SN_MONITOR;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001588 txn->status = 200;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001589 client_retnclose(t, &http_200_chunk);
1590 goto return_prx_cond;
1591 }
1592
1593 /*
1594 * 3: Maybe we have to copy the original REQURI for the logs ?
1595 * Note: we cannot log anymore if the request has been
1596 * classified as invalid.
1597 */
1598 if (unlikely(t->logs.logwait & LW_REQ)) {
1599 /* we have a complete HTTP request that we must log */
Willy Tarreau332f8bf2007-05-13 21:36:56 +02001600 if ((txn->uri = pool_alloc2(pool2_requri)) != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001601 int urilen = msg->sl.rq.l;
1602
1603 if (urilen >= REQURI_LEN)
1604 urilen = REQURI_LEN - 1;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001605 memcpy(txn->uri, &req->data[msg->som], urilen);
1606 txn->uri[urilen] = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001607
1608 if (!(t->logs.logwait &= ~LW_REQ))
Willy Tarreau42250582007-04-01 01:30:43 +02001609 http_sess_log(t);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001610 } else {
1611 Alert("HTTP logging : out of memory.\n");
1612 }
1613 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001614
Willy Tarreau06619262006-12-17 08:37:22 +01001615
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001616 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
1617 if (unlikely(msg->sl.rq.v_l == 0)) {
1618 int delta;
1619 char *cur_end;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001620 msg->sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001621 cur_end = msg->sol + msg->sl.rq.l;
1622 delta = 0;
Willy Tarreau06619262006-12-17 08:37:22 +01001623
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001624 if (msg->sl.rq.u_l == 0) {
1625 /* if no URI was set, add "/" */
1626 delta = buffer_replace2(req, cur_end, cur_end, " /", 2);
1627 cur_end += delta;
1628 msg->eoh += delta;
Willy Tarreau06619262006-12-17 08:37:22 +01001629 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001630 /* add HTTP version */
1631 delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
1632 msg->eoh += delta;
1633 cur_end += delta;
1634 cur_end = (char *)http_parse_reqline(msg, req->data,
1635 HTTP_MSG_RQMETH,
1636 msg->sol, cur_end + 1,
1637 NULL, NULL);
1638 if (unlikely(!cur_end))
1639 goto return_bad_req;
1640
1641 /* we have a full HTTP/1.0 request now and we know that
1642 * we have either a CR or an LF at <ptr>.
1643 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001644 hdr_idx_set_start(&txn->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
Willy Tarreau58f10d72006-12-04 02:26:12 +01001645 }
1646
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001647
1648 /* 5: we may need to capture headers */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001649 if (unlikely((t->logs.logwait & LW_REQHDR) && t->fe->req_cap))
Willy Tarreau117f59e2007-03-04 18:17:17 +01001650 capture_headers(req->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001651 txn->req.cap, t->fe->req_cap);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001652
1653 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001654 * 6: we will have to evaluate the filters.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001655 * As opposed to version 1.2, now they will be evaluated in the
1656 * filters order and not in the header order. This means that
1657 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001658 *
1659 * We can now check whether we want to switch to another
1660 * backend, in which case we will re-check the backend's
1661 * filters and various options. In order to support 3-level
1662 * switching, here's how we should proceed :
1663 *
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001664 * a) run be.
Willy Tarreau830ff452006-12-17 19:31:23 +01001665 * if (switch) then switch ->be to the new backend.
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001666 * b) run be if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001667 * There cannot be any switch from there, so ->be cannot be
1668 * changed anymore.
1669 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001670 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001671 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001672 * The response path will be able to apply either ->be, or
1673 * ->be then ->fe filters in order to match the reverse of
1674 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001675 */
1676
Willy Tarreau06619262006-12-17 08:37:22 +01001677 do {
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001678 struct acl_cond *cond;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001679 struct proxy *rule_set = t->be;
Willy Tarreau830ff452006-12-17 19:31:23 +01001680 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001681
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001682 /* first check whether we have some ACLs set to block this request */
1683 list_for_each_entry(cond, &cur_proxy->block_cond, list) {
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001684 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001685 if (cond->pol == ACL_COND_UNLESS)
1686 ret = !ret;
1687
1688 if (ret) {
1689 txn->status = 403;
1690 /* let's log the request time */
1691 t->logs.t_request = tv_ms_elapsed(&t->logs.tv_accept, &now);
1692 client_retnclose(t, error_message(t, HTTP_ERR_403));
1693 goto return_prx_cond;
1694 }
1695 }
1696
Willy Tarreau06619262006-12-17 08:37:22 +01001697 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01001698 if (rule_set->req_exp != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001699 if (apply_filters_to_request(t, req, rule_set->req_exp) < 0)
1700 goto return_bad_req;
Willy Tarreau53b6c742006-12-17 13:37:46 +01001701 }
1702
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001703 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
1704 /* to ensure correct connection accounting on
1705 * the backend, we count the connection for the
1706 * one managing the queue.
1707 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001708 t->be->beconn++;
1709 if (t->be->beconn > t->be->beconn_max)
1710 t->be->beconn_max = t->be->beconn;
1711 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001712 t->flags |= SN_BE_ASSIGNED;
1713 }
1714
Willy Tarreau06619262006-12-17 08:37:22 +01001715 /* has the request been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01001716 if (txn->flags & TX_CLDENY) {
Willy Tarreau06619262006-12-17 08:37:22 +01001717 /* no need to go further */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001718 txn->status = 403;
Willy Tarreau06619262006-12-17 08:37:22 +01001719 /* let's log the request time */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02001720 t->logs.t_request = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreau80587432006-12-24 17:47:20 +01001721 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01001722 goto return_prx_cond;
1723 }
1724
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001725 /* We might have to check for "Connection:" */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001726 if (((t->fe->options | t->be->options) & PR_O_HTTP_CLOSE) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001727 !(t->flags & SN_CONN_CLOSED)) {
1728 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001729 int cur_idx, old_idx, delta, val;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001730 struct hdr_idx_elem *cur_hdr;
Willy Tarreau06619262006-12-17 08:37:22 +01001731
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001732 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001733 old_idx = 0;
1734
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001735 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
1736 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001737 cur_ptr = cur_next;
1738 cur_end = cur_ptr + cur_hdr->len;
1739 cur_next = cur_end + cur_hdr->cr + 1;
1740
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001741 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
1742 if (val) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001743 /* 3 possibilities :
1744 * - we have already set Connection: close,
1745 * so we remove this line.
1746 * - we have not yet set Connection: close,
1747 * but this line indicates close. We leave
1748 * it untouched and set the flag.
1749 * - we have not yet set Connection: close,
1750 * and this line indicates non-close. We
1751 * replace it.
1752 */
1753 if (t->flags & SN_CONN_CLOSED) {
1754 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001755 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001756 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001757 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
1758 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001759 cur_hdr->len = 0;
1760 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001761 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
1762 delta = buffer_replace2(req, cur_ptr + val, cur_end,
1763 "close", 5);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001764 cur_next += delta;
1765 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001766 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001767 }
1768 t->flags |= SN_CONN_CLOSED;
1769 }
1770 }
1771 old_idx = cur_idx;
1772 }
Willy Tarreauf2f0ee82007-03-30 12:02:43 +02001773 }
1774 /* add request headers from the rule sets in the same order */
1775 for (cur_idx = 0; cur_idx < rule_set->nb_reqadd; cur_idx++) {
1776 if (unlikely(http_header_add_tail(req,
1777 &txn->req,
1778 &txn->hdr_idx,
1779 rule_set->req_add[cur_idx])) < 0)
1780 goto return_bad_req;
Willy Tarreau06619262006-12-17 08:37:22 +01001781 }
Willy Tarreaub2513902006-12-17 14:52:38 +01001782
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001783 /* check if stats URI was requested, and if an auth is needed */
Willy Tarreau0214c3a2007-01-07 13:47:30 +01001784 if (rule_set->uri_auth != NULL &&
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001785 (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)) {
Willy Tarreaub2513902006-12-17 14:52:38 +01001786 /* we have to check the URI and auth for this request */
1787 if (stats_check_uri_auth(t, rule_set))
1788 return 1;
1789 }
1790
Willy Tarreau5fdfb912007-01-01 23:11:07 +01001791 if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
1792 /* No backend was set, but there was a default
1793 * backend set in the frontend, so we use it and
1794 * loop again.
1795 */
1796 t->be = cur_proxy->defbe.be;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001797 t->be->beconn++;
1798 if (t->be->beconn > t->be->beconn_max)
1799 t->be->beconn_max = t->be->beconn;
1800 t->be->cum_beconn++;
Willy Tarreau5fdfb912007-01-01 23:11:07 +01001801 t->flags |= SN_BE_ASSIGNED;
1802 }
1803 } while (t->be != cur_proxy); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01001804
Willy Tarreau58f10d72006-12-04 02:26:12 +01001805
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001806 if (!(t->flags & SN_BE_ASSIGNED)) {
1807 /* To ensure correct connection accounting on
1808 * the backend, we count the connection for the
1809 * one managing the queue.
1810 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001811 t->be->beconn++;
1812 if (t->be->beconn > t->be->beconn_max)
1813 t->be->beconn_max = t->be->beconn;
1814 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001815 t->flags |= SN_BE_ASSIGNED;
1816 }
1817
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001818 /*
1819 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01001820 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001821 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01001822 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01001823 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001824
Willy Tarreau58f10d72006-12-04 02:26:12 +01001825
Willy Tarreau58f10d72006-12-04 02:26:12 +01001826
Willy Tarreau58f10d72006-12-04 02:26:12 +01001827
Willy Tarreau2a324282006-12-05 00:05:46 +01001828 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001829 * 7: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01001830 * so let's do the same now.
1831 */
1832
1833 /* It needs to look into the URI */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001834 if (t->be->appsession_name) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001835 get_srv_from_appsession(t, &req->data[msg->som], msg->sl.rq.l);
Willy Tarreau06619262006-12-17 08:37:22 +01001836 }
1837
1838
1839 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001840 * 8: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01001841 * Note that doing so might move headers in the request, but
1842 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01001843 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01001844 */
Willy Tarreau3d300592007-03-18 18:34:41 +01001845 if (!(txn->flags & (TX_CLDENY|TX_CLTARPIT)))
Willy Tarreau2a324282006-12-05 00:05:46 +01001846 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001847
Willy Tarreau58f10d72006-12-04 02:26:12 +01001848
Willy Tarreau2a324282006-12-05 00:05:46 +01001849 /*
Willy Tarreaubb046ac2007-03-03 19:17:03 +01001850 * 9: add X-Forwarded-For if either the frontend or the backend
1851 * asks for it.
Willy Tarreau2a324282006-12-05 00:05:46 +01001852 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001853 if ((t->fe->options | t->be->options) & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001854 if (t->cli_addr.ss_family == AF_INET) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02001855 /* Add an X-Forwarded-For header unless the source IP is
1856 * in the 'except' network range.
1857 */
1858 if ((!t->fe->except_mask.s_addr ||
1859 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->fe->except_mask.s_addr)
1860 != t->fe->except_net.s_addr) &&
1861 (!t->be->except_mask.s_addr ||
1862 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->be->except_mask.s_addr)
1863 != t->be->except_net.s_addr)) {
1864 int len;
1865 unsigned char *pn;
1866 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001867
Willy Tarreau7ac51f62007-03-25 16:00:04 +02001868 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d",
1869 pn[0], pn[1], pn[2], pn[3]);
1870
1871 if (unlikely(http_header_add_tail2(req, &txn->req,
1872 &txn->hdr_idx, trash, len)) < 0)
1873 goto return_bad_req;
1874 }
Willy Tarreau2a324282006-12-05 00:05:46 +01001875 }
1876 else if (t->cli_addr.ss_family == AF_INET6) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02001877 /* FIXME: for the sake of completeness, we should also support
1878 * 'except' here, although it is mostly useless in this case.
1879 */
Willy Tarreau2a324282006-12-05 00:05:46 +01001880 int len;
1881 char pn[INET6_ADDRSTRLEN];
1882 inet_ntop(AF_INET6,
1883 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
1884 pn, sizeof(pn));
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01001885 len = sprintf(trash, "X-Forwarded-For: %s", pn);
1886 if (unlikely(http_header_add_tail2(req, &txn->req,
1887 &txn->hdr_idx, trash, len)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01001888 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001889 }
1890 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001891
Willy Tarreau2a324282006-12-05 00:05:46 +01001892 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001893 * 10: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02001894 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaub2513902006-12-17 14:52:38 +01001895 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02001896 if (!(t->flags & SN_CONN_CLOSED) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001897 ((t->fe->options | t->be->options) & PR_O_HTTP_CLOSE)) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02001898 if ((unlikely(msg->sl.rq.v_l != 8) ||
1899 unlikely(req->data[msg->som + msg->sl.rq.v + 7] != '0')) &&
1900 unlikely(http_header_add_tail2(req, &txn->req, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01001901 "Connection: close", 17)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01001902 goto return_bad_req;
Willy Tarreaua15645d2007-03-18 16:22:39 +01001903 t->flags |= SN_CONN_CLOSED;
Willy Tarreaue15d9132006-12-14 22:26:42 +01001904 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001905
Willy Tarreau2a324282006-12-05 00:05:46 +01001906 /*************************************************************
1907 * OK, that's finished for the headers. We have done what we *
1908 * could. Let's switch to the DATA state. *
1909 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02001910
Willy Tarreau2a324282006-12-05 00:05:46 +01001911 t->cli_state = CL_STDATA;
1912 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001913
Willy Tarreau42aae5c2007-04-29 17:43:56 +02001914 t->logs.t_request = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001915
Willy Tarreaud825eef2007-05-12 22:35:00 +02001916 if (!tv_isset(&t->fe->clitimeout) ||
1917 (t->srv_state < SV_STDATA && tv_isset(&t->be->srvtimeout))) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001918 /* If the client has no timeout, or if the server is not ready yet,
1919 * and we know for sure that it can expire, then it's cleaner to
1920 * disable the timeout on the client side so that too low values
1921 * cannot make the sessions abort too early.
1922 *
1923 * FIXME-20050705: the server needs a way to re-enable this time-out
1924 * when it switches its state, otherwise a client can stay connected
1925 * indefinitely. This now seems to be OK.
1926 */
1927 tv_eternity(&req->rex);
1928 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001929
Willy Tarreau2a324282006-12-05 00:05:46 +01001930 /* When a connection is tarpitted, we use the queue timeout for the
1931 * tarpit delay, which currently happens to be the server's connect
1932 * timeout. If unset, then set it to zero because we really want it
1933 * to expire at one moment.
1934 */
Willy Tarreau3d300592007-03-18 18:34:41 +01001935 if (txn->flags & TX_CLTARPIT) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001936 t->req->l = 0;
1937 /* flush the request so that we can drop the connection early
1938 * if the client closes first.
1939 */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02001940 if (!tv_add_ifset(&req->cex, &now, &t->be->contimeout))
Willy Tarreaud825eef2007-05-12 22:35:00 +02001941 req->cex = now;
Willy Tarreau2a324282006-12-05 00:05:46 +01001942 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001943
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001944 /* OK let's go on with the BODY now */
Willy Tarreau06619262006-12-17 08:37:22 +01001945 goto process_data;
1946
1947 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001948 txn->req.msg_state = HTTP_MSG_ERROR;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001949 txn->status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01001950 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001951 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01001952 return_prx_cond:
1953 if (!(t->flags & SN_ERR_MASK))
1954 t->flags |= SN_ERR_PRXCOND;
1955 if (!(t->flags & SN_FINST_MASK))
1956 t->flags |= SN_FINST_R;
1957 return 1;
1958
Willy Tarreaubaaee002006-06-26 02:48:02 +02001959 }
1960 else if (c == CL_STDATA) {
1961 process_data:
1962 /* FIXME: this error handling is partly buggy because we always report
1963 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
1964 * or HEADER phase. BTW, it's not logical to expire the client while
1965 * we're waiting for the server to connect.
1966 */
1967 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001968 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02001969 buffer_shutr(req);
1970 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001971 fd_delete(t->cli_fd);
1972 t->cli_state = CL_STCLOSE;
1973 if (!(t->flags & SN_ERR_MASK))
1974 t->flags |= SN_ERR_CLICL;
1975 if (!(t->flags & SN_FINST_MASK)) {
1976 if (t->pend_pos)
1977 t->flags |= SN_FINST_Q;
1978 else if (s == SV_STCONN)
1979 t->flags |= SN_FINST_C;
1980 else
1981 t->flags |= SN_FINST_D;
1982 }
1983 return 1;
1984 }
1985 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001986 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02001987 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02001988 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001989 t->cli_state = CL_STSHUTR;
1990 return 1;
1991 }
1992 /* last server read and buffer empty */
1993 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02001994 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02001995 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001996 shutdown(t->cli_fd, SHUT_WR);
1997 /* We must ensure that the read part is still alive when switching
1998 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02001999 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002000 tv_add_ifset(&req->rex, &now, &t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002001 t->cli_state = CL_STSHUTW;
2002 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2003 return 1;
2004 }
2005 /* read timeout */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002006 else if (tv_isle(&req->rex, &now)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002007 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002008 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002009 t->cli_state = CL_STSHUTR;
2010 if (!(t->flags & SN_ERR_MASK))
2011 t->flags |= SN_ERR_CLITO;
2012 if (!(t->flags & SN_FINST_MASK)) {
2013 if (t->pend_pos)
2014 t->flags |= SN_FINST_Q;
2015 else if (s == SV_STCONN)
2016 t->flags |= SN_FINST_C;
2017 else
2018 t->flags |= SN_FINST_D;
2019 }
2020 return 1;
2021 }
2022 /* write timeout */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002023 else if (tv_isle(&rep->wex, &now)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002024 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02002025 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002026 shutdown(t->cli_fd, SHUT_WR);
2027 /* We must ensure that the read part is still alive when switching
2028 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002029 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002030 tv_add_ifset(&req->rex, &now, &t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002031
2032 t->cli_state = CL_STSHUTW;
2033 if (!(t->flags & SN_ERR_MASK))
2034 t->flags |= SN_ERR_CLITO;
2035 if (!(t->flags & SN_FINST_MASK)) {
2036 if (t->pend_pos)
2037 t->flags |= SN_FINST_Q;
2038 else if (s == SV_STCONN)
2039 t->flags |= SN_FINST_C;
2040 else
2041 t->flags |= SN_FINST_D;
2042 }
2043 return 1;
2044 }
2045
2046 if (req->l >= req->rlim - req->data) {
2047 /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02002048 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002049 /* stop reading until we get some space */
Willy Tarreaud7971282006-07-29 18:36:34 +02002050 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002051 }
2052 } else {
2053 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002054 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreaud825eef2007-05-12 22:35:00 +02002055 if (!tv_isset(&t->fe->clitimeout) ||
2056 (t->srv_state < SV_STDATA && tv_isset(&t->be->srvtimeout)))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002057 /* If the client has no timeout, or if the server not ready yet, and we
2058 * know for sure that it can expire, then it's cleaner to disable the
2059 * timeout on the client side so that too low values cannot make the
2060 * sessions abort too early.
2061 */
Willy Tarreaud7971282006-07-29 18:36:34 +02002062 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002063 else
Willy Tarreaud825eef2007-05-12 22:35:00 +02002064 tv_add(&req->rex, &now, &t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002065 }
2066 }
2067
2068 if ((rep->l == 0) ||
2069 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002070 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2071 /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002072 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002073 }
2074 } else {
2075 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002076 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2077 /* restart writing */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002078 if (tv_add_ifset(&rep->wex, &now, &t->fe->clitimeout)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002079 /* FIXME: to prevent the client from expiring read timeouts during writes,
2080 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002081 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002082 }
2083 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002084 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002085 }
2086 }
2087 return 0; /* other cases change nothing */
2088 }
2089 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002090 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002091 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002092 fd_delete(t->cli_fd);
2093 t->cli_state = CL_STCLOSE;
2094 if (!(t->flags & SN_ERR_MASK))
2095 t->flags |= SN_ERR_CLICL;
2096 if (!(t->flags & SN_FINST_MASK)) {
2097 if (t->pend_pos)
2098 t->flags |= SN_FINST_Q;
2099 else if (s == SV_STCONN)
2100 t->flags |= SN_FINST_C;
2101 else
2102 t->flags |= SN_FINST_D;
2103 }
2104 return 1;
2105 }
2106 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
2107 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002108 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002109 fd_delete(t->cli_fd);
2110 t->cli_state = CL_STCLOSE;
2111 return 1;
2112 }
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002113 else if (tv_isle(&rep->wex, &now)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002114 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002115 fd_delete(t->cli_fd);
2116 t->cli_state = CL_STCLOSE;
2117 if (!(t->flags & SN_ERR_MASK))
2118 t->flags |= SN_ERR_CLITO;
2119 if (!(t->flags & SN_FINST_MASK)) {
2120 if (t->pend_pos)
2121 t->flags |= SN_FINST_Q;
2122 else if (s == SV_STCONN)
2123 t->flags |= SN_FINST_C;
2124 else
2125 t->flags |= SN_FINST_D;
2126 }
2127 return 1;
2128 }
2129
2130 if (t->flags & SN_SELF_GEN) {
2131 produce_content(t);
2132 if (rep->l == 0) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002133 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002134 fd_delete(t->cli_fd);
2135 t->cli_state = CL_STCLOSE;
2136 return 1;
2137 }
2138 }
2139
2140 if ((rep->l == 0)
2141 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002142 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2143 /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002144 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002145 }
2146 } else {
2147 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002148 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2149 /* restart writing */
Willy Tarreau33014d02007-06-03 15:25:37 +02002150 if (!tv_add_ifset(&rep->wex, &now, &t->fe->clitimeout))
Willy Tarreaud7971282006-07-29 18:36:34 +02002151 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002152 }
2153 }
2154 return 0;
2155 }
2156 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002157 if (req->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002158 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002159 fd_delete(t->cli_fd);
2160 t->cli_state = CL_STCLOSE;
2161 if (!(t->flags & SN_ERR_MASK))
2162 t->flags |= SN_ERR_CLICL;
2163 if (!(t->flags & SN_FINST_MASK)) {
2164 if (t->pend_pos)
2165 t->flags |= SN_FINST_Q;
2166 else if (s == SV_STCONN)
2167 t->flags |= SN_FINST_C;
2168 else
2169 t->flags |= SN_FINST_D;
2170 }
2171 return 1;
2172 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002173 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002174 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002175 fd_delete(t->cli_fd);
2176 t->cli_state = CL_STCLOSE;
2177 return 1;
2178 }
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002179 else if (tv_isle(&req->rex, &now)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002180 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002181 fd_delete(t->cli_fd);
2182 t->cli_state = CL_STCLOSE;
2183 if (!(t->flags & SN_ERR_MASK))
2184 t->flags |= SN_ERR_CLITO;
2185 if (!(t->flags & SN_FINST_MASK)) {
2186 if (t->pend_pos)
2187 t->flags |= SN_FINST_Q;
2188 else if (s == SV_STCONN)
2189 t->flags |= SN_FINST_C;
2190 else
2191 t->flags |= SN_FINST_D;
2192 }
2193 return 1;
2194 }
2195 else if (req->l >= req->rlim - req->data) {
2196 /* no room to read more data */
2197
2198 /* FIXME-20050705: is it possible for a client to maintain a session
2199 * after the timeout by sending more data after it receives a close ?
2200 */
2201
Willy Tarreau66319382007-04-08 17:17:37 +02002202 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002203 /* stop reading until we get some space */
Willy Tarreaud7971282006-07-29 18:36:34 +02002204 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002205 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2206 }
2207 } else {
2208 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002209 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002210 if (!tv_add_ifset(&req->rex, &now, &t->fe->clitimeout))
Willy Tarreaud7971282006-07-29 18:36:34 +02002211 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002212 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2213 }
2214 }
2215 return 0;
2216 }
2217 else { /* CL_STCLOSE: nothing to do */
2218 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2219 int len;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002220 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 +02002221 write(1, trash, len);
2222 }
2223 return 0;
2224 }
2225 return 0;
2226}
2227
2228
2229/*
2230 * manages the server FSM and its socket. It returns 1 if a state has changed
2231 * (and a resync may be needed), 0 else.
2232 */
2233int process_srv(struct session *t)
2234{
2235 int s = t->srv_state;
2236 int c = t->cli_state;
Willy Tarreau3d300592007-03-18 18:34:41 +01002237 struct http_txn *txn = &t->txn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002238 struct buffer *req = t->req;
2239 struct buffer *rep = t->rep;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002240 int conn_err;
2241
2242#ifdef DEBUG_FULL
2243 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2244#endif
Willy Tarreauee991362007-05-14 14:37:50 +02002245
2246#if 0
2247 fprintf(stderr,"%s:%d fe->clito=%d.%d, fe->conto=%d.%d, fe->srvto=%d.%d\n",
2248 __FUNCTION__, __LINE__,
2249 t->fe->clitimeout.tv_sec, t->fe->clitimeout.tv_usec,
2250 t->fe->contimeout.tv_sec, t->fe->contimeout.tv_usec,
2251 t->fe->srvtimeout.tv_sec, t->fe->srvtimeout.tv_usec);
2252 fprintf(stderr,"%s:%d be->clito=%d.%d, be->conto=%d.%d, be->srvto=%d.%d\n",
2253 __FUNCTION__, __LINE__,
2254 t->be->clitimeout.tv_sec, t->be->clitimeout.tv_usec,
2255 t->be->contimeout.tv_sec, t->be->contimeout.tv_usec,
2256 t->be->srvtimeout.tv_sec, t->be->srvtimeout.tv_usec);
2257
2258 fprintf(stderr,"%s:%d req->cto=%d.%d, req->rto=%d.%d, req->wto=%d.%d\n",
2259 __FUNCTION__, __LINE__,
2260 req->cto.tv_sec, req->cto.tv_usec,
2261 req->rto.tv_sec, req->rto.tv_usec,
2262 req->wto.tv_sec, req->wto.tv_usec);
2263
2264 fprintf(stderr,"%s:%d rep->cto=%d.%d, rep->rto=%d.%d, rep->wto=%d.%d\n",
2265 __FUNCTION__, __LINE__,
2266 rep->cto.tv_sec, rep->cto.tv_usec,
2267 rep->rto.tv_sec, rep->rto.tv_usec,
2268 rep->wto.tv_sec, rep->wto.tv_usec);
2269#endif
2270
Willy Tarreaubaaee002006-06-26 02:48:02 +02002271 //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 +02002272 //EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
2273 //EV_FD_ISSET(t->srv_fd, DIR_RD), EV_FD_ISSET(t->srv_fd, DIR_WR)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002274 //);
2275 if (s == SV_STIDLE) {
2276 if (c == CL_STHEADERS)
2277 return 0; /* stay in idle, waiting for data to reach the client side */
2278 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
2279 (c == CL_STSHUTR &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002280 (t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02002281 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002282 if (t->pend_pos)
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002283 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002284 /* note that this must not return any error because it would be able to
2285 * overwrite the client_retnclose() output.
2286 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002287 if (txn->flags & TX_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01002288 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02002289 else
Willy Tarreau0f772532006-12-23 20:51:41 +01002290 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 +02002291
2292 return 1;
2293 }
2294 else {
Willy Tarreau3d300592007-03-18 18:34:41 +01002295 if (txn->flags & TX_CLTARPIT) {
Willy Tarreaub8750a82006-09-03 09:56:00 +02002296 /* This connection is being tarpitted. The CLIENT side has
2297 * already set the connect expiration date to the right
2298 * timeout. We just have to check that it has not expired.
2299 */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002300 if (!tv_isle(&req->cex, &now))
Willy Tarreaub8750a82006-09-03 09:56:00 +02002301 return 0;
2302
2303 /* We will set the queue timer to the time spent, just for
2304 * logging purposes. We fake a 500 server error, so that the
2305 * attacker will not suspect his connection has been tarpitted.
2306 * It will not cause trouble to the logs because we can exclude
2307 * the tarpitted connections by filtering on the 'PT' status flags.
2308 */
2309 tv_eternity(&req->cex);
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002310 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaub8750a82006-09-03 09:56:00 +02002311 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01002312 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02002313 return 1;
2314 }
2315
Willy Tarreaubaaee002006-06-26 02:48:02 +02002316 /* Right now, we will need to create a connection to the server.
2317 * We might already have tried, and got a connection pending, in
2318 * which case we will not do anything till it's pending. It's up
2319 * to any other session to release it and wake us up again.
2320 */
2321 if (t->pend_pos) {
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002322 if (!tv_isle(&req->cex, &now))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002323 return 0;
2324 else {
2325 /* we've been waiting too long here */
Willy Tarreaud7971282006-07-29 18:36:34 +02002326 tv_eternity(&req->cex);
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002327 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002328 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01002329 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002330 if (t->srv)
2331 t->srv->failed_conns++;
Willy Tarreau73de9892006-11-30 11:40:23 +01002332 t->fe->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002333 return 1;
2334 }
2335 }
2336
2337 do {
2338 /* first, get a connection */
2339 if (srv_redispatch_connect(t))
2340 return t->srv_state != SV_STIDLE;
2341
2342 /* try to (re-)connect to the server, and fail if we expire the
2343 * number of retries.
2344 */
2345 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002346 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002347 return t->srv_state != SV_STIDLE;
2348 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002349 } while (1);
2350 }
2351 }
2352 else if (s == SV_STCONN) { /* connection in progress */
2353 if (c == CL_STCLOSE || c == CL_STSHUTW ||
2354 (c == CL_STSHUTR &&
Willy Tarreauc9b654b2007-05-08 14:46:53 +02002355 ((t->req->l == 0 && !(req->flags & BF_WRITE_STATUS)) ||
2356 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02002357 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002358 fd_delete(t->srv_fd);
2359 if (t->srv)
2360 t->srv->cur_sess--;
2361
2362 /* note that this must not return any error because it would be able to
2363 * overwrite the client_retnclose() output.
2364 */
Willy Tarreau0f772532006-12-23 20:51:41 +01002365 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002366 return 1;
2367 }
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002368 if (!(req->flags & BF_WRITE_STATUS) && !tv_isle(&req->cex, &now)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002369 //fprintf(stderr,"1: c=%d, s=%d, now=%d.%06d, exp=%d.%06d\n", c, s, now.tv_sec, now.tv_usec, req->cex.tv_sec, req->cex.tv_usec);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002370 return 0; /* nothing changed */
2371 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002372 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002373 /* timeout, asynchronous connect error or first write error */
2374 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2375
2376 fd_delete(t->srv_fd);
2377 if (t->srv)
2378 t->srv->cur_sess--;
2379
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002380 if (!(req->flags & BF_WRITE_STATUS))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002381 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
2382 else
2383 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
2384
2385 /* ensure that we have enough retries left */
2386 if (srv_count_retry_down(t, conn_err))
2387 return 1;
2388
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002389 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002390 /* We're on our last chance, and the REDISP option was specified.
2391 * We will ignore cookie and force to balance or use the dispatcher.
2392 */
2393 /* let's try to offer this slot to anybody */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002394 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02002395 task_wakeup(t->srv->queue_mgt);
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002396
2397 if (t->srv)
2398 t->srv->failed_conns++;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002399 t->be->failed_conns++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002400
2401 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
2402 t->srv = NULL; /* it's left to the dispatcher to choose a server */
Willy Tarreaua5e65752007-03-18 20:53:22 +01002403 http_flush_cookie_flags(txn);
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002404
2405 /* first, get a connection */
2406 if (srv_redispatch_connect(t))
2407 return t->srv_state != SV_STIDLE;
2408 }
2409
Willy Tarreaubaaee002006-06-26 02:48:02 +02002410 do {
2411 /* Now we will try to either reconnect to the same server or
2412 * connect to another server. If the connection gets queued
2413 * because all servers are saturated, then we will go back to
2414 * the SV_STIDLE state.
2415 */
2416 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002417 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002418 return t->srv_state != SV_STCONN;
2419 }
2420
2421 /* we need to redispatch the connection to another server */
2422 if (srv_redispatch_connect(t))
2423 return t->srv_state != SV_STCONN;
2424 } while (1);
2425 }
2426 else { /* no error or write 0 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002427 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002428
2429 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2430 if (req->l == 0) /* nothing to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002431 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaud7971282006-07-29 18:36:34 +02002432 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002433 } else /* need the right to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002434 EV_FD_SET(t->srv_fd, DIR_WR);
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002435 if (tv_add_ifset(&req->wex, &now, &t->be->srvtimeout)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002436 /* FIXME: to prevent the server from expiring read timeouts during writes,
2437 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002438 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002439 }
2440 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002441 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002442 }
2443
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002444 if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreauf161a342007-04-08 16:59:42 +02002445 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002446 if (!tv_add_ifset(&rep->rex, &now, &t->be->srvtimeout))
Willy Tarreaud7971282006-07-29 18:36:34 +02002447 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002448
2449 t->srv_state = SV_STDATA;
2450 if (t->srv)
2451 t->srv->cum_sess++;
2452 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
2453
2454 /* if the user wants to log as soon as possible, without counting
2455 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002456 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002457 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
Willy Tarreau42250582007-04-01 01:30:43 +02002458 tcp_sess_log(t);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002459 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002460#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002461 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002462 /* TCP splicing supported by both FE and BE */
2463 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2464 }
2465#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002466 }
2467 else {
2468 t->srv_state = SV_STHEADERS;
2469 if (t->srv)
2470 t->srv->cum_sess++;
2471 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002472 t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
2473 /* reset hdr_idx which was already initialized by the request.
2474 * right now, the http parser does it.
2475 * hdr_idx_init(&t->txn.hdr_idx);
2476 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002477 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002478 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002479 return 1;
2480 }
2481 }
2482 else if (s == SV_STHEADERS) { /* receiving server headers */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002483 /*
2484 * Now parse the partial (or complete) lines.
2485 * We will check the response syntax, and also join multi-line
2486 * headers. An index of all the lines will be elaborated while
2487 * parsing.
2488 *
2489 * For the parsing, we use a 28 states FSM.
2490 *
2491 * Here is the information we currently have :
2492 * rep->data + req->som = beginning of response
2493 * rep->data + req->eoh = end of processed headers / start of current one
2494 * rep->data + req->eol = end of current header or line (LF or CRLF)
2495 * rep->lr = first non-visited byte
2496 * rep->r = end of data
2497 */
2498
2499 int cur_idx;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002500 struct http_msg *msg = &txn->rsp;
2501 struct proxy *cur_proxy;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002502
Willy Tarreaua15645d2007-03-18 16:22:39 +01002503 if (likely(rep->lr < rep->r))
2504 http_msg_analyzer(rep, msg, &txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002505
Willy Tarreaua15645d2007-03-18 16:22:39 +01002506 /* 1: we might have to print this header in debug mode */
2507 if (unlikely((global.mode & MODE_DEBUG) &&
2508 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
2509 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
2510 char *eol, *sol;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002511
Willy Tarreaua15645d2007-03-18 16:22:39 +01002512 sol = rep->data + msg->som;
2513 eol = sol + msg->sl.rq.l;
2514 debug_hdr("srvrep", t, sol, eol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002515
Willy Tarreaua15645d2007-03-18 16:22:39 +01002516 sol += hdr_idx_first_pos(&txn->hdr_idx);
2517 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002518
Willy Tarreaua15645d2007-03-18 16:22:39 +01002519 while (cur_idx) {
2520 eol = sol + txn->hdr_idx.v[cur_idx].len;
2521 debug_hdr("srvhdr", t, sol, eol);
2522 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
2523 cur_idx = txn->hdr_idx.v[cur_idx].next;
2524 }
2525 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002526
Willy Tarreaubaaee002006-06-26 02:48:02 +02002527
Willy Tarreau66319382007-04-08 17:17:37 +02002528 if ((rep->l < rep->rlim - rep->data) && EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002529 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreaua15645d2007-03-18 16:22:39 +01002530 * full. We cannot loop here since stream_sock_read will disable it only if
2531 * rep->l == rlim-data
2532 */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002533 if (!tv_add_ifset(&rep->rex, &now, &t->be->srvtimeout))
Willy Tarreaua15645d2007-03-18 16:22:39 +01002534 tv_eternity(&rep->rex);
2535 }
2536
2537
2538 /*
2539 * Now we quickly check if we have found a full valid response.
2540 * If not so, we check the FD and buffer states before leaving.
2541 * A full response is indicated by the fact that we have seen
2542 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
2543 * responses are checked first.
2544 *
2545 * Depending on whether the client is still there or not, we
2546 * may send an error response back or not. Note that normally
2547 * we should only check for HTTP status there, and check I/O
2548 * errors somewhere else.
2549 */
2550
2551 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
2552
2553 /* Invalid response, or read error or write error */
2554 if (unlikely((msg->msg_state == HTTP_MSG_ERROR) ||
2555 (req->flags & BF_WRITE_ERROR) ||
2556 (rep->flags & BF_READ_ERROR))) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002557 buffer_shutr(rep);
2558 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002559 fd_delete(t->srv_fd);
2560 if (t->srv) {
2561 t->srv->cur_sess--;
2562 t->srv->failed_resp++;
2563 }
2564 t->be->failed_resp++;
2565 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002566 txn->status = 502;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002567 client_return(t, error_message(t, HTTP_ERR_502));
2568 if (!(t->flags & SN_ERR_MASK))
2569 t->flags |= SN_ERR_SRVCL;
2570 if (!(t->flags & SN_FINST_MASK))
2571 t->flags |= SN_FINST_H;
2572 /* We used to have a free connection slot. Since we'll never use it,
2573 * we have to inform the server that it may be used by another session.
2574 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002575 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02002576 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002577
Willy Tarreaua15645d2007-03-18 16:22:39 +01002578 return 1;
2579 }
2580
2581 /* end of client write or end of server read.
2582 * since we are in header mode, if there's no space left for headers, we
2583 * won't be able to free more later, so the session will never terminate.
2584 */
2585 else if (unlikely(rep->flags & BF_READ_NULL ||
2586 c == CL_STSHUTW || c == CL_STCLOSE ||
2587 rep->l >= rep->rlim - rep->data)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002588 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002589 buffer_shutr(rep);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002590 t->srv_state = SV_STSHUTR;
2591 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2592 return 1;
2593 }
2594
2595 /* read timeout : return a 504 to the client.
2596 */
Willy Tarreauf161a342007-04-08 16:59:42 +02002597 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_RD) &&
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002598 tv_isle(&rep->rex, &now))) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002599 buffer_shutr(rep);
2600 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002601 fd_delete(t->srv_fd);
2602 if (t->srv) {
2603 t->srv->cur_sess--;
2604 t->srv->failed_resp++;
2605 }
2606 t->be->failed_resp++;
2607 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002608 txn->status = 504;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002609 client_return(t, error_message(t, HTTP_ERR_504));
2610 if (!(t->flags & SN_ERR_MASK))
2611 t->flags |= SN_ERR_SRVTO;
2612 if (!(t->flags & SN_FINST_MASK))
2613 t->flags |= SN_FINST_H;
2614 /* We used to have a free connection slot. Since we'll never use it,
2615 * we have to inform the server that it may be used by another session.
2616 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002617 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02002618 task_wakeup(t->srv->queue_mgt);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002619 return 1;
2620 }
2621
2622 /* last client read and buffer empty */
2623 /* FIXME!!! here, we don't want to switch to SHUTW if the
2624 * client shuts read too early, because we may still have
2625 * some work to do on the headers.
2626 * The side-effect is that if the client completely closes its
2627 * connection during SV_STHEADER, the connection to the server
2628 * is kept until a response comes back or the timeout is reached.
2629 */
2630 else if (unlikely((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) &&
2631 (req->l == 0))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002632 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02002633 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002634
2635 /* We must ensure that the read part is still
2636 * alive when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002637 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002638 tv_add_ifset(&rep->rex, &now, &t->be->srvtimeout);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002639
2640 shutdown(t->srv_fd, SHUT_WR);
2641 t->srv_state = SV_STSHUTW;
2642 return 1;
2643 }
2644
2645 /* write timeout */
2646 /* FIXME!!! here, we don't want to switch to SHUTW if the
2647 * client shuts read too early, because we may still have
2648 * some work to do on the headers.
2649 */
Willy Tarreauf161a342007-04-08 16:59:42 +02002650 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_WR) &&
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002651 tv_isle(&req->wex, &now))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002652 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02002653 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002654 shutdown(t->srv_fd, SHUT_WR);
2655 /* We must ensure that the read part is still alive
2656 * when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002657 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002658 tv_add_ifset(&rep->rex, &now, &t->be->srvtimeout);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002659
2660 t->srv_state = SV_STSHUTW;
2661 if (!(t->flags & SN_ERR_MASK))
2662 t->flags |= SN_ERR_SRVTO;
2663 if (!(t->flags & SN_FINST_MASK))
2664 t->flags |= SN_FINST_H;
2665 return 1;
2666 }
2667
2668 /*
2669 * And now the non-error cases.
2670 */
2671
2672 /* Data remaining in the request buffer.
2673 * This happens during the first pass here, and during
2674 * long posts.
2675 */
2676 else if (likely(req->l)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002677 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
2678 /* restart writing */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002679 if (tv_add_ifset(&req->wex, &now, &t->be->srvtimeout)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01002680 /* FIXME: to prevent the server from expiring read timeouts during writes,
2681 * we refresh it. */
2682 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002683 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01002684 else
2685 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002686 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01002687 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002688
Willy Tarreaua15645d2007-03-18 16:22:39 +01002689 /* nothing left in the request buffer */
2690 else {
Willy Tarreau66319382007-04-08 17:17:37 +02002691 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
2692 /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002693 tv_eternity(&req->wex);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002694 }
2695 }
2696
2697 return t->srv_state != SV_STHEADERS;
2698 }
2699
2700
2701 /*****************************************************************
2702 * More interesting part now : we know that we have a complete *
2703 * response which at least looks like HTTP. We have an indicator *
2704 * of each header's length, so we can parse them quickly. *
2705 ****************************************************************/
2706
Willy Tarreau9cdde232007-05-02 20:58:19 +02002707 /* ensure we keep this pointer to the beginning of the message */
2708 msg->sol = rep->data + msg->som;
2709
Willy Tarreaua15645d2007-03-18 16:22:39 +01002710 /*
2711 * 1: get the status code and check for cacheability.
2712 */
2713
2714 t->logs.logwait &= ~LW_RESP;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002715 txn->status = strl2ui(rep->data + msg->sl.st.c, msg->sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002716
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002717 switch (txn->status) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01002718 case 200:
2719 case 203:
2720 case 206:
2721 case 300:
2722 case 301:
2723 case 410:
2724 /* RFC2616 @13.4:
2725 * "A response received with a status code of
2726 * 200, 203, 206, 300, 301 or 410 MAY be stored
2727 * by a cache (...) unless a cache-control
2728 * directive prohibits caching."
2729 *
2730 * RFC2616 @9.5: POST method :
2731 * "Responses to this method are not cacheable,
2732 * unless the response includes appropriate
2733 * Cache-Control or Expires header fields."
2734 */
2735 if (likely(txn->meth != HTTP_METH_POST) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002736 unlikely(t->be->options & PR_O_CHK_CACHE))
Willy Tarreau3d300592007-03-18 18:34:41 +01002737 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002738 break;
2739 default:
2740 break;
2741 }
2742
2743 /*
2744 * 2: we may need to capture headers
2745 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002746 if (unlikely((t->logs.logwait & LW_RSPHDR) && t->fe->rsp_cap))
Willy Tarreaua15645d2007-03-18 16:22:39 +01002747 capture_headers(rep->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002748 txn->rsp.cap, t->fe->rsp_cap);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002749
2750 /*
2751 * 3: we will have to evaluate the filters.
2752 * As opposed to version 1.2, now they will be evaluated in the
2753 * filters order and not in the header order. This means that
2754 * each filter has to be validated among all headers.
2755 *
2756 * Filters are tried with ->be first, then with ->fe if it is
2757 * different from ->be.
2758 */
2759
2760 t->flags &= ~SN_CONN_CLOSED; /* prepare for inspection */
2761
2762 cur_proxy = t->be;
2763 while (1) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002764 struct proxy *rule_set = cur_proxy;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002765
2766 /* try headers filters */
2767 if (rule_set->rsp_exp != NULL) {
2768 if (apply_filters_to_response(t, rep, rule_set->rsp_exp) < 0) {
2769 return_bad_resp:
Willy Tarreaubaaee002006-06-26 02:48:02 +02002770 if (t->srv) {
2771 t->srv->cur_sess--;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002772 t->srv->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002773 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002774 cur_proxy->failed_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002775 return_srv_prx_502:
Willy Tarreaufa645582007-06-03 15:59:52 +02002776 buffer_shutr(rep);
2777 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002778 fd_delete(t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002779 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002780 txn->status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01002781 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002782 if (!(t->flags & SN_ERR_MASK))
2783 t->flags |= SN_ERR_PRXCOND;
2784 if (!(t->flags & SN_FINST_MASK))
2785 t->flags |= SN_FINST_H;
2786 /* We used to have a free connection slot. Since we'll never use it,
2787 * we have to inform the server that it may be used by another session.
2788 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002789 if (t->srv && may_dequeue_tasks(t->srv, cur_proxy))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02002790 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002791 return 1;
2792 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01002793 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002794
Willy Tarreaua15645d2007-03-18 16:22:39 +01002795 /* has the response been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01002796 if (txn->flags & TX_SVDENY) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01002797 if (t->srv) {
2798 t->srv->cur_sess--;
2799 t->srv->failed_secu++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002800 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002801 cur_proxy->denied_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002802 goto return_srv_prx_502;
2803 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002804
Willy Tarreaua15645d2007-03-18 16:22:39 +01002805 /* We might have to check for "Connection:" */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002806 if (((t->fe->options | t->be->options) & PR_O_HTTP_CLOSE) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01002807 !(t->flags & SN_CONN_CLOSED)) {
2808 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002809 int cur_idx, old_idx, delta, val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002810 struct hdr_idx_elem *cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002811
Willy Tarreaua15645d2007-03-18 16:22:39 +01002812 cur_next = rep->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
2813 old_idx = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002814
Willy Tarreaua15645d2007-03-18 16:22:39 +01002815 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
2816 cur_hdr = &txn->hdr_idx.v[cur_idx];
2817 cur_ptr = cur_next;
2818 cur_end = cur_ptr + cur_hdr->len;
2819 cur_next = cur_end + cur_hdr->cr + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002820
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002821 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
2822 if (val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01002823 /* 3 possibilities :
2824 * - we have already set Connection: close,
2825 * so we remove this line.
2826 * - we have not yet set Connection: close,
2827 * but this line indicates close. We leave
2828 * it untouched and set the flag.
2829 * - we have not yet set Connection: close,
2830 * and this line indicates non-close. We
2831 * replace it.
2832 */
2833 if (t->flags & SN_CONN_CLOSED) {
2834 delta = buffer_replace2(rep, cur_ptr, cur_next, NULL, 0);
2835 txn->rsp.eoh += delta;
2836 cur_next += delta;
2837 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
2838 txn->hdr_idx.used--;
2839 cur_hdr->len = 0;
2840 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002841 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
2842 delta = buffer_replace2(rep, cur_ptr + val, cur_end,
2843 "close", 5);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002844 cur_next += delta;
2845 cur_hdr->len += delta;
2846 txn->rsp.eoh += delta;
2847 }
2848 t->flags |= SN_CONN_CLOSED;
2849 }
2850 }
2851 old_idx = cur_idx;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002852 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01002853 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002854
Willy Tarreaua15645d2007-03-18 16:22:39 +01002855 /* add response headers from the rule sets in the same order */
2856 for (cur_idx = 0; cur_idx < rule_set->nb_rspadd; cur_idx++) {
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002857 if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx,
2858 rule_set->rsp_add[cur_idx])) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01002859 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002860 }
2861
Willy Tarreaua15645d2007-03-18 16:22:39 +01002862 /* check whether we're already working on the frontend */
2863 if (cur_proxy == t->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002864 break;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002865 cur_proxy = t->fe;
2866 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002867
Willy Tarreaua15645d2007-03-18 16:22:39 +01002868 /*
2869 * 4: check for server cookie.
2870 */
2871 manage_server_side_cookies(t, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002872
Willy Tarreaua15645d2007-03-18 16:22:39 +01002873 /*
2874 * 5: add server cookie in the response if needed
2875 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002876 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
2877 (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01002878 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002879
Willy Tarreaua15645d2007-03-18 16:22:39 +01002880 /* the server is known, it's not the one the client requested, we have to
2881 * insert a set-cookie here, except if we want to insert only on POST
2882 * requests and this one isn't. Note that servers which don't have cookies
2883 * (eg: some backup servers) will return a full cookie removal request.
Willy Tarreaubaaee002006-06-26 02:48:02 +02002884 */
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002885 len = sprintf(trash, "Set-Cookie: %s=%s; path=/",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002886 t->be->cookie_name,
Willy Tarreaua15645d2007-03-18 16:22:39 +01002887 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002888
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002889 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
2890 trash, len)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01002891 goto return_bad_resp;
Willy Tarreau3d300592007-03-18 18:34:41 +01002892 txn->flags |= TX_SCK_INSERTED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002893
Willy Tarreaua15645d2007-03-18 16:22:39 +01002894 /* Here, we will tell an eventual cache on the client side that we don't
2895 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
2896 * Some caches understand the correct form: 'no-cache="set-cookie"', but
2897 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
2898 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002899 if (t->be->options & PR_O_COOK_NOC) {
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002900 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
2901 "Cache-control: private", 22)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01002902 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002903 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01002904 }
2905
2906
2907 /*
2908 * 6: check for cache-control or pragma headers.
2909 */
2910 check_response_for_cacheability(t, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002911
Willy Tarreaubaaee002006-06-26 02:48:02 +02002912
Willy Tarreaua15645d2007-03-18 16:22:39 +01002913 /*
2914 * 7: check if result will be cacheable with a cookie.
2915 * We'll block the response if security checks have caught
2916 * nasty things such as a cacheable cookie.
2917 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002918 if (((txn->flags & (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) ==
2919 (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002920 (t->be->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002921
Willy Tarreaua15645d2007-03-18 16:22:39 +01002922 /* we're in presence of a cacheable response containing
2923 * a set-cookie header. We'll block it as requested by
2924 * the 'checkcache' option, and send an alert.
2925 */
2926 if (t->srv) {
2927 t->srv->cur_sess--;
2928 t->srv->failed_secu++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002929 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002930 t->be->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002931
Willy Tarreaua15645d2007-03-18 16:22:39 +01002932 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002933 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01002934 send_log(t->be, LOG_ALERT,
2935 "Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002936 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01002937 goto return_srv_prx_502;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002938 }
2939
Willy Tarreaua15645d2007-03-18 16:22:39 +01002940 /*
2941 * 8: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02002942 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01002943 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02002944 if (!(t->flags & SN_CONN_CLOSED) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002945 ((t->fe->options | t->be->options) & PR_O_HTTP_CLOSE)) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02002946 if ((unlikely(msg->sl.st.v_l != 8) ||
2947 unlikely(req->data[msg->som + 7] != '0')) &&
2948 unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002949 "Connection: close", 17)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01002950 goto return_bad_resp;
2951 t->flags |= SN_CONN_CLOSED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002952 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002953
Willy Tarreaubaaee002006-06-26 02:48:02 +02002954
Willy Tarreaua15645d2007-03-18 16:22:39 +01002955 /*************************************************************
2956 * OK, that's finished for the headers. We have done what we *
2957 * could. Let's switch to the DATA state. *
2958 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02002959
Willy Tarreaua15645d2007-03-18 16:22:39 +01002960 t->srv_state = SV_STDATA;
2961 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002962 t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002963
2964 /* client connection already closed or option 'forceclose' required :
2965 * we close the server's outgoing connection right now.
Willy Tarreaubaaee002006-06-26 02:48:02 +02002966 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002967 if ((req->l == 0) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002968 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->options & PR_O_FORCE_CLO)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002969 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02002970 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002971
2972 /* We must ensure that the read part is still alive when switching
2973 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002974 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002975 tv_add_ifset(&rep->rex, &now, &t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002976
Willy Tarreaua15645d2007-03-18 16:22:39 +01002977 shutdown(t->srv_fd, SHUT_WR);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002978 t->srv_state = SV_STSHUTW;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002979 }
2980
Willy Tarreaua15645d2007-03-18 16:22:39 +01002981#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002982 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01002983 /* TCP splicing supported by both FE and BE */
2984 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002985 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01002986#endif
2987 /* if the user wants to log as soon as possible, without counting
2988 bytes from the server, then this is the right moment. */
2989 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
2990 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreaub4987172007-03-18 16:28:03 +01002991 t->logs.bytes_in = txn->rsp.eoh;
Willy Tarreau42250582007-04-01 01:30:43 +02002992 if (t->fe->to_log & LW_REQ)
2993 http_sess_log(t);
2994 else
2995 tcp_sess_log(t);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002996 }
2997
Willy Tarreaua15645d2007-03-18 16:22:39 +01002998 /* Note: we must not try to cheat by jumping directly to DATA,
2999 * otherwise we would not let the client side wake up.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003000 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003001
3002 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003003 }
3004 else if (s == SV_STDATA) {
3005 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003006 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02003007 buffer_shutr(rep);
3008 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003009 fd_delete(t->srv_fd);
3010 if (t->srv) {
3011 t->srv->cur_sess--;
3012 t->srv->failed_resp++;
3013 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003014 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003015 t->srv_state = SV_STCLOSE;
3016 if (!(t->flags & SN_ERR_MASK))
3017 t->flags |= SN_ERR_SRVCL;
3018 if (!(t->flags & SN_FINST_MASK))
3019 t->flags |= SN_FINST_D;
3020 /* We used to have a free connection slot. Since we'll never use it,
3021 * we have to inform the server that it may be used by another session.
3022 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003023 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02003024 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003025
3026 return 1;
3027 }
3028 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003029 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003030 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003031 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003032 t->srv_state = SV_STSHUTR;
3033 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3034 return 1;
3035 }
3036 /* end of client read and no more data to send */
3037 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003038 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003039 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003040 shutdown(t->srv_fd, SHUT_WR);
3041 /* We must ensure that the read part is still alive when switching
3042 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003043 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003044 tv_add_ifset(&rep->rex, &now, &t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003045
3046 t->srv_state = SV_STSHUTW;
3047 return 1;
3048 }
3049 /* read timeout */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003050 else if (tv_isle(&rep->rex, &now)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003051 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003052 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003053 t->srv_state = SV_STSHUTR;
3054 if (!(t->flags & SN_ERR_MASK))
3055 t->flags |= SN_ERR_SRVTO;
3056 if (!(t->flags & SN_FINST_MASK))
3057 t->flags |= SN_FINST_D;
3058 return 1;
3059 }
3060 /* write timeout */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003061 else if (tv_isle(&req->wex, &now)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003062 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003063 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003064 shutdown(t->srv_fd, SHUT_WR);
3065 /* We must ensure that the read part is still alive when switching
3066 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003067 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003068 tv_add_ifset(&rep->rex, &now, &t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003069 t->srv_state = SV_STSHUTW;
3070 if (!(t->flags & SN_ERR_MASK))
3071 t->flags |= SN_ERR_SRVTO;
3072 if (!(t->flags & SN_FINST_MASK))
3073 t->flags |= SN_FINST_D;
3074 return 1;
3075 }
3076
3077 /* recompute request time-outs */
3078 if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003079 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3080 /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02003081 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003082 }
3083 }
3084 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau66319382007-04-08 17:17:37 +02003085 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3086 /* restart writing */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003087 if (tv_add_ifset(&req->wex, &now, &t->be->srvtimeout)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003088 /* FIXME: to prevent the server from expiring read timeouts during writes,
3089 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02003090 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003091 }
3092 else
Willy Tarreaud7971282006-07-29 18:36:34 +02003093 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003094 }
3095 }
3096
3097 /* recompute response time-outs */
3098 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003099 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02003100 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003101 }
3102 }
3103 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003104 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003105 if (!tv_add_ifset(&rep->rex, &now, &t->be->srvtimeout))
Willy Tarreaud7971282006-07-29 18:36:34 +02003106 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003107 }
3108 }
3109
3110 return 0; /* other cases change nothing */
3111 }
3112 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003113 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003114 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003115 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003116 fd_delete(t->srv_fd);
3117 if (t->srv) {
3118 t->srv->cur_sess--;
3119 t->srv->failed_resp++;
3120 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003121 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003122 //close(t->srv_fd);
3123 t->srv_state = SV_STCLOSE;
3124 if (!(t->flags & SN_ERR_MASK))
3125 t->flags |= SN_ERR_SRVCL;
3126 if (!(t->flags & SN_FINST_MASK))
3127 t->flags |= SN_FINST_D;
3128 /* We used to have a free connection slot. Since we'll never use it,
3129 * we have to inform the server that it may be used by another session.
3130 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003131 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02003132 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003133
3134 return 1;
3135 }
3136 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003137 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003138 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003139 fd_delete(t->srv_fd);
3140 if (t->srv)
3141 t->srv->cur_sess--;
3142 //close(t->srv_fd);
3143 t->srv_state = SV_STCLOSE;
3144 /* We used to have a free connection slot. Since we'll never use it,
3145 * we have to inform the server that it may be used by another session.
3146 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003147 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02003148 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003149
3150 return 1;
3151 }
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003152 else if (tv_isle(&req->wex, &now)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003153 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003154 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003155 fd_delete(t->srv_fd);
3156 if (t->srv)
3157 t->srv->cur_sess--;
3158 //close(t->srv_fd);
3159 t->srv_state = SV_STCLOSE;
3160 if (!(t->flags & SN_ERR_MASK))
3161 t->flags |= SN_ERR_SRVTO;
3162 if (!(t->flags & SN_FINST_MASK))
3163 t->flags |= SN_FINST_D;
3164 /* We used to have a free connection slot. Since we'll never use it,
3165 * we have to inform the server that it may be used by another session.
3166 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003167 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02003168 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003169
3170 return 1;
3171 }
3172 else if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003173 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3174 /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02003175 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003176 }
3177 }
3178 else { /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02003179 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3180 /* restart writing */
Willy Tarreau33014d02007-06-03 15:25:37 +02003181 if (!tv_add_ifset(&req->wex, &now, &t->be->srvtimeout))
Willy Tarreaud7971282006-07-29 18:36:34 +02003182 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003183 }
3184 }
3185 return 0;
3186 }
3187 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003188 if (rep->flags & BF_READ_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003189 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003190 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003191 fd_delete(t->srv_fd);
3192 if (t->srv) {
3193 t->srv->cur_sess--;
3194 t->srv->failed_resp++;
3195 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003196 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003197 //close(t->srv_fd);
3198 t->srv_state = SV_STCLOSE;
3199 if (!(t->flags & SN_ERR_MASK))
3200 t->flags |= SN_ERR_SRVCL;
3201 if (!(t->flags & SN_FINST_MASK))
3202 t->flags |= SN_FINST_D;
3203 /* We used to have a free connection slot. Since we'll never use it,
3204 * we have to inform the server that it may be used by another session.
3205 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003206 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02003207 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003208
3209 return 1;
3210 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003211 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003212 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003213 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003214 fd_delete(t->srv_fd);
3215 if (t->srv)
3216 t->srv->cur_sess--;
3217 //close(t->srv_fd);
3218 t->srv_state = SV_STCLOSE;
3219 /* We used to have a free connection slot. Since we'll never use it,
3220 * we have to inform the server that it may be used by another session.
3221 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003222 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02003223 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003224
3225 return 1;
3226 }
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003227 else if (tv_isle(&rep->rex, &now)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003228 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003229 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003230 fd_delete(t->srv_fd);
3231 if (t->srv)
3232 t->srv->cur_sess--;
3233 //close(t->srv_fd);
3234 t->srv_state = SV_STCLOSE;
3235 if (!(t->flags & SN_ERR_MASK))
3236 t->flags |= SN_ERR_SRVTO;
3237 if (!(t->flags & SN_FINST_MASK))
3238 t->flags |= SN_FINST_D;
3239 /* We used to have a free connection slot. Since we'll never use it,
3240 * we have to inform the server that it may be used by another session.
3241 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003242 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau96bcfd72007-04-29 10:41:56 +02003243 task_wakeup(t->srv->queue_mgt);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003244
3245 return 1;
3246 }
3247 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003248 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02003249 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003250 }
3251 }
3252 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003253 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003254 if (!tv_add_ifset(&rep->rex, &now, &t->be->srvtimeout))
Willy Tarreaud7971282006-07-29 18:36:34 +02003255 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003256 }
3257 }
3258 return 0;
3259 }
3260 else { /* SV_STCLOSE : nothing to do */
3261 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
3262 int len;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003263 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003264 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003265 write(1, trash, len);
3266 }
3267 return 0;
3268 }
3269 return 0;
3270}
3271
3272
3273/*
3274 * Produces data for the session <s> depending on its source. Expects to be
3275 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3276 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3277 * session, which it uses to keep on being called when there is free space in
3278 * the buffer, of simply by letting an empty buffer upon return. It returns 1
3279 * if it changes the session state from CL_STSHUTR, otherwise 0.
3280 */
3281int produce_content(struct session *s)
3282{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003283 if (s->data_source == DATA_SRC_NONE) {
3284 s->flags &= ~SN_SELF_GEN;
3285 return 1;
3286 }
3287 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003288 /* dump server statistics */
3289 return produce_content_stats(s);
3290 }
3291 else {
3292 /* unknown data source */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003293 s->txn.status = 500;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003294 client_retnclose(s, error_message(s, HTTP_ERR_500));
3295 if (!(s->flags & SN_ERR_MASK))
3296 s->flags |= SN_ERR_PRXCOND;
3297 if (!(s->flags & SN_FINST_MASK))
3298 s->flags |= SN_FINST_R;
3299 s->flags &= ~SN_SELF_GEN;
3300 return 1;
3301 }
3302}
3303
3304
3305/*
3306 * Produces statistics data for the session <s>. Expects to be called with
3307 * s->cli_state == CL_STSHUTR. It stops by itself by unsetting the SN_SELF_GEN
3308 * flag from the session, which it uses to keep on being called when there is
3309 * free space in the buffer, of simply by letting an empty buffer upon return.
3310 * It returns 1 if it changes the session state from CL_STSHUTR, otherwise 0.
3311 */
3312int produce_content_stats(struct session *s)
3313{
3314 struct buffer *rep = s->rep;
3315 struct proxy *px;
3316 struct chunk msg;
3317 unsigned int up;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003318
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003319 msg.len = 0;
3320 msg.str = trash;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003321
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003322 switch (s->data_state) {
3323 case DATA_ST_INIT:
3324 /* the function had not been called yet */
3325 s->flags |= SN_SELF_GEN; // more data will follow
Willy Tarreaubaaee002006-06-26 02:48:02 +02003326
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003327 chunk_printf(&msg, sizeof(trash),
3328 "HTTP/1.0 200 OK\r\n"
3329 "Cache-Control: no-cache\r\n"
3330 "Connection: close\r\n"
3331 "Content-Type: text/html\r\n"
3332 "\r\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003333
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003334 s->txn.status = 200;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003335 client_retnclose(s, &msg); // send the start of the response.
3336 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003337
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003338 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
3339 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
3340 if (!(s->flags & SN_FINST_MASK))
3341 s->flags |= SN_FINST_R;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003342
Willy Tarreaub326fcc2007-03-03 13:54:32 +01003343 if (s->txn.meth == HTTP_METH_HEAD) {
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003344 /* that's all we return in case of HEAD request */
3345 s->data_state = DATA_ST_FIN;
3346 s->flags &= ~SN_SELF_GEN;
3347 return 1;
3348 }
3349
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003350 s->data_state = DATA_ST_HEAD; /* let's start producing data */
3351 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003352
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003353 case DATA_ST_HEAD:
3354 /* WARNING! This must fit in the first buffer !!! */
3355 chunk_printf(&msg, sizeof(trash),
3356 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
3357 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
3358 "<style type=\"text/css\"><!--\n"
3359 "body {"
3360 " font-family: helvetica, arial;"
3361 " font-size: 12px;"
3362 " font-weight: normal;"
3363 " color: black;"
3364 " background: white;"
3365 "}\n"
3366 "th,td {"
3367 " font-size: 0.8em;"
3368 " align: center;"
Willy Tarreauf2b74c22007-03-25 22:44:08 +02003369 "}\n"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003370 "h1 {"
3371 " font-size: xx-large;"
3372 " margin-bottom: 0.5em;"
3373 "}\n"
3374 "h2 {"
3375 " font-family: helvetica, arial;"
3376 " font-size: x-large;"
3377 " font-weight: bold;"
3378 " font-style: italic;"
3379 " color: #6020a0;"
3380 " margin-top: 0em;"
3381 " margin-bottom: 0em;"
3382 "}\n"
3383 "h3 {"
3384 " font-family: helvetica, arial;"
3385 " font-size: 16px;"
3386 " font-weight: bold;"
3387 " color: #b00040;"
3388 " background: #e8e8d0;"
3389 " margin-top: 0em;"
3390 " margin-bottom: 0em;"
3391 "}\n"
3392 "li {"
3393 " margin-top: 0.25em;"
3394 " margin-right: 2em;"
3395 "}\n"
3396 ".hr {margin-top: 0.25em;"
3397 " border-color: black;"
3398 " border-bottom-style: solid;"
3399 "}\n"
3400 ".pxname {background: #b00040;color: #ffff40;font-weight: bold;}\n"
3401 ".titre {background: #20D0D0;color: #000000;font-weight: bold;}\n"
3402 ".total {background: #20D0D0;color: #ffff80;}\n"
3403 ".frontend {background: #e8e8d0;}\n"
3404 ".backend {background: #e8e8d0;}\n"
3405 ".active0 {background: #ff9090;}\n"
3406 ".active1 {background: #ffd020;}\n"
3407 ".active2 {background: #ffffa0;}\n"
3408 ".active3 {background: #c0ffc0;}\n"
3409 ".active4 {background: #e0e0e0;}\n"
3410 ".backup0 {background: #ff9090;}\n"
3411 ".backup1 {background: #ff80ff;}\n"
3412 ".backup2 {background: #c060ff;}\n"
3413 ".backup3 {background: #b0d0ff;}\n"
3414 ".backup4 {background: #e0e0e0;}\n"
3415 "table.tbl { border-collapse: collapse; border-style: none;}\n"
Willy Tarreau35d66b02007-01-02 00:28:21 +01003416 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; padding: 2px 3px; border-color: gray;}\n"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003417 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}\n"
3418 "table.tbl th.empty { border-style: none; empty-cells: hide;}\n"
3419 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
3420 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
3421 "table.lgd td.noborder { border-style: none; padding: 2px; white-space: nowrap;}\n"
Willy Tarreauf2b74c22007-03-25 22:44:08 +02003422 "-->\n"
3423 "</style></head>\n");
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003424
3425 if (buffer_write_chunk(rep, &msg) != 0)
3426 return 0;
3427
3428 s->data_state = DATA_ST_INFO;
3429 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003430
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003431 case DATA_ST_INFO:
3432 up = (now.tv_sec - start_date.tv_sec);
3433
3434 /* WARNING! this has to fit the first packet too.
3435 * We are around 3.5 kB, add adding entries will
3436 * become tricky if we want to support 4kB buffers !
3437 */
3438 chunk_printf(&msg, sizeof(trash),
3439 "<body><h1><a href=\"" PRODUCT_URL "\" style=\"text-decoration: none;\">"
3440 PRODUCT_NAME "</a></h1>\n"
3441 "<h2>Statistics Report for pid %d</h2>\n"
3442 "<hr width=\"100%%\" class=\"hr\">\n"
3443 "<h3>&gt; General process information</h3>\n"
3444 "<table border=0 cols=3><tr><td align=\"left\" nowrap width=\"1%%\">\n"
3445 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
3446 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
3447 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
3448 "<b>maxsock = </b> %d<br>\n"
3449 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
3450 "</td><td align=\"center\" nowrap>\n"
Willy Tarreauf2b74c22007-03-25 22:44:08 +02003451 "<table class=\"lgd\"><tr>\n"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003452 "<td class=\"active3\">&nbsp;</td><td class=\"noborder\">active UP </td>"
3453 "<td class=\"backup3\">&nbsp;</td><td class=\"noborder\">backup UP </td>"
Willy Tarreauf2b74c22007-03-25 22:44:08 +02003454 "</tr><tr>\n"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003455 "<td class=\"active2\"></td><td class=\"noborder\">active UP, going down </td>"
3456 "<td class=\"backup2\"></td><td class=\"noborder\">backup UP, going down </td>"
Willy Tarreauf2b74c22007-03-25 22:44:08 +02003457 "</tr><tr>\n"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003458 "<td class=\"active1\"></td><td class=\"noborder\">active DOWN, going up </td>"
3459 "<td class=\"backup1\"></td><td class=\"noborder\">backup DOWN, going up </td>"
Willy Tarreauf2b74c22007-03-25 22:44:08 +02003460 "</tr><tr>\n"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003461 "<td class=\"active0\"></td><td class=\"noborder\">active or backup DOWN &nbsp;</td>"
3462 "<td class=\"active4\"></td><td class=\"noborder\">not checked </td>"
3463 "</tr></table>\n"
3464 "</td>"
3465 "<td align=\"left\" nowrap width=\"1%%\">"
Willy Tarreauf2b74c22007-03-25 22:44:08 +02003466 "<b>External ressources:</b><ul style=\"margin-top: 0.25em;\">\n"
3467 "<li><a href=\"" PRODUCT_URL "\">Primary site</a><br>\n"
3468 "<li><a href=\"" PRODUCT_URL_UPD "\">Updates (v" PRODUCT_BRANCH ")</a><br>\n"
3469 "<li><a href=\"" PRODUCT_URL_DOC "\">Online manual</a><br>\n"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003470 "</ul>"
3471 "</td>"
3472 "</tr></table>\n"
3473 "",
3474 pid, pid, global.nbproc,
3475 up / 86400, (up % 86400) / 3600,
3476 (up % 3600) / 60, (up % 60),
3477 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
3478 global.rlimit_memmax ? " MB" : "",
3479 global.rlimit_nofile,
3480 global.maxsock,
3481 global.maxconn,
3482 actconn
3483 );
Willy Tarreaubaaee002006-06-26 02:48:02 +02003484
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003485 if (buffer_write_chunk(rep, &msg) != 0)
3486 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003487
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003488 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003489
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003490 s->data_ctx.stats.px = proxy;
3491 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
3492 s->data_state = DATA_ST_LIST;
3493 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003494
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003495 case DATA_ST_LIST:
3496 /* dump proxies */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003497 while (s->data_ctx.stats.px) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003498 px = s->data_ctx.stats.px;
3499 /* skip the disabled proxies and non-networked ones */
3500 if (px->state != PR_STSTOPPED && (px->cap & (PR_CAP_FE | PR_CAP_BE)))
3501 if (produce_content_stats_proxy(s, px) == 0)
3502 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003503
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003504 s->data_ctx.stats.px = px->next;
3505 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
3506 }
3507 /* here, we just have reached the last proxy */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003508
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003509 s->data_state = DATA_ST_END;
3510 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003511
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003512 case DATA_ST_END:
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003513 chunk_printf(&msg, sizeof(trash), "</body></html>\n");
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003514 if (buffer_write_chunk(rep, &msg) != 0)
3515 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003516
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003517 s->data_state = DATA_ST_FIN;
3518 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003519
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003520 case DATA_ST_FIN:
3521 s->flags &= ~SN_SELF_GEN;
3522 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003523
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003524 default:
3525 /* unknown state ! */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003526 s->txn.status = 500;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003527 client_retnclose(s, error_message(s, HTTP_ERR_500));
3528 if (!(s->flags & SN_ERR_MASK))
3529 s->flags |= SN_ERR_PRXCOND;
3530 if (!(s->flags & SN_FINST_MASK))
3531 s->flags |= SN_FINST_R;
3532 s->flags &= ~SN_SELF_GEN;
3533 return 1;
3534 }
3535}
Willy Tarreaubaaee002006-06-26 02:48:02 +02003536
Willy Tarreaubaaee002006-06-26 02:48:02 +02003537
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003538/*
3539 * Dumps statistics for a proxy.
3540 * Returns 0 if it had to stop dumping data because of lack of buffer space,
3541 * ot non-zero if everything completed.
3542 */
3543int produce_content_stats_proxy(struct session *s, struct proxy *px)
3544{
3545 struct buffer *rep = s->rep;
3546 struct server *sv;
3547 struct chunk msg;
3548
3549 msg.len = 0;
3550 msg.str = trash;
3551
3552 switch (s->data_ctx.stats.px_st) {
3553 case DATA_ST_PX_INIT:
3554 /* we are on a new proxy */
3555
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003556 if (s->be->uri_auth && s->be->uri_auth->scope) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003557 /* we have a limited scope, we have to check the proxy name */
3558 struct stat_scope *scope;
3559 int len;
3560
3561 len = strlen(px->id);
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003562 scope = s->be->uri_auth->scope;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003563
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003564 while (scope) {
3565 /* match exact proxy name */
3566 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3567 break;
3568
3569 /* match '.' which means 'self' proxy */
3570 if (!strcmp(scope->px_id, ".") && px == s->fe)
3571 break;
3572 scope = scope->next;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003573 }
3574
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003575 /* proxy name not found : don't dump anything */
3576 if (scope == NULL)
3577 return 1;
3578 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003579
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003580 s->data_ctx.stats.px_st = DATA_ST_PX_TH;
3581 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003582
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003583 case DATA_ST_PX_TH:
3584 /* print a new table */
3585 chunk_printf(&msg, sizeof(trash),
3586 "<table cols=\"20\" class=\"tbl\" width=\"100%%\">\n"
3587 "<tr align=\"center\" class=\"titre\">"
3588 "<th colspan=2 class=\"pxname\">%s</th>"
3589 "<th colspan=18 class=\"empty\"></th>"
3590 "</tr>\n"
3591 "<tr align=\"center\" class=\"titre\">"
3592 "<th rowspan=2></th>"
3593 "<th colspan=2>Queue</th><th colspan=4>Sessions</th>"
3594 "<th colspan=2>Bytes</th><th colspan=2>Denied</th>"
3595 "<th colspan=3>Errors</th><th colspan=6>Server</th>"
3596 "</tr>\n"
3597 "<tr align=\"center\" class=\"titre\">"
Willy Tarreau35d66b02007-01-02 00:28:21 +01003598 "<th>Cur</th><th>Max</th><th>Cur</th><th>Max</th>"
3599 "<th>Limit</th><th>Cumul</th><th>In</th><th>Out</th>"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003600 "<th>Req</th><th>Resp</th><th>Req</th><th>Conn</th>"
3601 "<th>Resp</th><th>Status</th><th>Weight</th><th>Act</th>"
3602 "<th>Bck</th><th>Check</th><th>Down</th></tr>\n"
3603 "",
3604 px->id);
3605
3606 if (buffer_write_chunk(rep, &msg) != 0)
3607 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003608
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003609 s->data_ctx.stats.px_st = DATA_ST_PX_FE;
3610 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003611
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003612 case DATA_ST_PX_FE:
3613 /* print the frontend */
3614 if (px->cap & PR_CAP_FE) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003615 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003616 /* name, queue */
3617 "<tr align=center class=\"frontend\"><td>Frontend</td><td colspan=2></td>"
3618 /* sessions : current, max, limit, cumul. */
3619 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
3620 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003621 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003622 /* denied: req, resp */
3623 "<td align=right>%d</td><td align=right>%d</td>"
3624 /* errors : request, connect, response */
3625 "<td align=right>%d</td><td align=right></td><td align=right></td>"
3626 /* server status : reflect backend status */
3627 "<td align=center>%s</td>"
3628 /* rest of server: nothing */
3629 "<td align=center colspan=5></td></tr>"
3630 "",
3631 px->feconn, px->feconn_max, px->maxconn, px->cum_feconn,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003632 px->bytes_in, px->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003633 px->denied_req, px->denied_resp,
3634 px->failed_req,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003635 px->state == PR_STRUN ? "OPEN" :
3636 px->state == PR_STIDLE ? "FULL" : "STOP");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003637
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003638 if (buffer_write_chunk(rep, &msg) != 0)
3639 return 0;
3640 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003641
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003642 s->data_ctx.stats.sv = px->srv; /* may be NULL */
3643 s->data_ctx.stats.px_st = DATA_ST_PX_SV;
3644 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003645
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003646 case DATA_ST_PX_SV:
3647 /* stats.sv has been initialized above */
3648 while (s->data_ctx.stats.sv != NULL) {
3649 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3650 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP, 4=unchecked */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003651
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003652 sv = s->data_ctx.stats.sv;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003653
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003654 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3655 if (!(sv->state & SRV_CHECKED))
3656 sv_state = 4;
3657 else if (sv->state & SRV_RUNNING)
3658 if (sv->health == sv->rise + sv->fall - 1)
3659 sv_state = 3; /* UP */
3660 else
3661 sv_state = 2; /* going down */
3662 else
3663 if (sv->health)
3664 sv_state = 1; /* going up */
3665 else
3666 sv_state = 0; /* DOWN */
3667
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003668 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003669 /* name */
3670 "<tr align=\"center\" class=\"%s%d\"><td>%s</td>"
3671 /* queue : current, max */
3672 "<td align=right>%d</td><td align=right>%d</td>"
3673 /* sessions : current, max, limit, cumul */
3674 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>"
3675 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003676 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003677 /* denied: req, resp */
3678 "<td align=right></td><td align=right>%d</td>"
3679 /* errors : request, connect, response */
3680 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
3681 "",
Willy Tarreau368e96a2007-01-07 00:16:15 +01003682 (sv->state & SRV_BACKUP) ? "backup" : "active",
Willy Tarreau128e9542007-01-01 22:01:43 +01003683 sv_state, sv->id,
3684 sv->nbpend, sv->nbpend_max,
3685 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003686 sv->bytes_in, sv->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003687 sv->failed_secu,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003688 sv->failed_conns, sv->failed_resp);
Willy Tarreau128e9542007-01-01 22:01:43 +01003689
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003690 /* status */
3691 chunk_printf(&msg, sizeof(trash), "<td nowrap>");
3692 chunk_printf(&msg, sizeof(trash),
3693 srv_hlt_st[sv_state],
3694 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3695 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3696
Willy Tarreau128e9542007-01-01 22:01:43 +01003697 chunk_printf(&msg, sizeof(trash),
3698 /* weight */
3699 "</td><td>%d</td>"
3700 /* act, bck */
3701 "<td>%s</td><td>%s</td>"
3702 "",
Willy Tarreau417fae02007-03-25 21:16:40 +02003703 sv->uweight,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003704 (sv->state & SRV_BACKUP) ? "-" : "Y",
3705 (sv->state & SRV_BACKUP) ? "Y" : "-");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003706
3707 /* check failures : unique, fatal */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003708 if (sv->state & SRV_CHECKED)
3709 chunk_printf(&msg, sizeof(trash),
3710 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3711 sv->failed_checks, sv->down_trans);
3712 else
3713 chunk_printf(&msg, sizeof(trash),
3714 "<td colspan=2></td></tr>\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003715
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003716 if (buffer_write_chunk(rep, &msg) != 0)
3717 return 0;
3718
3719 s->data_ctx.stats.sv = sv->next;
3720 } /* while sv */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003721
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003722 s->data_ctx.stats.px_st = DATA_ST_PX_BE;
3723 /* fall through */
3724
3725 case DATA_ST_PX_BE:
3726 /* print the backend */
3727 if (px->cap & PR_CAP_BE) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003728 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003729 /* name */
3730 "<tr align=center class=\"backend\"><td>Backend</td>"
3731 /* queue : current, max */
3732 "<td align=right>%d</td><td align=right>%d</td>"
3733 /* sessions : current, max, limit, cumul. */
3734 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
3735 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003736 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003737 /* denied: req, resp */
3738 "<td align=right>%d</td><td align=right>%d</td>"
3739 /* errors : request, connect, response */
3740 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
3741 /* server status : reflect backend status (up/down) : we display UP
3742 * if the backend has known working servers or if it has no server at
3743 * all (eg: for stats). Tthen we display the total weight, number of
3744 * active and backups. */
3745 "<td align=center>%s</td><td align=center>%d</td>"
3746 "<td align=center>%d</td><td align=center>%d</td>"
3747 /* rest of server: nothing */
3748 "<td align=center colspan=2></td></tr>"
3749 "",
3750 px->nbpend /* or px->totpend ? */, px->nbpend_max,
3751 px->beconn, px->beconn_max, px->fullconn, px->cum_beconn,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003752 px->bytes_in, px->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003753 px->denied_req, px->denied_resp,
3754 px->failed_conns, px->failed_resp,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003755 (px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN",
3756 px->srv_map_sz, px->srv_act, px->srv_bck);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003757
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003758 if (buffer_write_chunk(rep, &msg) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003759 return 0;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003760 }
3761
3762 s->data_ctx.stats.px_st = DATA_ST_PX_END;
3763 /* fall through */
3764
3765 case DATA_ST_PX_END:
3766 chunk_printf(&msg, sizeof(trash), "</table><p>\n");
3767
3768 if (buffer_write_chunk(rep, &msg) != 0)
3769 return 0;
3770
3771 s->data_ctx.stats.px_st = DATA_ST_PX_FIN;
3772 /* fall through */
3773
3774 case DATA_ST_PX_FIN:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003775 return 1;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003776
3777 default:
3778 /* unknown state, we should put an abort() here ! */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003779 return 1;
3780 }
3781}
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
3846 /* right now, the backend switch is not too much complicated
3847 * because we have associated req_cap and rsp_cap to the
3848 * frontend, and the beconn will be updated later.
3849 */
3850
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003851 t->rep->rto = t->req->wto = t->be->srvtimeout;
3852 t->req->cto = t->be->contimeout;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003853 last_hdr = 1;
3854 break;
3855
3856 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003857 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003858 last_hdr = 1;
3859 break;
3860
3861 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003862 txn->flags |= TX_CLDENY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003863 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003864 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003865 break;
3866
3867 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003868 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003869 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003870 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003871 break;
3872
3873 case ACT_REPLACE:
3874 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3875 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3876 /* FIXME: if the user adds a newline in the replacement, the
3877 * index will not be recalculated for now, and the new line
3878 * will not be counted as a new header.
3879 */
3880
3881 cur_end += delta;
3882 cur_next += delta;
3883 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003884 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003885 break;
3886
3887 case ACT_REMOVE:
3888 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3889 cur_next += delta;
3890
3891 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003892 txn->req.eoh += delta;
3893 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3894 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003895 cur_hdr->len = 0;
3896 cur_end = NULL; /* null-term has been rewritten */
3897 break;
3898
3899 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01003900 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003901 if (cur_end)
3902 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003903
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003904 /* keep the link from this header to next one in case of later
3905 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003906 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003907 old_idx = cur_idx;
3908 }
3909 return 0;
3910}
3911
3912
3913/* Apply the filter to the request line.
3914 * Returns 0 if nothing has been done, 1 if the filter has been applied,
3915 * or -1 if a replacement resulted in an invalid request line.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003916 * Since it can manage the switch to another backend, it updates the per-proxy
3917 * DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003918 */
3919int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
3920{
3921 char term;
3922 char *cur_ptr, *cur_end;
3923 int done;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003924 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003925 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003926
Willy Tarreau58f10d72006-12-04 02:26:12 +01003927
Willy Tarreau3d300592007-03-18 18:34:41 +01003928 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003929 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003930 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003931 (exp->action == ACT_ALLOW ||
3932 exp->action == ACT_DENY ||
3933 exp->action == ACT_TARPIT))
3934 return 0;
3935 else if (exp->action == ACT_REMOVE)
3936 return 0;
3937
3938 done = 0;
3939
Willy Tarreau9cdde232007-05-02 20:58:19 +02003940 cur_ptr = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003941 cur_end = cur_ptr + txn->req.sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003942
3943 /* Now we have the request line between cur_ptr and cur_end */
3944
3945 /* The annoying part is that pattern matching needs
3946 * that we modify the contents to null-terminate all
3947 * strings before testing them.
3948 */
3949
3950 term = *cur_end;
3951 *cur_end = '\0';
3952
3953 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3954 switch (exp->action) {
3955 case ACT_SETBE:
3956 /* It is not possible to jump a second time.
3957 * FIXME: should we return an HTTP/500 here so that
3958 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01003959 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003960 if (t->be != t->fe)
3961 break;
3962
3963 /* Swithing Proxy */
3964 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003965
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003966 /* right now, the backend switch is not too much complicated
3967 * because we have associated req_cap and rsp_cap to the
3968 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003969 */
3970
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003971 t->rep->rto = t->req->wto = t->be->srvtimeout;
3972 t->req->cto = t->be->contimeout;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003973 done = 1;
3974 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003975
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003976 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003977 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003978 done = 1;
3979 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003980
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003981 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003982 txn->flags |= TX_CLDENY;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003983 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003984 done = 1;
3985 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003986
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003987 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003988 txn->flags |= TX_CLTARPIT;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003989 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003990 done = 1;
3991 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003992
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003993 case ACT_REPLACE:
3994 *cur_end = term; /* restore the string terminator */
3995 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3996 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3997 /* FIXME: if the user adds a newline in the replacement, the
3998 * index will not be recalculated for now, and the new line
3999 * will not be counted as a new header.
4000 */
Willy Tarreaua496b602006-12-17 23:15:24 +01004001
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004002 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004003 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01004004
Willy Tarreau9cdde232007-05-02 20:58:19 +02004005 txn->req.sol = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004006 cur_end = (char *)http_parse_reqline(&txn->req, req->data,
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004007 HTTP_MSG_RQMETH,
4008 cur_ptr, cur_end + 1,
4009 NULL, NULL);
4010 if (unlikely(!cur_end))
4011 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01004012
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004013 /* we have a full request and we know that we have either a CR
4014 * or an LF at <ptr>.
4015 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004016 txn->meth = find_http_meth(cur_ptr, txn->req.sl.rq.m_l);
4017 hdr_idx_set_start(&txn->hdr_idx, txn->req.sl.rq.l, *cur_end == '\r');
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004018 /* there is no point trying this regex on headers */
4019 return 1;
4020 }
4021 }
4022 *cur_end = term; /* restore the string terminator */
4023 return done;
4024}
Willy Tarreau97de6242006-12-27 17:18:38 +01004025
Willy Tarreau58f10d72006-12-04 02:26:12 +01004026
Willy Tarreau58f10d72006-12-04 02:26:12 +01004027
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004028/*
4029 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
4030 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
Willy Tarreaua15645d2007-03-18 16:22:39 +01004031 * unparsable request. Since it can manage the switch to another backend, it
4032 * updates the per-proxy DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004033 */
4034int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
4035{
Willy Tarreau3d300592007-03-18 18:34:41 +01004036 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004037 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004038 while (exp && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004039 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004040
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004041 /*
4042 * The interleaving of transformations and verdicts
4043 * makes it difficult to decide to continue or stop
4044 * the evaluation.
4045 */
4046
Willy Tarreau3d300592007-03-18 18:34:41 +01004047 if ((txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004048 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4049 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
4050 exp = exp->next;
4051 continue;
4052 }
4053
4054 /* Apply the filter to the request line. */
4055 ret = apply_filter_to_req_line(t, req, exp);
4056 if (unlikely(ret < 0))
4057 return -1;
4058
4059 if (likely(ret == 0)) {
4060 /* The filter did not match the request, it can be
4061 * iterated through all headers.
4062 */
4063 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004064 }
4065 exp = exp->next;
4066 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004067 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004068}
4069
4070
Willy Tarreaua15645d2007-03-18 16:22:39 +01004071
Willy Tarreau58f10d72006-12-04 02:26:12 +01004072/*
4073 * Manager client-side cookie
4074 */
4075void manage_client_side_cookies(struct session *t, struct buffer *req)
4076{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004077 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004078 char *p1, *p2, *p3, *p4;
4079 char *del_colon, *del_cookie, *colon;
4080 int app_cookies;
4081
4082 appsess *asession_temp = NULL;
4083 appsess local_asession;
4084
4085 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004086 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004087
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004088 if (t->be->cookie_name == NULL &&
4089 t->be->appsession_name == NULL &&
4090 t->be->capture_name == NULL)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004091 return;
4092
Willy Tarreau2a324282006-12-05 00:05:46 +01004093 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004094 * we start with the start line.
4095 */
Willy Tarreau83969f42007-01-22 08:55:47 +01004096 old_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004097 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004098
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004099 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004100 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004101 int val;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004102
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004103 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01004104 cur_ptr = cur_next;
4105 cur_end = cur_ptr + cur_hdr->len;
4106 cur_next = cur_end + cur_hdr->cr + 1;
4107
4108 /* We have one full header between cur_ptr and cur_end, and the
4109 * next header starts at cur_next. We're only interested in
4110 * "Cookie:" headers.
4111 */
4112
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004113 val = http_header_match2(cur_ptr, cur_end, "Cookie", 6);
4114 if (!val) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004115 old_idx = cur_idx;
4116 continue;
4117 }
4118
4119 /* Now look for cookies. Conforming to RFC2109, we have to support
4120 * attributes whose name begin with a '$', and associate them with
4121 * the right cookie, if we want to delete this cookie.
4122 * So there are 3 cases for each cookie read :
4123 * 1) it's a special attribute, beginning with a '$' : ignore it.
4124 * 2) it's a server id cookie that we *MAY* want to delete : save
4125 * some pointers on it (last semi-colon, beginning of cookie...)
4126 * 3) it's an application cookie : we *MAY* have to delete a previous
4127 * "special" cookie.
4128 * At the end of loop, if a "special" cookie remains, we may have to
4129 * remove it. If no application cookie persists in the header, we
4130 * *MUST* delete it
4131 */
4132
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004133 colon = p1 = cur_ptr + val; /* first non-space char after 'Cookie:' */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004134
Willy Tarreau58f10d72006-12-04 02:26:12 +01004135 /* del_cookie == NULL => nothing to be deleted */
4136 del_colon = del_cookie = NULL;
4137 app_cookies = 0;
4138
4139 while (p1 < cur_end) {
4140 /* skip spaces and colons, but keep an eye on these ones */
4141 while (p1 < cur_end) {
4142 if (*p1 == ';' || *p1 == ',')
4143 colon = p1;
4144 else if (!isspace((int)*p1))
4145 break;
4146 p1++;
4147 }
4148
4149 if (p1 == cur_end)
4150 break;
4151
4152 /* p1 is at the beginning of the cookie name */
4153 p2 = p1;
4154 while (p2 < cur_end && *p2 != '=')
4155 p2++;
4156
4157 if (p2 == cur_end)
4158 break;
4159
4160 p3 = p2 + 1; /* skips the '=' sign */
4161 if (p3 == cur_end)
4162 break;
4163
4164 p4 = p3;
4165 while (p4 < cur_end && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
4166 p4++;
4167
4168 /* here, we have the cookie name between p1 and p2,
4169 * and its value between p3 and p4.
4170 * we can process it :
4171 *
4172 * Cookie: NAME=VALUE;
4173 * | || || |
4174 * | || || +--> p4
4175 * | || |+-------> p3
4176 * | || +--------> p2
4177 * | |+------------> p1
4178 * | +-------------> colon
4179 * +--------------------> cur_ptr
4180 */
4181
4182 if (*p1 == '$') {
4183 /* skip this one */
4184 }
4185 else {
4186 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004187 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004188 txn->cli_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004189 (p4 - p1 >= t->fe->capture_namelen) &&
4190 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004191 int log_len = p4 - p1;
4192
Willy Tarreau086b3b42007-05-13 21:45:51 +02004193 if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004194 Alert("HTTP logging : out of memory.\n");
4195 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004196 if (log_len > t->fe->capture_len)
4197 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004198 memcpy(txn->cli_cookie, p1, log_len);
4199 txn->cli_cookie[log_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004200 }
4201 }
4202
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004203 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4204 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004205 /* Cool... it's the right one */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004206 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004207 char *delim;
4208
4209 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4210 * have the server ID betweek p3 and delim, and the original cookie between
4211 * delim+1 and p4. Otherwise, delim==p4 :
4212 *
4213 * Cookie: NAME=SRV~VALUE;
4214 * | || || | |
4215 * | || || | +--> p4
4216 * | || || +--------> delim
4217 * | || |+-----------> p3
4218 * | || +------------> p2
4219 * | |+----------------> p1
4220 * | +-----------------> colon
4221 * +------------------------> cur_ptr
4222 */
4223
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004224 if (t->be->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004225 for (delim = p3; delim < p4; delim++)
4226 if (*delim == COOKIE_DELIM)
4227 break;
4228 }
4229 else
4230 delim = p4;
4231
4232
4233 /* Here, we'll look for the first running server which supports the cookie.
4234 * This allows to share a same cookie between several servers, for example
4235 * to dedicate backup servers to specific servers only.
4236 * However, to prevent clients from sticking to cookie-less backup server
4237 * when they have incidentely learned an empty cookie, we simply ignore
4238 * empty cookies and mark them as invalid.
4239 */
4240 if (delim == p3)
4241 srv = NULL;
4242
4243 while (srv) {
Willy Tarreau92f2ab12007-02-02 22:14:47 +01004244 if (srv->cookie && (srv->cklen == delim - p3) &&
4245 !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004246 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004247 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004248 txn->flags &= ~TX_CK_MASK;
4249 txn->flags |= TX_CK_VALID;
4250 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004251 t->srv = srv;
4252 break;
4253 } else {
4254 /* we found a server, but it's down */
Willy Tarreau3d300592007-03-18 18:34:41 +01004255 txn->flags &= ~TX_CK_MASK;
4256 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004257 }
4258 }
4259 srv = srv->next;
4260 }
4261
Willy Tarreau3d300592007-03-18 18:34:41 +01004262 if (!srv && !(txn->flags & TX_CK_DOWN)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004263 /* no server matched this cookie */
Willy Tarreau3d300592007-03-18 18:34:41 +01004264 txn->flags &= ~TX_CK_MASK;
4265 txn->flags |= TX_CK_INVALID;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004266 }
4267
4268 /* depending on the cookie mode, we may have to either :
4269 * - delete the complete cookie if we're in insert+indirect mode, so that
4270 * the server never sees it ;
4271 * - remove the server id from the cookie value, and tag the cookie as an
4272 * application cookie so that it does not get accidentely removed later,
4273 * if we're in cookie prefix mode
4274 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004275 if ((t->be->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004276 int delta; /* negative */
4277
4278 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
4279 p4 += delta;
4280 cur_end += delta;
4281 cur_next += delta;
4282 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004283 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004284
4285 del_cookie = del_colon = NULL;
4286 app_cookies++; /* protect the header from deletion */
4287 }
4288 else if (del_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004289 (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 +01004290 del_cookie = p1;
4291 del_colon = colon;
4292 }
4293 } else {
4294 /* now we know that we must keep this cookie since it's
4295 * not ours. But if we wanted to delete our cookie
4296 * earlier, we cannot remove the complete header, but we
4297 * can remove the previous block itself.
4298 */
4299 app_cookies++;
4300
4301 if (del_cookie != NULL) {
4302 int delta; /* negative */
4303
4304 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
4305 p4 += delta;
4306 cur_end += delta;
4307 cur_next += delta;
4308 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004309 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004310 del_cookie = del_colon = NULL;
4311 }
4312 }
4313
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004314 if ((t->be->appsession_name != NULL) &&
4315 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004316 /* first, let's see if the cookie is our appcookie*/
4317
4318 /* Cool... it's the right one */
4319
4320 asession_temp = &local_asession;
4321
Willy Tarreau63963c62007-05-13 21:29:55 +02004322 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004323 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4324 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4325 return;
4326 }
4327
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004328 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4329 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004330 asession_temp->serverid = NULL;
4331
4332 /* only do insert, if lookup fails */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004333 if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004334 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004335 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004336 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004337 Alert("Not enough memory process_cli():asession:calloc().\n");
4338 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4339 return;
4340 }
4341
4342 asession_temp->sessid = local_asession.sessid;
4343 asession_temp->serverid = local_asession.serverid;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004344 chtbl_insert(&(t->be->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004345 } else {
4346 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004347 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004348 }
4349
4350 if (asession_temp->serverid == NULL) {
4351 Alert("Found Application Session without matching server.\n");
4352 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004353 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004354 while (srv) {
4355 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004356 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004357 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004358 txn->flags &= ~TX_CK_MASK;
4359 txn->flags |= TX_CK_VALID;
4360 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004361 t->srv = srv;
4362 break;
4363 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01004364 txn->flags &= ~TX_CK_MASK;
4365 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004366 }
4367 }
4368 srv = srv->next;
4369 }/* end while(srv) */
4370 }/* end else if server == NULL */
4371
Willy Tarreaud825eef2007-05-12 22:35:00 +02004372 tv_add(&asession_temp->expire, &now, &t->be->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004373 }/* end if ((t->proxy->appsession_name != NULL) ... */
4374 }
4375
4376 /* we'll have to look for another cookie ... */
4377 p1 = p4;
4378 } /* while (p1 < cur_end) */
4379
4380 /* There's no more cookie on this line.
4381 * We may have marked the last one(s) for deletion.
4382 * We must do this now in two ways :
4383 * - if there is no app cookie, we simply delete the header ;
4384 * - if there are app cookies, we must delete the end of the
4385 * string properly, including the colon/semi-colon before
4386 * the cookie name.
4387 */
4388 if (del_cookie != NULL) {
4389 int delta;
4390 if (app_cookies) {
4391 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
4392 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004393 cur_hdr->len += delta;
4394 } else {
4395 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004396
4397 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004398 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4399 txn->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004400 cur_hdr->len = 0;
4401 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01004402 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004403 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004404 }
4405
4406 /* keep the link from this header to next one */
4407 old_idx = cur_idx;
4408 } /* end of cookie processing on this header */
4409}
4410
4411
Willy Tarreaua15645d2007-03-18 16:22:39 +01004412/* Iterate the same filter through all response headers contained in <rtr>.
4413 * Returns 1 if this filter can be stopped upon return, otherwise 0.
4414 */
4415int apply_filter_to_resp_headers(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4416{
4417 char term;
4418 char *cur_ptr, *cur_end, *cur_next;
4419 int cur_idx, old_idx, last_hdr;
4420 struct http_txn *txn = &t->txn;
4421 struct hdr_idx_elem *cur_hdr;
4422 int len, delta;
4423
4424 last_hdr = 0;
4425
4426 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4427 old_idx = 0;
4428
4429 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004430 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004431 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004432 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004433 (exp->action == ACT_ALLOW ||
4434 exp->action == ACT_DENY))
4435 return 0;
4436
4437 cur_idx = txn->hdr_idx.v[old_idx].next;
4438 if (!cur_idx)
4439 break;
4440
4441 cur_hdr = &txn->hdr_idx.v[cur_idx];
4442 cur_ptr = cur_next;
4443 cur_end = cur_ptr + cur_hdr->len;
4444 cur_next = cur_end + cur_hdr->cr + 1;
4445
4446 /* Now we have one header between cur_ptr and cur_end,
4447 * and the next header starts at cur_next.
4448 */
4449
4450 /* The annoying part is that pattern matching needs
4451 * that we modify the contents to null-terminate all
4452 * strings before testing them.
4453 */
4454
4455 term = *cur_end;
4456 *cur_end = '\0';
4457
4458 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4459 switch (exp->action) {
4460 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004461 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004462 last_hdr = 1;
4463 break;
4464
4465 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004466 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004467 last_hdr = 1;
4468 break;
4469
4470 case ACT_REPLACE:
4471 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4472 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4473 /* FIXME: if the user adds a newline in the replacement, the
4474 * index will not be recalculated for now, and the new line
4475 * will not be counted as a new header.
4476 */
4477
4478 cur_end += delta;
4479 cur_next += delta;
4480 cur_hdr->len += delta;
4481 txn->rsp.eoh += delta;
4482 break;
4483
4484 case ACT_REMOVE:
4485 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4486 cur_next += delta;
4487
4488 /* FIXME: this should be a separate function */
4489 txn->rsp.eoh += delta;
4490 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4491 txn->hdr_idx.used--;
4492 cur_hdr->len = 0;
4493 cur_end = NULL; /* null-term has been rewritten */
4494 break;
4495
4496 }
4497 }
4498 if (cur_end)
4499 *cur_end = term; /* restore the string terminator */
4500
4501 /* keep the link from this header to next one in case of later
4502 * removal of next header.
4503 */
4504 old_idx = cur_idx;
4505 }
4506 return 0;
4507}
4508
4509
4510/* Apply the filter to the status line in the response buffer <rtr>.
4511 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4512 * or -1 if a replacement resulted in an invalid status line.
4513 */
4514int apply_filter_to_sts_line(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4515{
4516 char term;
4517 char *cur_ptr, *cur_end;
4518 int done;
4519 struct http_txn *txn = &t->txn;
4520 int len, delta;
4521
4522
Willy Tarreau3d300592007-03-18 18:34:41 +01004523 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004524 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004525 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004526 (exp->action == ACT_ALLOW ||
4527 exp->action == ACT_DENY))
4528 return 0;
4529 else if (exp->action == ACT_REMOVE)
4530 return 0;
4531
4532 done = 0;
4533
Willy Tarreau9cdde232007-05-02 20:58:19 +02004534 cur_ptr = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004535 cur_end = cur_ptr + txn->rsp.sl.rq.l;
4536
4537 /* Now we have the status line between cur_ptr and cur_end */
4538
4539 /* The annoying part is that pattern matching needs
4540 * that we modify the contents to null-terminate all
4541 * strings before testing them.
4542 */
4543
4544 term = *cur_end;
4545 *cur_end = '\0';
4546
4547 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4548 switch (exp->action) {
4549 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004550 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004551 done = 1;
4552 break;
4553
4554 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004555 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004556 done = 1;
4557 break;
4558
4559 case ACT_REPLACE:
4560 *cur_end = term; /* restore the string terminator */
4561 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4562 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4563 /* FIXME: if the user adds a newline in the replacement, the
4564 * index will not be recalculated for now, and the new line
4565 * will not be counted as a new header.
4566 */
4567
4568 txn->rsp.eoh += delta;
4569 cur_end += delta;
4570
Willy Tarreau9cdde232007-05-02 20:58:19 +02004571 txn->rsp.sol = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004572 cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data,
Willy Tarreau02785762007-04-03 14:45:44 +02004573 HTTP_MSG_RPVER,
Willy Tarreaua15645d2007-03-18 16:22:39 +01004574 cur_ptr, cur_end + 1,
4575 NULL, NULL);
4576 if (unlikely(!cur_end))
4577 return -1;
4578
4579 /* we have a full respnse and we know that we have either a CR
4580 * or an LF at <ptr>.
4581 */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004582 txn->status = strl2ui(rtr->data + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004583 hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.rq.l, *cur_end == '\r');
4584 /* there is no point trying this regex on headers */
4585 return 1;
4586 }
4587 }
4588 *cur_end = term; /* restore the string terminator */
4589 return done;
4590}
4591
4592
4593
4594/*
4595 * Apply all the resp filters <exp> to all headers in buffer <rtr> of session <t>.
4596 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
4597 * unparsable response.
4598 */
4599int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4600{
Willy Tarreau3d300592007-03-18 18:34:41 +01004601 struct http_txn *txn = &t->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004602 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004603 while (exp && !(txn->flags & TX_SVDENY)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004604 int ret;
4605
4606 /*
4607 * The interleaving of transformations and verdicts
4608 * makes it difficult to decide to continue or stop
4609 * the evaluation.
4610 */
4611
Willy Tarreau3d300592007-03-18 18:34:41 +01004612 if ((txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004613 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4614 exp->action == ACT_PASS)) {
4615 exp = exp->next;
4616 continue;
4617 }
4618
4619 /* Apply the filter to the status line. */
4620 ret = apply_filter_to_sts_line(t, rtr, exp);
4621 if (unlikely(ret < 0))
4622 return -1;
4623
4624 if (likely(ret == 0)) {
4625 /* The filter did not match the response, it can be
4626 * iterated through all headers.
4627 */
4628 apply_filter_to_resp_headers(t, rtr, exp);
4629 }
4630 exp = exp->next;
4631 }
4632 return 0;
4633}
4634
4635
4636
4637/*
4638 * Manager server-side cookies
4639 */
4640void manage_server_side_cookies(struct session *t, struct buffer *rtr)
4641{
4642 struct http_txn *txn = &t->txn;
4643 char *p1, *p2, *p3, *p4;
4644
4645 appsess *asession_temp = NULL;
4646 appsess local_asession;
4647
4648 char *cur_ptr, *cur_end, *cur_next;
4649 int cur_idx, old_idx, delta;
4650
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004651 if (t->be->cookie_name == NULL &&
4652 t->be->appsession_name == NULL &&
4653 t->be->capture_name == NULL &&
4654 !(t->be->options & PR_O_CHK_CACHE))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004655 return;
4656
4657 /* Iterate through the headers.
4658 * we start with the start line.
4659 */
4660 old_idx = 0;
4661 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4662
4663 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
4664 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004665 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004666
4667 cur_hdr = &txn->hdr_idx.v[cur_idx];
4668 cur_ptr = cur_next;
4669 cur_end = cur_ptr + cur_hdr->len;
4670 cur_next = cur_end + cur_hdr->cr + 1;
4671
4672 /* We have one full header between cur_ptr and cur_end, and the
4673 * next header starts at cur_next. We're only interested in
4674 * "Cookie:" headers.
4675 */
4676
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004677 val = http_header_match2(cur_ptr, cur_end, "Set-Cookie", 10);
4678 if (!val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004679 old_idx = cur_idx;
4680 continue;
4681 }
4682
4683 /* OK, right now we know we have a set-cookie at cur_ptr */
Willy Tarreau3d300592007-03-18 18:34:41 +01004684 txn->flags |= TX_SCK_ANY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004685
4686
4687 /* maybe we only wanted to see if there was a set-cookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004688 if (t->be->cookie_name == NULL &&
4689 t->be->appsession_name == NULL &&
4690 t->be->capture_name == NULL)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004691 return;
4692
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004693 p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004694
4695 while (p1 < cur_end) { /* in fact, we'll break after the first cookie */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004696 if (p1 == cur_end || *p1 == ';') /* end of cookie */
4697 break;
4698
4699 /* p1 is at the beginning of the cookie name */
4700 p2 = p1;
4701
4702 while (p2 < cur_end && *p2 != '=' && *p2 != ';')
4703 p2++;
4704
4705 if (p2 == cur_end || *p2 == ';') /* next cookie */
4706 break;
4707
4708 p3 = p2 + 1; /* skip the '=' sign */
4709 if (p3 == cur_end)
4710 break;
4711
4712 p4 = p3;
4713 while (p4 < cur_end && !isspace((int)*p4) && *p4 != ';')
4714 p4++;
4715
4716 /* here, we have the cookie name between p1 and p2,
4717 * and its value between p3 and p4.
4718 * we can process it.
4719 */
4720
4721 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004722 if (t->be->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004723 txn->srv_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004724 (p4 - p1 >= t->be->capture_namelen) &&
4725 memcmp(p1, t->be->capture_name, t->be->capture_namelen) == 0) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004726 int log_len = p4 - p1;
4727
Willy Tarreau086b3b42007-05-13 21:45:51 +02004728 if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004729 Alert("HTTP logging : out of memory.\n");
4730 }
4731
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004732 if (log_len > t->be->capture_len)
4733 log_len = t->be->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004734 memcpy(txn->srv_cookie, p1, log_len);
4735 txn->srv_cookie[log_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004736 }
4737
4738 /* now check if we need to process it for persistence */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004739 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4740 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004741 /* Cool... it's the right one */
Willy Tarreau3d300592007-03-18 18:34:41 +01004742 txn->flags |= TX_SCK_SEEN;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004743
4744 /* If the cookie is in insert mode on a known server, we'll delete
4745 * this occurrence because we'll insert another one later.
4746 * We'll delete it too if the "indirect" option is set and we're in
4747 * a direct access. */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004748 if (((t->srv) && (t->be->options & PR_O_COOK_INS)) ||
4749 ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004750 /* this header must be deleted */
4751 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4752 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4753 txn->hdr_idx.used--;
4754 cur_hdr->len = 0;
4755 cur_next += delta;
4756 txn->rsp.eoh += delta;
4757
Willy Tarreau3d300592007-03-18 18:34:41 +01004758 txn->flags |= TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004759 }
4760 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004761 (t->be->options & PR_O_COOK_RW)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004762 /* replace bytes p3->p4 with the cookie name associated
4763 * with this server since we know it.
4764 */
4765 delta = buffer_replace2(rtr, p3, p4, t->srv->cookie, t->srv->cklen);
4766 cur_hdr->len += delta;
4767 cur_next += delta;
4768 txn->rsp.eoh += delta;
4769
Willy Tarreau3d300592007-03-18 18:34:41 +01004770 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004771 }
4772 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004773 (t->be->options & PR_O_COOK_PFX)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004774 /* insert the cookie name associated with this server
4775 * before existing cookie, and insert a delimitor between them..
4776 */
4777 delta = buffer_replace2(rtr, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4778 cur_hdr->len += delta;
4779 cur_next += delta;
4780 txn->rsp.eoh += delta;
4781
4782 p3[t->srv->cklen] = COOKIE_DELIM;
Willy Tarreau3d300592007-03-18 18:34:41 +01004783 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004784 }
4785 }
4786 /* next, let's see if the cookie is our appcookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004787 else if ((t->be->appsession_name != NULL) &&
4788 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004789
4790 /* Cool... it's the right one */
4791
4792 size_t server_id_len = strlen(t->srv->id) + 1;
4793 asession_temp = &local_asession;
4794
Willy Tarreau63963c62007-05-13 21:29:55 +02004795 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004796 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4797 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4798 return;
4799 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004800 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4801 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004802 asession_temp->serverid = NULL;
4803
4804 /* only do insert, if lookup fails */
4805 if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004806 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004807 Alert("Not enough Memory process_srv():asession:calloc().\n");
4808 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
4809 return;
4810 }
4811 asession_temp->sessid = local_asession.sessid;
4812 asession_temp->serverid = local_asession.serverid;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004813 chtbl_insert(&(t->be->htbl_proxy), (void *) asession_temp);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004814 }/* end if (chtbl_lookup()) */
4815 else {
4816 /* free wasted memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004817 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004818 } /* end else from if (chtbl_lookup()) */
4819
4820 if (asession_temp->serverid == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004821 if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004822 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4823 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4824 return;
4825 }
4826 asession_temp->serverid[0] = '\0';
4827 }
4828
4829 if (asession_temp->serverid[0] == '\0')
4830 memcpy(asession_temp->serverid, t->srv->id, server_id_len);
4831
Willy Tarreaud825eef2007-05-12 22:35:00 +02004832 tv_add(&asession_temp->expire, &now, &t->be->appsession_timeout);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004833
4834#if defined(DEBUG_HASH)
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004835 print_table(&(t->be->htbl_proxy));
Willy Tarreaua15645d2007-03-18 16:22:39 +01004836#endif
4837 }/* end if ((t->proxy->appsession_name != NULL) ... */
4838 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4839 } /* we're now at the end of the cookie value */
4840
4841 /* keep the link from this header to next one */
4842 old_idx = cur_idx;
4843 } /* end of cookie processing on this header */
4844}
4845
4846
4847
4848/*
4849 * Check if response is cacheable or not. Updates t->flags.
4850 */
4851void check_response_for_cacheability(struct session *t, struct buffer *rtr)
4852{
4853 struct http_txn *txn = &t->txn;
4854 char *p1, *p2;
4855
4856 char *cur_ptr, *cur_end, *cur_next;
4857 int cur_idx;
4858
Willy Tarreau3d300592007-03-18 18:34:41 +01004859 if (!txn->flags & TX_CACHEABLE)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004860 return;
4861
4862 /* Iterate through the headers.
4863 * we start with the start line.
4864 */
4865 cur_idx = 0;
4866 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4867
4868 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
4869 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004870 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004871
4872 cur_hdr = &txn->hdr_idx.v[cur_idx];
4873 cur_ptr = cur_next;
4874 cur_end = cur_ptr + cur_hdr->len;
4875 cur_next = cur_end + cur_hdr->cr + 1;
4876
4877 /* We have one full header between cur_ptr and cur_end, and the
4878 * next header starts at cur_next. We're only interested in
4879 * "Cookie:" headers.
4880 */
4881
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004882 val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
4883 if (val) {
4884 if ((cur_end - (cur_ptr + val) >= 8) &&
4885 strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
4886 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
4887 return;
4888 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01004889 }
4890
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004891 val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
4892 if (!val)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004893 continue;
4894
4895 /* OK, right now we know we have a cache-control header at cur_ptr */
4896
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004897 p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004898
4899 if (p1 >= cur_end) /* no more info */
4900 continue;
4901
4902 /* p1 is at the beginning of the value */
4903 p2 = p1;
4904
4905 while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((int)*p2))
4906 p2++;
4907
4908 /* we have a complete value between p1 and p2 */
4909 if (p2 < cur_end && *p2 == '=') {
4910 /* we have something of the form no-cache="set-cookie" */
4911 if ((cur_end - p1 >= 21) &&
4912 strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0
4913 && (p1[20] == '"' || p1[20] == ','))
Willy Tarreau3d300592007-03-18 18:34:41 +01004914 txn->flags &= ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004915 continue;
4916 }
4917
4918 /* OK, so we know that either p2 points to the end of string or to a comma */
4919 if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) ||
4920 ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) ||
4921 ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) ||
4922 ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004923 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004924 return;
4925 }
4926
4927 if ((p2 - p1 == 6) && strncasecmp(p1, "public", 6) == 0) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004928 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004929 continue;
4930 }
4931 }
4932}
4933
4934
Willy Tarreau58f10d72006-12-04 02:26:12 +01004935/*
4936 * Try to retrieve a known appsession in the URI, then the associated server.
4937 * If the server is found, it's assigned to the session.
4938 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004939void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004940{
Willy Tarreau3d300592007-03-18 18:34:41 +01004941 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004942 appsess *asession_temp = NULL;
4943 appsess local_asession;
4944 char *request_line;
4945
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004946 if (t->be->appsession_name == NULL ||
Willy Tarreaub326fcc2007-03-03 13:54:32 +01004947 (t->txn.meth != HTTP_METH_GET && t->txn.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004948 (request_line = memchr(begin, ';', len)) == NULL ||
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004949 ((1 + t->be->appsession_name_len + 1 + t->be->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004950 return;
4951
4952 /* skip ';' */
4953 request_line++;
4954
4955 /* look if we have a jsessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004956 if (strncasecmp(request_line, t->be->appsession_name, t->be->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004957 return;
4958
4959 /* skip jsessionid= */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004960 request_line += t->be->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004961
4962 /* First try if we already have an appsession */
4963 asession_temp = &local_asession;
4964
Willy Tarreau63963c62007-05-13 21:29:55 +02004965 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004966 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4967 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4968 return;
4969 }
4970
4971 /* Copy the sessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004972 memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
4973 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004974 asession_temp->serverid = NULL;
4975
4976 /* only do insert, if lookup fails */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004977 if (chtbl_lookup(&(t->be->htbl_proxy), (void *)&asession_temp)) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004978 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004979 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004980 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004981 Alert("Not enough memory process_cli():asession:calloc().\n");
4982 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4983 return;
4984 }
4985 asession_temp->sessid = local_asession.sessid;
4986 asession_temp->serverid = local_asession.serverid;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004987 chtbl_insert(&(t->be->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004988 }
4989 else {
4990 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004991 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004992 }
4993
Willy Tarreaud825eef2007-05-12 22:35:00 +02004994 tv_add(&asession_temp->expire, &now, &t->be->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004995 asession_temp->request_count++;
4996
4997#if defined(DEBUG_HASH)
4998 print_table(&(t->proxy->htbl_proxy));
4999#endif
5000 if (asession_temp->serverid == NULL) {
5001 Alert("Found Application Session without matching server.\n");
5002 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005003 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005004 while (srv) {
5005 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005006 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005007 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01005008 txn->flags &= ~TX_CK_MASK;
5009 txn->flags |= TX_CK_VALID;
5010 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005011 t->srv = srv;
5012 break;
5013 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01005014 txn->flags &= ~TX_CK_MASK;
5015 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005016 }
5017 }
5018 srv = srv->next;
5019 }
5020 }
5021}
5022
5023
Willy Tarreaub2513902006-12-17 14:52:38 +01005024/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005025 * In a GET or HEAD request, check if the requested URI matches the stats uri
5026 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01005027 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005028 * It is assumed that the request is either a HEAD or GET and that the
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005029 * t->be->uri_auth field is valid. An HTTP/401 response may be sent, or
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005030 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01005031 *
5032 * Returns 1 if the session's state changes, otherwise 0.
5033 */
5034int stats_check_uri_auth(struct session *t, struct proxy *backend)
5035{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005036 struct http_txn *txn = &t->txn;
Willy Tarreaub2513902006-12-17 14:52:38 +01005037 struct uri_auth *uri_auth = backend->uri_auth;
5038 struct user_auth *user;
5039 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005040 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01005041
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005042 /* check URI size */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005043 if (uri_auth->uri_len > txn->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01005044 return 0;
5045
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005046 h = t->req->data + txn->req.sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005047
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005048 /* the URI is in h */
5049 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01005050 return 0;
5051
5052 /* we are in front of a interceptable URI. Let's check
5053 * if there's an authentication and if it's valid.
5054 */
5055 user = uri_auth->users;
5056 if (!user) {
5057 /* no user auth required, it's OK */
5058 authenticated = 1;
5059 } else {
5060 authenticated = 0;
5061
5062 /* a user list is defined, we have to check.
5063 * skip 21 chars for "Authorization: Basic ".
5064 */
5065
5066 /* FIXME: this should move to an earlier place */
5067 cur_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005068 h = t->req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
5069 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
5070 int len = txn->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005071 if (len > 14 &&
5072 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005073 txn->auth_hdr.str = h;
5074 txn->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005075 break;
5076 }
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005077 h += len + txn->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01005078 }
5079
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005080 if (txn->auth_hdr.len < 21 ||
5081 memcmp(txn->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01005082 user = NULL;
5083
5084 while (user) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005085 if ((txn->auth_hdr.len == user->user_len + 14 + 7)
5086 && !memcmp(txn->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01005087 user->user_pwd, user->user_len)) {
5088 authenticated = 1;
5089 break;
5090 }
5091 user = user->next;
5092 }
5093 }
5094
5095 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01005096 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01005097
5098 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01005099 msg.str = trash;
5100 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005101 txn->status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01005102 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01005103 if (!(t->flags & SN_ERR_MASK))
5104 t->flags |= SN_ERR_PRXCOND;
5105 if (!(t->flags & SN_FINST_MASK))
5106 t->flags |= SN_FINST_R;
5107 return 1;
5108 }
5109
5110 /* The request is valid, the user is authenticate. Let's start sending
5111 * data.
5112 */
5113 t->cli_state = CL_STSHUTR;
5114 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02005115 t->logs.t_request = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaub2513902006-12-17 14:52:38 +01005116 t->data_source = DATA_SRC_STATS;
5117 t->data_state = DATA_ST_INIT;
5118 produce_content(t);
5119 return 1;
5120}
5121
5122
Willy Tarreaubaaee002006-06-26 02:48:02 +02005123/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01005124 * Print a debug line with a header
5125 */
5126void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
5127{
5128 int len, max;
5129 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
5130 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
5131 max = end - start;
5132 UBOUND(max, sizeof(trash) - len - 1);
5133 len += strlcpy2(trash + len, start, max + 1);
5134 trash[len++] = '\n';
5135 write(1, trash, len);
5136}
5137
5138
Willy Tarreau8797c062007-05-07 00:55:35 +02005139/************************************************************************/
5140/* The code below is dedicated to ACL parsing and matching */
5141/************************************************************************/
5142
5143
5144
5145
5146/* 1. Check on METHOD
5147 * We use the pre-parsed method if it is known, and store its number as an
5148 * integer. If it is unknown, we use the pointer and the length.
5149 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005150static int acl_parse_meth(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005151{
5152 int len, meth;
5153
Willy Tarreauae8b7962007-06-09 23:10:04 +02005154 len = strlen(*text);
5155 meth = find_http_meth(*text, len);
Willy Tarreau8797c062007-05-07 00:55:35 +02005156
5157 pattern->val.i = meth;
5158 if (meth == HTTP_METH_OTHER) {
Willy Tarreauae8b7962007-06-09 23:10:04 +02005159 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005160 if (!pattern->ptr.str)
5161 return 0;
5162 pattern->len = len;
5163 }
5164 return 1;
5165}
5166
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005167static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005168acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
5169 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005170{
5171 int meth;
5172 struct http_txn *txn = l7;
5173
5174 meth = txn->meth;
5175 test->i = meth;
5176 if (meth == HTTP_METH_OTHER) {
5177 test->len = txn->req.sl.rq.m_l;
5178 test->ptr = txn->req.sol;
5179 }
5180 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5181 return 1;
5182}
5183
5184static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
5185{
5186 if (test->i != pattern->val.i)
5187 return 0;
5188
5189 if (test->i != HTTP_METH_OTHER)
5190 return 1;
5191
5192 /* Other method, we must compare the strings */
5193 if (pattern->len != test->len)
5194 return 0;
5195 if (strncmp(pattern->ptr.str, test->ptr, test->len) != 0)
5196 return 0;
5197 return 1;
5198}
5199
5200/* 2. Check on Request/Status Version
5201 * We simply compare strings here.
5202 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005203static int acl_parse_ver(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005204{
Willy Tarreauae8b7962007-06-09 23:10:04 +02005205 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005206 if (!pattern->ptr.str)
5207 return 0;
Willy Tarreauae8b7962007-06-09 23:10:04 +02005208 pattern->len = strlen(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005209 return 1;
5210}
5211
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005212static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005213acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
5214 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005215{
5216 struct http_txn *txn = l7;
5217 char *ptr;
5218 int len;
5219
5220 len = txn->req.sl.rq.v_l;
5221 ptr = txn->req.sol + txn->req.sl.rq.v - txn->req.som;
5222
5223 while ((len-- > 0) && (*ptr++ != '/'));
5224 if (len <= 0)
5225 return 0;
5226
5227 test->ptr = ptr;
5228 test->len = len;
5229
5230 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5231 return 1;
5232}
5233
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005234static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005235acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
5236 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005237{
5238 struct http_txn *txn = l7;
5239 char *ptr;
5240 int len;
5241
5242 len = txn->rsp.sl.st.v_l;
5243 ptr = txn->rsp.sol;
5244
5245 while ((len-- > 0) && (*ptr++ != '/'));
5246 if (len <= 0)
5247 return 0;
5248
5249 test->ptr = ptr;
5250 test->len = len;
5251
5252 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5253 return 1;
5254}
5255
5256/* 3. Check on Status Code. We manipulate integers here. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005257static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005258acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, int dir,
5259 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005260{
5261 struct http_txn *txn = l7;
5262 char *ptr;
5263 int len;
5264
5265 len = txn->rsp.sl.st.c_l;
5266 ptr = txn->rsp.sol + txn->rsp.sl.st.c - txn->rsp.som;
5267
5268 test->i = __strl2ui(ptr, len);
5269 test->flags = ACL_TEST_F_VOL_1ST;
5270 return 1;
5271}
5272
5273/* 4. Check on URL/URI. A pointer to the URI is stored. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005274static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005275acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
5276 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005277{
5278 struct http_txn *txn = l7;
5279
5280 test->len = txn->req.sl.rq.u_l;
5281 test->ptr = txn->req.sol + txn->req.sl.rq.u;
5282
Willy Tarreauf3d25982007-05-08 22:45:09 +02005283 /* we do not need to set READ_ONLY because the data is in a buffer */
5284 test->flags = ACL_TEST_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +02005285 return 1;
5286}
5287
5288
5289
5290/************************************************************************/
5291/* All supported keywords must be declared here. */
5292/************************************************************************/
5293
5294/* Note: must not be declared <const> as its list will be overwritten */
5295static struct acl_kw_list acl_kws = {{ },{
5296 { "method", acl_parse_meth, acl_fetch_meth, acl_match_meth },
5297 { "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str },
5298 { "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str },
Willy Tarreauae8b7962007-06-09 23:10:04 +02005299 { "status", acl_parse_int, acl_fetch_stcode, acl_match_int },
Willy Tarreau8797c062007-05-07 00:55:35 +02005300
Willy Tarreauae8b7962007-06-09 23:10:04 +02005301 { "url", acl_parse_str, acl_fetch_url, acl_match_str },
5302 { "url_beg", acl_parse_str, acl_fetch_url, acl_match_beg },
5303 { "url_end", acl_parse_str, acl_fetch_url, acl_match_end },
5304 { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub },
5305 { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir },
5306 { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom },
5307 { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg },
Willy Tarreau8797c062007-05-07 00:55:35 +02005308
Willy Tarreauf3d25982007-05-08 22:45:09 +02005309 { NULL, NULL, NULL, NULL },
5310
5311#if 0
Willy Tarreau8797c062007-05-07 00:55:35 +02005312 { "line", acl_parse_str, acl_fetch_line, acl_match_str },
5313 { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg },
5314 { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg },
5315 { "line_end", acl_parse_str, acl_fetch_line, acl_match_end },
5316 { "line_sub", acl_parse_str, acl_fetch_line, acl_match_sub },
5317 { "line_dir", acl_parse_str, acl_fetch_line, acl_match_dir },
5318 { "line_dom", acl_parse_str, acl_fetch_line, acl_match_dom },
5319
5320 { "path", acl_parse_str, acl_fetch_path, acl_match_str },
5321 { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg },
5322 { "path_beg", acl_parse_str, acl_fetch_path, acl_match_beg },
5323 { "path_end", acl_parse_str, acl_fetch_path, acl_match_end },
5324 { "path_sub", acl_parse_str, acl_fetch_path, acl_match_sub },
5325 { "path_dir", acl_parse_str, acl_fetch_path, acl_match_dir },
5326 { "path_dom", acl_parse_str, acl_fetch_path, acl_match_dom },
5327
5328 { "hdr", acl_parse_str, acl_fetch_hdr, acl_match_str },
5329 { "hdr_reg", acl_parse_reg, acl_fetch_hdr, acl_match_reg },
5330 { "hdr_beg", acl_parse_str, acl_fetch_hdr, acl_match_beg },
5331 { "hdr_end", acl_parse_str, acl_fetch_hdr, acl_match_end },
5332 { "hdr_sub", acl_parse_str, acl_fetch_hdr, acl_match_sub },
5333 { "hdr_dir", acl_parse_str, acl_fetch_hdr, acl_match_dir },
5334 { "hdr_dom", acl_parse_str, acl_fetch_hdr, acl_match_dom },
5335 { "hdr_pst", acl_parse_none, acl_fetch_hdr, acl_match_pst },
5336
5337 { "cook", acl_parse_str, acl_fetch_cook, acl_match_str },
5338 { "cook_reg", acl_parse_reg, acl_fetch_cook, acl_match_reg },
5339 { "cook_beg", acl_parse_str, acl_fetch_cook, acl_match_beg },
5340 { "cook_end", acl_parse_str, acl_fetch_cook, acl_match_end },
5341 { "cook_sub", acl_parse_str, acl_fetch_cook, acl_match_sub },
5342 { "cook_dir", acl_parse_str, acl_fetch_cook, acl_match_dir },
5343 { "cook_dom", acl_parse_str, acl_fetch_cook, acl_match_dom },
5344 { "cook_pst", acl_parse_none, acl_fetch_cook, acl_match_pst },
5345
5346 { "auth_user", acl_parse_str, acl_fetch_user, acl_match_str },
5347 { "auth_regex", acl_parse_reg, acl_fetch_user, acl_match_reg },
5348 { "auth_clear", acl_parse_str, acl_fetch_auth, acl_match_str },
5349 { "auth_md5", acl_parse_str, acl_fetch_auth, acl_match_md5 },
5350 { NULL, NULL, NULL, NULL },
5351#endif
5352}};
5353
5354
5355__attribute__((constructor))
5356static void __http_protocol_init(void)
5357{
5358 acl_register_keywords(&acl_kws);
5359}
5360
5361
Willy Tarreau58f10d72006-12-04 02:26:12 +01005362/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02005363 * Local variables:
5364 * c-indent-level: 8
5365 * c-basic-offset: 8
5366 * End:
5367 */