blob: 9ab5a80c5d8f7a2161e4648a6e0296e31e3965e4 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * HTTP protocol analyzer
3 *
Willy Tarreau7c669d72008-06-20 15:04:11 +02004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <syslog.h>
Willy Tarreau42250582007-04-01 01:30:43 +020020#include <time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020021
22#include <sys/socket.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25
Willy Tarreau2dd0d472006-06-29 17:53:05 +020026#include <common/appsession.h>
27#include <common/compat.h>
28#include <common/config.h>
Willy Tarreaua4cd1f52006-12-16 19:57:26 +010029#include <common/debug.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020030#include <common/memory.h>
31#include <common/mini-clist.h>
32#include <common/standard.h>
Willy Tarreau0c303ee2008-07-07 00:09:58 +020033#include <common/ticks.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020034#include <common/time.h>
35#include <common/uri_auth.h>
36#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020037
38#include <types/capture.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020039#include <types/global.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020040
Willy Tarreau8797c062007-05-07 00:55:35 +020041#include <proto/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020042#include <proto/backend.h>
43#include <proto/buffers.h>
Willy Tarreau91861262007-10-17 17:06:05 +020044#include <proto/dumpstats.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020045#include <proto/fd.h>
46#include <proto/log.h>
Willy Tarreau58f10d72006-12-04 02:26:12 +010047#include <proto/hdr_idx.h>
Willy Tarreaub6866442008-07-14 23:54:42 +020048#include <proto/proto_tcp.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020049#include <proto/proto_http.h>
50#include <proto/queue.h>
Willy Tarreau91861262007-10-17 17:06:05 +020051#include <proto/senddata.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020052#include <proto/session.h>
53#include <proto/task.h>
54
Willy Tarreau6d1a9882007-01-07 02:03:04 +010055#ifdef CONFIG_HAP_TCPSPLICE
56#include <libtcpsplice.h>
57#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020058
Willy Tarreau58f10d72006-12-04 02:26:12 +010059#define DEBUG_PARSE_NO_SPEEDUP
60#undef DEBUG_PARSE_NO_SPEEDUP
61
Willy Tarreau976f1ee2006-12-17 10:06:03 +010062/* This is used to perform a quick jump as an alternative to a break/continue
63 * instruction. The first argument is the label for normal operation, and the
64 * second one is the break/continue instruction in the no_speedup mode.
65 */
66
67#ifdef DEBUG_PARSE_NO_SPEEDUP
68#define QUICK_JUMP(x,y) y
69#else
70#define QUICK_JUMP(x,y) goto x
71#endif
72
Willy Tarreau1c47f852006-07-09 08:22:27 +020073/* This is used by remote monitoring */
Willy Tarreau0f772532006-12-23 20:51:41 +010074const char HTTP_200[] =
Willy Tarreau1c47f852006-07-09 08:22:27 +020075 "HTTP/1.0 200 OK\r\n"
76 "Cache-Control: no-cache\r\n"
77 "Connection: close\r\n"
78 "Content-Type: text/html\r\n"
79 "\r\n"
80 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
81
Willy Tarreau0f772532006-12-23 20:51:41 +010082const struct chunk http_200_chunk = {
83 .str = (char *)&HTTP_200,
84 .len = sizeof(HTTP_200)-1
85};
86
Willy Tarreaub463dfb2008-06-07 23:08:56 +020087const char *HTTP_301 =
88 "HTTP/1.0 301 Moved Permantenly\r\n"
89 "Cache-Control: no-cache\r\n"
90 "Connection: close\r\n"
91 "Location: "; /* not terminated since it will be concatenated with the URL */
92
Willy Tarreau0f772532006-12-23 20:51:41 +010093const char *HTTP_302 =
94 "HTTP/1.0 302 Found\r\n"
95 "Cache-Control: no-cache\r\n"
96 "Connection: close\r\n"
97 "Location: "; /* not terminated since it will be concatenated with the URL */
98
99/* same as 302 except that the browser MUST retry with the GET method */
100const char *HTTP_303 =
101 "HTTP/1.0 303 See Other\r\n"
102 "Cache-Control: no-cache\r\n"
103 "Connection: close\r\n"
104 "Location: "; /* not terminated since it will be concatenated with the URL */
105
Willy Tarreaubaaee002006-06-26 02:48:02 +0200106/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
107const char *HTTP_401_fmt =
108 "HTTP/1.0 401 Unauthorized\r\n"
109 "Cache-Control: no-cache\r\n"
110 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +0200111 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200112 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
113 "\r\n"
114 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
115
Willy Tarreau0f772532006-12-23 20:51:41 +0100116
117const int http_err_codes[HTTP_ERR_SIZE] = {
118 [HTTP_ERR_400] = 400,
119 [HTTP_ERR_403] = 403,
120 [HTTP_ERR_408] = 408,
121 [HTTP_ERR_500] = 500,
122 [HTTP_ERR_502] = 502,
123 [HTTP_ERR_503] = 503,
124 [HTTP_ERR_504] = 504,
125};
126
Willy Tarreau80587432006-12-24 17:47:20 +0100127static const char *http_err_msgs[HTTP_ERR_SIZE] = {
Willy Tarreau0f772532006-12-23 20:51:41 +0100128 [HTTP_ERR_400] =
Willy Tarreau80587432006-12-24 17:47:20 +0100129 "HTTP/1.0 400 Bad request\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +0100130 "Cache-Control: no-cache\r\n"
131 "Connection: close\r\n"
132 "Content-Type: text/html\r\n"
133 "\r\n"
134 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
135
136 [HTTP_ERR_403] =
137 "HTTP/1.0 403 Forbidden\r\n"
138 "Cache-Control: no-cache\r\n"
139 "Connection: close\r\n"
140 "Content-Type: text/html\r\n"
141 "\r\n"
142 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
143
144 [HTTP_ERR_408] =
145 "HTTP/1.0 408 Request Time-out\r\n"
146 "Cache-Control: no-cache\r\n"
147 "Connection: close\r\n"
148 "Content-Type: text/html\r\n"
149 "\r\n"
150 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
151
152 [HTTP_ERR_500] =
153 "HTTP/1.0 500 Server Error\r\n"
154 "Cache-Control: no-cache\r\n"
155 "Connection: close\r\n"
156 "Content-Type: text/html\r\n"
157 "\r\n"
158 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n",
159
160 [HTTP_ERR_502] =
161 "HTTP/1.0 502 Bad Gateway\r\n"
162 "Cache-Control: no-cache\r\n"
163 "Connection: close\r\n"
164 "Content-Type: text/html\r\n"
165 "\r\n"
166 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n",
167
168 [HTTP_ERR_503] =
169 "HTTP/1.0 503 Service Unavailable\r\n"
170 "Cache-Control: no-cache\r\n"
171 "Connection: close\r\n"
172 "Content-Type: text/html\r\n"
173 "\r\n"
174 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n",
175
176 [HTTP_ERR_504] =
177 "HTTP/1.0 504 Gateway Time-out\r\n"
178 "Cache-Control: no-cache\r\n"
179 "Connection: close\r\n"
180 "Content-Type: text/html\r\n"
181 "\r\n"
182 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n",
183
184};
185
Willy Tarreau80587432006-12-24 17:47:20 +0100186/* We must put the messages here since GCC cannot initialize consts depending
187 * on strlen().
188 */
189struct chunk http_err_chunks[HTTP_ERR_SIZE];
190
Willy Tarreau42250582007-04-01 01:30:43 +0200191#define FD_SETS_ARE_BITFIELDS
192#ifdef FD_SETS_ARE_BITFIELDS
193/*
194 * This map is used with all the FD_* macros to check whether a particular bit
195 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
196 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
197 * byte should be encoded. Be careful to always pass bytes from 0 to 255
198 * exclusively to the macros.
199 */
200fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
201fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
202
203#else
204#error "Check if your OS uses bitfields for fd_sets"
205#endif
206
Willy Tarreau80587432006-12-24 17:47:20 +0100207void init_proto_http()
208{
Willy Tarreau42250582007-04-01 01:30:43 +0200209 int i;
210 char *tmp;
Willy Tarreau80587432006-12-24 17:47:20 +0100211 int msg;
Willy Tarreau42250582007-04-01 01:30:43 +0200212
Willy Tarreau80587432006-12-24 17:47:20 +0100213 for (msg = 0; msg < HTTP_ERR_SIZE; msg++) {
214 if (!http_err_msgs[msg]) {
215 Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n", msg);
216 abort();
217 }
218
219 http_err_chunks[msg].str = (char *)http_err_msgs[msg];
220 http_err_chunks[msg].len = strlen(http_err_msgs[msg]);
221 }
Willy Tarreau42250582007-04-01 01:30:43 +0200222
223 /* initialize the log header encoding map : '{|}"#' should be encoded with
224 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
225 * URL encoding only requires '"', '#' to be encoded as well as non-
226 * printable characters above.
227 */
228 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
229 memset(url_encode_map, 0, sizeof(url_encode_map));
230 for (i = 0; i < 32; i++) {
231 FD_SET(i, hdr_encode_map);
232 FD_SET(i, url_encode_map);
233 }
234 for (i = 127; i < 256; i++) {
235 FD_SET(i, hdr_encode_map);
236 FD_SET(i, url_encode_map);
237 }
238
239 tmp = "\"#{|}";
240 while (*tmp) {
241 FD_SET(*tmp, hdr_encode_map);
242 tmp++;
243 }
244
245 tmp = "\"#";
246 while (*tmp) {
247 FD_SET(*tmp, url_encode_map);
248 tmp++;
249 }
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200250
251 /* memory allocations */
252 pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED);
Willy Tarreau086b3b42007-05-13 21:45:51 +0200253 pool2_capture = create_pool("capture", CAPTURE_LEN, MEM_F_SHARED);
Willy Tarreau80587432006-12-24 17:47:20 +0100254}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200255
Willy Tarreau53b6c742006-12-17 13:37:46 +0100256/*
257 * We have 26 list of methods (1 per first letter), each of which can have
258 * up to 3 entries (2 valid, 1 null).
259 */
260struct http_method_desc {
261 http_meth_t meth;
262 int len;
263 const char text[8];
264};
265
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100266const struct http_method_desc http_methods[26][3] = {
Willy Tarreau53b6c742006-12-17 13:37:46 +0100267 ['C' - 'A'] = {
268 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
269 },
270 ['D' - 'A'] = {
271 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
272 },
273 ['G' - 'A'] = {
274 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
275 },
276 ['H' - 'A'] = {
277 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
278 },
279 ['P' - 'A'] = {
280 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
281 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
282 },
283 ['T' - 'A'] = {
284 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
285 },
286 /* rest is empty like this :
287 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
288 */
289};
290
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100291/* It is about twice as fast on recent architectures to lookup a byte in a
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +0200292 * table than to perform a boolean AND or OR between two tests. Refer to
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100293 * RFC2616 for those chars.
294 */
295
296const char http_is_spht[256] = {
297 [' '] = 1, ['\t'] = 1,
298};
299
300const char http_is_crlf[256] = {
301 ['\r'] = 1, ['\n'] = 1,
302};
303
304const char http_is_lws[256] = {
305 [' '] = 1, ['\t'] = 1,
306 ['\r'] = 1, ['\n'] = 1,
307};
308
309const char http_is_sep[256] = {
310 ['('] = 1, [')'] = 1, ['<'] = 1, ['>'] = 1,
311 ['@'] = 1, [','] = 1, [';'] = 1, [':'] = 1,
312 ['"'] = 1, ['/'] = 1, ['['] = 1, [']'] = 1,
313 ['{'] = 1, ['}'] = 1, ['?'] = 1, ['='] = 1,
314 [' '] = 1, ['\t'] = 1, ['\\'] = 1,
315};
316
317const char http_is_ctl[256] = {
318 [0 ... 31] = 1,
319 [127] = 1,
320};
321
322/*
323 * A token is any ASCII char that is neither a separator nor a CTL char.
324 * Do not overwrite values in assignment since gcc-2.95 will not handle
325 * them correctly. Instead, define every non-CTL char's status.
326 */
327const char http_is_token[256] = {
328 [' '] = 0, ['!'] = 1, ['"'] = 0, ['#'] = 1,
329 ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1,
330 ['('] = 0, [')'] = 0, ['*'] = 1, ['+'] = 1,
331 [','] = 0, ['-'] = 1, ['.'] = 1, ['/'] = 0,
332 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1,
333 ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1,
334 ['8'] = 1, ['9'] = 1, [':'] = 0, [';'] = 0,
335 ['<'] = 0, ['='] = 0, ['>'] = 0, ['?'] = 0,
336 ['@'] = 0, ['A'] = 1, ['B'] = 1, ['C'] = 1,
337 ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1,
338 ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1,
339 ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1,
340 ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1,
341 ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1,
342 ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 0,
343 ['\\'] = 0, [']'] = 0, ['^'] = 1, ['_'] = 1,
344 ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1,
345 ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1,
346 ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1,
347 ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1,
348 ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1,
349 ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1,
350 ['x'] = 1, ['y'] = 1, ['z'] = 1, ['{'] = 0,
351 ['|'] = 1, ['}'] = 0, ['~'] = 1,
352};
353
354
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100355/*
356 * An http ver_token is any ASCII which can be found in an HTTP version,
357 * which includes 'H', 'T', 'P', '/', '.' and any digit.
358 */
359const char http_is_ver_token[256] = {
360 ['.'] = 1, ['/'] = 1,
361 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1,
362 ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1,
363 ['H'] = 1, ['P'] = 1, ['T'] = 1,
364};
365
366
Willy Tarreaubaaee002006-06-26 02:48:02 +0200367#ifdef DEBUG_FULL
368static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
369static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
370#endif
371
Willy Tarreau42250582007-04-01 01:30:43 +0200372static void http_sess_log(struct session *s);
373
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100374/*
375 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
376 * CRLF. Text length is measured first, so it cannot be NULL.
377 * The header is also automatically added to the index <hdr_idx>, and the end
378 * of headers is automatically adjusted. The number of bytes added is returned
379 * on success, otherwise <0 is returned indicating an error.
380 */
381int http_header_add_tail(struct buffer *b, struct http_msg *msg,
382 struct hdr_idx *hdr_idx, const char *text)
383{
384 int bytes, len;
385
386 len = strlen(text);
387 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
388 if (!bytes)
389 return -1;
390 msg->eoh += bytes;
391 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
392}
393
394/*
395 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
396 * CRLF. <len> bytes are copied, not counting the CRLF. If <text> is NULL, then
397 * the buffer is only opened and the space reserved, but nothing is copied.
398 * The header is also automatically added to the index <hdr_idx>, and the end
399 * of headers is automatically adjusted. The number of bytes added is returned
400 * on success, otherwise <0 is returned indicating an error.
401 */
402int http_header_add_tail2(struct buffer *b, struct http_msg *msg,
403 struct hdr_idx *hdr_idx, const char *text, int len)
404{
405 int bytes;
406
407 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
408 if (!bytes)
409 return -1;
410 msg->eoh += bytes;
411 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
412}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200413
414/*
Willy Tarreauaa9dce32007-03-18 23:50:16 +0100415 * Checks if <hdr> is exactly <name> for <len> chars, and ends with a colon.
416 * If so, returns the position of the first non-space character relative to
417 * <hdr>, or <end>-<hdr> if not found before. If no value is found, it tries
418 * to return a pointer to the place after the first space. Returns 0 if the
419 * header name does not match. Checks are case-insensitive.
420 */
421int http_header_match2(const char *hdr, const char *end,
422 const char *name, int len)
423{
424 const char *val;
425
426 if (hdr + len >= end)
427 return 0;
428 if (hdr[len] != ':')
429 return 0;
430 if (strncasecmp(hdr, name, len) != 0)
431 return 0;
432 val = hdr + len + 1;
433 while (val < end && HTTP_IS_SPHT(*val))
434 val++;
435 if ((val >= end) && (len + 2 <= end - hdr))
436 return len + 2; /* we may replace starting from second space */
437 return val - hdr;
438}
439
Willy Tarreau33a7e692007-06-10 19:45:56 +0200440/* Find the end of the header value contained between <s> and <e>.
441 * See RFC2616, par 2.2 for more information. Note that it requires
442 * a valid header to return a valid result.
443 */
444const char *find_hdr_value_end(const char *s, const char *e)
445{
446 int quoted, qdpair;
447
448 quoted = qdpair = 0;
449 for (; s < e; s++) {
450 if (qdpair) qdpair = 0;
451 else if (quoted && *s == '\\') qdpair = 1;
452 else if (quoted && *s == '"') quoted = 0;
453 else if (*s == '"') quoted = 1;
454 else if (*s == ',') return s;
455 }
456 return s;
457}
458
459/* Find the first or next occurrence of header <name> in message buffer <sol>
460 * using headers index <idx>, and return it in the <ctx> structure. This
461 * structure holds everything necessary to use the header and find next
462 * occurrence. If its <idx> member is 0, the header is searched from the
463 * beginning. Otherwise, the next occurrence is returned. The function returns
464 * 1 when it finds a value, and 0 when there is no more.
465 */
466int http_find_header2(const char *name, int len,
467 const char *sol, struct hdr_idx *idx,
468 struct hdr_ctx *ctx)
469{
470 __label__ return_hdr, next_hdr;
471 const char *eol, *sov;
472 int cur_idx;
473
474 if (ctx->idx) {
475 /* We have previously returned a value, let's search
476 * another one on the same line.
477 */
478 cur_idx = ctx->idx;
479 sol = ctx->line;
480 sov = sol + ctx->val + ctx->vlen;
481 eol = sol + idx->v[cur_idx].len;
482
483 if (sov >= eol)
484 /* no more values in this header */
485 goto next_hdr;
486
487 /* values remaining for this header, skip the comma */
488 sov++;
489 while (sov < eol && http_is_lws[(unsigned char)*sov])
490 sov++;
491
492 goto return_hdr;
493 }
494
495 /* first request for this header */
496 sol += hdr_idx_first_pos(idx);
497 cur_idx = hdr_idx_first_idx(idx);
498
499 while (cur_idx) {
500 eol = sol + idx->v[cur_idx].len;
501
Willy Tarreau1ad7c6d2007-06-10 21:42:55 +0200502 if (len == 0) {
503 /* No argument was passed, we want any header.
504 * To achieve this, we simply build a fake request. */
505 while (sol + len < eol && sol[len] != ':')
506 len++;
507 name = sol;
508 }
509
Willy Tarreau33a7e692007-06-10 19:45:56 +0200510 if ((len < eol - sol) &&
511 (sol[len] == ':') &&
512 (strncasecmp(sol, name, len) == 0)) {
513
514 sov = sol + len + 1;
515 while (sov < eol && http_is_lws[(unsigned char)*sov])
516 sov++;
517 return_hdr:
518 ctx->line = sol;
519 ctx->idx = cur_idx;
520 ctx->val = sov - sol;
521
522 eol = find_hdr_value_end(sov, eol);
523 ctx->vlen = eol - sov;
524 return 1;
525 }
526 next_hdr:
527 sol = eol + idx->v[cur_idx].cr + 1;
528 cur_idx = idx->v[cur_idx].next;
529 }
530 return 0;
531}
532
533int http_find_header(const char *name,
534 const char *sol, struct hdr_idx *idx,
535 struct hdr_ctx *ctx)
536{
537 return http_find_header2(name, strlen(name), sol, idx, ctx);
538}
539
Willy Tarreaubaaee002006-06-26 02:48:02 +0200540/* This function turns the server state into the SV_STCLOSE, and sets
Willy Tarreau0f772532006-12-23 20:51:41 +0100541 * indicators accordingly. Note that if <status> is 0, or if the message
542 * pointer is NULL, then no message is returned.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200543 */
544void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreau0f772532006-12-23 20:51:41 +0100545 int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200546{
547 t->srv_state = SV_STCLOSE;
Willy Tarreau0f772532006-12-23 20:51:41 +0100548 if (status > 0 && msg) {
Willy Tarreau3bac9ff2007-03-18 17:31:28 +0100549 t->txn.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100550 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100551 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200552 }
553 if (!(t->flags & SN_ERR_MASK))
554 t->flags |= err;
555 if (!(t->flags & SN_FINST_MASK))
556 t->flags |= finst;
557}
558
Willy Tarreau80587432006-12-24 17:47:20 +0100559/* This function returns the appropriate error location for the given session
560 * and message.
561 */
562
563struct chunk *error_message(struct session *s, int msgnum)
564{
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200565 if (s->be->errmsg[msgnum].str)
566 return &s->be->errmsg[msgnum];
Willy Tarreau80587432006-12-24 17:47:20 +0100567 else if (s->fe->errmsg[msgnum].str)
568 return &s->fe->errmsg[msgnum];
569 else
570 return &http_err_chunks[msgnum];
571}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200572
Willy Tarreau53b6c742006-12-17 13:37:46 +0100573/*
574 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
575 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
576 */
577static http_meth_t find_http_meth(const char *str, const int len)
578{
579 unsigned char m;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100580 const struct http_method_desc *h;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100581
582 m = ((unsigned)*str - 'A');
583
584 if (m < 26) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100585 for (h = http_methods[m]; h->len > 0; h++) {
586 if (unlikely(h->len != len))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100587 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100588 if (likely(memcmp(str, h->text, h->len) == 0))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100589 return h->meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100590 };
591 return HTTP_METH_OTHER;
592 }
593 return HTTP_METH_NONE;
594
595}
596
Willy Tarreau21d2af32008-02-14 20:25:24 +0100597/* Parse the URI from the given transaction (which is assumed to be in request
598 * phase) and look for the "/" beginning the PATH. If not found, return NULL.
599 * It is returned otherwise.
600 */
601static char *
602http_get_path(struct http_txn *txn)
603{
604 char *ptr, *end;
605
606 ptr = txn->req.sol + txn->req.sl.rq.u;
607 end = ptr + txn->req.sl.rq.u_l;
608
609 if (ptr >= end)
610 return NULL;
611
612 /* RFC2616, par. 5.1.2 :
613 * Request-URI = "*" | absuri | abspath | authority
614 */
615
616 if (*ptr == '*')
617 return NULL;
618
619 if (isalpha((unsigned char)*ptr)) {
620 /* this is a scheme as described by RFC3986, par. 3.1 */
621 ptr++;
622 while (ptr < end &&
623 (isalnum((unsigned char)*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.'))
624 ptr++;
625 /* skip '://' */
626 if (ptr == end || *ptr++ != ':')
627 return NULL;
628 if (ptr == end || *ptr++ != '/')
629 return NULL;
630 if (ptr == end || *ptr++ != '/')
631 return NULL;
632 }
633 /* skip [user[:passwd]@]host[:[port]] */
634
635 while (ptr < end && *ptr != '/')
636 ptr++;
637
638 if (ptr == end)
639 return NULL;
640
641 /* OK, we got the '/' ! */
642 return ptr;
643}
644
Willy Tarreaubaaee002006-06-26 02:48:02 +0200645/* Processes the client and server jobs of a session task, then
646 * puts it back to the wait queue in a clean state, or
647 * cleans up its resources if it must be deleted. Returns
648 * the time the task accepts to wait, or TIME_ETERNITY for
649 * infinity.
650 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200651void process_session(struct task *t, int *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200652{
653 struct session *s = t->context;
654 int fsm_resync = 0;
655
656 do {
657 fsm_resync = 0;
658 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
659 fsm_resync |= process_cli(s);
660 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
661 fsm_resync |= process_srv(s);
662 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
663 } while (fsm_resync);
664
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200665 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100666
667 if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
668 session_process_counters(s);
669
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200670 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
671 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200672
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200673 t->expire = tick_first(tick_first(s->req->rex, s->req->wex),
674 tick_first(s->rep->rex, s->rep->wex));
675 t->expire = tick_first(t->expire, s->req->cex);
Willy Tarreau036fae02008-01-06 13:24:40 +0100676 if (s->cli_state == CL_STHEADERS)
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200677 t->expire = tick_first(t->expire, s->txn.exp);
Willy Tarreaub6866442008-07-14 23:54:42 +0200678 else if (s->cli_state == CL_STINSPECT)
679 t->expire = tick_first(t->expire, s->inspect_exp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200680
681 /* restore t to its place in the task list */
682 task_queue(t);
683
Willy Tarreaud825eef2007-05-12 22:35:00 +0200684 *next = t->expire;
685 return; /* nothing more to do */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200686 }
687
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100688 s->fe->feconn--;
689 if (s->flags & SN_BE_ASSIGNED)
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200690 s->be->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200691 actconn--;
692
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200693 if (unlikely((global.mode & MODE_DEBUG) &&
694 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200695 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100696 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200697 s->uniq_id, s->be->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100698 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200699 write(1, trash, len);
700 }
701
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200702 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100703 session_process_counters(s);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200704
705 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200706 if (s->logs.logwait &&
707 !(s->flags & SN_MONITOR) &&
Willy Tarreau42250582007-04-01 01:30:43 +0200708 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total)) {
709 if (s->fe->to_log & LW_REQ)
710 http_sess_log(s);
711 else
712 tcp_sess_log(s);
713 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200714
715 /* the task MUST not be in the run queue anymore */
716 task_delete(t);
717 session_free(s);
718 task_free(t);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200719 *next = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200720}
721
722
Willy Tarreau42250582007-04-01 01:30:43 +0200723extern const char sess_term_cond[8];
724extern const char sess_fin_state[8];
725extern const char *monthname[12];
726const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
727const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
728 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
729 unknown, Set-cookie Rewritten */
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200730struct pool_head *pool2_requri;
Willy Tarreau086b3b42007-05-13 21:45:51 +0200731struct pool_head *pool2_capture;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100732
Willy Tarreau42250582007-04-01 01:30:43 +0200733/*
734 * send a log for the session when we have enough info about it.
735 * Will not log if the frontend has no log defined.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100736 */
Willy Tarreau42250582007-04-01 01:30:43 +0200737static void http_sess_log(struct session *s)
738{
739 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
740 struct proxy *fe = s->fe;
741 struct proxy *be = s->be;
742 struct proxy *prx_log;
743 struct http_txn *txn = &s->txn;
744 int tolog;
745 char *uri, *h;
746 char *svid;
Willy Tarreaufe944602007-10-25 10:34:16 +0200747 struct tm tm;
Willy Tarreau42250582007-04-01 01:30:43 +0200748 static char tmpline[MAX_SYSLOG_LEN];
Willy Tarreau70089872008-06-13 21:12:51 +0200749 int t_request;
Willy Tarreau42250582007-04-01 01:30:43 +0200750 int hdr;
751
752 if (fe->logfac1 < 0 && fe->logfac2 < 0)
753 return;
754 prx_log = fe;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100755
Willy Tarreau42250582007-04-01 01:30:43 +0200756 if (s->cli_addr.ss_family == AF_INET)
757 inet_ntop(AF_INET,
758 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
759 pn, sizeof(pn));
760 else
761 inet_ntop(AF_INET6,
762 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
763 pn, sizeof(pn));
764
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200765 get_localtime(s->logs.accept_date.tv_sec, &tm);
Willy Tarreau42250582007-04-01 01:30:43 +0200766
767 /* FIXME: let's limit ourselves to frontend logging for now. */
768 tolog = fe->to_log;
769
770 h = tmpline;
771 if (fe->to_log & LW_REQHDR &&
772 txn->req.cap &&
773 (h < tmpline + sizeof(tmpline) - 10)) {
774 *(h++) = ' ';
775 *(h++) = '{';
776 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
777 if (hdr)
778 *(h++) = '|';
779 if (txn->req.cap[hdr] != NULL)
780 h = encode_string(h, tmpline + sizeof(tmpline) - 7,
781 '#', hdr_encode_map, txn->req.cap[hdr]);
782 }
783 *(h++) = '}';
784 }
785
786 if (fe->to_log & LW_RSPHDR &&
787 txn->rsp.cap &&
788 (h < tmpline + sizeof(tmpline) - 7)) {
789 *(h++) = ' ';
790 *(h++) = '{';
791 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
792 if (hdr)
793 *(h++) = '|';
794 if (txn->rsp.cap[hdr] != NULL)
795 h = encode_string(h, tmpline + sizeof(tmpline) - 4,
796 '#', hdr_encode_map, txn->rsp.cap[hdr]);
797 }
798 *(h++) = '}';
799 }
800
801 if (h < tmpline + sizeof(tmpline) - 4) {
802 *(h++) = ' ';
803 *(h++) = '"';
804 uri = txn->uri ? txn->uri : "<BADREQ>";
805 h = encode_string(h, tmpline + sizeof(tmpline) - 1,
806 '#', url_encode_map, uri);
807 *(h++) = '"';
808 }
809 *h = '\0';
810
811 svid = (tolog & LW_SVID) ?
812 (s->data_source != DATA_SRC_STATS) ?
813 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
814
Willy Tarreau70089872008-06-13 21:12:51 +0200815 t_request = -1;
816 if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
817 t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
818
Willy Tarreau42250582007-04-01 01:30:43 +0200819 send_log(prx_log, LOG_INFO,
820 "%s:%d [%02d/%s/%04d:%02d:%02d:%02d.%03d]"
821 " %s %s/%s %d/%d/%d/%d/%s%d %d %s%lld"
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100822 " %s %s %c%c%c%c %d/%d/%d/%d/%s%u %d/%d%s\n",
Willy Tarreau42250582007-04-01 01:30:43 +0200823 pn,
824 (s->cli_addr.ss_family == AF_INET) ?
825 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
826 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
Willy Tarreaufe944602007-10-25 10:34:16 +0200827 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200828 tm.tm_hour, tm.tm_min, tm.tm_sec, s->logs.accept_date.tv_usec/1000,
Willy Tarreau42250582007-04-01 01:30:43 +0200829 fe->id, be->id, svid,
Willy Tarreau70089872008-06-13 21:12:51 +0200830 t_request,
831 (s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1,
Willy Tarreau42250582007-04-01 01:30:43 +0200832 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
833 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
834 (tolog & LW_BYTES) ? "" : "+", s->logs.t_close,
835 txn->status,
Willy Tarreau8b3977f2008-01-18 11:16:32 +0100836 (tolog & LW_BYTES) ? "" : "+", s->logs.bytes_out,
Willy Tarreau42250582007-04-01 01:30:43 +0200837 txn->cli_cookie ? txn->cli_cookie : "-",
838 txn->srv_cookie ? txn->srv_cookie : "-",
839 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
840 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
841 (be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-',
842 (be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-',
843 actconn, fe->feconn, be->beconn, s->srv ? s->srv->cur_sess : 0,
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100844 (s->flags & SN_REDISP)?"+":"",
845 (s->conn_retries>0)?(be->conn_retries - s->conn_retries):be->conn_retries,
Willy Tarreau42250582007-04-01 01:30:43 +0200846 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
847
848 s->logs.logwait = 0;
849}
850
Willy Tarreau117f59e2007-03-04 18:17:17 +0100851
852/*
853 * Capture headers from message starting at <som> according to header list
854 * <cap_hdr>, and fill the <idx> structure appropriately.
855 */
856void capture_headers(char *som, struct hdr_idx *idx,
857 char **cap, struct cap_hdr *cap_hdr)
858{
859 char *eol, *sol, *col, *sov;
860 int cur_idx;
861 struct cap_hdr *h;
862 int len;
863
864 sol = som + hdr_idx_first_pos(idx);
865 cur_idx = hdr_idx_first_idx(idx);
866
867 while (cur_idx) {
868 eol = sol + idx->v[cur_idx].len;
869
870 col = sol;
871 while (col < eol && *col != ':')
872 col++;
873
874 sov = col + 1;
875 while (sov < eol && http_is_lws[(unsigned char)*sov])
876 sov++;
877
878 for (h = cap_hdr; h; h = h->next) {
879 if ((h->namelen == col - sol) &&
880 (strncasecmp(sol, h->name, h->namelen) == 0)) {
881 if (cap[h->index] == NULL)
882 cap[h->index] =
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200883 pool_alloc2(h->pool);
Willy Tarreau117f59e2007-03-04 18:17:17 +0100884
885 if (cap[h->index] == NULL) {
886 Alert("HTTP capture : out of memory.\n");
887 continue;
888 }
889
890 len = eol - sov;
891 if (len > h->len)
892 len = h->len;
893
894 memcpy(cap[h->index], sov, len);
895 cap[h->index][len]=0;
896 }
897 }
898 sol = eol + idx->v[cur_idx].cr + 1;
899 cur_idx = idx->v[cur_idx].next;
900 }
901}
902
903
Willy Tarreau42250582007-04-01 01:30:43 +0200904/* either we find an LF at <ptr> or we jump to <bad>.
905 */
906#define EXPECT_LF_HERE(ptr, bad) do { if (unlikely(*(ptr) != '\n')) goto bad; } while (0)
907
908/* plays with variables <ptr>, <end> and <state>. Jumps to <good> if OK,
909 * otherwise to <http_msg_ood> with <state> set to <st>.
910 */
911#define EAT_AND_JUMP_OR_RETURN(good, st) do { \
912 ptr++; \
913 if (likely(ptr < end)) \
914 goto good; \
915 else { \
916 state = (st); \
917 goto http_msg_ood; \
918 } \
919 } while (0)
920
921
Willy Tarreaubaaee002006-06-26 02:48:02 +0200922/*
Willy Tarreaua15645d2007-03-18 16:22:39 +0100923 * This function parses a status line between <ptr> and <end>, starting with
Willy Tarreau8973c702007-01-21 23:58:29 +0100924 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
925 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
926 * will give undefined results.
927 * Note that it is upon the caller's responsibility to ensure that ptr < end,
928 * and that msg->sol points to the beginning of the response.
929 * If a complete line is found (which implies that at least one CR or LF is
930 * found before <end>, the updated <ptr> is returned, otherwise NULL is
931 * returned indicating an incomplete line (which does not mean that parts have
932 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
933 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
934 * upon next call.
935 *
Willy Tarreau9cdde232007-05-02 20:58:19 +0200936 * This function was intentionally designed to be called from
Willy Tarreau8973c702007-01-21 23:58:29 +0100937 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
938 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +0200939 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreau8973c702007-01-21 23:58:29 +0100940 */
Willy Tarreaue69eada2008-01-27 00:34:10 +0100941const char *http_parse_stsline(struct http_msg *msg, const char *msg_buf,
942 unsigned int state, const char *ptr, const char *end,
943 char **ret_ptr, unsigned int *ret_state)
Willy Tarreau8973c702007-01-21 23:58:29 +0100944{
945 __label__
946 http_msg_rpver,
947 http_msg_rpver_sp,
948 http_msg_rpcode,
949 http_msg_rpcode_sp,
950 http_msg_rpreason,
951 http_msg_rpline_eol,
952 http_msg_ood, /* out of data */
953 http_msg_invalid;
954
955 switch (state) {
956 http_msg_rpver:
957 case HTTP_MSG_RPVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100958 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8973c702007-01-21 23:58:29 +0100959 EAT_AND_JUMP_OR_RETURN(http_msg_rpver, HTTP_MSG_RPVER);
960
961 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +0100962 msg->sl.st.v_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +0100963 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
964 }
965 goto http_msg_invalid;
966
967 http_msg_rpver_sp:
968 case HTTP_MSG_RPVER_SP:
969 if (likely(!HTTP_IS_LWS(*ptr))) {
970 msg->sl.st.c = ptr - msg_buf;
971 goto http_msg_rpcode;
972 }
973 if (likely(HTTP_IS_SPHT(*ptr)))
974 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
975 /* so it's a CR/LF, this is invalid */
976 goto http_msg_invalid;
977
978 http_msg_rpcode:
979 case HTTP_MSG_RPCODE:
980 if (likely(!HTTP_IS_LWS(*ptr)))
981 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode, HTTP_MSG_RPCODE);
982
983 if (likely(HTTP_IS_SPHT(*ptr))) {
984 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
985 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
986 }
987
988 /* so it's a CR/LF, so there is no reason phrase */
989 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
990 http_msg_rsp_reason:
991 /* FIXME: should we support HTTP responses without any reason phrase ? */
992 msg->sl.st.r = ptr - msg_buf;
993 msg->sl.st.r_l = 0;
994 goto http_msg_rpline_eol;
995
996 http_msg_rpcode_sp:
997 case HTTP_MSG_RPCODE_SP:
998 if (likely(!HTTP_IS_LWS(*ptr))) {
999 msg->sl.st.r = ptr - msg_buf;
1000 goto http_msg_rpreason;
1001 }
1002 if (likely(HTTP_IS_SPHT(*ptr)))
1003 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1004 /* so it's a CR/LF, so there is no reason phrase */
1005 goto http_msg_rsp_reason;
1006
1007 http_msg_rpreason:
1008 case HTTP_MSG_RPREASON:
1009 if (likely(!HTTP_IS_CRLF(*ptr)))
1010 EAT_AND_JUMP_OR_RETURN(http_msg_rpreason, HTTP_MSG_RPREASON);
1011 msg->sl.st.r_l = (ptr - msg_buf) - msg->sl.st.r;
1012 http_msg_rpline_eol:
1013 /* We have seen the end of line. Note that we do not
1014 * necessarily have the \n yet, but at least we know that we
1015 * have EITHER \r OR \n, otherwise the response would not be
1016 * complete. We can then record the response length and return
1017 * to the caller which will be able to register it.
1018 */
1019 msg->sl.st.l = ptr - msg->sol;
1020 return ptr;
1021
1022#ifdef DEBUG_FULL
1023 default:
1024 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1025 exit(1);
1026#endif
1027 }
1028
1029 http_msg_ood:
1030 /* out of data */
1031 if (ret_state)
1032 *ret_state = state;
1033 if (ret_ptr)
1034 *ret_ptr = (char *)ptr;
1035 return NULL;
1036
1037 http_msg_invalid:
1038 /* invalid message */
1039 if (ret_state)
1040 *ret_state = HTTP_MSG_ERROR;
1041 return NULL;
1042}
1043
1044
1045/*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001046 * This function parses a request line between <ptr> and <end>, starting with
1047 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
1048 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
1049 * will give undefined results.
1050 * Note that it is upon the caller's responsibility to ensure that ptr < end,
1051 * and that msg->sol points to the beginning of the request.
1052 * If a complete line is found (which implies that at least one CR or LF is
1053 * found before <end>, the updated <ptr> is returned, otherwise NULL is
1054 * returned indicating an incomplete line (which does not mean that parts have
1055 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
1056 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
1057 * upon next call.
1058 *
Willy Tarreau9cdde232007-05-02 20:58:19 +02001059 * This function was intentionally designed to be called from
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001060 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
1061 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +02001062 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001063 */
Willy Tarreaue69eada2008-01-27 00:34:10 +01001064const char *http_parse_reqline(struct http_msg *msg, const char *msg_buf,
1065 unsigned int state, const char *ptr, const char *end,
1066 char **ret_ptr, unsigned int *ret_state)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001067{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001068 __label__
1069 http_msg_rqmeth,
1070 http_msg_rqmeth_sp,
1071 http_msg_rquri,
1072 http_msg_rquri_sp,
1073 http_msg_rqver,
1074 http_msg_rqline_eol,
1075 http_msg_ood, /* out of data */
1076 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001077
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001078 switch (state) {
1079 http_msg_rqmeth:
1080 case HTTP_MSG_RQMETH:
1081 if (likely(HTTP_IS_TOKEN(*ptr)))
1082 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth, HTTP_MSG_RQMETH);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001083
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001084 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001085 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001086 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1087 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001088
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001089 if (likely(HTTP_IS_CRLF(*ptr))) {
1090 /* HTTP 0.9 request */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001091 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001092 http_msg_req09_uri:
1093 msg->sl.rq.u = ptr - msg_buf;
1094 http_msg_req09_uri_e:
1095 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1096 http_msg_req09_ver:
1097 msg->sl.rq.v = ptr - msg_buf;
1098 msg->sl.rq.v_l = 0;
1099 goto http_msg_rqline_eol;
1100 }
1101 goto http_msg_invalid;
1102
1103 http_msg_rqmeth_sp:
1104 case HTTP_MSG_RQMETH_SP:
1105 if (likely(!HTTP_IS_LWS(*ptr))) {
1106 msg->sl.rq.u = ptr - msg_buf;
1107 goto http_msg_rquri;
1108 }
1109 if (likely(HTTP_IS_SPHT(*ptr)))
1110 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1111 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1112 goto http_msg_req09_uri;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001113
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001114 http_msg_rquri:
1115 case HTTP_MSG_RQURI:
1116 if (likely(!HTTP_IS_LWS(*ptr)))
1117 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001118
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001119 if (likely(HTTP_IS_SPHT(*ptr))) {
1120 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1121 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1122 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001123
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001124 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1125 goto http_msg_req09_uri_e;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001126
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001127 http_msg_rquri_sp:
1128 case HTTP_MSG_RQURI_SP:
1129 if (likely(!HTTP_IS_LWS(*ptr))) {
1130 msg->sl.rq.v = ptr - msg_buf;
1131 goto http_msg_rqver;
1132 }
1133 if (likely(HTTP_IS_SPHT(*ptr)))
1134 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1135 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1136 goto http_msg_req09_ver;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001137
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001138 http_msg_rqver:
1139 case HTTP_MSG_RQVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001140 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001141 EAT_AND_JUMP_OR_RETURN(http_msg_rqver, HTTP_MSG_RQVER);
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001142
1143 if (likely(HTTP_IS_CRLF(*ptr))) {
1144 msg->sl.rq.v_l = (ptr - msg_buf) - msg->sl.rq.v;
1145 http_msg_rqline_eol:
1146 /* We have seen the end of line. Note that we do not
1147 * necessarily have the \n yet, but at least we know that we
1148 * have EITHER \r OR \n, otherwise the request would not be
1149 * complete. We can then record the request length and return
1150 * to the caller which will be able to register it.
1151 */
1152 msg->sl.rq.l = ptr - msg->sol;
1153 return ptr;
1154 }
1155
1156 /* neither an HTTP_VER token nor a CRLF */
1157 goto http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001158
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001159#ifdef DEBUG_FULL
1160 default:
1161 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1162 exit(1);
1163#endif
1164 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001165
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001166 http_msg_ood:
1167 /* out of data */
1168 if (ret_state)
1169 *ret_state = state;
1170 if (ret_ptr)
1171 *ret_ptr = (char *)ptr;
1172 return NULL;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001173
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001174 http_msg_invalid:
1175 /* invalid message */
1176 if (ret_state)
1177 *ret_state = HTTP_MSG_ERROR;
1178 return NULL;
1179}
Willy Tarreau58f10d72006-12-04 02:26:12 +01001180
1181
Willy Tarreau8973c702007-01-21 23:58:29 +01001182/*
1183 * This function parses an HTTP message, either a request or a response,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001184 * depending on the initial msg->msg_state. It can be preempted everywhere
Willy Tarreau8973c702007-01-21 23:58:29 +01001185 * when data are missing and recalled at the exact same location with no
1186 * information loss. The header index is re-initialized when switching from
Willy Tarreau9cdde232007-05-02 20:58:19 +02001187 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH. It modifies msg->sol among other
1188 * fields.
Willy Tarreau8973c702007-01-21 23:58:29 +01001189 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001190void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx *idx)
1191{
1192 __label__
1193 http_msg_rqbefore,
1194 http_msg_rqbefore_cr,
1195 http_msg_rqmeth,
1196 http_msg_rqline_end,
1197 http_msg_hdr_first,
1198 http_msg_hdr_name,
1199 http_msg_hdr_l1_sp,
1200 http_msg_hdr_l1_lf,
1201 http_msg_hdr_l1_lws,
1202 http_msg_hdr_val,
1203 http_msg_hdr_l2_lf,
1204 http_msg_hdr_l2_lws,
1205 http_msg_complete_header,
1206 http_msg_last_lf,
1207 http_msg_ood, /* out of data */
1208 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001209
Willy Tarreaue69eada2008-01-27 00:34:10 +01001210 unsigned int state; /* updated only when leaving the FSM */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001211 register char *ptr, *end; /* request pointers, to avoid dereferences */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001212
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001213 state = msg->msg_state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001214 ptr = buf->lr;
1215 end = buf->r;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001216
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001217 if (unlikely(ptr >= end))
1218 goto http_msg_ood;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001219
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001220 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +01001221 /*
1222 * First, states that are specific to the response only.
1223 * We check them first so that request and headers are
1224 * closer to each other (accessed more often).
1225 */
1226 http_msg_rpbefore:
1227 case HTTP_MSG_RPBEFORE:
1228 if (likely(HTTP_IS_TOKEN(*ptr))) {
1229 if (likely(ptr == buf->data)) {
1230 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001231 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001232 } else {
1233#if PARSE_PRESERVE_EMPTY_LINES
1234 /* only skip empty leading lines, don't remove them */
1235 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001236 msg->som = ptr - buf->data;
Willy Tarreau8973c702007-01-21 23:58:29 +01001237#else
1238 /* Remove empty leading lines, as recommended by
1239 * RFC2616. This takes a lot of time because we
1240 * must move all the buffer backwards, but this
1241 * is rarely needed. The method above will be
1242 * cleaner when we'll be able to start sending
1243 * the request from any place in the buffer.
1244 */
1245 buf->lr = ptr;
1246 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001247 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001248 msg->sol = buf->data;
1249 ptr = buf->data;
1250 end = buf->r;
1251#endif
1252 }
1253 hdr_idx_init(idx);
1254 state = HTTP_MSG_RPVER;
1255 goto http_msg_rpver;
1256 }
1257
1258 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1259 goto http_msg_invalid;
1260
1261 if (unlikely(*ptr == '\n'))
1262 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1263 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore_cr, HTTP_MSG_RPBEFORE_CR);
1264 /* stop here */
1265
1266 http_msg_rpbefore_cr:
1267 case HTTP_MSG_RPBEFORE_CR:
1268 EXPECT_LF_HERE(ptr, http_msg_invalid);
1269 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1270 /* stop here */
1271
1272 http_msg_rpver:
1273 case HTTP_MSG_RPVER:
1274 case HTTP_MSG_RPVER_SP:
1275 case HTTP_MSG_RPCODE:
1276 case HTTP_MSG_RPCODE_SP:
1277 case HTTP_MSG_RPREASON:
Willy Tarreaua15645d2007-03-18 16:22:39 +01001278 ptr = (char *)http_parse_stsline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001279 &buf->lr, &msg->msg_state);
Willy Tarreau8973c702007-01-21 23:58:29 +01001280 if (unlikely(!ptr))
1281 return;
1282
1283 /* we have a full response and we know that we have either a CR
1284 * or an LF at <ptr>.
1285 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001286 //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 +01001287 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
1288
1289 msg->sol = ptr;
1290 if (likely(*ptr == '\r'))
1291 EAT_AND_JUMP_OR_RETURN(http_msg_rpline_end, HTTP_MSG_RPLINE_END);
1292 goto http_msg_rpline_end;
1293
1294 http_msg_rpline_end:
1295 case HTTP_MSG_RPLINE_END:
1296 /* msg->sol must point to the first of CR or LF. */
1297 EXPECT_LF_HERE(ptr, http_msg_invalid);
1298 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
1299 /* stop here */
1300
1301 /*
1302 * Second, states that are specific to the request only
1303 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001304 http_msg_rqbefore:
1305 case HTTP_MSG_RQBEFORE:
1306 if (likely(HTTP_IS_TOKEN(*ptr))) {
1307 if (likely(ptr == buf->data)) {
1308 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001309 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001310 } else {
1311#if PARSE_PRESERVE_EMPTY_LINES
1312 /* only skip empty leading lines, don't remove them */
1313 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001314 msg->som = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001315#else
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001316 /* Remove empty leading lines, as recommended by
1317 * RFC2616. This takes a lot of time because we
1318 * must move all the buffer backwards, but this
1319 * is rarely needed. The method above will be
1320 * cleaner when we'll be able to start sending
1321 * the request from any place in the buffer.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001322 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001323 buf->lr = ptr;
1324 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001325 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001326 msg->sol = buf->data;
1327 ptr = buf->data;
1328 end = buf->r;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001329#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001330 }
Willy Tarreauf0d058e2007-01-25 12:03:42 +01001331 /* we will need this when keep-alive will be supported
1332 hdr_idx_init(idx);
1333 */
Willy Tarreau8973c702007-01-21 23:58:29 +01001334 state = HTTP_MSG_RQMETH;
1335 goto http_msg_rqmeth;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001336 }
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001337
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001338 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1339 goto http_msg_invalid;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001340
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001341 if (unlikely(*ptr == '\n'))
1342 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
1343 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore_cr, HTTP_MSG_RQBEFORE_CR);
Willy Tarreau8973c702007-01-21 23:58:29 +01001344 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001345
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001346 http_msg_rqbefore_cr:
1347 case HTTP_MSG_RQBEFORE_CR:
1348 EXPECT_LF_HERE(ptr, http_msg_invalid);
1349 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
Willy Tarreau8973c702007-01-21 23:58:29 +01001350 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001351
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001352 http_msg_rqmeth:
1353 case HTTP_MSG_RQMETH:
1354 case HTTP_MSG_RQMETH_SP:
1355 case HTTP_MSG_RQURI:
1356 case HTTP_MSG_RQURI_SP:
1357 case HTTP_MSG_RQVER:
1358 ptr = (char *)http_parse_reqline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001359 &buf->lr, &msg->msg_state);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001360 if (unlikely(!ptr))
1361 return;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001362
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001363 /* we have a full request and we know that we have either a CR
1364 * or an LF at <ptr>.
1365 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001366 //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 +01001367 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001368
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001369 msg->sol = ptr;
1370 if (likely(*ptr == '\r'))
1371 EAT_AND_JUMP_OR_RETURN(http_msg_rqline_end, HTTP_MSG_RQLINE_END);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001372 goto http_msg_rqline_end;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001373
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001374 http_msg_rqline_end:
1375 case HTTP_MSG_RQLINE_END:
1376 /* check for HTTP/0.9 request : no version information available.
1377 * msg->sol must point to the first of CR or LF.
1378 */
1379 if (unlikely(msg->sl.rq.v_l == 0))
1380 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001381
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001382 EXPECT_LF_HERE(ptr, http_msg_invalid);
1383 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
Willy Tarreau8973c702007-01-21 23:58:29 +01001384 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001385
Willy Tarreau8973c702007-01-21 23:58:29 +01001386 /*
1387 * Common states below
1388 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001389 http_msg_hdr_first:
1390 case HTTP_MSG_HDR_FIRST:
1391 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 Tarreau976f1ee2006-12-17 10:06:03 +01001399
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001400 http_msg_hdr_name:
1401 case HTTP_MSG_HDR_NAME:
1402 /* assumes msg->sol points to the first char */
1403 if (likely(HTTP_IS_TOKEN(*ptr)))
1404 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001405
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001406 if (likely(*ptr == ':')) {
1407 msg->col = ptr - buf->data;
1408 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
1409 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001410
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001411 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001412
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001413 http_msg_hdr_l1_sp:
1414 case HTTP_MSG_HDR_L1_SP:
1415 /* assumes msg->sol points to the first char and msg->col to the colon */
1416 if (likely(HTTP_IS_SPHT(*ptr)))
1417 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001418
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001419 /* header value can be basically anything except CR/LF */
1420 msg->sov = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001421
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001422 if (likely(!HTTP_IS_CRLF(*ptr))) {
1423 goto http_msg_hdr_val;
1424 }
1425
1426 if (likely(*ptr == '\r'))
1427 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lf, HTTP_MSG_HDR_L1_LF);
1428 goto http_msg_hdr_l1_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001429
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001430 http_msg_hdr_l1_lf:
1431 case HTTP_MSG_HDR_L1_LF:
1432 EXPECT_LF_HERE(ptr, http_msg_invalid);
1433 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lws, HTTP_MSG_HDR_L1_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001434
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001435 http_msg_hdr_l1_lws:
1436 case HTTP_MSG_HDR_L1_LWS:
1437 if (likely(HTTP_IS_SPHT(*ptr))) {
1438 /* replace HT,CR,LF with spaces */
1439 for (; buf->data+msg->sov < ptr; msg->sov++)
1440 buf->data[msg->sov] = ' ';
1441 goto http_msg_hdr_l1_sp;
1442 }
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001443 /* we had a header consisting only in spaces ! */
1444 msg->eol = buf->data + msg->sov;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001445 goto http_msg_complete_header;
1446
1447 http_msg_hdr_val:
1448 case HTTP_MSG_HDR_VAL:
1449 /* assumes msg->sol points to the first char, msg->col to the
1450 * colon, and msg->sov points to the first character of the
1451 * value.
1452 */
1453 if (likely(!HTTP_IS_CRLF(*ptr)))
1454 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001455
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001456 msg->eol = ptr;
1457 /* Note: we could also copy eol into ->eoh so that we have the
1458 * real header end in case it ends with lots of LWS, but is this
1459 * really needed ?
1460 */
1461 if (likely(*ptr == '\r'))
1462 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1463 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001464
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001465 http_msg_hdr_l2_lf:
1466 case HTTP_MSG_HDR_L2_LF:
1467 EXPECT_LF_HERE(ptr, http_msg_invalid);
1468 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001469
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001470 http_msg_hdr_l2_lws:
1471 case HTTP_MSG_HDR_L2_LWS:
1472 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1473 /* LWS: replace HT,CR,LF with spaces */
1474 for (; msg->eol < ptr; msg->eol++)
1475 *msg->eol = ' ';
1476 goto http_msg_hdr_val;
1477 }
1478 http_msg_complete_header:
1479 /*
1480 * It was a new header, so the last one is finished.
1481 * Assumes msg->sol points to the first char, msg->col to the
1482 * colon, msg->sov points to the first character of the value
1483 * and msg->eol to the first CR or LF so we know how the line
1484 * ends. We insert last header into the index.
1485 */
1486 /*
1487 fprintf(stderr,"registering %-2d bytes : ", msg->eol - msg->sol);
1488 write(2, msg->sol, msg->eol-msg->sol);
1489 fprintf(stderr,"\n");
1490 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001491
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001492 if (unlikely(hdr_idx_add(msg->eol - msg->sol, *msg->eol == '\r',
1493 idx, idx->tail) < 0))
1494 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001495
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001496 msg->sol = ptr;
1497 if (likely(!HTTP_IS_CRLF(*ptr))) {
1498 goto http_msg_hdr_name;
1499 }
1500
1501 if (likely(*ptr == '\r'))
1502 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1503 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001504
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001505 http_msg_last_lf:
1506 case HTTP_MSG_LAST_LF:
1507 /* Assumes msg->sol points to the first of either CR or LF */
1508 EXPECT_LF_HERE(ptr, http_msg_invalid);
1509 ptr++;
1510 buf->lr = ptr;
1511 msg->eoh = msg->sol - buf->data;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001512 msg->msg_state = HTTP_MSG_BODY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001513 return;
1514#ifdef DEBUG_FULL
1515 default:
1516 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1517 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001518#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001519 }
1520 http_msg_ood:
1521 /* out of data */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001522 msg->msg_state = state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001523 buf->lr = ptr;
1524 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001525
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001526 http_msg_invalid:
1527 /* invalid message */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001528 msg->msg_state = HTTP_MSG_ERROR;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001529 return;
1530}
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001531
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001532/*
1533 * manages the client FSM and its socket. BTW, it also tries to handle the
1534 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1535 * 0 else.
1536 */
1537int process_cli(struct session *t)
1538{
1539 int s = t->srv_state;
1540 int c = t->cli_state;
1541 struct buffer *req = t->req;
1542 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001543
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001544 DPRINTF(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
1545 cli_stnames[c], srv_stnames[s],
Willy Tarreauf161a342007-04-08 16:59:42 +02001546 EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001547 req->rex.tv_sec, req->rex.tv_usec,
1548 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001549
Willy Tarreaub6866442008-07-14 23:54:42 +02001550 if (c == CL_STINSPECT) {
1551 struct tcp_rule *rule;
1552 int partial;
1553
1554 /* We will abort if we encounter a read error. In theory,
1555 * we should not abort if we get a close, it might be
1556 * valid, also very unlikely. FIXME: we'll abort for now,
1557 * this will be easier to change later.
1558 */
1559 if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1560 t->inspect_exp = TICK_ETERNITY;
1561 buffer_shutr(req);
1562 fd_delete(t->cli_fd);
1563 t->cli_state = CL_STCLOSE;
1564 t->fe->failed_req++;
1565 if (!(t->flags & SN_ERR_MASK))
1566 t->flags |= SN_ERR_CLICL;
1567 if (!(t->flags & SN_FINST_MASK))
1568 t->flags |= SN_FINST_R;
1569 return 1;
1570 }
1571
1572 /* Abort if client read timeout has expired */
1573 else if (unlikely(tick_is_expired(req->rex, now_ms))) {
1574 t->inspect_exp = TICK_ETERNITY;
1575 buffer_shutr(req);
1576 fd_delete(t->cli_fd);
1577 t->cli_state = CL_STCLOSE;
1578 t->fe->failed_req++;
1579 if (!(t->flags & SN_ERR_MASK))
1580 t->flags |= SN_ERR_CLITO;
1581 if (!(t->flags & SN_FINST_MASK))
1582 t->flags |= SN_FINST_R;
1583 return 1;
1584 }
1585
1586 /* We don't know whether we have enough data, so must proceed
1587 * this way :
1588 * - iterate through all rules in their declaration order
1589 * - if one rule returns MISS, it means the inspect delay is
1590 * not over yet, then return immediately, otherwise consider
1591 * it as a non-match.
1592 * - if one rule returns OK, then return OK
1593 * - if one rule returns KO, then return KO
1594 */
1595
1596 if (tick_is_expired(t->inspect_exp, now_ms))
1597 partial = 0;
1598 else
1599 partial = ACL_PARTIAL;
1600
1601 list_for_each_entry(rule, &t->fe->tcp_req.inspect_rules, list) {
1602 int ret = ACL_PAT_PASS;
1603
1604 if (rule->cond) {
1605 ret = acl_exec_cond(rule->cond, t->fe, t, NULL, ACL_DIR_REQ | partial);
1606 if (ret == ACL_PAT_MISS) {
1607 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
1608 return 0;
1609 }
1610 ret = acl_pass(ret);
1611 if (rule->cond->pol == ACL_COND_UNLESS)
1612 ret = !ret;
1613 }
1614
1615 if (ret) {
1616 /* we have a matching rule. */
1617 if (rule->action == TCP_ACT_REJECT) {
1618 buffer_shutr(req);
1619 fd_delete(t->cli_fd);
1620 t->cli_state = CL_STCLOSE;
1621 t->fe->failed_req++;
1622 if (!(t->flags & SN_ERR_MASK))
1623 t->flags |= SN_ERR_PRXCOND;
1624 if (!(t->flags & SN_FINST_MASK))
1625 t->flags |= SN_FINST_R;
1626 t->inspect_exp = TICK_ETERNITY;
1627 return 1;
1628 }
1629 /* otherwise accept */
1630 break;
1631 }
1632 }
1633
1634 /* if we get there, it means we have no rule which matches, so
1635 * we apply the default accept.
1636 */
1637 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
1638 if (t->fe->mode == PR_MODE_HTTP) {
1639 t->cli_state = CL_STHEADERS;
1640 t->txn.exp = tick_add_ifset(now_ms, t->fe->timeout.httpreq);
1641 } else {
1642 t->cli_state = CL_STDATA;
1643 }
1644 t->inspect_exp = TICK_ETERNITY;
1645 return 1;
1646 }
1647 else if (c == CL_STHEADERS) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001648 /*
1649 * Now parse the partial (or complete) lines.
1650 * We will check the request syntax, and also join multi-line
1651 * headers. An index of all the lines will be elaborated while
1652 * parsing.
1653 *
Willy Tarreau8973c702007-01-21 23:58:29 +01001654 * For the parsing, we use a 28 states FSM.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001655 *
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001656 * Here is the information we currently have :
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001657 * req->data + req->som = beginning of request
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001658 * req->data + req->eoh = end of processed headers / start of current one
1659 * req->data + req->eol = end of current header or line (LF or CRLF)
1660 * req->lr = first non-visited byte
1661 * req->r = end of data
1662 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001663
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001664 int cur_idx;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001665 struct http_txn *txn = &t->txn;
1666 struct http_msg *msg = &txn->req;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001667 struct proxy *cur_proxy;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001668
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001669 if (likely(req->lr < req->r))
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001670 http_msg_analyzer(req, msg, &txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001671
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001672 /* 1: we might have to print this header in debug mode */
1673 if (unlikely((global.mode & MODE_DEBUG) &&
1674 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001675 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001676 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001677
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001678 sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001679 eol = sol + msg->sl.rq.l;
1680 debug_hdr("clireq", t, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001681
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001682 sol += hdr_idx_first_pos(&txn->hdr_idx);
1683 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001684
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001685 while (cur_idx) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001686 eol = sol + txn->hdr_idx.v[cur_idx].len;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001687 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001688 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
1689 cur_idx = txn->hdr_idx.v[cur_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001690 }
1691 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001692
Willy Tarreau58f10d72006-12-04 02:26:12 +01001693
1694 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001695 * Now we quickly check if we have found a full valid request.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001696 * If not so, we check the FD and buffer states before leaving.
1697 * A full request is indicated by the fact that we have seen
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001698 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
1699 * requests are checked first.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001700 *
1701 */
1702
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001703 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001704 /*
1705 * First, let's catch bad requests.
1706 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001707 if (unlikely(msg->msg_state == HTTP_MSG_ERROR))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001708 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001709
1710 /* 1: Since we are in header mode, if there's no space
1711 * left for headers, we won't be able to free more
1712 * later, so the session will never terminate. We
1713 * must terminate it now.
1714 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001715 if (unlikely(req->l >= req->rlim - req->data)) {
1716 /* FIXME: check if URI is set and return Status
1717 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001718 */
Willy Tarreau06619262006-12-17 08:37:22 +01001719 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001720 }
1721
1722 /* 2: have we encountered a read error or a close ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001723 else if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1724 /* read error, or last read : give up. */
Willy Tarreaufa645582007-06-03 15:59:52 +02001725 buffer_shutr(req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001726 fd_delete(t->cli_fd);
1727 t->cli_state = CL_STCLOSE;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001728 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001729 if (!(t->flags & SN_ERR_MASK))
1730 t->flags |= SN_ERR_CLICL;
1731 if (!(t->flags & SN_FINST_MASK))
1732 t->flags |= SN_FINST_R;
1733 return 1;
1734 }
1735
1736 /* 3: has the read timeout expired ? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001737 else if (unlikely(tick_is_expired(req->rex, now_ms) ||
1738 tick_is_expired(txn->exp, now_ms))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001739 /* read timeout : give up with an error message. */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001740 txn->status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +01001741 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001742 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001743 if (!(t->flags & SN_ERR_MASK))
1744 t->flags |= SN_ERR_CLITO;
1745 if (!(t->flags & SN_FINST_MASK))
1746 t->flags |= SN_FINST_R;
1747 return 1;
1748 }
1749
1750 /* 4: do we need to re-enable the read socket ? */
Willy Tarreau66319382007-04-08 17:17:37 +02001751 else if (unlikely(EV_FD_COND_S(t->cli_fd, DIR_RD))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02001752 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreau58f10d72006-12-04 02:26:12 +01001753 * full. We cannot loop here since stream_sock_read will disable it only if
1754 * req->l == rlim-data
1755 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001756 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001757 }
1758 return t->cli_state != CL_STHEADERS;
1759 }
1760
1761
1762 /****************************************************************
1763 * More interesting part now : we know that we have a complete *
1764 * request which at least looks like HTTP. We have an indicator *
1765 * of each header's length, so we can parse them quickly. *
1766 ****************************************************************/
1767
Willy Tarreau9cdde232007-05-02 20:58:19 +02001768 /* ensure we keep this pointer to the beginning of the message */
1769 msg->sol = req->data + msg->som;
1770
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001771 /*
1772 * 1: identify the method
1773 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001774 txn->meth = find_http_meth(&req->data[msg->som], msg->sl.rq.m_l);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001775
1776 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001777 * 2: check if the URI matches the monitor_uri.
Willy Tarreau06619262006-12-17 08:37:22 +01001778 * We have to do this for every request which gets in, because
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001779 * the monitor-uri is defined by the frontend.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001780 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001781 if (unlikely((t->fe->monitor_uri_len != 0) &&
1782 (t->fe->monitor_uri_len == msg->sl.rq.u_l) &&
1783 !memcmp(&req->data[msg->sl.rq.u],
1784 t->fe->monitor_uri,
1785 t->fe->monitor_uri_len))) {
1786 /*
1787 * We have found the monitor URI
1788 */
Willy Tarreaub80c2302007-11-30 20:51:32 +01001789 struct acl_cond *cond;
1790 cur_proxy = t->fe;
1791
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001792 t->flags |= SN_MONITOR;
Willy Tarreaub80c2302007-11-30 20:51:32 +01001793
1794 /* Check if we want to fail this monitor request or not */
1795 list_for_each_entry(cond, &cur_proxy->mon_fail_cond, list) {
1796 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001797
1798 ret = acl_pass(ret);
Willy Tarreaub80c2302007-11-30 20:51:32 +01001799 if (cond->pol == ACL_COND_UNLESS)
1800 ret = !ret;
1801
1802 if (ret) {
1803 /* we fail this request, let's return 503 service unavail */
1804 txn->status = 503;
1805 client_retnclose(t, error_message(t, HTTP_ERR_503));
1806 goto return_prx_cond;
1807 }
1808 }
1809
1810 /* nothing to fail, let's reply normaly */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001811 txn->status = 200;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001812 client_retnclose(t, &http_200_chunk);
1813 goto return_prx_cond;
1814 }
1815
1816 /*
1817 * 3: Maybe we have to copy the original REQURI for the logs ?
1818 * Note: we cannot log anymore if the request has been
1819 * classified as invalid.
1820 */
1821 if (unlikely(t->logs.logwait & LW_REQ)) {
1822 /* we have a complete HTTP request that we must log */
Willy Tarreau332f8bf2007-05-13 21:36:56 +02001823 if ((txn->uri = pool_alloc2(pool2_requri)) != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001824 int urilen = msg->sl.rq.l;
1825
1826 if (urilen >= REQURI_LEN)
1827 urilen = REQURI_LEN - 1;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001828 memcpy(txn->uri, &req->data[msg->som], urilen);
1829 txn->uri[urilen] = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001830
1831 if (!(t->logs.logwait &= ~LW_REQ))
Willy Tarreau42250582007-04-01 01:30:43 +02001832 http_sess_log(t);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001833 } else {
1834 Alert("HTTP logging : out of memory.\n");
1835 }
1836 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001837
Willy Tarreau06619262006-12-17 08:37:22 +01001838
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001839 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
1840 if (unlikely(msg->sl.rq.v_l == 0)) {
1841 int delta;
1842 char *cur_end;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001843 msg->sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001844 cur_end = msg->sol + msg->sl.rq.l;
1845 delta = 0;
Willy Tarreau06619262006-12-17 08:37:22 +01001846
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001847 if (msg->sl.rq.u_l == 0) {
1848 /* if no URI was set, add "/" */
1849 delta = buffer_replace2(req, cur_end, cur_end, " /", 2);
1850 cur_end += delta;
1851 msg->eoh += delta;
Willy Tarreau06619262006-12-17 08:37:22 +01001852 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001853 /* add HTTP version */
1854 delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
1855 msg->eoh += delta;
1856 cur_end += delta;
1857 cur_end = (char *)http_parse_reqline(msg, req->data,
1858 HTTP_MSG_RQMETH,
1859 msg->sol, cur_end + 1,
1860 NULL, NULL);
1861 if (unlikely(!cur_end))
1862 goto return_bad_req;
1863
1864 /* we have a full HTTP/1.0 request now and we know that
1865 * we have either a CR or an LF at <ptr>.
1866 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001867 hdr_idx_set_start(&txn->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
Willy Tarreau58f10d72006-12-04 02:26:12 +01001868 }
1869
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001870
1871 /* 5: we may need to capture headers */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001872 if (unlikely((t->logs.logwait & LW_REQHDR) && t->fe->req_cap))
Willy Tarreau117f59e2007-03-04 18:17:17 +01001873 capture_headers(req->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001874 txn->req.cap, t->fe->req_cap);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001875
1876 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001877 * 6: we will have to evaluate the filters.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001878 * As opposed to version 1.2, now they will be evaluated in the
1879 * filters order and not in the header order. This means that
1880 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001881 *
1882 * We can now check whether we want to switch to another
1883 * backend, in which case we will re-check the backend's
1884 * filters and various options. In order to support 3-level
1885 * switching, here's how we should proceed :
1886 *
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001887 * a) run be.
Willy Tarreau830ff452006-12-17 19:31:23 +01001888 * if (switch) then switch ->be to the new backend.
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001889 * b) run be if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001890 * There cannot be any switch from there, so ->be cannot be
1891 * changed anymore.
1892 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001893 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001894 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001895 * The response path will be able to apply either ->be, or
1896 * ->be then ->fe filters in order to match the reverse of
1897 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001898 */
1899
Willy Tarreau06619262006-12-17 08:37:22 +01001900 do {
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001901 struct acl_cond *cond;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001902 struct redirect_rule *rule;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001903 struct proxy *rule_set = t->be;
Willy Tarreau830ff452006-12-17 19:31:23 +01001904 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001905
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001906 /* first check whether we have some ACLs set to redirect this request */
1907 list_for_each_entry(rule, &cur_proxy->redirect_rules, list) {
1908 int ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001909
1910 ret = acl_pass(ret);
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001911 if (rule->cond->pol == ACL_COND_UNLESS)
1912 ret = !ret;
1913
1914 if (ret) {
1915 struct chunk rdr = { trash, 0 };
1916 const char *msg_fmt;
1917
1918 /* build redirect message */
1919 switch(rule->code) {
1920 case 303:
1921 rdr.len = strlen(HTTP_303);
1922 msg_fmt = HTTP_303;
1923 break;
1924 case 301:
1925 rdr.len = strlen(HTTP_301);
1926 msg_fmt = HTTP_301;
1927 break;
1928 case 302:
1929 default:
1930 rdr.len = strlen(HTTP_302);
1931 msg_fmt = HTTP_302;
1932 break;
1933 }
1934
1935 if (unlikely(rdr.len > sizeof(trash)))
1936 goto return_bad_req;
1937 memcpy(rdr.str, msg_fmt, rdr.len);
1938
1939 switch(rule->type) {
1940 case REDIRECT_TYPE_PREFIX: {
1941 const char *path;
1942 int pathlen;
1943
1944 path = http_get_path(txn);
1945 /* build message using path */
1946 if (path) {
1947 pathlen = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
1948 } else {
1949 path = "/";
1950 pathlen = 1;
1951 }
1952
1953 if (rdr.len + rule->rdr_len + pathlen > sizeof(trash) - 4)
1954 goto return_bad_req;
1955
1956 /* add prefix */
1957 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1958 rdr.len += rule->rdr_len;
1959
1960 /* add path */
1961 memcpy(rdr.str + rdr.len, path, pathlen);
1962 rdr.len += pathlen;
1963 break;
1964 }
1965 case REDIRECT_TYPE_LOCATION:
1966 default:
1967 if (rdr.len + rule->rdr_len > sizeof(trash) - 4)
1968 goto return_bad_req;
1969
1970 /* add location */
1971 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1972 rdr.len += rule->rdr_len;
1973 break;
1974 }
1975
1976 /* add end of headers */
1977 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
1978 rdr.len += 4;
1979
1980 txn->status = rule->code;
1981 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02001982 t->logs.tv_request = now;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001983 client_retnclose(t, &rdr);
1984 goto return_prx_cond;
1985 }
1986 }
1987
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001988 /* first check whether we have some ACLs set to block this request */
1989 list_for_each_entry(cond, &cur_proxy->block_cond, list) {
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001990 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001991
1992 ret = acl_pass(ret);
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001993 if (cond->pol == ACL_COND_UNLESS)
1994 ret = !ret;
1995
1996 if (ret) {
1997 txn->status = 403;
1998 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02001999 t->logs.tv_request = now;
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02002000 client_retnclose(t, error_message(t, HTTP_ERR_403));
2001 goto return_prx_cond;
2002 }
2003 }
2004
Willy Tarreau06619262006-12-17 08:37:22 +01002005 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01002006 if (rule_set->req_exp != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002007 if (apply_filters_to_request(t, req, rule_set->req_exp) < 0)
2008 goto return_bad_req;
Willy Tarreau53b6c742006-12-17 13:37:46 +01002009 }
2010
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002011 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
2012 /* to ensure correct connection accounting on
2013 * the backend, we count the connection for the
2014 * one managing the queue.
2015 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002016 t->be->beconn++;
2017 if (t->be->beconn > t->be->beconn_max)
2018 t->be->beconn_max = t->be->beconn;
2019 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002020 t->flags |= SN_BE_ASSIGNED;
2021 }
2022
Willy Tarreau06619262006-12-17 08:37:22 +01002023 /* has the request been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01002024 if (txn->flags & TX_CLDENY) {
Willy Tarreau06619262006-12-17 08:37:22 +01002025 /* no need to go further */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002026 txn->status = 403;
Willy Tarreau06619262006-12-17 08:37:22 +01002027 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02002028 t->logs.tv_request = now;
Willy Tarreau80587432006-12-24 17:47:20 +01002029 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01002030 goto return_prx_cond;
2031 }
2032
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002033 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002034 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002035 !(t->flags & SN_CONN_CLOSED)) {
2036 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002037 int cur_idx, old_idx, delta, val;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002038 struct hdr_idx_elem *cur_hdr;
Willy Tarreau06619262006-12-17 08:37:22 +01002039
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002040 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002041 old_idx = 0;
2042
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002043 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
2044 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002045 cur_ptr = cur_next;
2046 cur_end = cur_ptr + cur_hdr->len;
2047 cur_next = cur_end + cur_hdr->cr + 1;
2048
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002049 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
2050 if (val) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002051 /* 3 possibilities :
2052 * - we have already set Connection: close,
2053 * so we remove this line.
2054 * - we have not yet set Connection: close,
2055 * but this line indicates close. We leave
2056 * it untouched and set the flag.
2057 * - we have not yet set Connection: close,
2058 * and this line indicates non-close. We
2059 * replace it.
2060 */
2061 if (t->flags & SN_CONN_CLOSED) {
2062 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002063 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002064 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002065 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
2066 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002067 cur_hdr->len = 0;
2068 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002069 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
2070 delta = buffer_replace2(req, cur_ptr + val, cur_end,
2071 "close", 5);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002072 cur_next += delta;
2073 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002074 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002075 }
2076 t->flags |= SN_CONN_CLOSED;
2077 }
2078 }
2079 old_idx = cur_idx;
2080 }
Willy Tarreauf2f0ee82007-03-30 12:02:43 +02002081 }
2082 /* add request headers from the rule sets in the same order */
2083 for (cur_idx = 0; cur_idx < rule_set->nb_reqadd; cur_idx++) {
2084 if (unlikely(http_header_add_tail(req,
2085 &txn->req,
2086 &txn->hdr_idx,
2087 rule_set->req_add[cur_idx])) < 0)
2088 goto return_bad_req;
Willy Tarreau06619262006-12-17 08:37:22 +01002089 }
Willy Tarreaub2513902006-12-17 14:52:38 +01002090
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002091 /* check if stats URI was requested, and if an auth is needed */
Willy Tarreau0214c3a2007-01-07 13:47:30 +01002092 if (rule_set->uri_auth != NULL &&
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002093 (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)) {
Willy Tarreaub2513902006-12-17 14:52:38 +01002094 /* we have to check the URI and auth for this request */
2095 if (stats_check_uri_auth(t, rule_set))
2096 return 1;
2097 }
2098
Willy Tarreau55ea7572007-06-17 19:56:27 +02002099 /* now check whether we have some switching rules for this request */
2100 if (!(t->flags & SN_BE_ASSIGNED)) {
2101 struct switching_rule *rule;
2102
2103 list_for_each_entry(rule, &cur_proxy->switching_rules, list) {
2104 int ret;
2105
2106 ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02002107
2108 ret = acl_pass(ret);
Willy Tarreaua8cfa342008-07-09 11:23:31 +02002109 if (rule->cond->pol == ACL_COND_UNLESS)
Willy Tarreau55ea7572007-06-17 19:56:27 +02002110 ret = !ret;
2111
2112 if (ret) {
2113 t->be = rule->be.backend;
2114 t->be->beconn++;
2115 if (t->be->beconn > t->be->beconn_max)
2116 t->be->beconn_max = t->be->beconn;
2117 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002118
2119 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002120 t->rep->rto = t->req->wto = t->be->timeout.server;
2121 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002122 t->conn_retries = t->be->conn_retries;
Willy Tarreau55ea7572007-06-17 19:56:27 +02002123 t->flags |= SN_BE_ASSIGNED;
2124 break;
2125 }
2126 }
2127 }
2128
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002129 if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
2130 /* No backend was set, but there was a default
2131 * backend set in the frontend, so we use it and
2132 * loop again.
2133 */
2134 t->be = cur_proxy->defbe.be;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002135 t->be->beconn++;
2136 if (t->be->beconn > t->be->beconn_max)
2137 t->be->beconn_max = t->be->beconn;
2138 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002139
2140 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002141 t->rep->rto = t->req->wto = t->be->timeout.server;
2142 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002143 t->conn_retries = t->be->conn_retries;
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002144 t->flags |= SN_BE_ASSIGNED;
2145 }
2146 } while (t->be != cur_proxy); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01002147
Willy Tarreau58f10d72006-12-04 02:26:12 +01002148
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002149 if (!(t->flags & SN_BE_ASSIGNED)) {
2150 /* To ensure correct connection accounting on
2151 * the backend, we count the connection for the
2152 * one managing the queue.
2153 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002154 t->be->beconn++;
2155 if (t->be->beconn > t->be->beconn_max)
2156 t->be->beconn_max = t->be->beconn;
2157 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002158 t->flags |= SN_BE_ASSIGNED;
2159 }
2160
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002161 /*
2162 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01002163 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002164 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01002165 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01002166 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01002167
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01002168 /*
2169 * If HTTP PROXY is set we simply get remote server address
2170 * parsing incoming request.
2171 */
2172 if ((t->be->options & PR_O_HTTP_PROXY) && !(t->flags & SN_ADDR_SET)) {
2173 url2sa(req->data + msg->sl.rq.u, msg->sl.rq.u_l, &t->srv_addr);
2174 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002175
Willy Tarreau2a324282006-12-05 00:05:46 +01002176 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002177 * 7: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01002178 * so let's do the same now.
2179 */
2180
2181 /* It needs to look into the URI */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002182 if (t->be->appsession_name) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01002183 get_srv_from_appsession(t, &req->data[msg->som], msg->sl.rq.l);
Willy Tarreau06619262006-12-17 08:37:22 +01002184 }
2185
2186
2187 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002188 * 8: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01002189 * Note that doing so might move headers in the request, but
2190 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01002191 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01002192 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01002193 if ((t->be->cookie_name || t->be->appsession_name || t->be->capture_name)
2194 && !(txn->flags & (TX_CLDENY|TX_CLTARPIT)))
Willy Tarreau2a324282006-12-05 00:05:46 +01002195 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01002196
Willy Tarreau58f10d72006-12-04 02:26:12 +01002197
Willy Tarreau2a324282006-12-05 00:05:46 +01002198 /*
Willy Tarreaubb046ac2007-03-03 19:17:03 +01002199 * 9: add X-Forwarded-For if either the frontend or the backend
2200 * asks for it.
Willy Tarreau2a324282006-12-05 00:05:46 +01002201 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002202 if ((t->fe->options | t->be->options) & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002203 if (t->cli_addr.ss_family == AF_INET) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002204 /* Add an X-Forwarded-For header unless the source IP is
2205 * in the 'except' network range.
2206 */
2207 if ((!t->fe->except_mask.s_addr ||
2208 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->fe->except_mask.s_addr)
2209 != t->fe->except_net.s_addr) &&
2210 (!t->be->except_mask.s_addr ||
2211 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->be->except_mask.s_addr)
2212 != t->be->except_net.s_addr)) {
2213 int len;
2214 unsigned char *pn;
2215 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
Willy Tarreau45e73e32006-12-17 00:05:15 +01002216
Ross Westaf72a1d2008-08-03 10:51:45 +02002217 /* Note: we rely on the backend to get the header name to be used for
2218 * x-forwarded-for, because the header is really meant for the backends.
2219 * However, if the backend did not specify any option, we have to rely
2220 * on the frontend's header name.
2221 */
2222 if (t->be->fwdfor_hdr_len) {
2223 len = t->be->fwdfor_hdr_len;
2224 memcpy(trash, t->be->fwdfor_hdr_name, len);
2225 } else {
2226 len = t->fe->fwdfor_hdr_len;
2227 memcpy(trash, t->fe->fwdfor_hdr_name, len);
2228 }
2229 len += sprintf(trash + len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002230
Ross Westaf72a1d2008-08-03 10:51:45 +02002231 if (unlikely(http_header_add_tail2(req, &txn->req,
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002232 &txn->hdr_idx, trash, len)) < 0)
2233 goto return_bad_req;
2234 }
Willy Tarreau2a324282006-12-05 00:05:46 +01002235 }
2236 else if (t->cli_addr.ss_family == AF_INET6) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002237 /* FIXME: for the sake of completeness, we should also support
2238 * 'except' here, although it is mostly useless in this case.
2239 */
Willy Tarreau2a324282006-12-05 00:05:46 +01002240 int len;
2241 char pn[INET6_ADDRSTRLEN];
2242 inet_ntop(AF_INET6,
2243 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2244 pn, sizeof(pn));
Ross Westaf72a1d2008-08-03 10:51:45 +02002245
2246 /* Note: we rely on the backend to get the header name to be used for
2247 * x-forwarded-for, because the header is really meant for the backends.
2248 * However, if the backend did not specify any option, we have to rely
2249 * on the frontend's header name.
2250 */
2251 if (t->be->fwdfor_hdr_len) {
2252 len = t->be->fwdfor_hdr_len;
2253 memcpy(trash, t->be->fwdfor_hdr_name, len);
2254 } else {
2255 len = t->fe->fwdfor_hdr_len;
2256 memcpy(trash, t->fe->fwdfor_hdr_name, len);
2257 }
2258 len += sprintf(trash + len, ": %s", pn);
2259
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002260 if (unlikely(http_header_add_tail2(req, &txn->req,
2261 &txn->hdr_idx, trash, len)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002262 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01002263 }
2264 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002265
Willy Tarreau2a324282006-12-05 00:05:46 +01002266 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002267 * 10: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02002268 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaub2513902006-12-17 14:52:38 +01002269 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02002270 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002271 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02002272 if ((unlikely(msg->sl.rq.v_l != 8) ||
2273 unlikely(req->data[msg->som + msg->sl.rq.v + 7] != '0')) &&
2274 unlikely(http_header_add_tail2(req, &txn->req, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002275 "Connection: close", 17)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002276 goto return_bad_req;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002277 t->flags |= SN_CONN_CLOSED;
Willy Tarreaue15d9132006-12-14 22:26:42 +01002278 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002279 /* Before we switch to data, was assignment set in manage_client_side_cookie?
2280 * If not assigned, perhaps we are balancing on url_param, but this is a
2281 * POST; and the parameters are in the body, maybe scan there to find our server.
2282 * (unless headers overflowed the buffer?)
2283 */
2284 if (!(t->flags & (SN_ASSIGNED|SN_DIRECT)) &&
2285 t->txn.meth == HTTP_METH_POST && t->be->url_param_name != NULL &&
2286 t->be->url_param_post_limit != 0 && req->total < BUFSIZE &&
2287 memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) {
2288 /* are there enough bytes here? total == l || r || rlim ?
2289 * len is unsigned, but eoh is int,
2290 * how many bytes of body have we received?
2291 * eoh is the first empty line of the header
2292 */
2293 /* already established CRLF or LF at eoh, move to start of message, find message length in buffer */
2294 unsigned long len = req->total - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1);
2295
2296 /* If we have HTTP/1.1 and Expect: 100-continue, then abort.
2297 * We can't assume responsibility for the server's decision,
2298 * on this URI and header set. See rfc2616: 14.20, 8.2.3,
2299 * We also can't change our mind later, about which server to choose, so round robin.
2300 */
2301 if ((likely(msg->sl.rq.v_l == 8) && req->data[msg->som + msg->sl.rq.v + 7] == '1')) {
2302 struct hdr_ctx ctx;
2303 ctx.idx = 0;
2304 /* Expect is allowed in 1.1, look for it */
2305 http_find_header2("Expect", 6, msg->sol, &txn->hdr_idx, &ctx);
2306 if (ctx.idx != 0 &&
2307 unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val,"100-continue",12)==0))
2308 /* We can't reliablly stall and wait for data, because of
2309 * .NET clients that don't conform to rfc2616; so, no need for
2310 * the next block to check length expectations.
2311 * We could send 100 status back to the client, but then we need to
2312 * re-write headers, and send the message. And this isn't the right
2313 * place for that action.
2314 * TODO: support Expect elsewhere and delete this block.
2315 */
2316 goto end_check_maybe_wait_for_body;
2317 }
2318 if ( likely(len > t->be->url_param_post_limit) ) {
2319 /* nothing to do, we got enough */
2320 } else {
2321 /* limit implies we are supposed to need this many bytes
2322 * to find the parameter. Let's see how many bytes we can wait for.
2323 */
2324 long long hint = len;
2325 struct hdr_ctx ctx;
2326 ctx.idx = 0;
2327 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
2328 if (unlikely(ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",7)==0)) {
2329 t->srv_state = SV_STANALYZE;
2330 } else {
2331 ctx.idx = 0;
2332 http_find_header2("Content-Length", 14, msg->sol, &txn->hdr_idx, &ctx);
2333 /* now if we have a length, we'll take the hint */
2334 if ( ctx.idx ) {
2335 /* We have Content-Length */
2336 if ( strl2llrc(ctx.line+ctx.val,ctx.vlen, &hint) )
2337 hint = 0; /* parse failure, untrusted client */
2338 else {
2339 if ( hint > 0 )
2340 msg->hdr_content_len = hint;
2341 else
2342 hint = 0; /* bad client, sent negative length */
2343 }
2344 }
2345 /* but limited to what we care about, maybe we don't expect any entity data (hint == 0) */
2346 if ( t->be->url_param_post_limit < hint )
2347 hint = t->be->url_param_post_limit;
2348 /* now do we really need to buffer more data? */
2349 if ( len < hint )
2350 t->srv_state = SV_STANALYZE;
2351 /* else... There are no body bytes to wait for */
2352 }
2353 }
2354 }
2355 end_check_maybe_wait_for_body:
Willy Tarreaubaaee002006-06-26 02:48:02 +02002356
Willy Tarreau2a324282006-12-05 00:05:46 +01002357 /*************************************************************
2358 * OK, that's finished for the headers. We have done what we *
2359 * could. Let's switch to the DATA state. *
2360 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02002361
Willy Tarreau2a324282006-12-05 00:05:46 +01002362 t->cli_state = CL_STDATA;
2363 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002364
Willy Tarreau70089872008-06-13 21:12:51 +02002365 t->logs.tv_request = now;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002366
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002367 if (!t->fe->timeout.client ||
2368 (t->srv_state < SV_STDATA && t->be->timeout.server)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002369 /* If the client has no timeout, or if the server is not ready yet,
2370 * and we know for sure that it can expire, then it's cleaner to
2371 * disable the timeout on the client side so that too low values
2372 * cannot make the sessions abort too early.
2373 *
2374 * FIXME-20050705: the server needs a way to re-enable this time-out
2375 * when it switches its state, otherwise a client can stay connected
2376 * indefinitely. This now seems to be OK.
2377 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002378 req->rex = TICK_ETERNITY;
Willy Tarreau2a324282006-12-05 00:05:46 +01002379 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002380
Willy Tarreau1fa31262007-12-03 00:36:16 +01002381 /* When a connection is tarpitted, we use the tarpit timeout,
2382 * which may be the same as the connect timeout if unspecified.
2383 * If unset, then set it to zero because we really want it to
2384 * eventually expire.
Willy Tarreau2a324282006-12-05 00:05:46 +01002385 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002386 if (txn->flags & TX_CLTARPIT) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002387 t->req->l = 0;
2388 /* flush the request so that we can drop the connection early
2389 * if the client closes first.
2390 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002391 req->cex = tick_add_ifset(now_ms, t->be->timeout.tarpit);
2392 if (!req->cex)
2393 req->cex = now_ms;
Willy Tarreau2a324282006-12-05 00:05:46 +01002394 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002395
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002396 /* OK let's go on with the BODY now */
Willy Tarreau06619262006-12-17 08:37:22 +01002397 goto process_data;
2398
2399 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002400 txn->req.msg_state = HTTP_MSG_ERROR;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002401 txn->status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01002402 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002403 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01002404 return_prx_cond:
2405 if (!(t->flags & SN_ERR_MASK))
2406 t->flags |= SN_ERR_PRXCOND;
2407 if (!(t->flags & SN_FINST_MASK))
2408 t->flags |= SN_FINST_R;
2409 return 1;
2410
Willy Tarreaubaaee002006-06-26 02:48:02 +02002411 }
2412 else if (c == CL_STDATA) {
2413 process_data:
2414 /* FIXME: this error handling is partly buggy because we always report
2415 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
2416 * or HEADER phase. BTW, it's not logical to expire the client while
2417 * we're waiting for the server to connect.
2418 */
2419 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002420 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002421 buffer_shutr(req);
2422 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002423 fd_delete(t->cli_fd);
2424 t->cli_state = CL_STCLOSE;
2425 if (!(t->flags & SN_ERR_MASK))
2426 t->flags |= SN_ERR_CLICL;
2427 if (!(t->flags & SN_FINST_MASK)) {
2428 if (t->pend_pos)
2429 t->flags |= SN_FINST_Q;
2430 else if (s == SV_STCONN)
2431 t->flags |= SN_FINST_C;
2432 else
2433 t->flags |= SN_FINST_D;
2434 }
2435 return 1;
2436 }
2437 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002438 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002439 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002440 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002441 t->cli_state = CL_STSHUTR;
2442 return 1;
2443 }
2444 /* last server read and buffer empty */
2445 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002446 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02002447 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002448 shutdown(t->cli_fd, SHUT_WR);
2449 /* We must ensure that the read part is still alive when switching
2450 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002451 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002452 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002453 t->cli_state = CL_STSHUTW;
2454 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2455 return 1;
2456 }
2457 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002458 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002459 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002460 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002461 t->cli_state = CL_STSHUTR;
2462 if (!(t->flags & SN_ERR_MASK))
2463 t->flags |= SN_ERR_CLITO;
2464 if (!(t->flags & SN_FINST_MASK)) {
2465 if (t->pend_pos)
2466 t->flags |= SN_FINST_Q;
2467 else if (s == SV_STCONN)
2468 t->flags |= SN_FINST_C;
2469 else
2470 t->flags |= SN_FINST_D;
2471 }
2472 return 1;
2473 }
2474 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002475 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002476 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02002477 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002478 shutdown(t->cli_fd, SHUT_WR);
2479 /* We must ensure that the read part is still alive when switching
2480 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002481 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002482 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002483
2484 t->cli_state = CL_STSHUTW;
2485 if (!(t->flags & SN_ERR_MASK))
2486 t->flags |= SN_ERR_CLITO;
2487 if (!(t->flags & SN_FINST_MASK)) {
2488 if (t->pend_pos)
2489 t->flags |= SN_FINST_Q;
2490 else if (s == SV_STCONN)
2491 t->flags |= SN_FINST_C;
2492 else
2493 t->flags |= SN_FINST_D;
2494 }
2495 return 1;
2496 }
2497
2498 if (req->l >= req->rlim - req->data) {
2499 /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02002500 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002501 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002502 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002503 }
2504 } else {
2505 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002506 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002507 if (!t->fe->timeout.client ||
2508 (t->srv_state < SV_STDATA && t->be->timeout.server))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002509 /* If the client has no timeout, or if the server not ready yet, and we
2510 * know for sure that it can expire, then it's cleaner to disable the
2511 * timeout on the client side so that too low values cannot make the
2512 * sessions abort too early.
2513 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002514 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002515 else
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002516 req->rex = tick_add(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002517 }
2518 }
2519
2520 if ((rep->l == 0) ||
2521 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002522 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2523 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002524 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002525 }
2526 } else {
2527 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002528 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2529 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002530 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
2531 if (rep->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002532 /* FIXME: to prevent the client from expiring read timeouts during writes,
2533 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002534 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002535 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002536 }
2537 }
2538 return 0; /* other cases change nothing */
2539 }
2540 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002541 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002542 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002543 fd_delete(t->cli_fd);
2544 t->cli_state = CL_STCLOSE;
2545 if (!(t->flags & SN_ERR_MASK))
2546 t->flags |= SN_ERR_CLICL;
2547 if (!(t->flags & SN_FINST_MASK)) {
2548 if (t->pend_pos)
2549 t->flags |= SN_FINST_Q;
2550 else if (s == SV_STCONN)
2551 t->flags |= SN_FINST_C;
2552 else
2553 t->flags |= SN_FINST_D;
2554 }
2555 return 1;
2556 }
2557 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
2558 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002559 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002560 fd_delete(t->cli_fd);
2561 t->cli_state = CL_STCLOSE;
2562 return 1;
2563 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002564 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002565 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002566 fd_delete(t->cli_fd);
2567 t->cli_state = CL_STCLOSE;
2568 if (!(t->flags & SN_ERR_MASK))
2569 t->flags |= SN_ERR_CLITO;
2570 if (!(t->flags & SN_FINST_MASK)) {
2571 if (t->pend_pos)
2572 t->flags |= SN_FINST_Q;
2573 else if (s == SV_STCONN)
2574 t->flags |= SN_FINST_C;
2575 else
2576 t->flags |= SN_FINST_D;
2577 }
2578 return 1;
2579 }
2580
2581 if (t->flags & SN_SELF_GEN) {
2582 produce_content(t);
2583 if (rep->l == 0) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002584 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002585 fd_delete(t->cli_fd);
2586 t->cli_state = CL_STCLOSE;
2587 return 1;
2588 }
2589 }
2590
2591 if ((rep->l == 0)
2592 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002593 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2594 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002595 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002596 }
2597 } else {
2598 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002599 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2600 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002601 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002602 }
2603 }
2604 return 0;
2605 }
2606 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002607 if (req->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002608 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002609 fd_delete(t->cli_fd);
2610 t->cli_state = CL_STCLOSE;
2611 if (!(t->flags & SN_ERR_MASK))
2612 t->flags |= SN_ERR_CLICL;
2613 if (!(t->flags & SN_FINST_MASK)) {
2614 if (t->pend_pos)
2615 t->flags |= SN_FINST_Q;
2616 else if (s == SV_STCONN)
2617 t->flags |= SN_FINST_C;
2618 else
2619 t->flags |= SN_FINST_D;
2620 }
2621 return 1;
2622 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002623 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002624 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002625 fd_delete(t->cli_fd);
2626 t->cli_state = CL_STCLOSE;
2627 return 1;
2628 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002629 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002630 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002631 fd_delete(t->cli_fd);
2632 t->cli_state = CL_STCLOSE;
2633 if (!(t->flags & SN_ERR_MASK))
2634 t->flags |= SN_ERR_CLITO;
2635 if (!(t->flags & SN_FINST_MASK)) {
2636 if (t->pend_pos)
2637 t->flags |= SN_FINST_Q;
2638 else if (s == SV_STCONN)
2639 t->flags |= SN_FINST_C;
2640 else
2641 t->flags |= SN_FINST_D;
2642 }
2643 return 1;
2644 }
2645 else if (req->l >= req->rlim - req->data) {
2646 /* no room to read more data */
2647
2648 /* FIXME-20050705: is it possible for a client to maintain a session
2649 * after the timeout by sending more data after it receives a close ?
2650 */
2651
Willy Tarreau66319382007-04-08 17:17:37 +02002652 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002653 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002654 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002655 }
2656 } else {
2657 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002658 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002659 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002660 }
2661 }
2662 return 0;
2663 }
2664 else { /* CL_STCLOSE: nothing to do */
2665 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2666 int len;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002667 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 +02002668 write(1, trash, len);
2669 }
2670 return 0;
2671 }
2672 return 0;
2673}
2674
2675
2676/*
2677 * manages the server FSM and its socket. It returns 1 if a state has changed
2678 * (and a resync may be needed), 0 else.
2679 */
2680int process_srv(struct session *t)
2681{
2682 int s = t->srv_state;
2683 int c = t->cli_state;
Willy Tarreau3d300592007-03-18 18:34:41 +01002684 struct http_txn *txn = &t->txn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002685 struct buffer *req = t->req;
2686 struct buffer *rep = t->rep;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002687 int conn_err;
2688
2689#ifdef DEBUG_FULL
2690 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2691#endif
Willy Tarreauee991362007-05-14 14:37:50 +02002692
2693#if 0
2694 fprintf(stderr,"%s:%d fe->clito=%d.%d, fe->conto=%d.%d, fe->srvto=%d.%d\n",
2695 __FUNCTION__, __LINE__,
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002696 t->fe->timeout.client.tv_sec, t->fe->timeout.client.tv_usec,
2697 t->fe->timeout.connect.tv_sec, t->fe->timeout.connect.tv_usec,
2698 t->fe->timeout.server.tv_sec, t->fe->timeout.server.tv_usec);
Willy Tarreauee991362007-05-14 14:37:50 +02002699 fprintf(stderr,"%s:%d be->clito=%d.%d, be->conto=%d.%d, be->srvto=%d.%d\n",
2700 __FUNCTION__, __LINE__,
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002701 t->be->timeout.client.tv_sec, t->be->timeout.client.tv_usec,
2702 t->be->timeout.connect.tv_sec, t->be->timeout.connect.tv_usec,
2703 t->be->timeout.server.tv_sec, t->be->timeout.server.tv_usec);
Willy Tarreauee991362007-05-14 14:37:50 +02002704
2705 fprintf(stderr,"%s:%d req->cto=%d.%d, req->rto=%d.%d, req->wto=%d.%d\n",
2706 __FUNCTION__, __LINE__,
2707 req->cto.tv_sec, req->cto.tv_usec,
2708 req->rto.tv_sec, req->rto.tv_usec,
2709 req->wto.tv_sec, req->wto.tv_usec);
2710
2711 fprintf(stderr,"%s:%d rep->cto=%d.%d, rep->rto=%d.%d, rep->wto=%d.%d\n",
2712 __FUNCTION__, __LINE__,
2713 rep->cto.tv_sec, rep->cto.tv_usec,
2714 rep->rto.tv_sec, rep->rto.tv_usec,
2715 rep->wto.tv_sec, rep->wto.tv_usec);
2716#endif
2717
Willy Tarreaubaaee002006-06-26 02:48:02 +02002718 //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 +02002719 //EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
2720 //EV_FD_ISSET(t->srv_fd, DIR_RD), EV_FD_ISSET(t->srv_fd, DIR_WR)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002721 //);
2722 if (s == SV_STIDLE) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002723 /* NOTE: The client processor may switch to SV_STANALYZE, which switches back SV_STIDLE.
2724 * This is logcially after CL_STHEADERS completed, CL_STDATA has started, but
2725 * we need to defer server selection until more data arrives, if possible.
2726 * This is rare, and only if balancing on parameter hash with values in the entity of a POST
2727 */
Willy Tarreaub6866442008-07-14 23:54:42 +02002728 if (c == CL_STHEADERS || c == CL_STINSPECT)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002729 return 0; /* stay in idle, waiting for data to reach the client side */
2730 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
2731 (c == CL_STSHUTR &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002732 (t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002733 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002734 if (t->pend_pos)
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002735 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002736 /* note that this must not return any error because it would be able to
2737 * overwrite the client_retnclose() output.
2738 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002739 if (txn->flags & TX_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01002740 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02002741 else
Willy Tarreau0f772532006-12-23 20:51:41 +01002742 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 +02002743
2744 return 1;
2745 }
2746 else {
Willy Tarreau3d300592007-03-18 18:34:41 +01002747 if (txn->flags & TX_CLTARPIT) {
Willy Tarreaub8750a82006-09-03 09:56:00 +02002748 /* This connection is being tarpitted. The CLIENT side has
2749 * already set the connect expiration date to the right
2750 * timeout. We just have to check that it has not expired.
2751 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002752 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreaub8750a82006-09-03 09:56:00 +02002753 return 0;
2754
2755 /* We will set the queue timer to the time spent, just for
2756 * logging purposes. We fake a 500 server error, so that the
2757 * attacker will not suspect his connection has been tarpitted.
2758 * It will not cause trouble to the logs because we can exclude
2759 * the tarpitted connections by filtering on the 'PT' status flags.
2760 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002761 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002762 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaub8750a82006-09-03 09:56:00 +02002763 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01002764 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02002765 return 1;
2766 }
2767
Willy Tarreaubaaee002006-06-26 02:48:02 +02002768 /* Right now, we will need to create a connection to the server.
2769 * We might already have tried, and got a connection pending, in
2770 * which case we will not do anything till it's pending. It's up
2771 * to any other session to release it and wake us up again.
2772 */
2773 if (t->pend_pos) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002774 if (!tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002775 return 0;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002776 } else {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002777 /* we've been waiting too long here */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002778 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002779 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002780 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01002781 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002782 if (t->srv)
2783 t->srv->failed_conns++;
Willy Tarreau50fd1e12007-12-10 15:25:35 +01002784 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002785 return 1;
2786 }
2787 }
2788
2789 do {
2790 /* first, get a connection */
Willy Tarreau21d2af32008-02-14 20:25:24 +01002791 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
2792 t->flags |= SN_REDIRECTABLE;
2793
Willy Tarreaubaaee002006-06-26 02:48:02 +02002794 if (srv_redispatch_connect(t))
2795 return t->srv_state != SV_STIDLE;
2796
Willy Tarreau21d2af32008-02-14 20:25:24 +01002797 if ((t->flags & SN_REDIRECTABLE) && t->srv && t->srv->rdr_len) {
2798 /* Server supporting redirection and it is possible.
2799 * Invalid requests are reported as such. It concerns all
2800 * the largest ones.
2801 */
2802 struct chunk rdr;
2803 char *path;
2804 int len;
2805
2806 /* 1: create the response header */
2807 rdr.len = strlen(HTTP_302);
2808 rdr.str = trash;
2809 memcpy(rdr.str, HTTP_302, rdr.len);
2810
2811 /* 2: add the server's prefix */
2812 if (rdr.len + t->srv->rdr_len > sizeof(trash))
2813 goto cancel_redir;
2814
2815 memcpy(rdr.str + rdr.len, t->srv->rdr_pfx, t->srv->rdr_len);
2816 rdr.len += t->srv->rdr_len;
2817
2818 /* 3: add the request URI */
2819 path = http_get_path(txn);
2820 if (!path)
2821 goto cancel_redir;
2822 len = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
2823 if (rdr.len + len > sizeof(trash) - 4) /* 4 for CRLF-CRLF */
2824 goto cancel_redir;
2825
2826 memcpy(rdr.str + rdr.len, path, len);
2827 rdr.len += len;
2828 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
2829 rdr.len += 4;
2830
2831 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C, 302, &rdr);
2832 /* FIXME: we should increase a counter of redirects per server and per backend. */
2833 if (t->srv)
2834 t->srv->cum_sess++;
2835 return 1;
2836 cancel_redir:
2837 txn->status = 400;
2838 t->fe->failed_req++;
2839 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C,
2840 400, error_message(t, HTTP_ERR_400));
2841 return 1;
2842 }
2843
Willy Tarreaubaaee002006-06-26 02:48:02 +02002844 /* try to (re-)connect to the server, and fail if we expire the
2845 * number of retries.
2846 */
2847 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002848 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002849 return t->srv_state != SV_STIDLE;
2850 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002851 } while (1);
2852 }
2853 }
2854 else if (s == SV_STCONN) { /* connection in progress */
2855 if (c == CL_STCLOSE || c == CL_STSHUTW ||
2856 (c == CL_STSHUTR &&
Willy Tarreauc9b654b2007-05-08 14:46:53 +02002857 ((t->req->l == 0 && !(req->flags & BF_WRITE_STATUS)) ||
2858 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002859 req->cex = TICK_ETERNITY;
Willy Tarreauf899b942008-03-28 18:09:38 +01002860 if (!(t->flags & SN_CONN_TAR)) {
2861 /* if we are in turn-around, we have already closed the FD */
2862 fd_delete(t->srv_fd);
2863 if (t->srv) {
2864 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002865 sess_change_server(t, NULL);
Willy Tarreauf899b942008-03-28 18:09:38 +01002866 }
Willy Tarreau51406232008-03-10 22:04:20 +01002867 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002868
2869 /* note that this must not return any error because it would be able to
2870 * overwrite the client_retnclose() output.
2871 */
Willy Tarreau0f772532006-12-23 20:51:41 +01002872 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002873 return 1;
2874 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002875 if (!(req->flags & BF_WRITE_STATUS) && !tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002876 return 0; /* nothing changed */
2877 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002878 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002879 /* timeout, asynchronous connect error or first write error */
2880 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2881
Willy Tarreau541b5c22008-01-06 23:34:21 +01002882 if (t->flags & SN_CONN_TAR) {
2883 /* We are doing a turn-around waiting for a new connection attempt. */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002884 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreau541b5c22008-01-06 23:34:21 +01002885 return 0;
2886 t->flags &= ~SN_CONN_TAR;
2887 }
2888 else {
2889 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01002890 if (t->srv) {
Willy Tarreau541b5c22008-01-06 23:34:21 +01002891 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002892 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01002893 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002894
Willy Tarreau541b5c22008-01-06 23:34:21 +01002895 if (!(req->flags & BF_WRITE_STATUS))
2896 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
2897 else
2898 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
2899
2900 /* ensure that we have enough retries left */
2901 if (srv_count_retry_down(t, conn_err))
2902 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002903
Willy Tarreau541b5c22008-01-06 23:34:21 +01002904 if (req->flags & BF_WRITE_ERROR) {
2905 /* we encountered an immediate connection error, and we
2906 * will have to retry connecting to the same server, most
2907 * likely leading to the same result. To avoid this, we
2908 * fake a connection timeout to retry after a turn-around
2909 * time of 1 second. We will wait in the previous if block.
2910 */
2911 t->flags |= SN_CONN_TAR;
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002912 req->cex = tick_add(now_ms, MS_TO_TICKS(1000));
Willy Tarreau541b5c22008-01-06 23:34:21 +01002913 return 0;
2914 }
2915 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002916
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002917 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002918 /* We're on our last chance, and the REDISP option was specified.
2919 * We will ignore cookie and force to balance or use the dispatcher.
2920 */
2921 /* let's try to offer this slot to anybody */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002922 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02002923 process_srv_queue(t->srv);
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002924
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01002925 /* it's left to the dispatcher to choose a server */
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002926 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
Willy Tarreau7c669d72008-06-20 15:04:11 +02002927 t->prev_srv = t->srv;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002928
2929 /* first, get a connection */
2930 if (srv_redispatch_connect(t))
Willy Tarreau00559e72008-01-06 23:46:19 +01002931 return t->srv_state != SV_STCONN;
Krzysztof Piotr Oledzki626a19b2008-02-04 02:10:09 +01002932 } else {
2933 if (t->srv)
2934 t->srv->retries++;
2935 t->be->retries++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002936 }
2937
Willy Tarreaubaaee002006-06-26 02:48:02 +02002938 do {
2939 /* Now we will try to either reconnect to the same server or
2940 * connect to another server. If the connection gets queued
2941 * because all servers are saturated, then we will go back to
2942 * the SV_STIDLE state.
2943 */
2944 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002945 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002946 return t->srv_state != SV_STCONN;
2947 }
2948
2949 /* we need to redispatch the connection to another server */
2950 if (srv_redispatch_connect(t))
2951 return t->srv_state != SV_STCONN;
2952 } while (1);
2953 }
2954 else { /* no error or write 0 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002955 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002956
2957 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2958 if (req->l == 0) /* nothing to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002959 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002960 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002961 } else /* need the right to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002962 EV_FD_SET(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002963 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
2964 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002965 /* FIXME: to prevent the server from expiring read timeouts during writes,
2966 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002967 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002968 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002969 }
2970
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002971 if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreauf161a342007-04-08 16:59:42 +02002972 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002973 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002974 t->srv_state = SV_STDATA;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002975 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
2976
2977 /* if the user wants to log as soon as possible, without counting
2978 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002979 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002980 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
Willy Tarreau42250582007-04-01 01:30:43 +02002981 tcp_sess_log(t);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002982 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002983#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002984 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002985 /* TCP splicing supported by both FE and BE */
2986 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2987 }
2988#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002989 }
2990 else {
2991 t->srv_state = SV_STHEADERS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002992 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002993 t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
2994 /* reset hdr_idx which was already initialized by the request.
2995 * right now, the http parser does it.
2996 * hdr_idx_init(&t->txn.hdr_idx);
2997 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002998 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002999 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003000 return 1;
3001 }
3002 }
3003 else if (s == SV_STHEADERS) { /* receiving server headers */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003004 /*
3005 * Now parse the partial (or complete) lines.
3006 * We will check the response syntax, and also join multi-line
3007 * headers. An index of all the lines will be elaborated while
3008 * parsing.
3009 *
3010 * For the parsing, we use a 28 states FSM.
3011 *
3012 * Here is the information we currently have :
3013 * rep->data + req->som = beginning of response
3014 * rep->data + req->eoh = end of processed headers / start of current one
3015 * rep->data + req->eol = end of current header or line (LF or CRLF)
3016 * rep->lr = first non-visited byte
3017 * rep->r = end of data
3018 */
3019
3020 int cur_idx;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003021 struct http_msg *msg = &txn->rsp;
3022 struct proxy *cur_proxy;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003023
Willy Tarreaua15645d2007-03-18 16:22:39 +01003024 if (likely(rep->lr < rep->r))
3025 http_msg_analyzer(rep, msg, &txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003026
Willy Tarreaua15645d2007-03-18 16:22:39 +01003027 /* 1: we might have to print this header in debug mode */
3028 if (unlikely((global.mode & MODE_DEBUG) &&
3029 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
3030 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
3031 char *eol, *sol;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003032
Willy Tarreaua15645d2007-03-18 16:22:39 +01003033 sol = rep->data + msg->som;
3034 eol = sol + msg->sl.rq.l;
3035 debug_hdr("srvrep", t, sol, eol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003036
Willy Tarreaua15645d2007-03-18 16:22:39 +01003037 sol += hdr_idx_first_pos(&txn->hdr_idx);
3038 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003039
Willy Tarreaua15645d2007-03-18 16:22:39 +01003040 while (cur_idx) {
3041 eol = sol + txn->hdr_idx.v[cur_idx].len;
3042 debug_hdr("srvhdr", t, sol, eol);
3043 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
3044 cur_idx = txn->hdr_idx.v[cur_idx].next;
3045 }
3046 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003047
Willy Tarreaubaaee002006-06-26 02:48:02 +02003048
Willy Tarreau66319382007-04-08 17:17:37 +02003049 if ((rep->l < rep->rlim - rep->data) && EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003050 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreaua15645d2007-03-18 16:22:39 +01003051 * full. We cannot loop here since stream_sock_read will disable it only if
3052 * rep->l == rlim-data
3053 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003054 req->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003055 }
3056
3057
3058 /*
3059 * Now we quickly check if we have found a full valid response.
3060 * If not so, we check the FD and buffer states before leaving.
3061 * A full response is indicated by the fact that we have seen
3062 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
3063 * responses are checked first.
3064 *
3065 * Depending on whether the client is still there or not, we
3066 * may send an error response back or not. Note that normally
3067 * we should only check for HTTP status there, and check I/O
3068 * errors somewhere else.
3069 */
3070
3071 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
3072
3073 /* Invalid response, or read error or write error */
3074 if (unlikely((msg->msg_state == HTTP_MSG_ERROR) ||
3075 (req->flags & BF_WRITE_ERROR) ||
3076 (rep->flags & BF_READ_ERROR))) {
Willy Tarreaufa645582007-06-03 15:59:52 +02003077 buffer_shutr(rep);
3078 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003079 fd_delete(t->srv_fd);
3080 if (t->srv) {
3081 t->srv->cur_sess--;
3082 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003083 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003084 }
3085 t->be->failed_resp++;
3086 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003087 txn->status = 502;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003088 client_return(t, error_message(t, HTTP_ERR_502));
3089 if (!(t->flags & SN_ERR_MASK))
3090 t->flags |= SN_ERR_SRVCL;
3091 if (!(t->flags & SN_FINST_MASK))
3092 t->flags |= SN_FINST_H;
3093 /* We used to have a free connection slot. Since we'll never use it,
3094 * we have to inform the server that it may be used by another session.
3095 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003096 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003097 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003098
Willy Tarreaua15645d2007-03-18 16:22:39 +01003099 return 1;
3100 }
3101
3102 /* end of client write or end of server read.
3103 * since we are in header mode, if there's no space left for headers, we
3104 * won't be able to free more later, so the session will never terminate.
3105 */
3106 else if (unlikely(rep->flags & BF_READ_NULL ||
3107 c == CL_STSHUTW || c == CL_STCLOSE ||
3108 rep->l >= rep->rlim - rep->data)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003109 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003110 buffer_shutr(rep);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003111 t->srv_state = SV_STSHUTR;
3112 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3113 return 1;
3114 }
3115
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003116 /* read timeout : return a 504 to the client. */
Willy Tarreauf161a342007-04-08 16:59:42 +02003117 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_RD) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003118 tick_is_expired(rep->rex, now_ms))) {
Willy Tarreaufa645582007-06-03 15:59:52 +02003119 buffer_shutr(rep);
3120 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003121 fd_delete(t->srv_fd);
3122 if (t->srv) {
3123 t->srv->cur_sess--;
3124 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003125 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003126 }
3127 t->be->failed_resp++;
3128 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003129 txn->status = 504;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003130 client_return(t, error_message(t, HTTP_ERR_504));
3131 if (!(t->flags & SN_ERR_MASK))
3132 t->flags |= SN_ERR_SRVTO;
3133 if (!(t->flags & SN_FINST_MASK))
3134 t->flags |= SN_FINST_H;
3135 /* We used to have a free connection slot. Since we'll never use it,
3136 * we have to inform the server that it may be used by another session.
3137 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003138 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003139 process_srv_queue(t->srv);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003140 return 1;
3141 }
3142
3143 /* last client read and buffer empty */
3144 /* FIXME!!! here, we don't want to switch to SHUTW if the
3145 * client shuts read too early, because we may still have
3146 * some work to do on the headers.
3147 * The side-effect is that if the client completely closes its
3148 * connection during SV_STHEADER, the connection to the server
3149 * is kept until a response comes back or the timeout is reached.
3150 */
3151 else if (unlikely((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) &&
3152 (req->l == 0))) {
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 Tarreaua15645d2007-03-18 16:22:39 +01003155
3156 /* We must ensure that the read part is still
3157 * alive when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003158 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003159 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003160
3161 shutdown(t->srv_fd, SHUT_WR);
3162 t->srv_state = SV_STSHUTW;
3163 return 1;
3164 }
3165
3166 /* write timeout */
3167 /* FIXME!!! here, we don't want to switch to SHUTW if the
3168 * client shuts read too early, because we may still have
3169 * some work to do on the headers.
3170 */
Willy Tarreauf161a342007-04-08 16:59:42 +02003171 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_WR) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003172 tick_is_expired(req->wex, now_ms))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003173 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003174 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003175 shutdown(t->srv_fd, SHUT_WR);
3176 /* We must ensure that the read part is still alive
3177 * when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003178 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003179 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003180
3181 t->srv_state = SV_STSHUTW;
3182 if (!(t->flags & SN_ERR_MASK))
3183 t->flags |= SN_ERR_SRVTO;
3184 if (!(t->flags & SN_FINST_MASK))
3185 t->flags |= SN_FINST_H;
3186 return 1;
3187 }
3188
3189 /*
3190 * And now the non-error cases.
3191 */
3192
3193 /* Data remaining in the request buffer.
3194 * This happens during the first pass here, and during
3195 * long posts.
3196 */
3197 else if (likely(req->l)) {
Willy Tarreau66319382007-04-08 17:17:37 +02003198 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3199 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003200 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3201 if (req->wex) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003202 /* FIXME: to prevent the server from expiring read timeouts during writes,
3203 * we refresh it. */
3204 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003205 }
3206 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003207 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003208
Willy Tarreaua15645d2007-03-18 16:22:39 +01003209 /* nothing left in the request buffer */
3210 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003211 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3212 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003213 req->wex = TICK_ETERNITY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003214 }
3215 }
3216
3217 return t->srv_state != SV_STHEADERS;
3218 }
3219
3220
3221 /*****************************************************************
3222 * More interesting part now : we know that we have a complete *
3223 * response which at least looks like HTTP. We have an indicator *
3224 * of each header's length, so we can parse them quickly. *
3225 ****************************************************************/
3226
Willy Tarreau9cdde232007-05-02 20:58:19 +02003227 /* ensure we keep this pointer to the beginning of the message */
3228 msg->sol = rep->data + msg->som;
3229
Willy Tarreaua15645d2007-03-18 16:22:39 +01003230 /*
3231 * 1: get the status code and check for cacheability.
3232 */
3233
3234 t->logs.logwait &= ~LW_RESP;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003235 txn->status = strl2ui(rep->data + msg->sl.st.c, msg->sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003236
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003237 switch (txn->status) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003238 case 200:
3239 case 203:
3240 case 206:
3241 case 300:
3242 case 301:
3243 case 410:
3244 /* RFC2616 @13.4:
3245 * "A response received with a status code of
3246 * 200, 203, 206, 300, 301 or 410 MAY be stored
3247 * by a cache (...) unless a cache-control
3248 * directive prohibits caching."
3249 *
3250 * RFC2616 @9.5: POST method :
3251 * "Responses to this method are not cacheable,
3252 * unless the response includes appropriate
3253 * Cache-Control or Expires header fields."
3254 */
3255 if (likely(txn->meth != HTTP_METH_POST) &&
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003256 (t->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
Willy Tarreau3d300592007-03-18 18:34:41 +01003257 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003258 break;
3259 default:
3260 break;
3261 }
3262
3263 /*
3264 * 2: we may need to capture headers
3265 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003266 if (unlikely((t->logs.logwait & LW_RSPHDR) && t->fe->rsp_cap))
Willy Tarreaua15645d2007-03-18 16:22:39 +01003267 capture_headers(rep->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003268 txn->rsp.cap, t->fe->rsp_cap);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003269
3270 /*
3271 * 3: we will have to evaluate the filters.
3272 * As opposed to version 1.2, now they will be evaluated in the
3273 * filters order and not in the header order. This means that
3274 * each filter has to be validated among all headers.
3275 *
3276 * Filters are tried with ->be first, then with ->fe if it is
3277 * different from ->be.
3278 */
3279
3280 t->flags &= ~SN_CONN_CLOSED; /* prepare for inspection */
3281
3282 cur_proxy = t->be;
3283 while (1) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003284 struct proxy *rule_set = cur_proxy;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003285
3286 /* try headers filters */
3287 if (rule_set->rsp_exp != NULL) {
3288 if (apply_filters_to_response(t, rep, rule_set->rsp_exp) < 0) {
3289 return_bad_resp:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003290 if (t->srv) {
3291 t->srv->cur_sess--;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003292 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003293 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003294 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003295 cur_proxy->failed_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003296 return_srv_prx_502:
Willy Tarreaufa645582007-06-03 15:59:52 +02003297 buffer_shutr(rep);
3298 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003299 fd_delete(t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003300 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003301 txn->status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01003302 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003303 if (!(t->flags & SN_ERR_MASK))
3304 t->flags |= SN_ERR_PRXCOND;
3305 if (!(t->flags & SN_FINST_MASK))
3306 t->flags |= SN_FINST_H;
3307 /* We used to have a free connection slot. Since we'll never use it,
3308 * we have to inform the server that it may be used by another session.
3309 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003310 if (t->srv && may_dequeue_tasks(t->srv, cur_proxy))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003311 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003312 return 1;
3313 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003314 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003315
Willy Tarreaua15645d2007-03-18 16:22:39 +01003316 /* has the response been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01003317 if (txn->flags & TX_SVDENY) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003318 if (t->srv) {
3319 t->srv->cur_sess--;
3320 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003321 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003322 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003323 cur_proxy->denied_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003324 goto return_srv_prx_502;
3325 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003326
Willy Tarreaua15645d2007-03-18 16:22:39 +01003327 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003328 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01003329 !(t->flags & SN_CONN_CLOSED)) {
3330 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003331 int cur_idx, old_idx, delta, val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003332 struct hdr_idx_elem *cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003333
Willy Tarreaua15645d2007-03-18 16:22:39 +01003334 cur_next = rep->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
3335 old_idx = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003336
Willy Tarreaua15645d2007-03-18 16:22:39 +01003337 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
3338 cur_hdr = &txn->hdr_idx.v[cur_idx];
3339 cur_ptr = cur_next;
3340 cur_end = cur_ptr + cur_hdr->len;
3341 cur_next = cur_end + cur_hdr->cr + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003342
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003343 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
3344 if (val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003345 /* 3 possibilities :
3346 * - we have already set Connection: close,
3347 * so we remove this line.
3348 * - we have not yet set Connection: close,
3349 * but this line indicates close. We leave
3350 * it untouched and set the flag.
3351 * - we have not yet set Connection: close,
3352 * and this line indicates non-close. We
3353 * replace it.
3354 */
3355 if (t->flags & SN_CONN_CLOSED) {
3356 delta = buffer_replace2(rep, cur_ptr, cur_next, NULL, 0);
3357 txn->rsp.eoh += delta;
3358 cur_next += delta;
3359 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3360 txn->hdr_idx.used--;
3361 cur_hdr->len = 0;
3362 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003363 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
3364 delta = buffer_replace2(rep, cur_ptr + val, cur_end,
3365 "close", 5);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003366 cur_next += delta;
3367 cur_hdr->len += delta;
3368 txn->rsp.eoh += delta;
3369 }
3370 t->flags |= SN_CONN_CLOSED;
3371 }
3372 }
3373 old_idx = cur_idx;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003374 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003375 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003376
Willy Tarreaua15645d2007-03-18 16:22:39 +01003377 /* add response headers from the rule sets in the same order */
3378 for (cur_idx = 0; cur_idx < rule_set->nb_rspadd; cur_idx++) {
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003379 if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx,
3380 rule_set->rsp_add[cur_idx])) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003381 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003382 }
3383
Willy Tarreaua15645d2007-03-18 16:22:39 +01003384 /* check whether we're already working on the frontend */
3385 if (cur_proxy == t->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003386 break;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003387 cur_proxy = t->fe;
3388 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003389
Willy Tarreaua15645d2007-03-18 16:22:39 +01003390 /*
3391 * 4: check for server cookie.
3392 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003393 if (t->be->cookie_name || t->be->appsession_name || t->be->capture_name
3394 || (t->be->options & PR_O_CHK_CACHE))
3395 manage_server_side_cookies(t, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003396
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003397
Willy Tarreaua15645d2007-03-18 16:22:39 +01003398 /*
Willy Tarreau396d2c62007-11-04 19:30:00 +01003399 * 5: check for cache-control or pragma headers if required.
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003400 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003401 if ((t->be->options & (PR_O_COOK_NOC | PR_O_CHK_CACHE)) != 0)
3402 check_response_for_cacheability(t, rep);
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003403
3404 /*
3405 * 6: add server cookie in the response if needed
Willy Tarreaua15645d2007-03-18 16:22:39 +01003406 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003407 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
3408 (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003409 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003410
Willy Tarreaua15645d2007-03-18 16:22:39 +01003411 /* the server is known, it's not the one the client requested, we have to
3412 * insert a set-cookie here, except if we want to insert only on POST
3413 * requests and this one isn't. Note that servers which don't have cookies
3414 * (eg: some backup servers) will return a full cookie removal request.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003415 */
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003416 len = sprintf(trash, "Set-Cookie: %s=%s; path=/",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003417 t->be->cookie_name,
Willy Tarreaua15645d2007-03-18 16:22:39 +01003418 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003419
Krzysztof Piotr Oledzki1acf2172008-05-29 23:03:34 +02003420 if (t->be->cookie_domain)
3421 len += sprintf(trash+len, "; domain=%s", t->be->cookie_domain);
Krzysztof Piotr Oledzkiefe3b6f2008-05-23 23:49:32 +02003422
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003423 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3424 trash, len)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003425 goto return_bad_resp;
Willy Tarreau3d300592007-03-18 18:34:41 +01003426 txn->flags |= TX_SCK_INSERTED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003427
Willy Tarreaua15645d2007-03-18 16:22:39 +01003428 /* Here, we will tell an eventual cache on the client side that we don't
3429 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3430 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3431 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3432 */
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003433 if ((t->be->options & PR_O_COOK_NOC) && (txn->flags & TX_CACHEABLE)) {
3434
3435 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
3436
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003437 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3438 "Cache-control: private", 22)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003439 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003440 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003441 }
3442
3443
3444 /*
Willy Tarreaua15645d2007-03-18 16:22:39 +01003445 * 7: check if result will be cacheable with a cookie.
3446 * We'll block the response if security checks have caught
3447 * nasty things such as a cacheable cookie.
3448 */
Willy Tarreau3d300592007-03-18 18:34:41 +01003449 if (((txn->flags & (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) ==
3450 (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003451 (t->be->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003452
Willy Tarreaua15645d2007-03-18 16:22:39 +01003453 /* we're in presence of a cacheable response containing
3454 * a set-cookie header. We'll block it as requested by
3455 * the 'checkcache' option, and send an alert.
3456 */
3457 if (t->srv) {
3458 t->srv->cur_sess--;
3459 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003460 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003461 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003462 t->be->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003463
Willy Tarreaua15645d2007-03-18 16:22:39 +01003464 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003465 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003466 send_log(t->be, LOG_ALERT,
3467 "Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003468 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003469 goto return_srv_prx_502;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003470 }
3471
Willy Tarreaua15645d2007-03-18 16:22:39 +01003472 /*
3473 * 8: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02003474 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003475 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02003476 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003477 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02003478 if ((unlikely(msg->sl.st.v_l != 8) ||
3479 unlikely(req->data[msg->som + 7] != '0')) &&
3480 unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003481 "Connection: close", 17)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003482 goto return_bad_resp;
3483 t->flags |= SN_CONN_CLOSED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003484 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003485
Willy Tarreaubaaee002006-06-26 02:48:02 +02003486
Willy Tarreaua15645d2007-03-18 16:22:39 +01003487 /*************************************************************
3488 * OK, that's finished for the headers. We have done what we *
3489 * could. Let's switch to the DATA state. *
3490 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02003491
Willy Tarreaua15645d2007-03-18 16:22:39 +01003492 t->srv_state = SV_STDATA;
3493 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02003494 t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003495
3496 /* client connection already closed or option 'forceclose' required :
3497 * we close the server's outgoing connection right now.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003498 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003499 if ((req->l == 0) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003500 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->options & PR_O_FORCE_CLO)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003501 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003502 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003503
3504 /* We must ensure that the read part is still alive when switching
3505 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003506 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003507 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003508
Willy Tarreaua15645d2007-03-18 16:22:39 +01003509 shutdown(t->srv_fd, SHUT_WR);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003510 t->srv_state = SV_STSHUTW;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003511 }
3512
Willy Tarreaua15645d2007-03-18 16:22:39 +01003513#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003514 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003515 /* TCP splicing supported by both FE and BE */
3516 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003517 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003518#endif
3519 /* if the user wants to log as soon as possible, without counting
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003520 * bytes from the server, then this is the right moment. We have
3521 * to temporarily assign bytes_out to log what we currently have.
3522 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003523 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
3524 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreau8b3977f2008-01-18 11:16:32 +01003525 t->logs.bytes_out = txn->rsp.eoh;
Willy Tarreau42250582007-04-01 01:30:43 +02003526 if (t->fe->to_log & LW_REQ)
3527 http_sess_log(t);
3528 else
3529 tcp_sess_log(t);
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003530 t->logs.bytes_out = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003531 }
3532
Willy Tarreaua15645d2007-03-18 16:22:39 +01003533 /* Note: we must not try to cheat by jumping directly to DATA,
3534 * otherwise we would not let the client side wake up.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003535 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003536
3537 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003538 }
3539 else if (s == SV_STDATA) {
3540 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003541 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02003542 buffer_shutr(rep);
3543 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003544 fd_delete(t->srv_fd);
3545 if (t->srv) {
3546 t->srv->cur_sess--;
3547 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003548 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003549 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003550 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003551 t->srv_state = SV_STCLOSE;
3552 if (!(t->flags & SN_ERR_MASK))
3553 t->flags |= SN_ERR_SRVCL;
3554 if (!(t->flags & SN_FINST_MASK))
3555 t->flags |= SN_FINST_D;
3556 /* We used to have a free connection slot. Since we'll never use it,
3557 * we have to inform the server that it may be used by another session.
3558 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003559 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003560 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003561
3562 return 1;
3563 }
3564 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003565 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003566 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003567 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003568 t->srv_state = SV_STSHUTR;
3569 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3570 return 1;
3571 }
3572 /* end of client read and no more data to send */
3573 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003574 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003575 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003576 shutdown(t->srv_fd, SHUT_WR);
3577 /* We must ensure that the read part is still alive when switching
3578 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003579 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003580 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003581
3582 t->srv_state = SV_STSHUTW;
3583 return 1;
3584 }
3585 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003586 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003587 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003588 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003589 t->srv_state = SV_STSHUTR;
3590 if (!(t->flags & SN_ERR_MASK))
3591 t->flags |= SN_ERR_SRVTO;
3592 if (!(t->flags & SN_FINST_MASK))
3593 t->flags |= SN_FINST_D;
3594 return 1;
3595 }
3596 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003597 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003598 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003599 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003600 shutdown(t->srv_fd, SHUT_WR);
3601 /* We must ensure that the read part is still alive when switching
3602 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003603 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003604 rep->cex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003605 t->srv_state = SV_STSHUTW;
3606 if (!(t->flags & SN_ERR_MASK))
3607 t->flags |= SN_ERR_SRVTO;
3608 if (!(t->flags & SN_FINST_MASK))
3609 t->flags |= SN_FINST_D;
3610 return 1;
3611 }
3612
3613 /* recompute request time-outs */
3614 if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003615 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3616 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003617 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003618 }
3619 }
3620 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau66319382007-04-08 17:17:37 +02003621 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3622 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003623 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3624 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003625 /* FIXME: to prevent the server from expiring read timeouts during writes,
3626 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02003627 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003628 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003629 }
3630 }
3631
3632 /* recompute response time-outs */
3633 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003634 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003635 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003636 }
3637 }
3638 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003639 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003640 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003641 }
3642 }
3643
3644 return 0; /* other cases change nothing */
3645 }
3646 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003647 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003648 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003649 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003650 fd_delete(t->srv_fd);
3651 if (t->srv) {
3652 t->srv->cur_sess--;
3653 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003654 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003655 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003656 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003657 //close(t->srv_fd);
3658 t->srv_state = SV_STCLOSE;
3659 if (!(t->flags & SN_ERR_MASK))
3660 t->flags |= SN_ERR_SRVCL;
3661 if (!(t->flags & SN_FINST_MASK))
3662 t->flags |= SN_FINST_D;
3663 /* We used to have a free connection slot. Since we'll never use it,
3664 * we have to inform the server that it may be used by another session.
3665 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003666 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003667 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003668
3669 return 1;
3670 }
3671 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003672 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003673 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003674 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003675 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003676 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003677 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003678 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003679 //close(t->srv_fd);
3680 t->srv_state = SV_STCLOSE;
3681 /* We used to have a free connection slot. Since we'll never use it,
3682 * we have to inform the server that it may be used by another session.
3683 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003684 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003685 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003686
3687 return 1;
3688 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003689 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003690 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003691 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003692 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003693 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003694 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003695 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003696 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003697 //close(t->srv_fd);
3698 t->srv_state = SV_STCLOSE;
3699 if (!(t->flags & SN_ERR_MASK))
3700 t->flags |= SN_ERR_SRVTO;
3701 if (!(t->flags & SN_FINST_MASK))
3702 t->flags |= SN_FINST_D;
3703 /* We used to have a free connection slot. Since we'll never use it,
3704 * we have to inform the server that it may be used by another session.
3705 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003706 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003707 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003708
3709 return 1;
3710 }
3711 else if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003712 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3713 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003714 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003715 }
3716 }
3717 else { /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02003718 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3719 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003720 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003721 }
3722 }
3723 return 0;
3724 }
3725 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003726 if (rep->flags & BF_READ_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003727 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003728 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003729 fd_delete(t->srv_fd);
3730 if (t->srv) {
3731 t->srv->cur_sess--;
3732 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003733 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003734 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003735 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003736 //close(t->srv_fd);
3737 t->srv_state = SV_STCLOSE;
3738 if (!(t->flags & SN_ERR_MASK))
3739 t->flags |= SN_ERR_SRVCL;
3740 if (!(t->flags & SN_FINST_MASK))
3741 t->flags |= SN_FINST_D;
3742 /* We used to have a free connection slot. Since we'll never use it,
3743 * we have to inform the server that it may be used by another session.
3744 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003745 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003746 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003747
3748 return 1;
3749 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003750 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003751 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003752 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003753 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003754 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003755 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003756 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003757 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003758 //close(t->srv_fd);
3759 t->srv_state = SV_STCLOSE;
3760 /* We used to have a free connection slot. Since we'll never use it,
3761 * we have to inform the server that it may be used by another session.
3762 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003763 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003764 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003765
3766 return 1;
3767 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003768 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003769 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003770 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003771 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003772 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003773 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003774 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003775 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003776 //close(t->srv_fd);
3777 t->srv_state = SV_STCLOSE;
3778 if (!(t->flags & SN_ERR_MASK))
3779 t->flags |= SN_ERR_SRVTO;
3780 if (!(t->flags & SN_FINST_MASK))
3781 t->flags |= SN_FINST_D;
3782 /* We used to have a free connection slot. Since we'll never use it,
3783 * we have to inform the server that it may be used by another session.
3784 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003785 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003786 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003787
3788 return 1;
3789 }
3790 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003791 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003792 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003793 }
3794 }
3795 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003796 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003797 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003798 }
3799 }
3800 return 0;
3801 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003802 else if (s == SV_STANALYZE){
3803 /* this server state is set by the client to study the body for server assignment */
3804
3805 /* Have we been through this long enough to timeout? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003806 if (!tick_is_expired(req->rex, now_ms)) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003807 /* balance url_param check_post should have been the only to get into this.
3808 * just wait for data, check to compare how much
3809 */
3810 struct http_msg * msg = &t->txn.req;
3811 unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 :msg->eoh + 1;
3812 unsigned long len = req->total - body;
3813 long long limit = t->be->url_param_post_limit;
3814 struct hdr_ctx ctx;
3815 ctx.idx = 0;
3816 /* now if we have a length, we'll take the hint */
3817 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
3818 if ( ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",ctx.vlen)==0) {
3819 unsigned int chunk = 0;
3820 while ( body < req->total && !HTTP_IS_CRLF(msg->sol[body])) {
3821 char c = msg->sol[body];
3822 if (ishex(c)) {
3823 unsigned int hex = toupper(c) - '0';
3824 if ( hex > 9 )
3825 hex -= 'A' - '9' - 1;
3826 chunk = (chunk << 4) | hex;
3827 }
3828 else break;
3829 body++;
3830 len--;
3831 }
3832 if ( body == req->total )
3833 return 0; /* end of buffer? data missing! */
3834
3835 if ( memcmp(msg->sol+body, "\r\n", 2) != 0 )
3836 return 0; /* chunked encoding len ends with CRLF, and we don't have it yet */
3837
3838 /* if we support more then one chunk here, we have to do it again when assigning server
3839 1. how much entity data do we have? new var
3840 2. should save entity_start, entity_cursor, elen & rlen in req; so we don't repeat scanning here
3841 3. test if elen > limit, or set new limit to elen if 0 (end of entity found)
3842 */
3843
3844 if ( chunk < limit )
3845 limit = chunk; /* only reading one chunk */
3846 } else {
3847 if ( msg->hdr_content_len < limit )
3848 limit = msg->hdr_content_len;
3849 }
3850 if ( len < limit )
3851 return 0;
3852 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003853 t->srv_state = SV_STIDLE;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003854 return 1;
3855 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003856 else { /* SV_STCLOSE : nothing to do */
3857 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
3858 int len;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003859 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003860 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003861 write(1, trash, len);
3862 }
3863 return 0;
3864 }
3865 return 0;
3866}
3867
3868
3869/*
3870 * Produces data for the session <s> depending on its source. Expects to be
3871 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3872 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3873 * session, which it uses to keep on being called when there is free space in
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003874 * the buffer, or simply by letting an empty buffer upon return. It returns 1
Willy Tarreaubaaee002006-06-26 02:48:02 +02003875 * if it changes the session state from CL_STSHUTR, otherwise 0.
3876 */
3877int produce_content(struct session *s)
3878{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003879 if (s->data_source == DATA_SRC_NONE) {
3880 s->flags &= ~SN_SELF_GEN;
3881 return 1;
3882 }
3883 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003884 /* dump server statistics */
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01003885 int ret = stats_dump_http(s, s->be->uri_auth);
Willy Tarreau91861262007-10-17 17:06:05 +02003886 if (ret >= 0)
3887 return ret;
3888 /* -1 indicates an error */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003889 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003890
Willy Tarreau91861262007-10-17 17:06:05 +02003891 /* unknown data source or internal error */
3892 s->txn.status = 500;
3893 client_retnclose(s, error_message(s, HTTP_ERR_500));
3894 if (!(s->flags & SN_ERR_MASK))
3895 s->flags |= SN_ERR_PRXCOND;
3896 if (!(s->flags & SN_FINST_MASK))
3897 s->flags |= SN_FINST_R;
3898 s->flags &= ~SN_SELF_GEN;
3899 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003900}
3901
3902
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003903/* Iterate the same filter through all request headers.
3904 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003905 * Since it can manage the switch to another backend, it updates the per-proxy
3906 * DENY stats.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003907 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003908int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003909{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003910 char term;
3911 char *cur_ptr, *cur_end, *cur_next;
3912 int cur_idx, old_idx, last_hdr;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003913 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003914 struct hdr_idx_elem *cur_hdr;
3915 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003916
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003917 last_hdr = 0;
3918
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003919 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003920 old_idx = 0;
3921
3922 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01003923 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003924 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003925 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003926 (exp->action == ACT_ALLOW ||
3927 exp->action == ACT_DENY ||
3928 exp->action == ACT_TARPIT))
3929 return 0;
3930
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003931 cur_idx = txn->hdr_idx.v[old_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003932 if (!cur_idx)
3933 break;
3934
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003935 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003936 cur_ptr = cur_next;
3937 cur_end = cur_ptr + cur_hdr->len;
3938 cur_next = cur_end + cur_hdr->cr + 1;
3939
3940 /* Now we have one header between cur_ptr and cur_end,
3941 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003942 */
3943
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003944 /* The annoying part is that pattern matching needs
3945 * that we modify the contents to null-terminate all
3946 * strings before testing them.
3947 */
3948
3949 term = *cur_end;
3950 *cur_end = '\0';
3951
3952 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3953 switch (exp->action) {
3954 case ACT_SETBE:
3955 /* It is not possible to jump a second time.
3956 * FIXME: should we return an HTTP/500 here so that
3957 * the admin knows there's a problem ?
3958 */
3959 if (t->be != t->fe)
3960 break;
3961
3962 /* Swithing Proxy */
3963 t->be = (struct proxy *) exp->replace;
3964
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003965 /* right now, the backend switch is not overly complicated
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003966 * because we have associated req_cap and rsp_cap to the
3967 * frontend, and the beconn will be updated later.
3968 */
3969
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003970 t->rep->rto = t->req->wto = t->be->timeout.server;
3971 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02003972 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003973 last_hdr = 1;
3974 break;
3975
3976 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003977 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003978 last_hdr = 1;
3979 break;
3980
3981 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003982 txn->flags |= TX_CLDENY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003983 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003984 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003985 break;
3986
3987 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003988 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003989 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003990 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003991 break;
3992
3993 case ACT_REPLACE:
3994 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3995 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3996 /* FIXME: if the user adds a newline in the replacement, the
3997 * index will not be recalculated for now, and the new line
3998 * will not be counted as a new header.
3999 */
4000
4001 cur_end += delta;
4002 cur_next += delta;
4003 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004004 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004005 break;
4006
4007 case ACT_REMOVE:
4008 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
4009 cur_next += delta;
4010
4011 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004012 txn->req.eoh += delta;
4013 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4014 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004015 cur_hdr->len = 0;
4016 cur_end = NULL; /* null-term has been rewritten */
4017 break;
4018
4019 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004020 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004021 if (cur_end)
4022 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004023
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004024 /* keep the link from this header to next one in case of later
4025 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004026 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004027 old_idx = cur_idx;
4028 }
4029 return 0;
4030}
4031
4032
4033/* Apply the filter to the request line.
4034 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4035 * or -1 if a replacement resulted in an invalid request line.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004036 * Since it can manage the switch to another backend, it updates the per-proxy
4037 * DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004038 */
4039int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
4040{
4041 char term;
4042 char *cur_ptr, *cur_end;
4043 int done;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004044 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004045 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004046
Willy Tarreau58f10d72006-12-04 02:26:12 +01004047
Willy Tarreau3d300592007-03-18 18:34:41 +01004048 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004049 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004050 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004051 (exp->action == ACT_ALLOW ||
4052 exp->action == ACT_DENY ||
4053 exp->action == ACT_TARPIT))
4054 return 0;
4055 else if (exp->action == ACT_REMOVE)
4056 return 0;
4057
4058 done = 0;
4059
Willy Tarreau9cdde232007-05-02 20:58:19 +02004060 cur_ptr = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004061 cur_end = cur_ptr + txn->req.sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004062
4063 /* Now we have the request line between cur_ptr and cur_end */
4064
4065 /* The annoying part is that pattern matching needs
4066 * that we modify the contents to null-terminate all
4067 * strings before testing them.
4068 */
4069
4070 term = *cur_end;
4071 *cur_end = '\0';
4072
4073 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4074 switch (exp->action) {
4075 case ACT_SETBE:
4076 /* It is not possible to jump a second time.
4077 * FIXME: should we return an HTTP/500 here so that
4078 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01004079 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004080 if (t->be != t->fe)
4081 break;
4082
4083 /* Swithing Proxy */
4084 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004085
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004086 /* right now, the backend switch is not too much complicated
4087 * because we have associated req_cap and rsp_cap to the
4088 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004089 */
4090
Willy Tarreaud7c30f92007-12-03 01:38:36 +01004091 t->rep->rto = t->req->wto = t->be->timeout.server;
4092 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02004093 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004094 done = 1;
4095 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004096
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004097 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004098 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004099 done = 1;
4100 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004101
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004102 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004103 txn->flags |= TX_CLDENY;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004104 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004105 done = 1;
4106 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004107
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004108 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01004109 txn->flags |= TX_CLTARPIT;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004110 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004111 done = 1;
4112 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004113
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004114 case ACT_REPLACE:
4115 *cur_end = term; /* restore the string terminator */
4116 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4117 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
4118 /* FIXME: if the user adds a newline in the replacement, the
4119 * index will not be recalculated for now, and the new line
4120 * will not be counted as a new header.
4121 */
Willy Tarreaua496b602006-12-17 23:15:24 +01004122
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004123 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004124 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01004125
Willy Tarreau9cdde232007-05-02 20:58:19 +02004126 txn->req.sol = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004127 cur_end = (char *)http_parse_reqline(&txn->req, req->data,
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004128 HTTP_MSG_RQMETH,
4129 cur_ptr, cur_end + 1,
4130 NULL, NULL);
4131 if (unlikely(!cur_end))
4132 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01004133
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004134 /* we have a full request and we know that we have either a CR
4135 * or an LF at <ptr>.
4136 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004137 txn->meth = find_http_meth(cur_ptr, txn->req.sl.rq.m_l);
4138 hdr_idx_set_start(&txn->hdr_idx, txn->req.sl.rq.l, *cur_end == '\r');
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004139 /* there is no point trying this regex on headers */
4140 return 1;
4141 }
4142 }
4143 *cur_end = term; /* restore the string terminator */
4144 return done;
4145}
Willy Tarreau97de6242006-12-27 17:18:38 +01004146
Willy Tarreau58f10d72006-12-04 02:26:12 +01004147
Willy Tarreau58f10d72006-12-04 02:26:12 +01004148
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004149/*
4150 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
4151 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
Willy Tarreaua15645d2007-03-18 16:22:39 +01004152 * unparsable request. Since it can manage the switch to another backend, it
4153 * updates the per-proxy DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004154 */
4155int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
4156{
Willy Tarreau3d300592007-03-18 18:34:41 +01004157 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004158 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004159 while (exp && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004160 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004161
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004162 /*
4163 * The interleaving of transformations and verdicts
4164 * makes it difficult to decide to continue or stop
4165 * the evaluation.
4166 */
4167
Willy Tarreau3d300592007-03-18 18:34:41 +01004168 if ((txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004169 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4170 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
4171 exp = exp->next;
4172 continue;
4173 }
4174
4175 /* Apply the filter to the request line. */
4176 ret = apply_filter_to_req_line(t, req, exp);
4177 if (unlikely(ret < 0))
4178 return -1;
4179
4180 if (likely(ret == 0)) {
4181 /* The filter did not match the request, it can be
4182 * iterated through all headers.
4183 */
4184 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004185 }
4186 exp = exp->next;
4187 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004188 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004189}
4190
4191
Willy Tarreaua15645d2007-03-18 16:22:39 +01004192
Willy Tarreau58f10d72006-12-04 02:26:12 +01004193/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004194 * Manage client-side cookie. It can impact performance by about 2% so it is
4195 * desirable to call it only when needed.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004196 */
4197void manage_client_side_cookies(struct session *t, struct buffer *req)
4198{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004199 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004200 char *p1, *p2, *p3, *p4;
4201 char *del_colon, *del_cookie, *colon;
4202 int app_cookies;
4203
4204 appsess *asession_temp = NULL;
4205 appsess local_asession;
4206
4207 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004208 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004209
Willy Tarreau2a324282006-12-05 00:05:46 +01004210 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004211 * we start with the start line.
4212 */
Willy Tarreau83969f42007-01-22 08:55:47 +01004213 old_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004214 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004215
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004216 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004217 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004218 int val;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004219
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004220 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01004221 cur_ptr = cur_next;
4222 cur_end = cur_ptr + cur_hdr->len;
4223 cur_next = cur_end + cur_hdr->cr + 1;
4224
4225 /* We have one full header between cur_ptr and cur_end, and the
4226 * next header starts at cur_next. We're only interested in
4227 * "Cookie:" headers.
4228 */
4229
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004230 val = http_header_match2(cur_ptr, cur_end, "Cookie", 6);
4231 if (!val) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004232 old_idx = cur_idx;
4233 continue;
4234 }
4235
4236 /* Now look for cookies. Conforming to RFC2109, we have to support
4237 * attributes whose name begin with a '$', and associate them with
4238 * the right cookie, if we want to delete this cookie.
4239 * So there are 3 cases for each cookie read :
4240 * 1) it's a special attribute, beginning with a '$' : ignore it.
4241 * 2) it's a server id cookie that we *MAY* want to delete : save
4242 * some pointers on it (last semi-colon, beginning of cookie...)
4243 * 3) it's an application cookie : we *MAY* have to delete a previous
4244 * "special" cookie.
4245 * At the end of loop, if a "special" cookie remains, we may have to
4246 * remove it. If no application cookie persists in the header, we
4247 * *MUST* delete it
4248 */
4249
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004250 colon = p1 = cur_ptr + val; /* first non-space char after 'Cookie:' */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004251
Willy Tarreau58f10d72006-12-04 02:26:12 +01004252 /* del_cookie == NULL => nothing to be deleted */
4253 del_colon = del_cookie = NULL;
4254 app_cookies = 0;
4255
4256 while (p1 < cur_end) {
4257 /* skip spaces and colons, but keep an eye on these ones */
4258 while (p1 < cur_end) {
4259 if (*p1 == ';' || *p1 == ',')
4260 colon = p1;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004261 else if (!isspace((unsigned char)*p1))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004262 break;
4263 p1++;
4264 }
4265
4266 if (p1 == cur_end)
4267 break;
4268
4269 /* p1 is at the beginning of the cookie name */
4270 p2 = p1;
4271 while (p2 < cur_end && *p2 != '=')
4272 p2++;
4273
4274 if (p2 == cur_end)
4275 break;
4276
4277 p3 = p2 + 1; /* skips the '=' sign */
4278 if (p3 == cur_end)
4279 break;
4280
4281 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004282 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';' && *p4 != ',')
Willy Tarreau58f10d72006-12-04 02:26:12 +01004283 p4++;
4284
4285 /* here, we have the cookie name between p1 and p2,
4286 * and its value between p3 and p4.
4287 * we can process it :
4288 *
4289 * Cookie: NAME=VALUE;
4290 * | || || |
4291 * | || || +--> p4
4292 * | || |+-------> p3
4293 * | || +--------> p2
4294 * | |+------------> p1
4295 * | +-------------> colon
4296 * +--------------------> cur_ptr
4297 */
4298
4299 if (*p1 == '$') {
4300 /* skip this one */
4301 }
4302 else {
4303 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004304 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004305 txn->cli_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004306 (p4 - p1 >= t->fe->capture_namelen) &&
4307 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004308 int log_len = p4 - p1;
4309
Willy Tarreau086b3b42007-05-13 21:45:51 +02004310 if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004311 Alert("HTTP logging : out of memory.\n");
4312 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004313 if (log_len > t->fe->capture_len)
4314 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004315 memcpy(txn->cli_cookie, p1, log_len);
4316 txn->cli_cookie[log_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004317 }
4318 }
4319
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004320 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4321 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004322 /* Cool... it's the right one */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004323 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004324 char *delim;
4325
4326 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4327 * have the server ID betweek p3 and delim, and the original cookie between
4328 * delim+1 and p4. Otherwise, delim==p4 :
4329 *
4330 * Cookie: NAME=SRV~VALUE;
4331 * | || || | |
4332 * | || || | +--> p4
4333 * | || || +--------> delim
4334 * | || |+-----------> p3
4335 * | || +------------> p2
4336 * | |+----------------> p1
4337 * | +-----------------> colon
4338 * +------------------------> cur_ptr
4339 */
4340
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004341 if (t->be->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004342 for (delim = p3; delim < p4; delim++)
4343 if (*delim == COOKIE_DELIM)
4344 break;
4345 }
4346 else
4347 delim = p4;
4348
4349
4350 /* Here, we'll look for the first running server which supports the cookie.
4351 * This allows to share a same cookie between several servers, for example
4352 * to dedicate backup servers to specific servers only.
4353 * However, to prevent clients from sticking to cookie-less backup server
4354 * when they have incidentely learned an empty cookie, we simply ignore
4355 * empty cookies and mark them as invalid.
4356 */
4357 if (delim == p3)
4358 srv = NULL;
4359
4360 while (srv) {
Willy Tarreau92f2ab12007-02-02 22:14:47 +01004361 if (srv->cookie && (srv->cklen == delim - p3) &&
4362 !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004363 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004364 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004365 txn->flags &= ~TX_CK_MASK;
4366 txn->flags |= TX_CK_VALID;
4367 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004368 t->srv = srv;
4369 break;
4370 } else {
4371 /* we found a server, but it's down */
Willy Tarreau3d300592007-03-18 18:34:41 +01004372 txn->flags &= ~TX_CK_MASK;
4373 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004374 }
4375 }
4376 srv = srv->next;
4377 }
4378
Willy Tarreau3d300592007-03-18 18:34:41 +01004379 if (!srv && !(txn->flags & TX_CK_DOWN)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004380 /* no server matched this cookie */
Willy Tarreau3d300592007-03-18 18:34:41 +01004381 txn->flags &= ~TX_CK_MASK;
4382 txn->flags |= TX_CK_INVALID;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004383 }
4384
4385 /* depending on the cookie mode, we may have to either :
4386 * - delete the complete cookie if we're in insert+indirect mode, so that
4387 * the server never sees it ;
4388 * - remove the server id from the cookie value, and tag the cookie as an
4389 * application cookie so that it does not get accidentely removed later,
4390 * if we're in cookie prefix mode
4391 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004392 if ((t->be->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004393 int delta; /* negative */
4394
4395 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
4396 p4 += delta;
4397 cur_end += delta;
4398 cur_next += delta;
4399 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004400 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004401
4402 del_cookie = del_colon = NULL;
4403 app_cookies++; /* protect the header from deletion */
4404 }
4405 else if (del_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004406 (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 +01004407 del_cookie = p1;
4408 del_colon = colon;
4409 }
4410 } else {
4411 /* now we know that we must keep this cookie since it's
4412 * not ours. But if we wanted to delete our cookie
4413 * earlier, we cannot remove the complete header, but we
4414 * can remove the previous block itself.
4415 */
4416 app_cookies++;
4417
4418 if (del_cookie != NULL) {
4419 int delta; /* negative */
4420
4421 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
4422 p4 += delta;
4423 cur_end += delta;
4424 cur_next += delta;
4425 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004426 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004427 del_cookie = del_colon = NULL;
4428 }
4429 }
4430
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004431 if ((t->be->appsession_name != NULL) &&
4432 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004433 /* first, let's see if the cookie is our appcookie*/
4434
4435 /* Cool... it's the right one */
4436
4437 asession_temp = &local_asession;
4438
Willy Tarreau63963c62007-05-13 21:29:55 +02004439 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004440 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4441 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4442 return;
4443 }
4444
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004445 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4446 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004447 asession_temp->serverid = NULL;
Willy Tarreau51041c72007-09-09 21:56:53 +02004448
Willy Tarreau58f10d72006-12-04 02:26:12 +01004449 /* only do insert, if lookup fails */
Willy Tarreau51041c72007-09-09 21:56:53 +02004450 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4451 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004452 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004453 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004454 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004455 Alert("Not enough memory process_cli():asession:calloc().\n");
4456 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4457 return;
4458 }
4459
4460 asession_temp->sessid = local_asession.sessid;
4461 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004462 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004463 } else {
4464 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004465 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004466 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004467 if (asession_temp->serverid == NULL) {
4468 Alert("Found Application Session without matching server.\n");
4469 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004470 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004471 while (srv) {
4472 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004473 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004474 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004475 txn->flags &= ~TX_CK_MASK;
4476 txn->flags |= TX_CK_VALID;
4477 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004478 t->srv = srv;
4479 break;
4480 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01004481 txn->flags &= ~TX_CK_MASK;
4482 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004483 }
4484 }
4485 srv = srv->next;
4486 }/* end while(srv) */
4487 }/* end else if server == NULL */
4488
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004489 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004490 }/* end if ((t->proxy->appsession_name != NULL) ... */
4491 }
4492
4493 /* we'll have to look for another cookie ... */
4494 p1 = p4;
4495 } /* while (p1 < cur_end) */
4496
4497 /* There's no more cookie on this line.
4498 * We may have marked the last one(s) for deletion.
4499 * We must do this now in two ways :
4500 * - if there is no app cookie, we simply delete the header ;
4501 * - if there are app cookies, we must delete the end of the
4502 * string properly, including the colon/semi-colon before
4503 * the cookie name.
4504 */
4505 if (del_cookie != NULL) {
4506 int delta;
4507 if (app_cookies) {
4508 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
4509 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004510 cur_hdr->len += delta;
4511 } else {
4512 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004513
4514 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004515 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4516 txn->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004517 cur_hdr->len = 0;
4518 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01004519 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004520 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004521 }
4522
4523 /* keep the link from this header to next one */
4524 old_idx = cur_idx;
4525 } /* end of cookie processing on this header */
4526}
4527
4528
Willy Tarreaua15645d2007-03-18 16:22:39 +01004529/* Iterate the same filter through all response headers contained in <rtr>.
4530 * Returns 1 if this filter can be stopped upon return, otherwise 0.
4531 */
4532int apply_filter_to_resp_headers(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4533{
4534 char term;
4535 char *cur_ptr, *cur_end, *cur_next;
4536 int cur_idx, old_idx, last_hdr;
4537 struct http_txn *txn = &t->txn;
4538 struct hdr_idx_elem *cur_hdr;
4539 int len, delta;
4540
4541 last_hdr = 0;
4542
4543 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4544 old_idx = 0;
4545
4546 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004547 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004548 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004549 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004550 (exp->action == ACT_ALLOW ||
4551 exp->action == ACT_DENY))
4552 return 0;
4553
4554 cur_idx = txn->hdr_idx.v[old_idx].next;
4555 if (!cur_idx)
4556 break;
4557
4558 cur_hdr = &txn->hdr_idx.v[cur_idx];
4559 cur_ptr = cur_next;
4560 cur_end = cur_ptr + cur_hdr->len;
4561 cur_next = cur_end + cur_hdr->cr + 1;
4562
4563 /* Now we have one header between cur_ptr and cur_end,
4564 * and the next header starts at cur_next.
4565 */
4566
4567 /* The annoying part is that pattern matching needs
4568 * that we modify the contents to null-terminate all
4569 * strings before testing them.
4570 */
4571
4572 term = *cur_end;
4573 *cur_end = '\0';
4574
4575 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4576 switch (exp->action) {
4577 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004578 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004579 last_hdr = 1;
4580 break;
4581
4582 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004583 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004584 last_hdr = 1;
4585 break;
4586
4587 case ACT_REPLACE:
4588 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4589 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4590 /* FIXME: if the user adds a newline in the replacement, the
4591 * index will not be recalculated for now, and the new line
4592 * will not be counted as a new header.
4593 */
4594
4595 cur_end += delta;
4596 cur_next += delta;
4597 cur_hdr->len += delta;
4598 txn->rsp.eoh += delta;
4599 break;
4600
4601 case ACT_REMOVE:
4602 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4603 cur_next += delta;
4604
4605 /* FIXME: this should be a separate function */
4606 txn->rsp.eoh += delta;
4607 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4608 txn->hdr_idx.used--;
4609 cur_hdr->len = 0;
4610 cur_end = NULL; /* null-term has been rewritten */
4611 break;
4612
4613 }
4614 }
4615 if (cur_end)
4616 *cur_end = term; /* restore the string terminator */
4617
4618 /* keep the link from this header to next one in case of later
4619 * removal of next header.
4620 */
4621 old_idx = cur_idx;
4622 }
4623 return 0;
4624}
4625
4626
4627/* Apply the filter to the status line in the response buffer <rtr>.
4628 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4629 * or -1 if a replacement resulted in an invalid status line.
4630 */
4631int apply_filter_to_sts_line(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4632{
4633 char term;
4634 char *cur_ptr, *cur_end;
4635 int done;
4636 struct http_txn *txn = &t->txn;
4637 int len, delta;
4638
4639
Willy Tarreau3d300592007-03-18 18:34:41 +01004640 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004641 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004642 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004643 (exp->action == ACT_ALLOW ||
4644 exp->action == ACT_DENY))
4645 return 0;
4646 else if (exp->action == ACT_REMOVE)
4647 return 0;
4648
4649 done = 0;
4650
Willy Tarreau9cdde232007-05-02 20:58:19 +02004651 cur_ptr = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004652 cur_end = cur_ptr + txn->rsp.sl.rq.l;
4653
4654 /* Now we have the status line between cur_ptr and cur_end */
4655
4656 /* The annoying part is that pattern matching needs
4657 * that we modify the contents to null-terminate all
4658 * strings before testing them.
4659 */
4660
4661 term = *cur_end;
4662 *cur_end = '\0';
4663
4664 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4665 switch (exp->action) {
4666 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004667 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004668 done = 1;
4669 break;
4670
4671 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004672 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004673 done = 1;
4674 break;
4675
4676 case ACT_REPLACE:
4677 *cur_end = term; /* restore the string terminator */
4678 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4679 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4680 /* FIXME: if the user adds a newline in the replacement, the
4681 * index will not be recalculated for now, and the new line
4682 * will not be counted as a new header.
4683 */
4684
4685 txn->rsp.eoh += delta;
4686 cur_end += delta;
4687
Willy Tarreau9cdde232007-05-02 20:58:19 +02004688 txn->rsp.sol = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004689 cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data,
Willy Tarreau02785762007-04-03 14:45:44 +02004690 HTTP_MSG_RPVER,
Willy Tarreaua15645d2007-03-18 16:22:39 +01004691 cur_ptr, cur_end + 1,
4692 NULL, NULL);
4693 if (unlikely(!cur_end))
4694 return -1;
4695
4696 /* we have a full respnse and we know that we have either a CR
4697 * or an LF at <ptr>.
4698 */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004699 txn->status = strl2ui(rtr->data + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004700 hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.rq.l, *cur_end == '\r');
4701 /* there is no point trying this regex on headers */
4702 return 1;
4703 }
4704 }
4705 *cur_end = term; /* restore the string terminator */
4706 return done;
4707}
4708
4709
4710
4711/*
4712 * Apply all the resp filters <exp> to all headers in buffer <rtr> of session <t>.
4713 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
4714 * unparsable response.
4715 */
4716int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4717{
Willy Tarreau3d300592007-03-18 18:34:41 +01004718 struct http_txn *txn = &t->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004719 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004720 while (exp && !(txn->flags & TX_SVDENY)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004721 int ret;
4722
4723 /*
4724 * The interleaving of transformations and verdicts
4725 * makes it difficult to decide to continue or stop
4726 * the evaluation.
4727 */
4728
Willy Tarreau3d300592007-03-18 18:34:41 +01004729 if ((txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004730 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4731 exp->action == ACT_PASS)) {
4732 exp = exp->next;
4733 continue;
4734 }
4735
4736 /* Apply the filter to the status line. */
4737 ret = apply_filter_to_sts_line(t, rtr, exp);
4738 if (unlikely(ret < 0))
4739 return -1;
4740
4741 if (likely(ret == 0)) {
4742 /* The filter did not match the response, it can be
4743 * iterated through all headers.
4744 */
4745 apply_filter_to_resp_headers(t, rtr, exp);
4746 }
4747 exp = exp->next;
4748 }
4749 return 0;
4750}
4751
4752
4753
4754/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004755 * Manage server-side cookies. It can impact performance by about 2% so it is
4756 * desirable to call it only when needed.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004757 */
4758void manage_server_side_cookies(struct session *t, struct buffer *rtr)
4759{
4760 struct http_txn *txn = &t->txn;
4761 char *p1, *p2, *p3, *p4;
4762
4763 appsess *asession_temp = NULL;
4764 appsess local_asession;
4765
4766 char *cur_ptr, *cur_end, *cur_next;
4767 int cur_idx, old_idx, delta;
4768
Willy Tarreaua15645d2007-03-18 16:22:39 +01004769 /* Iterate through the headers.
4770 * we start with the start line.
4771 */
4772 old_idx = 0;
4773 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4774
4775 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
4776 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004777 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004778
4779 cur_hdr = &txn->hdr_idx.v[cur_idx];
4780 cur_ptr = cur_next;
4781 cur_end = cur_ptr + cur_hdr->len;
4782 cur_next = cur_end + cur_hdr->cr + 1;
4783
4784 /* We have one full header between cur_ptr and cur_end, and the
4785 * next header starts at cur_next. We're only interested in
4786 * "Cookie:" headers.
4787 */
4788
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004789 val = http_header_match2(cur_ptr, cur_end, "Set-Cookie", 10);
4790 if (!val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004791 old_idx = cur_idx;
4792 continue;
4793 }
4794
4795 /* OK, right now we know we have a set-cookie at cur_ptr */
Willy Tarreau3d300592007-03-18 18:34:41 +01004796 txn->flags |= TX_SCK_ANY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004797
4798
4799 /* maybe we only wanted to see if there was a set-cookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004800 if (t->be->cookie_name == NULL &&
4801 t->be->appsession_name == NULL &&
4802 t->be->capture_name == NULL)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004803 return;
4804
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004805 p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004806
4807 while (p1 < cur_end) { /* in fact, we'll break after the first cookie */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004808 if (p1 == cur_end || *p1 == ';') /* end of cookie */
4809 break;
4810
4811 /* p1 is at the beginning of the cookie name */
4812 p2 = p1;
4813
4814 while (p2 < cur_end && *p2 != '=' && *p2 != ';')
4815 p2++;
4816
4817 if (p2 == cur_end || *p2 == ';') /* next cookie */
4818 break;
4819
4820 p3 = p2 + 1; /* skip the '=' sign */
4821 if (p3 == cur_end)
4822 break;
4823
4824 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004825 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';')
Willy Tarreaua15645d2007-03-18 16:22:39 +01004826 p4++;
4827
4828 /* here, we have the cookie name between p1 and p2,
4829 * and its value between p3 and p4.
4830 * we can process it.
4831 */
4832
4833 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004834 if (t->be->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004835 txn->srv_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004836 (p4 - p1 >= t->be->capture_namelen) &&
4837 memcmp(p1, t->be->capture_name, t->be->capture_namelen) == 0) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004838 int log_len = p4 - p1;
4839
Willy Tarreau086b3b42007-05-13 21:45:51 +02004840 if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004841 Alert("HTTP logging : out of memory.\n");
4842 }
4843
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004844 if (log_len > t->be->capture_len)
4845 log_len = t->be->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004846 memcpy(txn->srv_cookie, p1, log_len);
4847 txn->srv_cookie[log_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004848 }
4849
4850 /* now check if we need to process it for persistence */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004851 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4852 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004853 /* Cool... it's the right one */
Willy Tarreau3d300592007-03-18 18:34:41 +01004854 txn->flags |= TX_SCK_SEEN;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004855
4856 /* If the cookie is in insert mode on a known server, we'll delete
4857 * this occurrence because we'll insert another one later.
4858 * We'll delete it too if the "indirect" option is set and we're in
4859 * a direct access. */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004860 if (((t->srv) && (t->be->options & PR_O_COOK_INS)) ||
4861 ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004862 /* this header must be deleted */
4863 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4864 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4865 txn->hdr_idx.used--;
4866 cur_hdr->len = 0;
4867 cur_next += delta;
4868 txn->rsp.eoh += delta;
4869
Willy Tarreau3d300592007-03-18 18:34:41 +01004870 txn->flags |= TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004871 }
4872 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004873 (t->be->options & PR_O_COOK_RW)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004874 /* replace bytes p3->p4 with the cookie name associated
4875 * with this server since we know it.
4876 */
4877 delta = buffer_replace2(rtr, p3, p4, t->srv->cookie, t->srv->cklen);
4878 cur_hdr->len += delta;
4879 cur_next += delta;
4880 txn->rsp.eoh += delta;
4881
Willy Tarreau3d300592007-03-18 18:34:41 +01004882 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004883 }
4884 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004885 (t->be->options & PR_O_COOK_PFX)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004886 /* insert the cookie name associated with this server
4887 * before existing cookie, and insert a delimitor between them..
4888 */
4889 delta = buffer_replace2(rtr, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4890 cur_hdr->len += delta;
4891 cur_next += delta;
4892 txn->rsp.eoh += delta;
4893
4894 p3[t->srv->cklen] = COOKIE_DELIM;
Willy Tarreau3d300592007-03-18 18:34:41 +01004895 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004896 }
4897 }
4898 /* next, let's see if the cookie is our appcookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004899 else if ((t->be->appsession_name != NULL) &&
4900 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004901
4902 /* Cool... it's the right one */
4903
4904 size_t server_id_len = strlen(t->srv->id) + 1;
4905 asession_temp = &local_asession;
4906
Willy Tarreau63963c62007-05-13 21:29:55 +02004907 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004908 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4909 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4910 return;
4911 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004912 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4913 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004914 asession_temp->serverid = NULL;
4915
4916 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01004917 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4918 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004919 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004920 Alert("Not enough Memory process_srv():asession:calloc().\n");
4921 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
4922 return;
4923 }
4924 asession_temp->sessid = local_asession.sessid;
4925 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004926 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
4927 } else {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004928 /* free wasted memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004929 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau51041c72007-09-09 21:56:53 +02004930 }
4931
Willy Tarreaua15645d2007-03-18 16:22:39 +01004932 if (asession_temp->serverid == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004933 if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004934 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4935 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4936 return;
4937 }
4938 asession_temp->serverid[0] = '\0';
4939 }
4940
4941 if (asession_temp->serverid[0] == '\0')
4942 memcpy(asession_temp->serverid, t->srv->id, server_id_len);
4943
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004944 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004945
4946#if defined(DEBUG_HASH)
Willy Tarreau51041c72007-09-09 21:56:53 +02004947 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreaua15645d2007-03-18 16:22:39 +01004948#endif
4949 }/* end if ((t->proxy->appsession_name != NULL) ... */
4950 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4951 } /* we're now at the end of the cookie value */
4952
4953 /* keep the link from this header to next one */
4954 old_idx = cur_idx;
4955 } /* end of cookie processing on this header */
4956}
4957
4958
4959
4960/*
4961 * Check if response is cacheable or not. Updates t->flags.
4962 */
4963void check_response_for_cacheability(struct session *t, struct buffer *rtr)
4964{
4965 struct http_txn *txn = &t->txn;
4966 char *p1, *p2;
4967
4968 char *cur_ptr, *cur_end, *cur_next;
4969 int cur_idx;
4970
Willy Tarreau5df51872007-11-25 16:20:08 +01004971 if (!(txn->flags & TX_CACHEABLE))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004972 return;
4973
4974 /* Iterate through the headers.
4975 * we start with the start line.
4976 */
4977 cur_idx = 0;
4978 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4979
4980 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
4981 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004982 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004983
4984 cur_hdr = &txn->hdr_idx.v[cur_idx];
4985 cur_ptr = cur_next;
4986 cur_end = cur_ptr + cur_hdr->len;
4987 cur_next = cur_end + cur_hdr->cr + 1;
4988
4989 /* We have one full header between cur_ptr and cur_end, and the
4990 * next header starts at cur_next. We're only interested in
4991 * "Cookie:" headers.
4992 */
4993
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004994 val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
4995 if (val) {
4996 if ((cur_end - (cur_ptr + val) >= 8) &&
4997 strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
4998 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
4999 return;
5000 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01005001 }
5002
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005003 val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
5004 if (!val)
Willy Tarreaua15645d2007-03-18 16:22:39 +01005005 continue;
5006
5007 /* OK, right now we know we have a cache-control header at cur_ptr */
5008
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005009 p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01005010
5011 if (p1 >= cur_end) /* no more info */
5012 continue;
5013
5014 /* p1 is at the beginning of the value */
5015 p2 = p1;
5016
Willy Tarreau8f8e6452007-06-17 21:51:38 +02005017 while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((unsigned char)*p2))
Willy Tarreaua15645d2007-03-18 16:22:39 +01005018 p2++;
5019
5020 /* we have a complete value between p1 and p2 */
5021 if (p2 < cur_end && *p2 == '=') {
5022 /* we have something of the form no-cache="set-cookie" */
5023 if ((cur_end - p1 >= 21) &&
5024 strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0
5025 && (p1[20] == '"' || p1[20] == ','))
Willy Tarreau3d300592007-03-18 18:34:41 +01005026 txn->flags &= ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005027 continue;
5028 }
5029
5030 /* OK, so we know that either p2 points to the end of string or to a comma */
5031 if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) ||
5032 ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) ||
5033 ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) ||
5034 ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005035 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005036 return;
5037 }
5038
5039 if ((p2 - p1 == 6) && strncasecmp(p1, "public", 6) == 0) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005040 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005041 continue;
5042 }
5043 }
5044}
5045
5046
Willy Tarreau58f10d72006-12-04 02:26:12 +01005047/*
5048 * Try to retrieve a known appsession in the URI, then the associated server.
5049 * If the server is found, it's assigned to the session.
5050 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005051void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01005052{
Willy Tarreau3d300592007-03-18 18:34:41 +01005053 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005054 appsess *asession_temp = NULL;
5055 appsess local_asession;
5056 char *request_line;
5057
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005058 if (t->be->appsession_name == NULL ||
Willy Tarreaub326fcc2007-03-03 13:54:32 +01005059 (t->txn.meth != HTTP_METH_GET && t->txn.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005060 (request_line = memchr(begin, ';', len)) == NULL ||
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005061 ((1 + t->be->appsession_name_len + 1 + t->be->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01005062 return;
5063
5064 /* skip ';' */
5065 request_line++;
5066
5067 /* look if we have a jsessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005068 if (strncasecmp(request_line, t->be->appsession_name, t->be->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01005069 return;
5070
5071 /* skip jsessionid= */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005072 request_line += t->be->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005073
5074 /* First try if we already have an appsession */
5075 asession_temp = &local_asession;
5076
Willy Tarreau63963c62007-05-13 21:29:55 +02005077 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005078 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
5079 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
5080 return;
5081 }
5082
5083 /* Copy the sessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005084 memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
5085 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005086 asession_temp->serverid = NULL;
5087
5088 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01005089 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
5090 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02005091 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005092 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005093 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005094 Alert("Not enough memory process_cli():asession:calloc().\n");
5095 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
5096 return;
5097 }
5098 asession_temp->sessid = local_asession.sessid;
5099 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02005100 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005101 }
5102 else {
5103 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005104 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005105 }
Willy Tarreau51041c72007-09-09 21:56:53 +02005106
Willy Tarreau0c303ee2008-07-07 00:09:58 +02005107 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005108 asession_temp->request_count++;
Willy Tarreau51041c72007-09-09 21:56:53 +02005109
Willy Tarreau58f10d72006-12-04 02:26:12 +01005110#if defined(DEBUG_HASH)
Willy Tarreau51041c72007-09-09 21:56:53 +02005111 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreau58f10d72006-12-04 02:26:12 +01005112#endif
5113 if (asession_temp->serverid == NULL) {
5114 Alert("Found Application Session without matching server.\n");
5115 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005116 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005117 while (srv) {
5118 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005119 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005120 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01005121 txn->flags &= ~TX_CK_MASK;
5122 txn->flags |= TX_CK_VALID;
5123 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005124 t->srv = srv;
5125 break;
5126 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01005127 txn->flags &= ~TX_CK_MASK;
5128 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005129 }
5130 }
5131 srv = srv->next;
5132 }
5133 }
5134}
5135
5136
Willy Tarreaub2513902006-12-17 14:52:38 +01005137/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005138 * In a GET or HEAD request, check if the requested URI matches the stats uri
5139 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01005140 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005141 * It is assumed that the request is either a HEAD or GET and that the
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005142 * t->be->uri_auth field is valid. An HTTP/401 response may be sent, or
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005143 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01005144 *
5145 * Returns 1 if the session's state changes, otherwise 0.
5146 */
5147int stats_check_uri_auth(struct session *t, struct proxy *backend)
5148{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005149 struct http_txn *txn = &t->txn;
Willy Tarreaub2513902006-12-17 14:52:38 +01005150 struct uri_auth *uri_auth = backend->uri_auth;
5151 struct user_auth *user;
5152 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005153 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01005154
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005155 memset(&t->data_ctx.stats, 0, sizeof(t->data_ctx.stats));
5156
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005157 /* check URI size */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005158 if (uri_auth->uri_len > txn->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01005159 return 0;
5160
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005161 h = t->req->data + txn->req.sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005162
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005163 /* the URI is in h */
5164 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01005165 return 0;
5166
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005167 h += uri_auth->uri_len;
5168 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 3) {
5169 if (memcmp(h, ";up", 3) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005170 t->data_ctx.stats.flags |= STAT_HIDE_DOWN;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005171 break;
5172 }
5173 h++;
5174 }
5175
5176 if (uri_auth->refresh) {
5177 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5178 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 10) {
5179 if (memcmp(h, ";norefresh", 10) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005180 t->data_ctx.stats.flags |= STAT_NO_REFRESH;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005181 break;
5182 }
5183 h++;
5184 }
5185 }
5186
Willy Tarreau55bb8452007-10-17 18:44:57 +02005187 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5188 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 4) {
5189 if (memcmp(h, ";csv", 4) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005190 t->data_ctx.stats.flags |= STAT_FMT_CSV;
Willy Tarreau55bb8452007-10-17 18:44:57 +02005191 break;
5192 }
5193 h++;
5194 }
5195
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005196 t->data_ctx.stats.flags |= STAT_SHOW_STAT | STAT_SHOW_INFO;
5197
Willy Tarreaub2513902006-12-17 14:52:38 +01005198 /* we are in front of a interceptable URI. Let's check
5199 * if there's an authentication and if it's valid.
5200 */
5201 user = uri_auth->users;
5202 if (!user) {
5203 /* no user auth required, it's OK */
5204 authenticated = 1;
5205 } else {
5206 authenticated = 0;
5207
5208 /* a user list is defined, we have to check.
5209 * skip 21 chars for "Authorization: Basic ".
5210 */
5211
5212 /* FIXME: this should move to an earlier place */
5213 cur_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005214 h = t->req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
5215 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
5216 int len = txn->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005217 if (len > 14 &&
5218 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005219 txn->auth_hdr.str = h;
5220 txn->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005221 break;
5222 }
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005223 h += len + txn->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01005224 }
5225
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005226 if (txn->auth_hdr.len < 21 ||
5227 memcmp(txn->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01005228 user = NULL;
5229
5230 while (user) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005231 if ((txn->auth_hdr.len == user->user_len + 14 + 7)
5232 && !memcmp(txn->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01005233 user->user_pwd, user->user_len)) {
5234 authenticated = 1;
5235 break;
5236 }
5237 user = user->next;
5238 }
5239 }
5240
5241 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01005242 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01005243
5244 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01005245 msg.str = trash;
5246 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005247 txn->status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01005248 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01005249 if (!(t->flags & SN_ERR_MASK))
5250 t->flags |= SN_ERR_PRXCOND;
5251 if (!(t->flags & SN_FINST_MASK))
5252 t->flags |= SN_FINST_R;
5253 return 1;
5254 }
5255
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005256 /* The request is valid, the user is authenticated. Let's start sending
Willy Tarreaub2513902006-12-17 14:52:38 +01005257 * data.
5258 */
Willy Tarreau284c7b32008-06-29 16:38:43 +02005259 EV_FD_CLR(t->cli_fd, DIR_RD);
5260 buffer_shutr(t->req);
5261 buffer_shutr(t->rep);
Willy Tarreaub2513902006-12-17 14:52:38 +01005262 t->cli_state = CL_STSHUTR;
5263 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau70089872008-06-13 21:12:51 +02005264 t->logs.tv_request = now;
Willy Tarreaub2513902006-12-17 14:52:38 +01005265 t->data_source = DATA_SRC_STATS;
5266 t->data_state = DATA_ST_INIT;
Willy Tarreau91e99932008-06-30 07:51:00 +02005267 t->task->nice = -32; /* small boost for HTTP statistics */
Willy Tarreaub2513902006-12-17 14:52:38 +01005268 produce_content(t);
5269 return 1;
5270}
5271
5272
Willy Tarreaubaaee002006-06-26 02:48:02 +02005273/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01005274 * Print a debug line with a header
5275 */
5276void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
5277{
5278 int len, max;
5279 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
5280 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
5281 max = end - start;
5282 UBOUND(max, sizeof(trash) - len - 1);
5283 len += strlcpy2(trash + len, start, max + 1);
5284 trash[len++] = '\n';
5285 write(1, trash, len);
5286}
5287
5288
Willy Tarreau8797c062007-05-07 00:55:35 +02005289/************************************************************************/
5290/* The code below is dedicated to ACL parsing and matching */
5291/************************************************************************/
5292
5293
5294
5295
5296/* 1. Check on METHOD
5297 * We use the pre-parsed method if it is known, and store its number as an
5298 * integer. If it is unknown, we use the pointer and the length.
5299 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005300static int acl_parse_meth(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005301{
5302 int len, meth;
5303
Willy Tarreauae8b7962007-06-09 23:10:04 +02005304 len = strlen(*text);
5305 meth = find_http_meth(*text, len);
Willy Tarreau8797c062007-05-07 00:55:35 +02005306
5307 pattern->val.i = meth;
5308 if (meth == HTTP_METH_OTHER) {
Willy Tarreauae8b7962007-06-09 23:10:04 +02005309 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005310 if (!pattern->ptr.str)
5311 return 0;
5312 pattern->len = len;
5313 }
5314 return 1;
5315}
5316
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005317static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005318acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
5319 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005320{
5321 int meth;
5322 struct http_txn *txn = l7;
5323
Willy Tarreaub6866442008-07-14 23:54:42 +02005324 if (!txn)
5325 return 0;
5326
Willy Tarreauc11416f2007-06-17 16:58:38 +02005327 if (txn->req.msg_state != HTTP_MSG_BODY)
5328 return 0;
5329
Willy Tarreau8797c062007-05-07 00:55:35 +02005330 meth = txn->meth;
5331 test->i = meth;
5332 if (meth == HTTP_METH_OTHER) {
Willy Tarreauc11416f2007-06-17 16:58:38 +02005333 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5334 /* ensure the indexes are not affected */
5335 return 0;
Willy Tarreau8797c062007-05-07 00:55:35 +02005336 test->len = txn->req.sl.rq.m_l;
5337 test->ptr = txn->req.sol;
5338 }
5339 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5340 return 1;
5341}
5342
5343static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
5344{
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005345 int icase;
5346
Willy Tarreau8797c062007-05-07 00:55:35 +02005347 if (test->i != pattern->val.i)
Willy Tarreau11382812008-07-09 16:18:21 +02005348 return ACL_PAT_FAIL;
Willy Tarreau8797c062007-05-07 00:55:35 +02005349
5350 if (test->i != HTTP_METH_OTHER)
Willy Tarreau11382812008-07-09 16:18:21 +02005351 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005352
5353 /* Other method, we must compare the strings */
5354 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +02005355 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005356
5357 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
5358 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) != 0) ||
5359 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +02005360 return ACL_PAT_FAIL;
5361 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005362}
5363
5364/* 2. Check on Request/Status Version
5365 * We simply compare strings here.
5366 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005367static int acl_parse_ver(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005368{
Willy Tarreauae8b7962007-06-09 23:10:04 +02005369 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005370 if (!pattern->ptr.str)
5371 return 0;
Willy Tarreauae8b7962007-06-09 23:10:04 +02005372 pattern->len = strlen(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005373 return 1;
5374}
5375
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005376static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005377acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
5378 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005379{
5380 struct http_txn *txn = l7;
5381 char *ptr;
5382 int len;
5383
Willy Tarreaub6866442008-07-14 23:54:42 +02005384 if (!txn)
5385 return 0;
5386
Willy Tarreauc11416f2007-06-17 16:58:38 +02005387 if (txn->req.msg_state != HTTP_MSG_BODY)
5388 return 0;
5389
Willy Tarreau8797c062007-05-07 00:55:35 +02005390 len = txn->req.sl.rq.v_l;
5391 ptr = txn->req.sol + txn->req.sl.rq.v - txn->req.som;
5392
5393 while ((len-- > 0) && (*ptr++ != '/'));
5394 if (len <= 0)
5395 return 0;
5396
5397 test->ptr = ptr;
5398 test->len = len;
5399
5400 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5401 return 1;
5402}
5403
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005404static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005405acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
5406 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005407{
5408 struct http_txn *txn = l7;
5409 char *ptr;
5410 int len;
5411
Willy Tarreaub6866442008-07-14 23:54:42 +02005412 if (!txn)
5413 return 0;
5414
Willy Tarreauc11416f2007-06-17 16:58:38 +02005415 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5416 return 0;
5417
Willy Tarreau8797c062007-05-07 00:55:35 +02005418 len = txn->rsp.sl.st.v_l;
5419 ptr = txn->rsp.sol;
5420
5421 while ((len-- > 0) && (*ptr++ != '/'));
5422 if (len <= 0)
5423 return 0;
5424
5425 test->ptr = ptr;
5426 test->len = len;
5427
5428 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5429 return 1;
5430}
5431
5432/* 3. Check on Status Code. We manipulate integers here. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005433static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005434acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, int dir,
5435 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005436{
5437 struct http_txn *txn = l7;
5438 char *ptr;
5439 int len;
5440
Willy Tarreaub6866442008-07-14 23:54:42 +02005441 if (!txn)
5442 return 0;
5443
Willy Tarreauc11416f2007-06-17 16:58:38 +02005444 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5445 return 0;
5446
Willy Tarreau8797c062007-05-07 00:55:35 +02005447 len = txn->rsp.sl.st.c_l;
5448 ptr = txn->rsp.sol + txn->rsp.sl.st.c - txn->rsp.som;
5449
5450 test->i = __strl2ui(ptr, len);
5451 test->flags = ACL_TEST_F_VOL_1ST;
5452 return 1;
5453}
5454
5455/* 4. Check on URL/URI. A pointer to the URI is stored. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005456static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005457acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
5458 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005459{
5460 struct http_txn *txn = l7;
5461
Willy Tarreaub6866442008-07-14 23:54:42 +02005462 if (!txn)
5463 return 0;
5464
Willy Tarreauc11416f2007-06-17 16:58:38 +02005465 if (txn->req.msg_state != HTTP_MSG_BODY)
5466 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005467
Willy Tarreauc11416f2007-06-17 16:58:38 +02005468 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5469 /* ensure the indexes are not affected */
5470 return 0;
5471
Willy Tarreau8797c062007-05-07 00:55:35 +02005472 test->len = txn->req.sl.rq.u_l;
5473 test->ptr = txn->req.sol + txn->req.sl.rq.u;
5474
Willy Tarreauf3d25982007-05-08 22:45:09 +02005475 /* we do not need to set READ_ONLY because the data is in a buffer */
5476 test->flags = ACL_TEST_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +02005477 return 1;
5478}
5479
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005480static int
5481acl_fetch_url_ip(struct proxy *px, struct session *l4, void *l7, int dir,
5482 struct acl_expr *expr, struct acl_test *test)
5483{
5484 struct http_txn *txn = l7;
5485
Willy Tarreaub6866442008-07-14 23:54:42 +02005486 if (!txn)
5487 return 0;
5488
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005489 if (txn->req.msg_state != HTTP_MSG_BODY)
5490 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005491
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005492 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5493 /* ensure the indexes are not affected */
5494 return 0;
5495
5496 /* Parse HTTP request */
5497 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5498 test->ptr = (void *)&((struct sockaddr_in *)&l4->srv_addr)->sin_addr;
5499 test->i = AF_INET;
5500
5501 /*
5502 * If we are parsing url in frontend space, we prepare backend stage
5503 * to not parse again the same url ! optimization lazyness...
5504 */
5505 if (px->options & PR_O_HTTP_PROXY)
5506 l4->flags |= SN_ADDR_SET;
5507
5508 test->flags = ACL_TEST_F_READ_ONLY;
5509 return 1;
5510}
5511
5512static int
5513acl_fetch_url_port(struct proxy *px, struct session *l4, void *l7, int dir,
5514 struct acl_expr *expr, struct acl_test *test)
5515{
5516 struct http_txn *txn = l7;
5517
Willy Tarreaub6866442008-07-14 23:54:42 +02005518 if (!txn)
5519 return 0;
5520
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005521 if (txn->req.msg_state != HTTP_MSG_BODY)
5522 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005523
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005524 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5525 /* ensure the indexes are not affected */
5526 return 0;
5527
5528 /* Same optimization as url_ip */
5529 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5530 test->i = ntohs(((struct sockaddr_in *)&l4->srv_addr)->sin_port);
5531
5532 if (px->options & PR_O_HTTP_PROXY)
5533 l4->flags |= SN_ADDR_SET;
5534
5535 test->flags = ACL_TEST_F_READ_ONLY;
5536 return 1;
5537}
5538
Willy Tarreauc11416f2007-06-17 16:58:38 +02005539/* 5. Check on HTTP header. A pointer to the beginning of the value is returned.
5540 * This generic function is used by both acl_fetch_chdr() and acl_fetch_shdr().
5541 */
Willy Tarreau33a7e692007-06-10 19:45:56 +02005542static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005543acl_fetch_hdr(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005544 struct acl_expr *expr, struct acl_test *test)
5545{
5546 struct http_txn *txn = l7;
5547 struct hdr_idx *idx = &txn->hdr_idx;
5548 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005549
Willy Tarreaub6866442008-07-14 23:54:42 +02005550 if (!txn)
5551 return 0;
5552
Willy Tarreau33a7e692007-06-10 19:45:56 +02005553 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5554 /* search for header from the beginning */
5555 ctx->idx = 0;
5556
Willy Tarreau33a7e692007-06-10 19:45:56 +02005557 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5558 test->flags |= ACL_TEST_F_FETCH_MORE;
5559 test->flags |= ACL_TEST_F_VOL_HDR;
5560 test->len = ctx->vlen;
5561 test->ptr = (char *)ctx->line + ctx->val;
5562 return 1;
5563 }
5564
5565 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5566 test->flags |= ACL_TEST_F_VOL_HDR;
5567 return 0;
5568}
5569
Willy Tarreau33a7e692007-06-10 19:45:56 +02005570static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005571acl_fetch_chdr(struct proxy *px, struct session *l4, void *l7, int dir,
5572 struct acl_expr *expr, struct acl_test *test)
5573{
5574 struct http_txn *txn = l7;
5575
Willy Tarreaub6866442008-07-14 23:54:42 +02005576 if (!txn)
5577 return 0;
5578
Willy Tarreauc11416f2007-06-17 16:58:38 +02005579 if (txn->req.msg_state != HTTP_MSG_BODY)
5580 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005581
Willy Tarreauc11416f2007-06-17 16:58:38 +02005582 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5583 /* ensure the indexes are not affected */
5584 return 0;
5585
5586 return acl_fetch_hdr(px, l4, txn, txn->req.sol, expr, test);
5587}
5588
5589static int
5590acl_fetch_shdr(struct proxy *px, struct session *l4, void *l7, int dir,
5591 struct acl_expr *expr, struct acl_test *test)
5592{
5593 struct http_txn *txn = l7;
5594
Willy Tarreaub6866442008-07-14 23:54:42 +02005595 if (!txn)
5596 return 0;
5597
Willy Tarreauc11416f2007-06-17 16:58:38 +02005598 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5599 return 0;
5600
5601 return acl_fetch_hdr(px, l4, txn, txn->rsp.sol, expr, test);
5602}
5603
5604/* 6. Check on HTTP header count. The number of occurrences is returned.
5605 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
5606 */
5607static int
5608acl_fetch_hdr_cnt(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005609 struct acl_expr *expr, struct acl_test *test)
5610{
5611 struct http_txn *txn = l7;
5612 struct hdr_idx *idx = &txn->hdr_idx;
5613 struct hdr_ctx ctx;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005614 int cnt;
Willy Tarreau8797c062007-05-07 00:55:35 +02005615
Willy Tarreaub6866442008-07-14 23:54:42 +02005616 if (!txn)
5617 return 0;
5618
Willy Tarreau33a7e692007-06-10 19:45:56 +02005619 ctx.idx = 0;
5620 cnt = 0;
5621 while (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, &ctx))
5622 cnt++;
5623
5624 test->i = cnt;
5625 test->flags = ACL_TEST_F_VOL_HDR;
5626 return 1;
5627}
5628
Willy Tarreauc11416f2007-06-17 16:58:38 +02005629static int
5630acl_fetch_chdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5631 struct acl_expr *expr, struct acl_test *test)
5632{
5633 struct http_txn *txn = l7;
5634
Willy Tarreaub6866442008-07-14 23:54:42 +02005635 if (!txn)
5636 return 0;
5637
Willy Tarreauc11416f2007-06-17 16:58:38 +02005638 if (txn->req.msg_state != HTTP_MSG_BODY)
5639 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005640
Willy Tarreauc11416f2007-06-17 16:58:38 +02005641 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5642 /* ensure the indexes are not affected */
5643 return 0;
5644
5645 return acl_fetch_hdr_cnt(px, l4, txn, txn->req.sol, expr, test);
5646}
5647
5648static int
5649acl_fetch_shdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5650 struct acl_expr *expr, struct acl_test *test)
5651{
5652 struct http_txn *txn = l7;
5653
Willy Tarreaub6866442008-07-14 23:54:42 +02005654 if (!txn)
5655 return 0;
5656
Willy Tarreauc11416f2007-06-17 16:58:38 +02005657 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5658 return 0;
5659
5660 return acl_fetch_hdr_cnt(px, l4, txn, txn->rsp.sol, expr, test);
5661}
5662
Willy Tarreau33a7e692007-06-10 19:45:56 +02005663/* 7. Check on HTTP header's integer value. The integer value is returned.
5664 * FIXME: the type is 'int', it may not be appropriate for everything.
Willy Tarreauc11416f2007-06-17 16:58:38 +02005665 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
Willy Tarreau33a7e692007-06-10 19:45:56 +02005666 */
5667static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005668acl_fetch_hdr_val(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005669 struct acl_expr *expr, struct acl_test *test)
5670{
5671 struct http_txn *txn = l7;
5672 struct hdr_idx *idx = &txn->hdr_idx;
5673 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005674
Willy Tarreaub6866442008-07-14 23:54:42 +02005675 if (!txn)
5676 return 0;
5677
Willy Tarreau33a7e692007-06-10 19:45:56 +02005678 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5679 /* search for header from the beginning */
5680 ctx->idx = 0;
5681
Willy Tarreau33a7e692007-06-10 19:45:56 +02005682 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5683 test->flags |= ACL_TEST_F_FETCH_MORE;
5684 test->flags |= ACL_TEST_F_VOL_HDR;
5685 test->i = strl2ic((char *)ctx->line + ctx->val, ctx->vlen);
5686 return 1;
5687 }
5688
5689 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5690 test->flags |= ACL_TEST_F_VOL_HDR;
5691 return 0;
5692}
5693
Willy Tarreauc11416f2007-06-17 16:58:38 +02005694static int
5695acl_fetch_chdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5696 struct acl_expr *expr, struct acl_test *test)
5697{
5698 struct http_txn *txn = l7;
5699
Willy Tarreaub6866442008-07-14 23:54:42 +02005700 if (!txn)
5701 return 0;
5702
Willy Tarreauc11416f2007-06-17 16:58:38 +02005703 if (txn->req.msg_state != HTTP_MSG_BODY)
5704 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005705
Willy Tarreauc11416f2007-06-17 16:58:38 +02005706 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5707 /* ensure the indexes are not affected */
5708 return 0;
5709
5710 return acl_fetch_hdr_val(px, l4, txn, txn->req.sol, expr, test);
5711}
5712
5713static int
5714acl_fetch_shdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5715 struct acl_expr *expr, struct acl_test *test)
5716{
5717 struct http_txn *txn = l7;
5718
Willy Tarreaub6866442008-07-14 23:54:42 +02005719 if (!txn)
5720 return 0;
5721
Willy Tarreauc11416f2007-06-17 16:58:38 +02005722 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5723 return 0;
5724
5725 return acl_fetch_hdr_val(px, l4, txn, txn->rsp.sol, expr, test);
5726}
5727
Willy Tarreau737b0c12007-06-10 21:28:46 +02005728/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at
5729 * the first '/' after the possible hostname, and ends before the possible '?'.
5730 */
5731static int
5732acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
5733 struct acl_expr *expr, struct acl_test *test)
5734{
5735 struct http_txn *txn = l7;
5736 char *ptr, *end;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005737
Willy Tarreaub6866442008-07-14 23:54:42 +02005738 if (!txn)
5739 return 0;
5740
Willy Tarreauc11416f2007-06-17 16:58:38 +02005741 if (txn->req.msg_state != HTTP_MSG_BODY)
5742 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005743
Willy Tarreauc11416f2007-06-17 16:58:38 +02005744 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5745 /* ensure the indexes are not affected */
5746 return 0;
5747
Willy Tarreau21d2af32008-02-14 20:25:24 +01005748 end = txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
5749 ptr = http_get_path(txn);
5750 if (!ptr)
Willy Tarreau737b0c12007-06-10 21:28:46 +02005751 return 0;
5752
5753 /* OK, we got the '/' ! */
5754 test->ptr = ptr;
5755
5756 while (ptr < end && *ptr != '?')
5757 ptr++;
5758
5759 test->len = ptr - test->ptr;
5760
5761 /* we do not need to set READ_ONLY because the data is in a buffer */
5762 test->flags = ACL_TEST_F_VOL_1ST;
5763 return 1;
5764}
5765
5766
Willy Tarreau8797c062007-05-07 00:55:35 +02005767
5768/************************************************************************/
5769/* All supported keywords must be declared here. */
5770/************************************************************************/
5771
5772/* Note: must not be declared <const> as its list will be overwritten */
5773static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005774 { "method", acl_parse_meth, acl_fetch_meth, acl_match_meth, ACL_USE_L7REQ_PERMANENT },
5775 { "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5776 { "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str, ACL_USE_L7RTR_VOLATILE },
5777 { "status", acl_parse_int, acl_fetch_stcode, acl_match_int, ACL_USE_L7RTR_PERMANENT },
Willy Tarreau8797c062007-05-07 00:55:35 +02005778
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005779 { "url", acl_parse_str, acl_fetch_url, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5780 { "url_beg", acl_parse_str, acl_fetch_url, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5781 { "url_end", acl_parse_str, acl_fetch_url, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5782 { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5783 { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5784 { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
5785 { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5786 { "url_ip", acl_parse_ip, acl_fetch_url_ip, acl_match_ip, ACL_USE_L7REQ_VOLATILE },
5787 { "url_port", acl_parse_int, acl_fetch_url_port, acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau8797c062007-05-07 00:55:35 +02005788
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005789 /* note: we should set hdr* to use ACL_USE_HDR_VOLATILE, and chdr* to use L7REQ_VOLATILE */
5790 { "hdr", acl_parse_str, acl_fetch_chdr, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5791 { "hdr_reg", acl_parse_reg, acl_fetch_chdr, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5792 { "hdr_beg", acl_parse_str, acl_fetch_chdr, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5793 { "hdr_end", acl_parse_str, acl_fetch_chdr, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5794 { "hdr_sub", acl_parse_str, acl_fetch_chdr, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5795 { "hdr_dir", acl_parse_str, acl_fetch_chdr, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5796 { "hdr_dom", acl_parse_str, acl_fetch_chdr, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
5797 { "hdr_cnt", acl_parse_int, acl_fetch_chdr_cnt,acl_match_int, ACL_USE_L7REQ_VOLATILE },
5798 { "hdr_val", acl_parse_int, acl_fetch_chdr_val,acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreauc11416f2007-06-17 16:58:38 +02005799
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005800 { "shdr", acl_parse_str, acl_fetch_shdr, acl_match_str, ACL_USE_L7RTR_VOLATILE },
5801 { "shdr_reg", acl_parse_reg, acl_fetch_shdr, acl_match_reg, ACL_USE_L7RTR_VOLATILE },
5802 { "shdr_beg", acl_parse_str, acl_fetch_shdr, acl_match_beg, ACL_USE_L7RTR_VOLATILE },
5803 { "shdr_end", acl_parse_str, acl_fetch_shdr, acl_match_end, ACL_USE_L7RTR_VOLATILE },
5804 { "shdr_sub", acl_parse_str, acl_fetch_shdr, acl_match_sub, ACL_USE_L7RTR_VOLATILE },
5805 { "shdr_dir", acl_parse_str, acl_fetch_shdr, acl_match_dir, ACL_USE_L7RTR_VOLATILE },
5806 { "shdr_dom", acl_parse_str, acl_fetch_shdr, acl_match_dom, ACL_USE_L7RTR_VOLATILE },
5807 { "shdr_cnt", acl_parse_int, acl_fetch_shdr_cnt,acl_match_int, ACL_USE_L7RTR_VOLATILE },
5808 { "shdr_val", acl_parse_int, acl_fetch_shdr_val,acl_match_int, ACL_USE_L7RTR_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005809
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005810 { "path", acl_parse_str, acl_fetch_path, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5811 { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5812 { "path_beg", acl_parse_str, acl_fetch_path, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5813 { "path_end", acl_parse_str, acl_fetch_path, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5814 { "path_sub", acl_parse_str, acl_fetch_path, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5815 { "path_dir", acl_parse_str, acl_fetch_path, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5816 { "path_dom", acl_parse_str, acl_fetch_path, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005817
Willy Tarreauf3d25982007-05-08 22:45:09 +02005818 { NULL, NULL, NULL, NULL },
5819
5820#if 0
Willy Tarreau8797c062007-05-07 00:55:35 +02005821 { "line", acl_parse_str, acl_fetch_line, acl_match_str },
5822 { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg },
5823 { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg },
5824 { "line_end", acl_parse_str, acl_fetch_line, acl_match_end },
5825 { "line_sub", acl_parse_str, acl_fetch_line, acl_match_sub },
5826 { "line_dir", acl_parse_str, acl_fetch_line, acl_match_dir },
5827 { "line_dom", acl_parse_str, acl_fetch_line, acl_match_dom },
5828
Willy Tarreau8797c062007-05-07 00:55:35 +02005829 { "cook", acl_parse_str, acl_fetch_cook, acl_match_str },
5830 { "cook_reg", acl_parse_reg, acl_fetch_cook, acl_match_reg },
5831 { "cook_beg", acl_parse_str, acl_fetch_cook, acl_match_beg },
5832 { "cook_end", acl_parse_str, acl_fetch_cook, acl_match_end },
5833 { "cook_sub", acl_parse_str, acl_fetch_cook, acl_match_sub },
5834 { "cook_dir", acl_parse_str, acl_fetch_cook, acl_match_dir },
5835 { "cook_dom", acl_parse_str, acl_fetch_cook, acl_match_dom },
5836 { "cook_pst", acl_parse_none, acl_fetch_cook, acl_match_pst },
5837
5838 { "auth_user", acl_parse_str, acl_fetch_user, acl_match_str },
5839 { "auth_regex", acl_parse_reg, acl_fetch_user, acl_match_reg },
5840 { "auth_clear", acl_parse_str, acl_fetch_auth, acl_match_str },
5841 { "auth_md5", acl_parse_str, acl_fetch_auth, acl_match_md5 },
5842 { NULL, NULL, NULL, NULL },
5843#endif
5844}};
5845
5846
5847__attribute__((constructor))
5848static void __http_protocol_init(void)
5849{
5850 acl_register_keywords(&acl_kws);
5851}
5852
5853
Willy Tarreau58f10d72006-12-04 02:26:12 +01005854/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02005855 * Local variables:
5856 * c-indent-level: 8
5857 * c-basic-offset: 8
5858 * End:
5859 */