blob: 5b1221f1cd457d2e77bce35097914f2909e786b2 [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
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002217 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d",
2218 pn[0], pn[1], pn[2], pn[3]);
2219
2220 if (unlikely(http_header_add_tail2(req, &txn->req,
2221 &txn->hdr_idx, trash, len)) < 0)
2222 goto return_bad_req;
2223 }
Willy Tarreau2a324282006-12-05 00:05:46 +01002224 }
2225 else if (t->cli_addr.ss_family == AF_INET6) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002226 /* FIXME: for the sake of completeness, we should also support
2227 * 'except' here, although it is mostly useless in this case.
2228 */
Willy Tarreau2a324282006-12-05 00:05:46 +01002229 int len;
2230 char pn[INET6_ADDRSTRLEN];
2231 inet_ntop(AF_INET6,
2232 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2233 pn, sizeof(pn));
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002234 len = sprintf(trash, "X-Forwarded-For: %s", pn);
2235 if (unlikely(http_header_add_tail2(req, &txn->req,
2236 &txn->hdr_idx, trash, len)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002237 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01002238 }
2239 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002240
Willy Tarreau2a324282006-12-05 00:05:46 +01002241 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002242 * 10: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02002243 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaub2513902006-12-17 14:52:38 +01002244 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02002245 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002246 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02002247 if ((unlikely(msg->sl.rq.v_l != 8) ||
2248 unlikely(req->data[msg->som + msg->sl.rq.v + 7] != '0')) &&
2249 unlikely(http_header_add_tail2(req, &txn->req, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002250 "Connection: close", 17)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002251 goto return_bad_req;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002252 t->flags |= SN_CONN_CLOSED;
Willy Tarreaue15d9132006-12-14 22:26:42 +01002253 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002254 /* Before we switch to data, was assignment set in manage_client_side_cookie?
2255 * If not assigned, perhaps we are balancing on url_param, but this is a
2256 * POST; and the parameters are in the body, maybe scan there to find our server.
2257 * (unless headers overflowed the buffer?)
2258 */
2259 if (!(t->flags & (SN_ASSIGNED|SN_DIRECT)) &&
2260 t->txn.meth == HTTP_METH_POST && t->be->url_param_name != NULL &&
2261 t->be->url_param_post_limit != 0 && req->total < BUFSIZE &&
2262 memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) {
2263 /* are there enough bytes here? total == l || r || rlim ?
2264 * len is unsigned, but eoh is int,
2265 * how many bytes of body have we received?
2266 * eoh is the first empty line of the header
2267 */
2268 /* already established CRLF or LF at eoh, move to start of message, find message length in buffer */
2269 unsigned long len = req->total - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1);
2270
2271 /* If we have HTTP/1.1 and Expect: 100-continue, then abort.
2272 * We can't assume responsibility for the server's decision,
2273 * on this URI and header set. See rfc2616: 14.20, 8.2.3,
2274 * We also can't change our mind later, about which server to choose, so round robin.
2275 */
2276 if ((likely(msg->sl.rq.v_l == 8) && req->data[msg->som + msg->sl.rq.v + 7] == '1')) {
2277 struct hdr_ctx ctx;
2278 ctx.idx = 0;
2279 /* Expect is allowed in 1.1, look for it */
2280 http_find_header2("Expect", 6, msg->sol, &txn->hdr_idx, &ctx);
2281 if (ctx.idx != 0 &&
2282 unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val,"100-continue",12)==0))
2283 /* We can't reliablly stall and wait for data, because of
2284 * .NET clients that don't conform to rfc2616; so, no need for
2285 * the next block to check length expectations.
2286 * We could send 100 status back to the client, but then we need to
2287 * re-write headers, and send the message. And this isn't the right
2288 * place for that action.
2289 * TODO: support Expect elsewhere and delete this block.
2290 */
2291 goto end_check_maybe_wait_for_body;
2292 }
2293 if ( likely(len > t->be->url_param_post_limit) ) {
2294 /* nothing to do, we got enough */
2295 } else {
2296 /* limit implies we are supposed to need this many bytes
2297 * to find the parameter. Let's see how many bytes we can wait for.
2298 */
2299 long long hint = len;
2300 struct hdr_ctx ctx;
2301 ctx.idx = 0;
2302 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
2303 if (unlikely(ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",7)==0)) {
2304 t->srv_state = SV_STANALYZE;
2305 } else {
2306 ctx.idx = 0;
2307 http_find_header2("Content-Length", 14, msg->sol, &txn->hdr_idx, &ctx);
2308 /* now if we have a length, we'll take the hint */
2309 if ( ctx.idx ) {
2310 /* We have Content-Length */
2311 if ( strl2llrc(ctx.line+ctx.val,ctx.vlen, &hint) )
2312 hint = 0; /* parse failure, untrusted client */
2313 else {
2314 if ( hint > 0 )
2315 msg->hdr_content_len = hint;
2316 else
2317 hint = 0; /* bad client, sent negative length */
2318 }
2319 }
2320 /* but limited to what we care about, maybe we don't expect any entity data (hint == 0) */
2321 if ( t->be->url_param_post_limit < hint )
2322 hint = t->be->url_param_post_limit;
2323 /* now do we really need to buffer more data? */
2324 if ( len < hint )
2325 t->srv_state = SV_STANALYZE;
2326 /* else... There are no body bytes to wait for */
2327 }
2328 }
2329 }
2330 end_check_maybe_wait_for_body:
Willy Tarreaubaaee002006-06-26 02:48:02 +02002331
Willy Tarreau2a324282006-12-05 00:05:46 +01002332 /*************************************************************
2333 * OK, that's finished for the headers. We have done what we *
2334 * could. Let's switch to the DATA state. *
2335 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02002336
Willy Tarreau2a324282006-12-05 00:05:46 +01002337 t->cli_state = CL_STDATA;
2338 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002339
Willy Tarreau70089872008-06-13 21:12:51 +02002340 t->logs.tv_request = now;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002341
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002342 if (!t->fe->timeout.client ||
2343 (t->srv_state < SV_STDATA && t->be->timeout.server)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002344 /* If the client has no timeout, or if the server is not ready yet,
2345 * and we know for sure that it can expire, then it's cleaner to
2346 * disable the timeout on the client side so that too low values
2347 * cannot make the sessions abort too early.
2348 *
2349 * FIXME-20050705: the server needs a way to re-enable this time-out
2350 * when it switches its state, otherwise a client can stay connected
2351 * indefinitely. This now seems to be OK.
2352 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002353 req->rex = TICK_ETERNITY;
Willy Tarreau2a324282006-12-05 00:05:46 +01002354 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002355
Willy Tarreau1fa31262007-12-03 00:36:16 +01002356 /* When a connection is tarpitted, we use the tarpit timeout,
2357 * which may be the same as the connect timeout if unspecified.
2358 * If unset, then set it to zero because we really want it to
2359 * eventually expire.
Willy Tarreau2a324282006-12-05 00:05:46 +01002360 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002361 if (txn->flags & TX_CLTARPIT) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002362 t->req->l = 0;
2363 /* flush the request so that we can drop the connection early
2364 * if the client closes first.
2365 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002366 req->cex = tick_add_ifset(now_ms, t->be->timeout.tarpit);
2367 if (!req->cex)
2368 req->cex = now_ms;
Willy Tarreau2a324282006-12-05 00:05:46 +01002369 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002370
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002371 /* OK let's go on with the BODY now */
Willy Tarreau06619262006-12-17 08:37:22 +01002372 goto process_data;
2373
2374 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002375 txn->req.msg_state = HTTP_MSG_ERROR;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002376 txn->status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01002377 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002378 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01002379 return_prx_cond:
2380 if (!(t->flags & SN_ERR_MASK))
2381 t->flags |= SN_ERR_PRXCOND;
2382 if (!(t->flags & SN_FINST_MASK))
2383 t->flags |= SN_FINST_R;
2384 return 1;
2385
Willy Tarreaubaaee002006-06-26 02:48:02 +02002386 }
2387 else if (c == CL_STDATA) {
2388 process_data:
2389 /* FIXME: this error handling is partly buggy because we always report
2390 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
2391 * or HEADER phase. BTW, it's not logical to expire the client while
2392 * we're waiting for the server to connect.
2393 */
2394 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002395 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002396 buffer_shutr(req);
2397 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002398 fd_delete(t->cli_fd);
2399 t->cli_state = CL_STCLOSE;
2400 if (!(t->flags & SN_ERR_MASK))
2401 t->flags |= SN_ERR_CLICL;
2402 if (!(t->flags & SN_FINST_MASK)) {
2403 if (t->pend_pos)
2404 t->flags |= SN_FINST_Q;
2405 else if (s == SV_STCONN)
2406 t->flags |= SN_FINST_C;
2407 else
2408 t->flags |= SN_FINST_D;
2409 }
2410 return 1;
2411 }
2412 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002413 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002414 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002415 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002416 t->cli_state = CL_STSHUTR;
2417 return 1;
2418 }
2419 /* last server read and buffer empty */
2420 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002421 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02002422 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002423 shutdown(t->cli_fd, SHUT_WR);
2424 /* We must ensure that the read part is still alive when switching
2425 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002426 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002427 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002428 t->cli_state = CL_STSHUTW;
2429 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2430 return 1;
2431 }
2432 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002433 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002434 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002435 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002436 t->cli_state = CL_STSHUTR;
2437 if (!(t->flags & SN_ERR_MASK))
2438 t->flags |= SN_ERR_CLITO;
2439 if (!(t->flags & SN_FINST_MASK)) {
2440 if (t->pend_pos)
2441 t->flags |= SN_FINST_Q;
2442 else if (s == SV_STCONN)
2443 t->flags |= SN_FINST_C;
2444 else
2445 t->flags |= SN_FINST_D;
2446 }
2447 return 1;
2448 }
2449 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002450 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002451 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02002452 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002453 shutdown(t->cli_fd, SHUT_WR);
2454 /* We must ensure that the read part is still alive when switching
2455 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002456 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002457 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002458
2459 t->cli_state = CL_STSHUTW;
2460 if (!(t->flags & SN_ERR_MASK))
2461 t->flags |= SN_ERR_CLITO;
2462 if (!(t->flags & SN_FINST_MASK)) {
2463 if (t->pend_pos)
2464 t->flags |= SN_FINST_Q;
2465 else if (s == SV_STCONN)
2466 t->flags |= SN_FINST_C;
2467 else
2468 t->flags |= SN_FINST_D;
2469 }
2470 return 1;
2471 }
2472
2473 if (req->l >= req->rlim - req->data) {
2474 /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02002475 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002476 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002477 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002478 }
2479 } else {
2480 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002481 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002482 if (!t->fe->timeout.client ||
2483 (t->srv_state < SV_STDATA && t->be->timeout.server))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002484 /* If the client has no timeout, or if the server not ready yet, and we
2485 * know for sure that it can expire, then it's cleaner to disable the
2486 * timeout on the client side so that too low values cannot make the
2487 * sessions abort too early.
2488 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002489 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002490 else
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002491 req->rex = tick_add(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002492 }
2493 }
2494
2495 if ((rep->l == 0) ||
2496 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002497 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2498 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002499 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002500 }
2501 } else {
2502 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002503 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2504 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002505 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
2506 if (rep->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002507 /* FIXME: to prevent the client from expiring read timeouts during writes,
2508 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002509 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002510 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002511 }
2512 }
2513 return 0; /* other cases change nothing */
2514 }
2515 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002516 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002517 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002518 fd_delete(t->cli_fd);
2519 t->cli_state = CL_STCLOSE;
2520 if (!(t->flags & SN_ERR_MASK))
2521 t->flags |= SN_ERR_CLICL;
2522 if (!(t->flags & SN_FINST_MASK)) {
2523 if (t->pend_pos)
2524 t->flags |= SN_FINST_Q;
2525 else if (s == SV_STCONN)
2526 t->flags |= SN_FINST_C;
2527 else
2528 t->flags |= SN_FINST_D;
2529 }
2530 return 1;
2531 }
2532 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
2533 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002534 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002535 fd_delete(t->cli_fd);
2536 t->cli_state = CL_STCLOSE;
2537 return 1;
2538 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002539 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002540 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002541 fd_delete(t->cli_fd);
2542 t->cli_state = CL_STCLOSE;
2543 if (!(t->flags & SN_ERR_MASK))
2544 t->flags |= SN_ERR_CLITO;
2545 if (!(t->flags & SN_FINST_MASK)) {
2546 if (t->pend_pos)
2547 t->flags |= SN_FINST_Q;
2548 else if (s == SV_STCONN)
2549 t->flags |= SN_FINST_C;
2550 else
2551 t->flags |= SN_FINST_D;
2552 }
2553 return 1;
2554 }
2555
2556 if (t->flags & SN_SELF_GEN) {
2557 produce_content(t);
2558 if (rep->l == 0) {
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 }
2564 }
2565
2566 if ((rep->l == 0)
2567 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002568 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2569 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002570 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002571 }
2572 } else {
2573 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002574 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2575 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002576 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002577 }
2578 }
2579 return 0;
2580 }
2581 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002582 if (req->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002583 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002584 fd_delete(t->cli_fd);
2585 t->cli_state = CL_STCLOSE;
2586 if (!(t->flags & SN_ERR_MASK))
2587 t->flags |= SN_ERR_CLICL;
2588 if (!(t->flags & SN_FINST_MASK)) {
2589 if (t->pend_pos)
2590 t->flags |= SN_FINST_Q;
2591 else if (s == SV_STCONN)
2592 t->flags |= SN_FINST_C;
2593 else
2594 t->flags |= SN_FINST_D;
2595 }
2596 return 1;
2597 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002598 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002599 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002600 fd_delete(t->cli_fd);
2601 t->cli_state = CL_STCLOSE;
2602 return 1;
2603 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002604 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002605 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002606 fd_delete(t->cli_fd);
2607 t->cli_state = CL_STCLOSE;
2608 if (!(t->flags & SN_ERR_MASK))
2609 t->flags |= SN_ERR_CLITO;
2610 if (!(t->flags & SN_FINST_MASK)) {
2611 if (t->pend_pos)
2612 t->flags |= SN_FINST_Q;
2613 else if (s == SV_STCONN)
2614 t->flags |= SN_FINST_C;
2615 else
2616 t->flags |= SN_FINST_D;
2617 }
2618 return 1;
2619 }
2620 else if (req->l >= req->rlim - req->data) {
2621 /* no room to read more data */
2622
2623 /* FIXME-20050705: is it possible for a client to maintain a session
2624 * after the timeout by sending more data after it receives a close ?
2625 */
2626
Willy Tarreau66319382007-04-08 17:17:37 +02002627 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002628 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002629 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002630 }
2631 } else {
2632 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002633 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002634 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002635 }
2636 }
2637 return 0;
2638 }
2639 else { /* CL_STCLOSE: nothing to do */
2640 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2641 int len;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002642 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 +02002643 write(1, trash, len);
2644 }
2645 return 0;
2646 }
2647 return 0;
2648}
2649
2650
2651/*
2652 * manages the server FSM and its socket. It returns 1 if a state has changed
2653 * (and a resync may be needed), 0 else.
2654 */
2655int process_srv(struct session *t)
2656{
2657 int s = t->srv_state;
2658 int c = t->cli_state;
Willy Tarreau3d300592007-03-18 18:34:41 +01002659 struct http_txn *txn = &t->txn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002660 struct buffer *req = t->req;
2661 struct buffer *rep = t->rep;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002662 int conn_err;
2663
2664#ifdef DEBUG_FULL
2665 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2666#endif
Willy Tarreauee991362007-05-14 14:37:50 +02002667
2668#if 0
2669 fprintf(stderr,"%s:%d fe->clito=%d.%d, fe->conto=%d.%d, fe->srvto=%d.%d\n",
2670 __FUNCTION__, __LINE__,
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002671 t->fe->timeout.client.tv_sec, t->fe->timeout.client.tv_usec,
2672 t->fe->timeout.connect.tv_sec, t->fe->timeout.connect.tv_usec,
2673 t->fe->timeout.server.tv_sec, t->fe->timeout.server.tv_usec);
Willy Tarreauee991362007-05-14 14:37:50 +02002674 fprintf(stderr,"%s:%d be->clito=%d.%d, be->conto=%d.%d, be->srvto=%d.%d\n",
2675 __FUNCTION__, __LINE__,
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002676 t->be->timeout.client.tv_sec, t->be->timeout.client.tv_usec,
2677 t->be->timeout.connect.tv_sec, t->be->timeout.connect.tv_usec,
2678 t->be->timeout.server.tv_sec, t->be->timeout.server.tv_usec);
Willy Tarreauee991362007-05-14 14:37:50 +02002679
2680 fprintf(stderr,"%s:%d req->cto=%d.%d, req->rto=%d.%d, req->wto=%d.%d\n",
2681 __FUNCTION__, __LINE__,
2682 req->cto.tv_sec, req->cto.tv_usec,
2683 req->rto.tv_sec, req->rto.tv_usec,
2684 req->wto.tv_sec, req->wto.tv_usec);
2685
2686 fprintf(stderr,"%s:%d rep->cto=%d.%d, rep->rto=%d.%d, rep->wto=%d.%d\n",
2687 __FUNCTION__, __LINE__,
2688 rep->cto.tv_sec, rep->cto.tv_usec,
2689 rep->rto.tv_sec, rep->rto.tv_usec,
2690 rep->wto.tv_sec, rep->wto.tv_usec);
2691#endif
2692
Willy Tarreaubaaee002006-06-26 02:48:02 +02002693 //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 +02002694 //EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
2695 //EV_FD_ISSET(t->srv_fd, DIR_RD), EV_FD_ISSET(t->srv_fd, DIR_WR)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002696 //);
2697 if (s == SV_STIDLE) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002698 /* NOTE: The client processor may switch to SV_STANALYZE, which switches back SV_STIDLE.
2699 * This is logcially after CL_STHEADERS completed, CL_STDATA has started, but
2700 * we need to defer server selection until more data arrives, if possible.
2701 * This is rare, and only if balancing on parameter hash with values in the entity of a POST
2702 */
Willy Tarreaub6866442008-07-14 23:54:42 +02002703 if (c == CL_STHEADERS || c == CL_STINSPECT)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002704 return 0; /* stay in idle, waiting for data to reach the client side */
2705 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
2706 (c == CL_STSHUTR &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002707 (t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002708 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002709 if (t->pend_pos)
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002710 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002711 /* note that this must not return any error because it would be able to
2712 * overwrite the client_retnclose() output.
2713 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002714 if (txn->flags & TX_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01002715 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02002716 else
Willy Tarreau0f772532006-12-23 20:51:41 +01002717 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 +02002718
2719 return 1;
2720 }
2721 else {
Willy Tarreau3d300592007-03-18 18:34:41 +01002722 if (txn->flags & TX_CLTARPIT) {
Willy Tarreaub8750a82006-09-03 09:56:00 +02002723 /* This connection is being tarpitted. The CLIENT side has
2724 * already set the connect expiration date to the right
2725 * timeout. We just have to check that it has not expired.
2726 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002727 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreaub8750a82006-09-03 09:56:00 +02002728 return 0;
2729
2730 /* We will set the queue timer to the time spent, just for
2731 * logging purposes. We fake a 500 server error, so that the
2732 * attacker will not suspect his connection has been tarpitted.
2733 * It will not cause trouble to the logs because we can exclude
2734 * the tarpitted connections by filtering on the 'PT' status flags.
2735 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002736 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002737 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaub8750a82006-09-03 09:56:00 +02002738 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01002739 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02002740 return 1;
2741 }
2742
Willy Tarreaubaaee002006-06-26 02:48:02 +02002743 /* Right now, we will need to create a connection to the server.
2744 * We might already have tried, and got a connection pending, in
2745 * which case we will not do anything till it's pending. It's up
2746 * to any other session to release it and wake us up again.
2747 */
2748 if (t->pend_pos) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002749 if (!tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002750 return 0;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002751 } else {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002752 /* we've been waiting too long here */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002753 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002754 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002755 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01002756 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002757 if (t->srv)
2758 t->srv->failed_conns++;
Willy Tarreau50fd1e12007-12-10 15:25:35 +01002759 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002760 return 1;
2761 }
2762 }
2763
2764 do {
2765 /* first, get a connection */
Willy Tarreau21d2af32008-02-14 20:25:24 +01002766 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
2767 t->flags |= SN_REDIRECTABLE;
2768
Willy Tarreaubaaee002006-06-26 02:48:02 +02002769 if (srv_redispatch_connect(t))
2770 return t->srv_state != SV_STIDLE;
2771
Willy Tarreau21d2af32008-02-14 20:25:24 +01002772 if ((t->flags & SN_REDIRECTABLE) && t->srv && t->srv->rdr_len) {
2773 /* Server supporting redirection and it is possible.
2774 * Invalid requests are reported as such. It concerns all
2775 * the largest ones.
2776 */
2777 struct chunk rdr;
2778 char *path;
2779 int len;
2780
2781 /* 1: create the response header */
2782 rdr.len = strlen(HTTP_302);
2783 rdr.str = trash;
2784 memcpy(rdr.str, HTTP_302, rdr.len);
2785
2786 /* 2: add the server's prefix */
2787 if (rdr.len + t->srv->rdr_len > sizeof(trash))
2788 goto cancel_redir;
2789
2790 memcpy(rdr.str + rdr.len, t->srv->rdr_pfx, t->srv->rdr_len);
2791 rdr.len += t->srv->rdr_len;
2792
2793 /* 3: add the request URI */
2794 path = http_get_path(txn);
2795 if (!path)
2796 goto cancel_redir;
2797 len = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
2798 if (rdr.len + len > sizeof(trash) - 4) /* 4 for CRLF-CRLF */
2799 goto cancel_redir;
2800
2801 memcpy(rdr.str + rdr.len, path, len);
2802 rdr.len += len;
2803 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
2804 rdr.len += 4;
2805
2806 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C, 302, &rdr);
2807 /* FIXME: we should increase a counter of redirects per server and per backend. */
2808 if (t->srv)
2809 t->srv->cum_sess++;
2810 return 1;
2811 cancel_redir:
2812 txn->status = 400;
2813 t->fe->failed_req++;
2814 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C,
2815 400, error_message(t, HTTP_ERR_400));
2816 return 1;
2817 }
2818
Willy Tarreaubaaee002006-06-26 02:48:02 +02002819 /* try to (re-)connect to the server, and fail if we expire the
2820 * number of retries.
2821 */
2822 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002823 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002824 return t->srv_state != SV_STIDLE;
2825 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002826 } while (1);
2827 }
2828 }
2829 else if (s == SV_STCONN) { /* connection in progress */
2830 if (c == CL_STCLOSE || c == CL_STSHUTW ||
2831 (c == CL_STSHUTR &&
Willy Tarreauc9b654b2007-05-08 14:46:53 +02002832 ((t->req->l == 0 && !(req->flags & BF_WRITE_STATUS)) ||
2833 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002834 req->cex = TICK_ETERNITY;
Willy Tarreauf899b942008-03-28 18:09:38 +01002835 if (!(t->flags & SN_CONN_TAR)) {
2836 /* if we are in turn-around, we have already closed the FD */
2837 fd_delete(t->srv_fd);
2838 if (t->srv) {
2839 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002840 sess_change_server(t, NULL);
Willy Tarreauf899b942008-03-28 18:09:38 +01002841 }
Willy Tarreau51406232008-03-10 22:04:20 +01002842 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002843
2844 /* note that this must not return any error because it would be able to
2845 * overwrite the client_retnclose() output.
2846 */
Willy Tarreau0f772532006-12-23 20:51:41 +01002847 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002848 return 1;
2849 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002850 if (!(req->flags & BF_WRITE_STATUS) && !tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002851 return 0; /* nothing changed */
2852 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002853 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002854 /* timeout, asynchronous connect error or first write error */
2855 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2856
Willy Tarreau541b5c22008-01-06 23:34:21 +01002857 if (t->flags & SN_CONN_TAR) {
2858 /* We are doing a turn-around waiting for a new connection attempt. */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002859 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreau541b5c22008-01-06 23:34:21 +01002860 return 0;
2861 t->flags &= ~SN_CONN_TAR;
2862 }
2863 else {
2864 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01002865 if (t->srv) {
Willy Tarreau541b5c22008-01-06 23:34:21 +01002866 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002867 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01002868 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002869
Willy Tarreau541b5c22008-01-06 23:34:21 +01002870 if (!(req->flags & BF_WRITE_STATUS))
2871 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
2872 else
2873 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
2874
2875 /* ensure that we have enough retries left */
2876 if (srv_count_retry_down(t, conn_err))
2877 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002878
Willy Tarreau541b5c22008-01-06 23:34:21 +01002879 if (req->flags & BF_WRITE_ERROR) {
2880 /* we encountered an immediate connection error, and we
2881 * will have to retry connecting to the same server, most
2882 * likely leading to the same result. To avoid this, we
2883 * fake a connection timeout to retry after a turn-around
2884 * time of 1 second. We will wait in the previous if block.
2885 */
2886 t->flags |= SN_CONN_TAR;
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002887 req->cex = tick_add(now_ms, MS_TO_TICKS(1000));
Willy Tarreau541b5c22008-01-06 23:34:21 +01002888 return 0;
2889 }
2890 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002891
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002892 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002893 /* We're on our last chance, and the REDISP option was specified.
2894 * We will ignore cookie and force to balance or use the dispatcher.
2895 */
2896 /* let's try to offer this slot to anybody */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002897 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02002898 process_srv_queue(t->srv);
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002899
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01002900 /* it's left to the dispatcher to choose a server */
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002901 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
Willy Tarreau7c669d72008-06-20 15:04:11 +02002902 t->prev_srv = t->srv;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002903
2904 /* first, get a connection */
2905 if (srv_redispatch_connect(t))
Willy Tarreau00559e72008-01-06 23:46:19 +01002906 return t->srv_state != SV_STCONN;
Krzysztof Piotr Oledzki626a19b2008-02-04 02:10:09 +01002907 } else {
2908 if (t->srv)
2909 t->srv->retries++;
2910 t->be->retries++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002911 }
2912
Willy Tarreaubaaee002006-06-26 02:48:02 +02002913 do {
2914 /* Now we will try to either reconnect to the same server or
2915 * connect to another server. If the connection gets queued
2916 * because all servers are saturated, then we will go back to
2917 * the SV_STIDLE state.
2918 */
2919 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002920 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002921 return t->srv_state != SV_STCONN;
2922 }
2923
2924 /* we need to redispatch the connection to another server */
2925 if (srv_redispatch_connect(t))
2926 return t->srv_state != SV_STCONN;
2927 } while (1);
2928 }
2929 else { /* no error or write 0 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002930 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002931
2932 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2933 if (req->l == 0) /* nothing to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002934 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002935 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002936 } else /* need the right to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002937 EV_FD_SET(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002938 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
2939 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002940 /* FIXME: to prevent the server from expiring read timeouts during writes,
2941 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002942 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002943 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002944 }
2945
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002946 if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreauf161a342007-04-08 16:59:42 +02002947 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002948 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002949 t->srv_state = SV_STDATA;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002950 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
2951
2952 /* if the user wants to log as soon as possible, without counting
2953 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002954 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002955 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
Willy Tarreau42250582007-04-01 01:30:43 +02002956 tcp_sess_log(t);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002957 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002958#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002959 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002960 /* TCP splicing supported by both FE and BE */
2961 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2962 }
2963#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002964 }
2965 else {
2966 t->srv_state = SV_STHEADERS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002967 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002968 t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
2969 /* reset hdr_idx which was already initialized by the request.
2970 * right now, the http parser does it.
2971 * hdr_idx_init(&t->txn.hdr_idx);
2972 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002973 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002974 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002975 return 1;
2976 }
2977 }
2978 else if (s == SV_STHEADERS) { /* receiving server headers */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002979 /*
2980 * Now parse the partial (or complete) lines.
2981 * We will check the response syntax, and also join multi-line
2982 * headers. An index of all the lines will be elaborated while
2983 * parsing.
2984 *
2985 * For the parsing, we use a 28 states FSM.
2986 *
2987 * Here is the information we currently have :
2988 * rep->data + req->som = beginning of response
2989 * rep->data + req->eoh = end of processed headers / start of current one
2990 * rep->data + req->eol = end of current header or line (LF or CRLF)
2991 * rep->lr = first non-visited byte
2992 * rep->r = end of data
2993 */
2994
2995 int cur_idx;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002996 struct http_msg *msg = &txn->rsp;
2997 struct proxy *cur_proxy;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002998
Willy Tarreaua15645d2007-03-18 16:22:39 +01002999 if (likely(rep->lr < rep->r))
3000 http_msg_analyzer(rep, msg, &txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003001
Willy Tarreaua15645d2007-03-18 16:22:39 +01003002 /* 1: we might have to print this header in debug mode */
3003 if (unlikely((global.mode & MODE_DEBUG) &&
3004 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
3005 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
3006 char *eol, *sol;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003007
Willy Tarreaua15645d2007-03-18 16:22:39 +01003008 sol = rep->data + msg->som;
3009 eol = sol + msg->sl.rq.l;
3010 debug_hdr("srvrep", t, sol, eol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003011
Willy Tarreaua15645d2007-03-18 16:22:39 +01003012 sol += hdr_idx_first_pos(&txn->hdr_idx);
3013 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003014
Willy Tarreaua15645d2007-03-18 16:22:39 +01003015 while (cur_idx) {
3016 eol = sol + txn->hdr_idx.v[cur_idx].len;
3017 debug_hdr("srvhdr", t, sol, eol);
3018 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
3019 cur_idx = txn->hdr_idx.v[cur_idx].next;
3020 }
3021 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003022
Willy Tarreaubaaee002006-06-26 02:48:02 +02003023
Willy Tarreau66319382007-04-08 17:17:37 +02003024 if ((rep->l < rep->rlim - rep->data) && EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003025 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreaua15645d2007-03-18 16:22:39 +01003026 * full. We cannot loop here since stream_sock_read will disable it only if
3027 * rep->l == rlim-data
3028 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003029 req->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003030 }
3031
3032
3033 /*
3034 * Now we quickly check if we have found a full valid response.
3035 * If not so, we check the FD and buffer states before leaving.
3036 * A full response is indicated by the fact that we have seen
3037 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
3038 * responses are checked first.
3039 *
3040 * Depending on whether the client is still there or not, we
3041 * may send an error response back or not. Note that normally
3042 * we should only check for HTTP status there, and check I/O
3043 * errors somewhere else.
3044 */
3045
3046 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
3047
3048 /* Invalid response, or read error or write error */
3049 if (unlikely((msg->msg_state == HTTP_MSG_ERROR) ||
3050 (req->flags & BF_WRITE_ERROR) ||
3051 (rep->flags & BF_READ_ERROR))) {
Willy Tarreaufa645582007-06-03 15:59:52 +02003052 buffer_shutr(rep);
3053 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003054 fd_delete(t->srv_fd);
3055 if (t->srv) {
3056 t->srv->cur_sess--;
3057 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003058 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003059 }
3060 t->be->failed_resp++;
3061 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003062 txn->status = 502;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003063 client_return(t, error_message(t, HTTP_ERR_502));
3064 if (!(t->flags & SN_ERR_MASK))
3065 t->flags |= SN_ERR_SRVCL;
3066 if (!(t->flags & SN_FINST_MASK))
3067 t->flags |= SN_FINST_H;
3068 /* We used to have a free connection slot. Since we'll never use it,
3069 * we have to inform the server that it may be used by another session.
3070 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003071 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003072 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003073
Willy Tarreaua15645d2007-03-18 16:22:39 +01003074 return 1;
3075 }
3076
3077 /* end of client write or end of server read.
3078 * since we are in header mode, if there's no space left for headers, we
3079 * won't be able to free more later, so the session will never terminate.
3080 */
3081 else if (unlikely(rep->flags & BF_READ_NULL ||
3082 c == CL_STSHUTW || c == CL_STCLOSE ||
3083 rep->l >= rep->rlim - rep->data)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003084 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003085 buffer_shutr(rep);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003086 t->srv_state = SV_STSHUTR;
3087 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3088 return 1;
3089 }
3090
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003091 /* read timeout : return a 504 to the client. */
Willy Tarreauf161a342007-04-08 16:59:42 +02003092 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_RD) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003093 tick_is_expired(rep->rex, now_ms))) {
Willy Tarreaufa645582007-06-03 15:59:52 +02003094 buffer_shutr(rep);
3095 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003096 fd_delete(t->srv_fd);
3097 if (t->srv) {
3098 t->srv->cur_sess--;
3099 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003100 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003101 }
3102 t->be->failed_resp++;
3103 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003104 txn->status = 504;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003105 client_return(t, error_message(t, HTTP_ERR_504));
3106 if (!(t->flags & SN_ERR_MASK))
3107 t->flags |= SN_ERR_SRVTO;
3108 if (!(t->flags & SN_FINST_MASK))
3109 t->flags |= SN_FINST_H;
3110 /* We used to have a free connection slot. Since we'll never use it,
3111 * we have to inform the server that it may be used by another session.
3112 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003113 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003114 process_srv_queue(t->srv);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003115 return 1;
3116 }
3117
3118 /* last client read and buffer empty */
3119 /* FIXME!!! here, we don't want to switch to SHUTW if the
3120 * client shuts read too early, because we may still have
3121 * some work to do on the headers.
3122 * The side-effect is that if the client completely closes its
3123 * connection during SV_STHEADER, the connection to the server
3124 * is kept until a response comes back or the timeout is reached.
3125 */
3126 else if (unlikely((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) &&
3127 (req->l == 0))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003128 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003129 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003130
3131 /* We must ensure that the read part is still
3132 * alive when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003133 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003134 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003135
3136 shutdown(t->srv_fd, SHUT_WR);
3137 t->srv_state = SV_STSHUTW;
3138 return 1;
3139 }
3140
3141 /* write timeout */
3142 /* FIXME!!! here, we don't want to switch to SHUTW if the
3143 * client shuts read too early, because we may still have
3144 * some work to do on the headers.
3145 */
Willy Tarreauf161a342007-04-08 16:59:42 +02003146 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_WR) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003147 tick_is_expired(req->wex, now_ms))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003148 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003149 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003150 shutdown(t->srv_fd, SHUT_WR);
3151 /* We must ensure that the read part is still alive
3152 * when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003153 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003154 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003155
3156 t->srv_state = SV_STSHUTW;
3157 if (!(t->flags & SN_ERR_MASK))
3158 t->flags |= SN_ERR_SRVTO;
3159 if (!(t->flags & SN_FINST_MASK))
3160 t->flags |= SN_FINST_H;
3161 return 1;
3162 }
3163
3164 /*
3165 * And now the non-error cases.
3166 */
3167
3168 /* Data remaining in the request buffer.
3169 * This happens during the first pass here, and during
3170 * long posts.
3171 */
3172 else if (likely(req->l)) {
Willy Tarreau66319382007-04-08 17:17:37 +02003173 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3174 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003175 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3176 if (req->wex) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003177 /* FIXME: to prevent the server from expiring read timeouts during writes,
3178 * we refresh it. */
3179 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003180 }
3181 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003182 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003183
Willy Tarreaua15645d2007-03-18 16:22:39 +01003184 /* nothing left in the request buffer */
3185 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003186 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3187 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003188 req->wex = TICK_ETERNITY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003189 }
3190 }
3191
3192 return t->srv_state != SV_STHEADERS;
3193 }
3194
3195
3196 /*****************************************************************
3197 * More interesting part now : we know that we have a complete *
3198 * response which at least looks like HTTP. We have an indicator *
3199 * of each header's length, so we can parse them quickly. *
3200 ****************************************************************/
3201
Willy Tarreau9cdde232007-05-02 20:58:19 +02003202 /* ensure we keep this pointer to the beginning of the message */
3203 msg->sol = rep->data + msg->som;
3204
Willy Tarreaua15645d2007-03-18 16:22:39 +01003205 /*
3206 * 1: get the status code and check for cacheability.
3207 */
3208
3209 t->logs.logwait &= ~LW_RESP;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003210 txn->status = strl2ui(rep->data + msg->sl.st.c, msg->sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003211
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003212 switch (txn->status) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003213 case 200:
3214 case 203:
3215 case 206:
3216 case 300:
3217 case 301:
3218 case 410:
3219 /* RFC2616 @13.4:
3220 * "A response received with a status code of
3221 * 200, 203, 206, 300, 301 or 410 MAY be stored
3222 * by a cache (...) unless a cache-control
3223 * directive prohibits caching."
3224 *
3225 * RFC2616 @9.5: POST method :
3226 * "Responses to this method are not cacheable,
3227 * unless the response includes appropriate
3228 * Cache-Control or Expires header fields."
3229 */
3230 if (likely(txn->meth != HTTP_METH_POST) &&
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003231 (t->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
Willy Tarreau3d300592007-03-18 18:34:41 +01003232 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003233 break;
3234 default:
3235 break;
3236 }
3237
3238 /*
3239 * 2: we may need to capture headers
3240 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003241 if (unlikely((t->logs.logwait & LW_RSPHDR) && t->fe->rsp_cap))
Willy Tarreaua15645d2007-03-18 16:22:39 +01003242 capture_headers(rep->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003243 txn->rsp.cap, t->fe->rsp_cap);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003244
3245 /*
3246 * 3: we will have to evaluate the filters.
3247 * As opposed to version 1.2, now they will be evaluated in the
3248 * filters order and not in the header order. This means that
3249 * each filter has to be validated among all headers.
3250 *
3251 * Filters are tried with ->be first, then with ->fe if it is
3252 * different from ->be.
3253 */
3254
3255 t->flags &= ~SN_CONN_CLOSED; /* prepare for inspection */
3256
3257 cur_proxy = t->be;
3258 while (1) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003259 struct proxy *rule_set = cur_proxy;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003260
3261 /* try headers filters */
3262 if (rule_set->rsp_exp != NULL) {
3263 if (apply_filters_to_response(t, rep, rule_set->rsp_exp) < 0) {
3264 return_bad_resp:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003265 if (t->srv) {
3266 t->srv->cur_sess--;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003267 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003268 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003269 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003270 cur_proxy->failed_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003271 return_srv_prx_502:
Willy Tarreaufa645582007-06-03 15:59:52 +02003272 buffer_shutr(rep);
3273 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003274 fd_delete(t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003275 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003276 txn->status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01003277 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003278 if (!(t->flags & SN_ERR_MASK))
3279 t->flags |= SN_ERR_PRXCOND;
3280 if (!(t->flags & SN_FINST_MASK))
3281 t->flags |= SN_FINST_H;
3282 /* We used to have a free connection slot. Since we'll never use it,
3283 * we have to inform the server that it may be used by another session.
3284 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003285 if (t->srv && may_dequeue_tasks(t->srv, cur_proxy))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003286 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003287 return 1;
3288 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003289 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003290
Willy Tarreaua15645d2007-03-18 16:22:39 +01003291 /* has the response been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01003292 if (txn->flags & TX_SVDENY) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003293 if (t->srv) {
3294 t->srv->cur_sess--;
3295 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003296 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003297 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003298 cur_proxy->denied_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003299 goto return_srv_prx_502;
3300 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003301
Willy Tarreaua15645d2007-03-18 16:22:39 +01003302 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003303 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01003304 !(t->flags & SN_CONN_CLOSED)) {
3305 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003306 int cur_idx, old_idx, delta, val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003307 struct hdr_idx_elem *cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003308
Willy Tarreaua15645d2007-03-18 16:22:39 +01003309 cur_next = rep->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
3310 old_idx = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003311
Willy Tarreaua15645d2007-03-18 16:22:39 +01003312 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
3313 cur_hdr = &txn->hdr_idx.v[cur_idx];
3314 cur_ptr = cur_next;
3315 cur_end = cur_ptr + cur_hdr->len;
3316 cur_next = cur_end + cur_hdr->cr + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003317
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003318 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
3319 if (val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003320 /* 3 possibilities :
3321 * - we have already set Connection: close,
3322 * so we remove this line.
3323 * - we have not yet set Connection: close,
3324 * but this line indicates close. We leave
3325 * it untouched and set the flag.
3326 * - we have not yet set Connection: close,
3327 * and this line indicates non-close. We
3328 * replace it.
3329 */
3330 if (t->flags & SN_CONN_CLOSED) {
3331 delta = buffer_replace2(rep, cur_ptr, cur_next, NULL, 0);
3332 txn->rsp.eoh += delta;
3333 cur_next += delta;
3334 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3335 txn->hdr_idx.used--;
3336 cur_hdr->len = 0;
3337 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003338 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
3339 delta = buffer_replace2(rep, cur_ptr + val, cur_end,
3340 "close", 5);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003341 cur_next += delta;
3342 cur_hdr->len += delta;
3343 txn->rsp.eoh += delta;
3344 }
3345 t->flags |= SN_CONN_CLOSED;
3346 }
3347 }
3348 old_idx = cur_idx;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003349 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003350 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003351
Willy Tarreaua15645d2007-03-18 16:22:39 +01003352 /* add response headers from the rule sets in the same order */
3353 for (cur_idx = 0; cur_idx < rule_set->nb_rspadd; cur_idx++) {
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003354 if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx,
3355 rule_set->rsp_add[cur_idx])) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003356 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003357 }
3358
Willy Tarreaua15645d2007-03-18 16:22:39 +01003359 /* check whether we're already working on the frontend */
3360 if (cur_proxy == t->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003361 break;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003362 cur_proxy = t->fe;
3363 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003364
Willy Tarreaua15645d2007-03-18 16:22:39 +01003365 /*
3366 * 4: check for server cookie.
3367 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003368 if (t->be->cookie_name || t->be->appsession_name || t->be->capture_name
3369 || (t->be->options & PR_O_CHK_CACHE))
3370 manage_server_side_cookies(t, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003371
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003372
Willy Tarreaua15645d2007-03-18 16:22:39 +01003373 /*
Willy Tarreau396d2c62007-11-04 19:30:00 +01003374 * 5: check for cache-control or pragma headers if required.
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003375 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003376 if ((t->be->options & (PR_O_COOK_NOC | PR_O_CHK_CACHE)) != 0)
3377 check_response_for_cacheability(t, rep);
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003378
3379 /*
3380 * 6: add server cookie in the response if needed
Willy Tarreaua15645d2007-03-18 16:22:39 +01003381 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003382 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
3383 (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003384 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003385
Willy Tarreaua15645d2007-03-18 16:22:39 +01003386 /* the server is known, it's not the one the client requested, we have to
3387 * insert a set-cookie here, except if we want to insert only on POST
3388 * requests and this one isn't. Note that servers which don't have cookies
3389 * (eg: some backup servers) will return a full cookie removal request.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003390 */
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003391 len = sprintf(trash, "Set-Cookie: %s=%s; path=/",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003392 t->be->cookie_name,
Willy Tarreaua15645d2007-03-18 16:22:39 +01003393 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003394
Krzysztof Piotr Oledzki1acf2172008-05-29 23:03:34 +02003395 if (t->be->cookie_domain)
3396 len += sprintf(trash+len, "; domain=%s", t->be->cookie_domain);
Krzysztof Piotr Oledzkiefe3b6f2008-05-23 23:49:32 +02003397
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003398 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3399 trash, len)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003400 goto return_bad_resp;
Willy Tarreau3d300592007-03-18 18:34:41 +01003401 txn->flags |= TX_SCK_INSERTED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003402
Willy Tarreaua15645d2007-03-18 16:22:39 +01003403 /* Here, we will tell an eventual cache on the client side that we don't
3404 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3405 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3406 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3407 */
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003408 if ((t->be->options & PR_O_COOK_NOC) && (txn->flags & TX_CACHEABLE)) {
3409
3410 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
3411
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003412 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3413 "Cache-control: private", 22)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003414 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003415 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003416 }
3417
3418
3419 /*
Willy Tarreaua15645d2007-03-18 16:22:39 +01003420 * 7: check if result will be cacheable with a cookie.
3421 * We'll block the response if security checks have caught
3422 * nasty things such as a cacheable cookie.
3423 */
Willy Tarreau3d300592007-03-18 18:34:41 +01003424 if (((txn->flags & (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) ==
3425 (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003426 (t->be->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003427
Willy Tarreaua15645d2007-03-18 16:22:39 +01003428 /* we're in presence of a cacheable response containing
3429 * a set-cookie header. We'll block it as requested by
3430 * the 'checkcache' option, and send an alert.
3431 */
3432 if (t->srv) {
3433 t->srv->cur_sess--;
3434 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003435 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003436 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003437 t->be->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003438
Willy Tarreaua15645d2007-03-18 16:22:39 +01003439 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003440 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003441 send_log(t->be, LOG_ALERT,
3442 "Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003443 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003444 goto return_srv_prx_502;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003445 }
3446
Willy Tarreaua15645d2007-03-18 16:22:39 +01003447 /*
3448 * 8: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02003449 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003450 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02003451 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003452 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02003453 if ((unlikely(msg->sl.st.v_l != 8) ||
3454 unlikely(req->data[msg->som + 7] != '0')) &&
3455 unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003456 "Connection: close", 17)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003457 goto return_bad_resp;
3458 t->flags |= SN_CONN_CLOSED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003459 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003460
Willy Tarreaubaaee002006-06-26 02:48:02 +02003461
Willy Tarreaua15645d2007-03-18 16:22:39 +01003462 /*************************************************************
3463 * OK, that's finished for the headers. We have done what we *
3464 * could. Let's switch to the DATA state. *
3465 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02003466
Willy Tarreaua15645d2007-03-18 16:22:39 +01003467 t->srv_state = SV_STDATA;
3468 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02003469 t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003470
3471 /* client connection already closed or option 'forceclose' required :
3472 * we close the server's outgoing connection right now.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003473 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003474 if ((req->l == 0) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003475 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->options & PR_O_FORCE_CLO)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003476 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003477 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003478
3479 /* We must ensure that the read part is still alive when switching
3480 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003481 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003482 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003483
Willy Tarreaua15645d2007-03-18 16:22:39 +01003484 shutdown(t->srv_fd, SHUT_WR);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003485 t->srv_state = SV_STSHUTW;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003486 }
3487
Willy Tarreaua15645d2007-03-18 16:22:39 +01003488#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003489 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003490 /* TCP splicing supported by both FE and BE */
3491 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003492 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003493#endif
3494 /* if the user wants to log as soon as possible, without counting
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003495 * bytes from the server, then this is the right moment. We have
3496 * to temporarily assign bytes_out to log what we currently have.
3497 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003498 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
3499 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreau8b3977f2008-01-18 11:16:32 +01003500 t->logs.bytes_out = txn->rsp.eoh;
Willy Tarreau42250582007-04-01 01:30:43 +02003501 if (t->fe->to_log & LW_REQ)
3502 http_sess_log(t);
3503 else
3504 tcp_sess_log(t);
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003505 t->logs.bytes_out = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003506 }
3507
Willy Tarreaua15645d2007-03-18 16:22:39 +01003508 /* Note: we must not try to cheat by jumping directly to DATA,
3509 * otherwise we would not let the client side wake up.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003510 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003511
3512 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003513 }
3514 else if (s == SV_STDATA) {
3515 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003516 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02003517 buffer_shutr(rep);
3518 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003519 fd_delete(t->srv_fd);
3520 if (t->srv) {
3521 t->srv->cur_sess--;
3522 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003523 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003524 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003525 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003526 t->srv_state = SV_STCLOSE;
3527 if (!(t->flags & SN_ERR_MASK))
3528 t->flags |= SN_ERR_SRVCL;
3529 if (!(t->flags & SN_FINST_MASK))
3530 t->flags |= SN_FINST_D;
3531 /* We used to have a free connection slot. Since we'll never use it,
3532 * we have to inform the server that it may be used by another session.
3533 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003534 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003535 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003536
3537 return 1;
3538 }
3539 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003540 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003541 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003542 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003543 t->srv_state = SV_STSHUTR;
3544 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3545 return 1;
3546 }
3547 /* end of client read and no more data to send */
3548 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003549 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003550 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003551 shutdown(t->srv_fd, SHUT_WR);
3552 /* We must ensure that the read part is still alive when switching
3553 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003554 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003555 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003556
3557 t->srv_state = SV_STSHUTW;
3558 return 1;
3559 }
3560 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003561 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003562 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003563 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003564 t->srv_state = SV_STSHUTR;
3565 if (!(t->flags & SN_ERR_MASK))
3566 t->flags |= SN_ERR_SRVTO;
3567 if (!(t->flags & SN_FINST_MASK))
3568 t->flags |= SN_FINST_D;
3569 return 1;
3570 }
3571 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003572 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003573 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003574 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003575 shutdown(t->srv_fd, SHUT_WR);
3576 /* We must ensure that the read part is still alive when switching
3577 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003578 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003579 rep->cex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003580 t->srv_state = SV_STSHUTW;
3581 if (!(t->flags & SN_ERR_MASK))
3582 t->flags |= SN_ERR_SRVTO;
3583 if (!(t->flags & SN_FINST_MASK))
3584 t->flags |= SN_FINST_D;
3585 return 1;
3586 }
3587
3588 /* recompute request time-outs */
3589 if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003590 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3591 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003592 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003593 }
3594 }
3595 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau66319382007-04-08 17:17:37 +02003596 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3597 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003598 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3599 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003600 /* FIXME: to prevent the server from expiring read timeouts during writes,
3601 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02003602 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003603 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003604 }
3605 }
3606
3607 /* recompute response time-outs */
3608 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003609 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003610 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003611 }
3612 }
3613 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003614 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003615 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003616 }
3617 }
3618
3619 return 0; /* other cases change nothing */
3620 }
3621 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003622 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003623 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003624 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003625 fd_delete(t->srv_fd);
3626 if (t->srv) {
3627 t->srv->cur_sess--;
3628 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003629 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003630 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003631 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003632 //close(t->srv_fd);
3633 t->srv_state = SV_STCLOSE;
3634 if (!(t->flags & SN_ERR_MASK))
3635 t->flags |= SN_ERR_SRVCL;
3636 if (!(t->flags & SN_FINST_MASK))
3637 t->flags |= SN_FINST_D;
3638 /* We used to have a free connection slot. Since we'll never use it,
3639 * we have to inform the server that it may be used by another session.
3640 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003641 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003642 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003643
3644 return 1;
3645 }
3646 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003647 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003648 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003649 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003650 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003651 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003652 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003653 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003654 //close(t->srv_fd);
3655 t->srv_state = SV_STCLOSE;
3656 /* We used to have a free connection slot. Since we'll never use it,
3657 * we have to inform the server that it may be used by another session.
3658 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003659 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003660 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003661
3662 return 1;
3663 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003664 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003665 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003666 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003667 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003668 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003669 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003670 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003671 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003672 //close(t->srv_fd);
3673 t->srv_state = SV_STCLOSE;
3674 if (!(t->flags & SN_ERR_MASK))
3675 t->flags |= SN_ERR_SRVTO;
3676 if (!(t->flags & SN_FINST_MASK))
3677 t->flags |= SN_FINST_D;
3678 /* We used to have a free connection slot. Since we'll never use it,
3679 * we have to inform the server that it may be used by another session.
3680 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003681 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003682 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003683
3684 return 1;
3685 }
3686 else if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003687 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3688 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003689 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003690 }
3691 }
3692 else { /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02003693 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3694 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003695 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003696 }
3697 }
3698 return 0;
3699 }
3700 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003701 if (rep->flags & BF_READ_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003702 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003703 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003704 fd_delete(t->srv_fd);
3705 if (t->srv) {
3706 t->srv->cur_sess--;
3707 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003708 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003709 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003710 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003711 //close(t->srv_fd);
3712 t->srv_state = SV_STCLOSE;
3713 if (!(t->flags & SN_ERR_MASK))
3714 t->flags |= SN_ERR_SRVCL;
3715 if (!(t->flags & SN_FINST_MASK))
3716 t->flags |= SN_FINST_D;
3717 /* We used to have a free connection slot. Since we'll never use it,
3718 * we have to inform the server that it may be used by another session.
3719 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003720 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003721 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003722
3723 return 1;
3724 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003725 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003726 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003727 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003728 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003729 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003730 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003731 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003732 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003733 //close(t->srv_fd);
3734 t->srv_state = SV_STCLOSE;
3735 /* We used to have a free connection slot. Since we'll never use it,
3736 * we have to inform the server that it may be used by another session.
3737 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003738 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003739 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003740
3741 return 1;
3742 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003743 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003744 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003745 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003746 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003747 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003748 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003749 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003750 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003751 //close(t->srv_fd);
3752 t->srv_state = SV_STCLOSE;
3753 if (!(t->flags & SN_ERR_MASK))
3754 t->flags |= SN_ERR_SRVTO;
3755 if (!(t->flags & SN_FINST_MASK))
3756 t->flags |= SN_FINST_D;
3757 /* We used to have a free connection slot. Since we'll never use it,
3758 * we have to inform the server that it may be used by another session.
3759 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003760 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003761 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003762
3763 return 1;
3764 }
3765 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003766 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003767 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003768 }
3769 }
3770 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003771 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003772 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003773 }
3774 }
3775 return 0;
3776 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003777 else if (s == SV_STANALYZE){
3778 /* this server state is set by the client to study the body for server assignment */
3779
3780 /* Have we been through this long enough to timeout? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003781 if (!tick_is_expired(req->rex, now_ms)) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003782 /* balance url_param check_post should have been the only to get into this.
3783 * just wait for data, check to compare how much
3784 */
3785 struct http_msg * msg = &t->txn.req;
3786 unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 :msg->eoh + 1;
3787 unsigned long len = req->total - body;
3788 long long limit = t->be->url_param_post_limit;
3789 struct hdr_ctx ctx;
3790 ctx.idx = 0;
3791 /* now if we have a length, we'll take the hint */
3792 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
3793 if ( ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",ctx.vlen)==0) {
3794 unsigned int chunk = 0;
3795 while ( body < req->total && !HTTP_IS_CRLF(msg->sol[body])) {
3796 char c = msg->sol[body];
3797 if (ishex(c)) {
3798 unsigned int hex = toupper(c) - '0';
3799 if ( hex > 9 )
3800 hex -= 'A' - '9' - 1;
3801 chunk = (chunk << 4) | hex;
3802 }
3803 else break;
3804 body++;
3805 len--;
3806 }
3807 if ( body == req->total )
3808 return 0; /* end of buffer? data missing! */
3809
3810 if ( memcmp(msg->sol+body, "\r\n", 2) != 0 )
3811 return 0; /* chunked encoding len ends with CRLF, and we don't have it yet */
3812
3813 /* if we support more then one chunk here, we have to do it again when assigning server
3814 1. how much entity data do we have? new var
3815 2. should save entity_start, entity_cursor, elen & rlen in req; so we don't repeat scanning here
3816 3. test if elen > limit, or set new limit to elen if 0 (end of entity found)
3817 */
3818
3819 if ( chunk < limit )
3820 limit = chunk; /* only reading one chunk */
3821 } else {
3822 if ( msg->hdr_content_len < limit )
3823 limit = msg->hdr_content_len;
3824 }
3825 if ( len < limit )
3826 return 0;
3827 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003828 t->srv_state = SV_STIDLE;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003829 return 1;
3830 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003831 else { /* SV_STCLOSE : nothing to do */
3832 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
3833 int len;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003834 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003835 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003836 write(1, trash, len);
3837 }
3838 return 0;
3839 }
3840 return 0;
3841}
3842
3843
3844/*
3845 * Produces data for the session <s> depending on its source. Expects to be
3846 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3847 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3848 * session, which it uses to keep on being called when there is free space in
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003849 * the buffer, or simply by letting an empty buffer upon return. It returns 1
Willy Tarreaubaaee002006-06-26 02:48:02 +02003850 * if it changes the session state from CL_STSHUTR, otherwise 0.
3851 */
3852int produce_content(struct session *s)
3853{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003854 if (s->data_source == DATA_SRC_NONE) {
3855 s->flags &= ~SN_SELF_GEN;
3856 return 1;
3857 }
3858 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003859 /* dump server statistics */
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01003860 int ret = stats_dump_http(s, s->be->uri_auth);
Willy Tarreau91861262007-10-17 17:06:05 +02003861 if (ret >= 0)
3862 return ret;
3863 /* -1 indicates an error */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003864 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003865
Willy Tarreau91861262007-10-17 17:06:05 +02003866 /* unknown data source or internal error */
3867 s->txn.status = 500;
3868 client_retnclose(s, error_message(s, HTTP_ERR_500));
3869 if (!(s->flags & SN_ERR_MASK))
3870 s->flags |= SN_ERR_PRXCOND;
3871 if (!(s->flags & SN_FINST_MASK))
3872 s->flags |= SN_FINST_R;
3873 s->flags &= ~SN_SELF_GEN;
3874 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003875}
3876
3877
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003878/* Iterate the same filter through all request headers.
3879 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003880 * Since it can manage the switch to another backend, it updates the per-proxy
3881 * DENY stats.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003882 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003883int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003884{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003885 char term;
3886 char *cur_ptr, *cur_end, *cur_next;
3887 int cur_idx, old_idx, last_hdr;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003888 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003889 struct hdr_idx_elem *cur_hdr;
3890 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003891
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003892 last_hdr = 0;
3893
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003894 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003895 old_idx = 0;
3896
3897 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01003898 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003899 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003900 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003901 (exp->action == ACT_ALLOW ||
3902 exp->action == ACT_DENY ||
3903 exp->action == ACT_TARPIT))
3904 return 0;
3905
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003906 cur_idx = txn->hdr_idx.v[old_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003907 if (!cur_idx)
3908 break;
3909
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003910 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003911 cur_ptr = cur_next;
3912 cur_end = cur_ptr + cur_hdr->len;
3913 cur_next = cur_end + cur_hdr->cr + 1;
3914
3915 /* Now we have one header between cur_ptr and cur_end,
3916 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003917 */
3918
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003919 /* The annoying part is that pattern matching needs
3920 * that we modify the contents to null-terminate all
3921 * strings before testing them.
3922 */
3923
3924 term = *cur_end;
3925 *cur_end = '\0';
3926
3927 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3928 switch (exp->action) {
3929 case ACT_SETBE:
3930 /* It is not possible to jump a second time.
3931 * FIXME: should we return an HTTP/500 here so that
3932 * the admin knows there's a problem ?
3933 */
3934 if (t->be != t->fe)
3935 break;
3936
3937 /* Swithing Proxy */
3938 t->be = (struct proxy *) exp->replace;
3939
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003940 /* right now, the backend switch is not overly complicated
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003941 * because we have associated req_cap and rsp_cap to the
3942 * frontend, and the beconn will be updated later.
3943 */
3944
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003945 t->rep->rto = t->req->wto = t->be->timeout.server;
3946 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02003947 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003948 last_hdr = 1;
3949 break;
3950
3951 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003952 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003953 last_hdr = 1;
3954 break;
3955
3956 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003957 txn->flags |= TX_CLDENY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003958 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003959 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003960 break;
3961
3962 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003963 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003964 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003965 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003966 break;
3967
3968 case ACT_REPLACE:
3969 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3970 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3971 /* FIXME: if the user adds a newline in the replacement, the
3972 * index will not be recalculated for now, and the new line
3973 * will not be counted as a new header.
3974 */
3975
3976 cur_end += delta;
3977 cur_next += delta;
3978 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003979 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003980 break;
3981
3982 case ACT_REMOVE:
3983 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3984 cur_next += delta;
3985
3986 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003987 txn->req.eoh += delta;
3988 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3989 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003990 cur_hdr->len = 0;
3991 cur_end = NULL; /* null-term has been rewritten */
3992 break;
3993
3994 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01003995 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003996 if (cur_end)
3997 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003998
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003999 /* keep the link from this header to next one in case of later
4000 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004001 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004002 old_idx = cur_idx;
4003 }
4004 return 0;
4005}
4006
4007
4008/* Apply the filter to the request line.
4009 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4010 * or -1 if a replacement resulted in an invalid request line.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004011 * Since it can manage the switch to another backend, it updates the per-proxy
4012 * DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004013 */
4014int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
4015{
4016 char term;
4017 char *cur_ptr, *cur_end;
4018 int done;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004019 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004020 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004021
Willy Tarreau58f10d72006-12-04 02:26:12 +01004022
Willy Tarreau3d300592007-03-18 18:34:41 +01004023 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004024 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004025 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004026 (exp->action == ACT_ALLOW ||
4027 exp->action == ACT_DENY ||
4028 exp->action == ACT_TARPIT))
4029 return 0;
4030 else if (exp->action == ACT_REMOVE)
4031 return 0;
4032
4033 done = 0;
4034
Willy Tarreau9cdde232007-05-02 20:58:19 +02004035 cur_ptr = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004036 cur_end = cur_ptr + txn->req.sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004037
4038 /* Now we have the request line between cur_ptr and cur_end */
4039
4040 /* The annoying part is that pattern matching needs
4041 * that we modify the contents to null-terminate all
4042 * strings before testing them.
4043 */
4044
4045 term = *cur_end;
4046 *cur_end = '\0';
4047
4048 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4049 switch (exp->action) {
4050 case ACT_SETBE:
4051 /* It is not possible to jump a second time.
4052 * FIXME: should we return an HTTP/500 here so that
4053 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01004054 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004055 if (t->be != t->fe)
4056 break;
4057
4058 /* Swithing Proxy */
4059 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004060
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004061 /* right now, the backend switch is not too much complicated
4062 * because we have associated req_cap and rsp_cap to the
4063 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004064 */
4065
Willy Tarreaud7c30f92007-12-03 01:38:36 +01004066 t->rep->rto = t->req->wto = t->be->timeout.server;
4067 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02004068 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004069 done = 1;
4070 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004071
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004072 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004073 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004074 done = 1;
4075 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004076
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004077 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004078 txn->flags |= TX_CLDENY;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004079 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004080 done = 1;
4081 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004082
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004083 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01004084 txn->flags |= TX_CLTARPIT;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004085 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004086 done = 1;
4087 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004088
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004089 case ACT_REPLACE:
4090 *cur_end = term; /* restore the string terminator */
4091 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4092 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
4093 /* FIXME: if the user adds a newline in the replacement, the
4094 * index will not be recalculated for now, and the new line
4095 * will not be counted as a new header.
4096 */
Willy Tarreaua496b602006-12-17 23:15:24 +01004097
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004098 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004099 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01004100
Willy Tarreau9cdde232007-05-02 20:58:19 +02004101 txn->req.sol = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004102 cur_end = (char *)http_parse_reqline(&txn->req, req->data,
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004103 HTTP_MSG_RQMETH,
4104 cur_ptr, cur_end + 1,
4105 NULL, NULL);
4106 if (unlikely(!cur_end))
4107 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01004108
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004109 /* we have a full request and we know that we have either a CR
4110 * or an LF at <ptr>.
4111 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004112 txn->meth = find_http_meth(cur_ptr, txn->req.sl.rq.m_l);
4113 hdr_idx_set_start(&txn->hdr_idx, txn->req.sl.rq.l, *cur_end == '\r');
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004114 /* there is no point trying this regex on headers */
4115 return 1;
4116 }
4117 }
4118 *cur_end = term; /* restore the string terminator */
4119 return done;
4120}
Willy Tarreau97de6242006-12-27 17:18:38 +01004121
Willy Tarreau58f10d72006-12-04 02:26:12 +01004122
Willy Tarreau58f10d72006-12-04 02:26:12 +01004123
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004124/*
4125 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
4126 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
Willy Tarreaua15645d2007-03-18 16:22:39 +01004127 * unparsable request. Since it can manage the switch to another backend, it
4128 * updates the per-proxy DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004129 */
4130int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
4131{
Willy Tarreau3d300592007-03-18 18:34:41 +01004132 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004133 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004134 while (exp && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004135 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004136
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004137 /*
4138 * The interleaving of transformations and verdicts
4139 * makes it difficult to decide to continue or stop
4140 * the evaluation.
4141 */
4142
Willy Tarreau3d300592007-03-18 18:34:41 +01004143 if ((txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004144 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4145 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
4146 exp = exp->next;
4147 continue;
4148 }
4149
4150 /* Apply the filter to the request line. */
4151 ret = apply_filter_to_req_line(t, req, exp);
4152 if (unlikely(ret < 0))
4153 return -1;
4154
4155 if (likely(ret == 0)) {
4156 /* The filter did not match the request, it can be
4157 * iterated through all headers.
4158 */
4159 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004160 }
4161 exp = exp->next;
4162 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004163 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004164}
4165
4166
Willy Tarreaua15645d2007-03-18 16:22:39 +01004167
Willy Tarreau58f10d72006-12-04 02:26:12 +01004168/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004169 * Manage client-side cookie. It can impact performance by about 2% so it is
4170 * desirable to call it only when needed.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004171 */
4172void manage_client_side_cookies(struct session *t, struct buffer *req)
4173{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004174 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004175 char *p1, *p2, *p3, *p4;
4176 char *del_colon, *del_cookie, *colon;
4177 int app_cookies;
4178
4179 appsess *asession_temp = NULL;
4180 appsess local_asession;
4181
4182 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004183 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004184
Willy Tarreau2a324282006-12-05 00:05:46 +01004185 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004186 * we start with the start line.
4187 */
Willy Tarreau83969f42007-01-22 08:55:47 +01004188 old_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004189 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004190
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004191 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004192 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004193 int val;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004194
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004195 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01004196 cur_ptr = cur_next;
4197 cur_end = cur_ptr + cur_hdr->len;
4198 cur_next = cur_end + cur_hdr->cr + 1;
4199
4200 /* We have one full header between cur_ptr and cur_end, and the
4201 * next header starts at cur_next. We're only interested in
4202 * "Cookie:" headers.
4203 */
4204
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004205 val = http_header_match2(cur_ptr, cur_end, "Cookie", 6);
4206 if (!val) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004207 old_idx = cur_idx;
4208 continue;
4209 }
4210
4211 /* Now look for cookies. Conforming to RFC2109, we have to support
4212 * attributes whose name begin with a '$', and associate them with
4213 * the right cookie, if we want to delete this cookie.
4214 * So there are 3 cases for each cookie read :
4215 * 1) it's a special attribute, beginning with a '$' : ignore it.
4216 * 2) it's a server id cookie that we *MAY* want to delete : save
4217 * some pointers on it (last semi-colon, beginning of cookie...)
4218 * 3) it's an application cookie : we *MAY* have to delete a previous
4219 * "special" cookie.
4220 * At the end of loop, if a "special" cookie remains, we may have to
4221 * remove it. If no application cookie persists in the header, we
4222 * *MUST* delete it
4223 */
4224
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004225 colon = p1 = cur_ptr + val; /* first non-space char after 'Cookie:' */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004226
Willy Tarreau58f10d72006-12-04 02:26:12 +01004227 /* del_cookie == NULL => nothing to be deleted */
4228 del_colon = del_cookie = NULL;
4229 app_cookies = 0;
4230
4231 while (p1 < cur_end) {
4232 /* skip spaces and colons, but keep an eye on these ones */
4233 while (p1 < cur_end) {
4234 if (*p1 == ';' || *p1 == ',')
4235 colon = p1;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004236 else if (!isspace((unsigned char)*p1))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004237 break;
4238 p1++;
4239 }
4240
4241 if (p1 == cur_end)
4242 break;
4243
4244 /* p1 is at the beginning of the cookie name */
4245 p2 = p1;
4246 while (p2 < cur_end && *p2 != '=')
4247 p2++;
4248
4249 if (p2 == cur_end)
4250 break;
4251
4252 p3 = p2 + 1; /* skips the '=' sign */
4253 if (p3 == cur_end)
4254 break;
4255
4256 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004257 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';' && *p4 != ',')
Willy Tarreau58f10d72006-12-04 02:26:12 +01004258 p4++;
4259
4260 /* here, we have the cookie name between p1 and p2,
4261 * and its value between p3 and p4.
4262 * we can process it :
4263 *
4264 * Cookie: NAME=VALUE;
4265 * | || || |
4266 * | || || +--> p4
4267 * | || |+-------> p3
4268 * | || +--------> p2
4269 * | |+------------> p1
4270 * | +-------------> colon
4271 * +--------------------> cur_ptr
4272 */
4273
4274 if (*p1 == '$') {
4275 /* skip this one */
4276 }
4277 else {
4278 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004279 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004280 txn->cli_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004281 (p4 - p1 >= t->fe->capture_namelen) &&
4282 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004283 int log_len = p4 - p1;
4284
Willy Tarreau086b3b42007-05-13 21:45:51 +02004285 if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004286 Alert("HTTP logging : out of memory.\n");
4287 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004288 if (log_len > t->fe->capture_len)
4289 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004290 memcpy(txn->cli_cookie, p1, log_len);
4291 txn->cli_cookie[log_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004292 }
4293 }
4294
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004295 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4296 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004297 /* Cool... it's the right one */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004298 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004299 char *delim;
4300
4301 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4302 * have the server ID betweek p3 and delim, and the original cookie between
4303 * delim+1 and p4. Otherwise, delim==p4 :
4304 *
4305 * Cookie: NAME=SRV~VALUE;
4306 * | || || | |
4307 * | || || | +--> p4
4308 * | || || +--------> delim
4309 * | || |+-----------> p3
4310 * | || +------------> p2
4311 * | |+----------------> p1
4312 * | +-----------------> colon
4313 * +------------------------> cur_ptr
4314 */
4315
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004316 if (t->be->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004317 for (delim = p3; delim < p4; delim++)
4318 if (*delim == COOKIE_DELIM)
4319 break;
4320 }
4321 else
4322 delim = p4;
4323
4324
4325 /* Here, we'll look for the first running server which supports the cookie.
4326 * This allows to share a same cookie between several servers, for example
4327 * to dedicate backup servers to specific servers only.
4328 * However, to prevent clients from sticking to cookie-less backup server
4329 * when they have incidentely learned an empty cookie, we simply ignore
4330 * empty cookies and mark them as invalid.
4331 */
4332 if (delim == p3)
4333 srv = NULL;
4334
4335 while (srv) {
Willy Tarreau92f2ab12007-02-02 22:14:47 +01004336 if (srv->cookie && (srv->cklen == delim - p3) &&
4337 !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004338 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004339 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004340 txn->flags &= ~TX_CK_MASK;
4341 txn->flags |= TX_CK_VALID;
4342 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004343 t->srv = srv;
4344 break;
4345 } else {
4346 /* we found a server, but it's down */
Willy Tarreau3d300592007-03-18 18:34:41 +01004347 txn->flags &= ~TX_CK_MASK;
4348 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004349 }
4350 }
4351 srv = srv->next;
4352 }
4353
Willy Tarreau3d300592007-03-18 18:34:41 +01004354 if (!srv && !(txn->flags & TX_CK_DOWN)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004355 /* no server matched this cookie */
Willy Tarreau3d300592007-03-18 18:34:41 +01004356 txn->flags &= ~TX_CK_MASK;
4357 txn->flags |= TX_CK_INVALID;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004358 }
4359
4360 /* depending on the cookie mode, we may have to either :
4361 * - delete the complete cookie if we're in insert+indirect mode, so that
4362 * the server never sees it ;
4363 * - remove the server id from the cookie value, and tag the cookie as an
4364 * application cookie so that it does not get accidentely removed later,
4365 * if we're in cookie prefix mode
4366 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004367 if ((t->be->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004368 int delta; /* negative */
4369
4370 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
4371 p4 += delta;
4372 cur_end += delta;
4373 cur_next += delta;
4374 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004375 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004376
4377 del_cookie = del_colon = NULL;
4378 app_cookies++; /* protect the header from deletion */
4379 }
4380 else if (del_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004381 (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 +01004382 del_cookie = p1;
4383 del_colon = colon;
4384 }
4385 } else {
4386 /* now we know that we must keep this cookie since it's
4387 * not ours. But if we wanted to delete our cookie
4388 * earlier, we cannot remove the complete header, but we
4389 * can remove the previous block itself.
4390 */
4391 app_cookies++;
4392
4393 if (del_cookie != NULL) {
4394 int delta; /* negative */
4395
4396 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
4397 p4 += delta;
4398 cur_end += delta;
4399 cur_next += delta;
4400 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004401 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004402 del_cookie = del_colon = NULL;
4403 }
4404 }
4405
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004406 if ((t->be->appsession_name != NULL) &&
4407 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004408 /* first, let's see if the cookie is our appcookie*/
4409
4410 /* Cool... it's the right one */
4411
4412 asession_temp = &local_asession;
4413
Willy Tarreau63963c62007-05-13 21:29:55 +02004414 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004415 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4416 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4417 return;
4418 }
4419
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004420 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4421 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004422 asession_temp->serverid = NULL;
Willy Tarreau51041c72007-09-09 21:56:53 +02004423
Willy Tarreau58f10d72006-12-04 02:26:12 +01004424 /* only do insert, if lookup fails */
Willy Tarreau51041c72007-09-09 21:56:53 +02004425 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4426 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004427 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004428 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004429 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004430 Alert("Not enough memory process_cli():asession:calloc().\n");
4431 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4432 return;
4433 }
4434
4435 asession_temp->sessid = local_asession.sessid;
4436 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004437 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004438 } else {
4439 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004440 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004441 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004442 if (asession_temp->serverid == NULL) {
4443 Alert("Found Application Session without matching server.\n");
4444 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004445 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004446 while (srv) {
4447 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004448 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004449 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004450 txn->flags &= ~TX_CK_MASK;
4451 txn->flags |= TX_CK_VALID;
4452 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004453 t->srv = srv;
4454 break;
4455 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01004456 txn->flags &= ~TX_CK_MASK;
4457 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004458 }
4459 }
4460 srv = srv->next;
4461 }/* end while(srv) */
4462 }/* end else if server == NULL */
4463
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004464 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004465 }/* end if ((t->proxy->appsession_name != NULL) ... */
4466 }
4467
4468 /* we'll have to look for another cookie ... */
4469 p1 = p4;
4470 } /* while (p1 < cur_end) */
4471
4472 /* There's no more cookie on this line.
4473 * We may have marked the last one(s) for deletion.
4474 * We must do this now in two ways :
4475 * - if there is no app cookie, we simply delete the header ;
4476 * - if there are app cookies, we must delete the end of the
4477 * string properly, including the colon/semi-colon before
4478 * the cookie name.
4479 */
4480 if (del_cookie != NULL) {
4481 int delta;
4482 if (app_cookies) {
4483 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
4484 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004485 cur_hdr->len += delta;
4486 } else {
4487 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004488
4489 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004490 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4491 txn->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004492 cur_hdr->len = 0;
4493 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01004494 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004495 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004496 }
4497
4498 /* keep the link from this header to next one */
4499 old_idx = cur_idx;
4500 } /* end of cookie processing on this header */
4501}
4502
4503
Willy Tarreaua15645d2007-03-18 16:22:39 +01004504/* Iterate the same filter through all response headers contained in <rtr>.
4505 * Returns 1 if this filter can be stopped upon return, otherwise 0.
4506 */
4507int apply_filter_to_resp_headers(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4508{
4509 char term;
4510 char *cur_ptr, *cur_end, *cur_next;
4511 int cur_idx, old_idx, last_hdr;
4512 struct http_txn *txn = &t->txn;
4513 struct hdr_idx_elem *cur_hdr;
4514 int len, delta;
4515
4516 last_hdr = 0;
4517
4518 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4519 old_idx = 0;
4520
4521 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004522 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004523 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004524 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004525 (exp->action == ACT_ALLOW ||
4526 exp->action == ACT_DENY))
4527 return 0;
4528
4529 cur_idx = txn->hdr_idx.v[old_idx].next;
4530 if (!cur_idx)
4531 break;
4532
4533 cur_hdr = &txn->hdr_idx.v[cur_idx];
4534 cur_ptr = cur_next;
4535 cur_end = cur_ptr + cur_hdr->len;
4536 cur_next = cur_end + cur_hdr->cr + 1;
4537
4538 /* Now we have one header between cur_ptr and cur_end,
4539 * and the next header starts at cur_next.
4540 */
4541
4542 /* The annoying part is that pattern matching needs
4543 * that we modify the contents to null-terminate all
4544 * strings before testing them.
4545 */
4546
4547 term = *cur_end;
4548 *cur_end = '\0';
4549
4550 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4551 switch (exp->action) {
4552 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004553 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004554 last_hdr = 1;
4555 break;
4556
4557 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004558 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004559 last_hdr = 1;
4560 break;
4561
4562 case ACT_REPLACE:
4563 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4564 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4565 /* FIXME: if the user adds a newline in the replacement, the
4566 * index will not be recalculated for now, and the new line
4567 * will not be counted as a new header.
4568 */
4569
4570 cur_end += delta;
4571 cur_next += delta;
4572 cur_hdr->len += delta;
4573 txn->rsp.eoh += delta;
4574 break;
4575
4576 case ACT_REMOVE:
4577 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4578 cur_next += delta;
4579
4580 /* FIXME: this should be a separate function */
4581 txn->rsp.eoh += delta;
4582 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4583 txn->hdr_idx.used--;
4584 cur_hdr->len = 0;
4585 cur_end = NULL; /* null-term has been rewritten */
4586 break;
4587
4588 }
4589 }
4590 if (cur_end)
4591 *cur_end = term; /* restore the string terminator */
4592
4593 /* keep the link from this header to next one in case of later
4594 * removal of next header.
4595 */
4596 old_idx = cur_idx;
4597 }
4598 return 0;
4599}
4600
4601
4602/* Apply the filter to the status line in the response buffer <rtr>.
4603 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4604 * or -1 if a replacement resulted in an invalid status line.
4605 */
4606int apply_filter_to_sts_line(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4607{
4608 char term;
4609 char *cur_ptr, *cur_end;
4610 int done;
4611 struct http_txn *txn = &t->txn;
4612 int len, delta;
4613
4614
Willy Tarreau3d300592007-03-18 18:34:41 +01004615 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004616 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004617 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004618 (exp->action == ACT_ALLOW ||
4619 exp->action == ACT_DENY))
4620 return 0;
4621 else if (exp->action == ACT_REMOVE)
4622 return 0;
4623
4624 done = 0;
4625
Willy Tarreau9cdde232007-05-02 20:58:19 +02004626 cur_ptr = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004627 cur_end = cur_ptr + txn->rsp.sl.rq.l;
4628
4629 /* Now we have the status line between cur_ptr and cur_end */
4630
4631 /* The annoying part is that pattern matching needs
4632 * that we modify the contents to null-terminate all
4633 * strings before testing them.
4634 */
4635
4636 term = *cur_end;
4637 *cur_end = '\0';
4638
4639 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4640 switch (exp->action) {
4641 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004642 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004643 done = 1;
4644 break;
4645
4646 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004647 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004648 done = 1;
4649 break;
4650
4651 case ACT_REPLACE:
4652 *cur_end = term; /* restore the string terminator */
4653 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4654 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4655 /* FIXME: if the user adds a newline in the replacement, the
4656 * index will not be recalculated for now, and the new line
4657 * will not be counted as a new header.
4658 */
4659
4660 txn->rsp.eoh += delta;
4661 cur_end += delta;
4662
Willy Tarreau9cdde232007-05-02 20:58:19 +02004663 txn->rsp.sol = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004664 cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data,
Willy Tarreau02785762007-04-03 14:45:44 +02004665 HTTP_MSG_RPVER,
Willy Tarreaua15645d2007-03-18 16:22:39 +01004666 cur_ptr, cur_end + 1,
4667 NULL, NULL);
4668 if (unlikely(!cur_end))
4669 return -1;
4670
4671 /* we have a full respnse and we know that we have either a CR
4672 * or an LF at <ptr>.
4673 */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004674 txn->status = strl2ui(rtr->data + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004675 hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.rq.l, *cur_end == '\r');
4676 /* there is no point trying this regex on headers */
4677 return 1;
4678 }
4679 }
4680 *cur_end = term; /* restore the string terminator */
4681 return done;
4682}
4683
4684
4685
4686/*
4687 * Apply all the resp filters <exp> to all headers in buffer <rtr> of session <t>.
4688 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
4689 * unparsable response.
4690 */
4691int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4692{
Willy Tarreau3d300592007-03-18 18:34:41 +01004693 struct http_txn *txn = &t->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004694 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004695 while (exp && !(txn->flags & TX_SVDENY)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004696 int ret;
4697
4698 /*
4699 * The interleaving of transformations and verdicts
4700 * makes it difficult to decide to continue or stop
4701 * the evaluation.
4702 */
4703
Willy Tarreau3d300592007-03-18 18:34:41 +01004704 if ((txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004705 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4706 exp->action == ACT_PASS)) {
4707 exp = exp->next;
4708 continue;
4709 }
4710
4711 /* Apply the filter to the status line. */
4712 ret = apply_filter_to_sts_line(t, rtr, exp);
4713 if (unlikely(ret < 0))
4714 return -1;
4715
4716 if (likely(ret == 0)) {
4717 /* The filter did not match the response, it can be
4718 * iterated through all headers.
4719 */
4720 apply_filter_to_resp_headers(t, rtr, exp);
4721 }
4722 exp = exp->next;
4723 }
4724 return 0;
4725}
4726
4727
4728
4729/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004730 * Manage server-side cookies. It can impact performance by about 2% so it is
4731 * desirable to call it only when needed.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004732 */
4733void manage_server_side_cookies(struct session *t, struct buffer *rtr)
4734{
4735 struct http_txn *txn = &t->txn;
4736 char *p1, *p2, *p3, *p4;
4737
4738 appsess *asession_temp = NULL;
4739 appsess local_asession;
4740
4741 char *cur_ptr, *cur_end, *cur_next;
4742 int cur_idx, old_idx, delta;
4743
Willy Tarreaua15645d2007-03-18 16:22:39 +01004744 /* Iterate through the headers.
4745 * we start with the start line.
4746 */
4747 old_idx = 0;
4748 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4749
4750 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
4751 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004752 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004753
4754 cur_hdr = &txn->hdr_idx.v[cur_idx];
4755 cur_ptr = cur_next;
4756 cur_end = cur_ptr + cur_hdr->len;
4757 cur_next = cur_end + cur_hdr->cr + 1;
4758
4759 /* We have one full header between cur_ptr and cur_end, and the
4760 * next header starts at cur_next. We're only interested in
4761 * "Cookie:" headers.
4762 */
4763
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004764 val = http_header_match2(cur_ptr, cur_end, "Set-Cookie", 10);
4765 if (!val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004766 old_idx = cur_idx;
4767 continue;
4768 }
4769
4770 /* OK, right now we know we have a set-cookie at cur_ptr */
Willy Tarreau3d300592007-03-18 18:34:41 +01004771 txn->flags |= TX_SCK_ANY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004772
4773
4774 /* maybe we only wanted to see if there was a set-cookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004775 if (t->be->cookie_name == NULL &&
4776 t->be->appsession_name == NULL &&
4777 t->be->capture_name == NULL)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004778 return;
4779
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004780 p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004781
4782 while (p1 < cur_end) { /* in fact, we'll break after the first cookie */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004783 if (p1 == cur_end || *p1 == ';') /* end of cookie */
4784 break;
4785
4786 /* p1 is at the beginning of the cookie name */
4787 p2 = p1;
4788
4789 while (p2 < cur_end && *p2 != '=' && *p2 != ';')
4790 p2++;
4791
4792 if (p2 == cur_end || *p2 == ';') /* next cookie */
4793 break;
4794
4795 p3 = p2 + 1; /* skip the '=' sign */
4796 if (p3 == cur_end)
4797 break;
4798
4799 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004800 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';')
Willy Tarreaua15645d2007-03-18 16:22:39 +01004801 p4++;
4802
4803 /* here, we have the cookie name between p1 and p2,
4804 * and its value between p3 and p4.
4805 * we can process it.
4806 */
4807
4808 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004809 if (t->be->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004810 txn->srv_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004811 (p4 - p1 >= t->be->capture_namelen) &&
4812 memcmp(p1, t->be->capture_name, t->be->capture_namelen) == 0) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004813 int log_len = p4 - p1;
4814
Willy Tarreau086b3b42007-05-13 21:45:51 +02004815 if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004816 Alert("HTTP logging : out of memory.\n");
4817 }
4818
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004819 if (log_len > t->be->capture_len)
4820 log_len = t->be->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004821 memcpy(txn->srv_cookie, p1, log_len);
4822 txn->srv_cookie[log_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004823 }
4824
4825 /* now check if we need to process it for persistence */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004826 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4827 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004828 /* Cool... it's the right one */
Willy Tarreau3d300592007-03-18 18:34:41 +01004829 txn->flags |= TX_SCK_SEEN;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004830
4831 /* If the cookie is in insert mode on a known server, we'll delete
4832 * this occurrence because we'll insert another one later.
4833 * We'll delete it too if the "indirect" option is set and we're in
4834 * a direct access. */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004835 if (((t->srv) && (t->be->options & PR_O_COOK_INS)) ||
4836 ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004837 /* this header must be deleted */
4838 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4839 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4840 txn->hdr_idx.used--;
4841 cur_hdr->len = 0;
4842 cur_next += delta;
4843 txn->rsp.eoh += delta;
4844
Willy Tarreau3d300592007-03-18 18:34:41 +01004845 txn->flags |= TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004846 }
4847 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004848 (t->be->options & PR_O_COOK_RW)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004849 /* replace bytes p3->p4 with the cookie name associated
4850 * with this server since we know it.
4851 */
4852 delta = buffer_replace2(rtr, p3, p4, t->srv->cookie, t->srv->cklen);
4853 cur_hdr->len += delta;
4854 cur_next += delta;
4855 txn->rsp.eoh += delta;
4856
Willy Tarreau3d300592007-03-18 18:34:41 +01004857 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004858 }
4859 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004860 (t->be->options & PR_O_COOK_PFX)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004861 /* insert the cookie name associated with this server
4862 * before existing cookie, and insert a delimitor between them..
4863 */
4864 delta = buffer_replace2(rtr, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4865 cur_hdr->len += delta;
4866 cur_next += delta;
4867 txn->rsp.eoh += delta;
4868
4869 p3[t->srv->cklen] = COOKIE_DELIM;
Willy Tarreau3d300592007-03-18 18:34:41 +01004870 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004871 }
4872 }
4873 /* next, let's see if the cookie is our appcookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004874 else if ((t->be->appsession_name != NULL) &&
4875 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004876
4877 /* Cool... it's the right one */
4878
4879 size_t server_id_len = strlen(t->srv->id) + 1;
4880 asession_temp = &local_asession;
4881
Willy Tarreau63963c62007-05-13 21:29:55 +02004882 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004883 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4884 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4885 return;
4886 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004887 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4888 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004889 asession_temp->serverid = NULL;
4890
4891 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01004892 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4893 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004894 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004895 Alert("Not enough Memory process_srv():asession:calloc().\n");
4896 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
4897 return;
4898 }
4899 asession_temp->sessid = local_asession.sessid;
4900 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004901 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
4902 } else {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004903 /* free wasted memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004904 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau51041c72007-09-09 21:56:53 +02004905 }
4906
Willy Tarreaua15645d2007-03-18 16:22:39 +01004907 if (asession_temp->serverid == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004908 if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004909 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4910 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4911 return;
4912 }
4913 asession_temp->serverid[0] = '\0';
4914 }
4915
4916 if (asession_temp->serverid[0] == '\0')
4917 memcpy(asession_temp->serverid, t->srv->id, server_id_len);
4918
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004919 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004920
4921#if defined(DEBUG_HASH)
Willy Tarreau51041c72007-09-09 21:56:53 +02004922 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreaua15645d2007-03-18 16:22:39 +01004923#endif
4924 }/* end if ((t->proxy->appsession_name != NULL) ... */
4925 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4926 } /* we're now at the end of the cookie value */
4927
4928 /* keep the link from this header to next one */
4929 old_idx = cur_idx;
4930 } /* end of cookie processing on this header */
4931}
4932
4933
4934
4935/*
4936 * Check if response is cacheable or not. Updates t->flags.
4937 */
4938void check_response_for_cacheability(struct session *t, struct buffer *rtr)
4939{
4940 struct http_txn *txn = &t->txn;
4941 char *p1, *p2;
4942
4943 char *cur_ptr, *cur_end, *cur_next;
4944 int cur_idx;
4945
Willy Tarreau5df51872007-11-25 16:20:08 +01004946 if (!(txn->flags & TX_CACHEABLE))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004947 return;
4948
4949 /* Iterate through the headers.
4950 * we start with the start line.
4951 */
4952 cur_idx = 0;
4953 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4954
4955 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
4956 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004957 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004958
4959 cur_hdr = &txn->hdr_idx.v[cur_idx];
4960 cur_ptr = cur_next;
4961 cur_end = cur_ptr + cur_hdr->len;
4962 cur_next = cur_end + cur_hdr->cr + 1;
4963
4964 /* We have one full header between cur_ptr and cur_end, and the
4965 * next header starts at cur_next. We're only interested in
4966 * "Cookie:" headers.
4967 */
4968
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004969 val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
4970 if (val) {
4971 if ((cur_end - (cur_ptr + val) >= 8) &&
4972 strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
4973 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
4974 return;
4975 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01004976 }
4977
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004978 val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
4979 if (!val)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004980 continue;
4981
4982 /* OK, right now we know we have a cache-control header at cur_ptr */
4983
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004984 p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004985
4986 if (p1 >= cur_end) /* no more info */
4987 continue;
4988
4989 /* p1 is at the beginning of the value */
4990 p2 = p1;
4991
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004992 while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((unsigned char)*p2))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004993 p2++;
4994
4995 /* we have a complete value between p1 and p2 */
4996 if (p2 < cur_end && *p2 == '=') {
4997 /* we have something of the form no-cache="set-cookie" */
4998 if ((cur_end - p1 >= 21) &&
4999 strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0
5000 && (p1[20] == '"' || p1[20] == ','))
Willy Tarreau3d300592007-03-18 18:34:41 +01005001 txn->flags &= ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005002 continue;
5003 }
5004
5005 /* OK, so we know that either p2 points to the end of string or to a comma */
5006 if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) ||
5007 ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) ||
5008 ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) ||
5009 ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005010 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005011 return;
5012 }
5013
5014 if ((p2 - p1 == 6) && strncasecmp(p1, "public", 6) == 0) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005015 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005016 continue;
5017 }
5018 }
5019}
5020
5021
Willy Tarreau58f10d72006-12-04 02:26:12 +01005022/*
5023 * Try to retrieve a known appsession in the URI, then the associated server.
5024 * If the server is found, it's assigned to the session.
5025 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005026void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01005027{
Willy Tarreau3d300592007-03-18 18:34:41 +01005028 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005029 appsess *asession_temp = NULL;
5030 appsess local_asession;
5031 char *request_line;
5032
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005033 if (t->be->appsession_name == NULL ||
Willy Tarreaub326fcc2007-03-03 13:54:32 +01005034 (t->txn.meth != HTTP_METH_GET && t->txn.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005035 (request_line = memchr(begin, ';', len)) == NULL ||
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005036 ((1 + t->be->appsession_name_len + 1 + t->be->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01005037 return;
5038
5039 /* skip ';' */
5040 request_line++;
5041
5042 /* look if we have a jsessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005043 if (strncasecmp(request_line, t->be->appsession_name, t->be->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01005044 return;
5045
5046 /* skip jsessionid= */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005047 request_line += t->be->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005048
5049 /* First try if we already have an appsession */
5050 asession_temp = &local_asession;
5051
Willy Tarreau63963c62007-05-13 21:29:55 +02005052 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005053 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
5054 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
5055 return;
5056 }
5057
5058 /* Copy the sessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005059 memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
5060 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005061 asession_temp->serverid = NULL;
5062
5063 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01005064 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
5065 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02005066 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005067 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005068 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005069 Alert("Not enough memory process_cli():asession:calloc().\n");
5070 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
5071 return;
5072 }
5073 asession_temp->sessid = local_asession.sessid;
5074 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02005075 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005076 }
5077 else {
5078 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005079 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005080 }
Willy Tarreau51041c72007-09-09 21:56:53 +02005081
Willy Tarreau0c303ee2008-07-07 00:09:58 +02005082 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005083 asession_temp->request_count++;
Willy Tarreau51041c72007-09-09 21:56:53 +02005084
Willy Tarreau58f10d72006-12-04 02:26:12 +01005085#if defined(DEBUG_HASH)
Willy Tarreau51041c72007-09-09 21:56:53 +02005086 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreau58f10d72006-12-04 02:26:12 +01005087#endif
5088 if (asession_temp->serverid == NULL) {
5089 Alert("Found Application Session without matching server.\n");
5090 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005091 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005092 while (srv) {
5093 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005094 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005095 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01005096 txn->flags &= ~TX_CK_MASK;
5097 txn->flags |= TX_CK_VALID;
5098 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005099 t->srv = srv;
5100 break;
5101 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01005102 txn->flags &= ~TX_CK_MASK;
5103 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005104 }
5105 }
5106 srv = srv->next;
5107 }
5108 }
5109}
5110
5111
Willy Tarreaub2513902006-12-17 14:52:38 +01005112/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005113 * In a GET or HEAD request, check if the requested URI matches the stats uri
5114 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01005115 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005116 * It is assumed that the request is either a HEAD or GET and that the
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005117 * t->be->uri_auth field is valid. An HTTP/401 response may be sent, or
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005118 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01005119 *
5120 * Returns 1 if the session's state changes, otherwise 0.
5121 */
5122int stats_check_uri_auth(struct session *t, struct proxy *backend)
5123{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005124 struct http_txn *txn = &t->txn;
Willy Tarreaub2513902006-12-17 14:52:38 +01005125 struct uri_auth *uri_auth = backend->uri_auth;
5126 struct user_auth *user;
5127 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005128 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01005129
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005130 memset(&t->data_ctx.stats, 0, sizeof(t->data_ctx.stats));
5131
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005132 /* check URI size */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005133 if (uri_auth->uri_len > txn->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01005134 return 0;
5135
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005136 h = t->req->data + txn->req.sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005137
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005138 /* the URI is in h */
5139 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01005140 return 0;
5141
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005142 h += uri_auth->uri_len;
5143 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 3) {
5144 if (memcmp(h, ";up", 3) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005145 t->data_ctx.stats.flags |= STAT_HIDE_DOWN;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005146 break;
5147 }
5148 h++;
5149 }
5150
5151 if (uri_auth->refresh) {
5152 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5153 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 10) {
5154 if (memcmp(h, ";norefresh", 10) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005155 t->data_ctx.stats.flags |= STAT_NO_REFRESH;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005156 break;
5157 }
5158 h++;
5159 }
5160 }
5161
Willy Tarreau55bb8452007-10-17 18:44:57 +02005162 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5163 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 4) {
5164 if (memcmp(h, ";csv", 4) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005165 t->data_ctx.stats.flags |= STAT_FMT_CSV;
Willy Tarreau55bb8452007-10-17 18:44:57 +02005166 break;
5167 }
5168 h++;
5169 }
5170
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005171 t->data_ctx.stats.flags |= STAT_SHOW_STAT | STAT_SHOW_INFO;
5172
Willy Tarreaub2513902006-12-17 14:52:38 +01005173 /* we are in front of a interceptable URI. Let's check
5174 * if there's an authentication and if it's valid.
5175 */
5176 user = uri_auth->users;
5177 if (!user) {
5178 /* no user auth required, it's OK */
5179 authenticated = 1;
5180 } else {
5181 authenticated = 0;
5182
5183 /* a user list is defined, we have to check.
5184 * skip 21 chars for "Authorization: Basic ".
5185 */
5186
5187 /* FIXME: this should move to an earlier place */
5188 cur_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005189 h = t->req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
5190 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
5191 int len = txn->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005192 if (len > 14 &&
5193 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005194 txn->auth_hdr.str = h;
5195 txn->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005196 break;
5197 }
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005198 h += len + txn->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01005199 }
5200
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005201 if (txn->auth_hdr.len < 21 ||
5202 memcmp(txn->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01005203 user = NULL;
5204
5205 while (user) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005206 if ((txn->auth_hdr.len == user->user_len + 14 + 7)
5207 && !memcmp(txn->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01005208 user->user_pwd, user->user_len)) {
5209 authenticated = 1;
5210 break;
5211 }
5212 user = user->next;
5213 }
5214 }
5215
5216 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01005217 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01005218
5219 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01005220 msg.str = trash;
5221 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005222 txn->status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01005223 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01005224 if (!(t->flags & SN_ERR_MASK))
5225 t->flags |= SN_ERR_PRXCOND;
5226 if (!(t->flags & SN_FINST_MASK))
5227 t->flags |= SN_FINST_R;
5228 return 1;
5229 }
5230
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005231 /* The request is valid, the user is authenticated. Let's start sending
Willy Tarreaub2513902006-12-17 14:52:38 +01005232 * data.
5233 */
Willy Tarreau284c7b32008-06-29 16:38:43 +02005234 EV_FD_CLR(t->cli_fd, DIR_RD);
5235 buffer_shutr(t->req);
5236 buffer_shutr(t->rep);
Willy Tarreaub2513902006-12-17 14:52:38 +01005237 t->cli_state = CL_STSHUTR;
5238 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau70089872008-06-13 21:12:51 +02005239 t->logs.tv_request = now;
Willy Tarreaub2513902006-12-17 14:52:38 +01005240 t->data_source = DATA_SRC_STATS;
5241 t->data_state = DATA_ST_INIT;
Willy Tarreau91e99932008-06-30 07:51:00 +02005242 t->task->nice = -32; /* small boost for HTTP statistics */
Willy Tarreaub2513902006-12-17 14:52:38 +01005243 produce_content(t);
5244 return 1;
5245}
5246
5247
Willy Tarreaubaaee002006-06-26 02:48:02 +02005248/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01005249 * Print a debug line with a header
5250 */
5251void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
5252{
5253 int len, max;
5254 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
5255 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
5256 max = end - start;
5257 UBOUND(max, sizeof(trash) - len - 1);
5258 len += strlcpy2(trash + len, start, max + 1);
5259 trash[len++] = '\n';
5260 write(1, trash, len);
5261}
5262
5263
Willy Tarreau8797c062007-05-07 00:55:35 +02005264/************************************************************************/
5265/* The code below is dedicated to ACL parsing and matching */
5266/************************************************************************/
5267
5268
5269
5270
5271/* 1. Check on METHOD
5272 * We use the pre-parsed method if it is known, and store its number as an
5273 * integer. If it is unknown, we use the pointer and the length.
5274 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005275static int acl_parse_meth(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005276{
5277 int len, meth;
5278
Willy Tarreauae8b7962007-06-09 23:10:04 +02005279 len = strlen(*text);
5280 meth = find_http_meth(*text, len);
Willy Tarreau8797c062007-05-07 00:55:35 +02005281
5282 pattern->val.i = meth;
5283 if (meth == HTTP_METH_OTHER) {
Willy Tarreauae8b7962007-06-09 23:10:04 +02005284 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005285 if (!pattern->ptr.str)
5286 return 0;
5287 pattern->len = len;
5288 }
5289 return 1;
5290}
5291
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005292static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005293acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
5294 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005295{
5296 int meth;
5297 struct http_txn *txn = l7;
5298
Willy Tarreaub6866442008-07-14 23:54:42 +02005299 if (!txn)
5300 return 0;
5301
Willy Tarreauc11416f2007-06-17 16:58:38 +02005302 if (txn->req.msg_state != HTTP_MSG_BODY)
5303 return 0;
5304
Willy Tarreau8797c062007-05-07 00:55:35 +02005305 meth = txn->meth;
5306 test->i = meth;
5307 if (meth == HTTP_METH_OTHER) {
Willy Tarreauc11416f2007-06-17 16:58:38 +02005308 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5309 /* ensure the indexes are not affected */
5310 return 0;
Willy Tarreau8797c062007-05-07 00:55:35 +02005311 test->len = txn->req.sl.rq.m_l;
5312 test->ptr = txn->req.sol;
5313 }
5314 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5315 return 1;
5316}
5317
5318static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
5319{
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005320 int icase;
5321
Willy Tarreau8797c062007-05-07 00:55:35 +02005322 if (test->i != pattern->val.i)
Willy Tarreau11382812008-07-09 16:18:21 +02005323 return ACL_PAT_FAIL;
Willy Tarreau8797c062007-05-07 00:55:35 +02005324
5325 if (test->i != HTTP_METH_OTHER)
Willy Tarreau11382812008-07-09 16:18:21 +02005326 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005327
5328 /* Other method, we must compare the strings */
5329 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +02005330 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005331
5332 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
5333 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) != 0) ||
5334 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +02005335 return ACL_PAT_FAIL;
5336 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005337}
5338
5339/* 2. Check on Request/Status Version
5340 * We simply compare strings here.
5341 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005342static int acl_parse_ver(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005343{
Willy Tarreauae8b7962007-06-09 23:10:04 +02005344 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005345 if (!pattern->ptr.str)
5346 return 0;
Willy Tarreauae8b7962007-06-09 23:10:04 +02005347 pattern->len = strlen(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005348 return 1;
5349}
5350
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005351static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005352acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
5353 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005354{
5355 struct http_txn *txn = l7;
5356 char *ptr;
5357 int len;
5358
Willy Tarreaub6866442008-07-14 23:54:42 +02005359 if (!txn)
5360 return 0;
5361
Willy Tarreauc11416f2007-06-17 16:58:38 +02005362 if (txn->req.msg_state != HTTP_MSG_BODY)
5363 return 0;
5364
Willy Tarreau8797c062007-05-07 00:55:35 +02005365 len = txn->req.sl.rq.v_l;
5366 ptr = txn->req.sol + txn->req.sl.rq.v - txn->req.som;
5367
5368 while ((len-- > 0) && (*ptr++ != '/'));
5369 if (len <= 0)
5370 return 0;
5371
5372 test->ptr = ptr;
5373 test->len = len;
5374
5375 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5376 return 1;
5377}
5378
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005379static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005380acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
5381 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005382{
5383 struct http_txn *txn = l7;
5384 char *ptr;
5385 int len;
5386
Willy Tarreaub6866442008-07-14 23:54:42 +02005387 if (!txn)
5388 return 0;
5389
Willy Tarreauc11416f2007-06-17 16:58:38 +02005390 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5391 return 0;
5392
Willy Tarreau8797c062007-05-07 00:55:35 +02005393 len = txn->rsp.sl.st.v_l;
5394 ptr = txn->rsp.sol;
5395
5396 while ((len-- > 0) && (*ptr++ != '/'));
5397 if (len <= 0)
5398 return 0;
5399
5400 test->ptr = ptr;
5401 test->len = len;
5402
5403 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5404 return 1;
5405}
5406
5407/* 3. Check on Status Code. We manipulate integers here. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005408static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005409acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, int dir,
5410 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005411{
5412 struct http_txn *txn = l7;
5413 char *ptr;
5414 int len;
5415
Willy Tarreaub6866442008-07-14 23:54:42 +02005416 if (!txn)
5417 return 0;
5418
Willy Tarreauc11416f2007-06-17 16:58:38 +02005419 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5420 return 0;
5421
Willy Tarreau8797c062007-05-07 00:55:35 +02005422 len = txn->rsp.sl.st.c_l;
5423 ptr = txn->rsp.sol + txn->rsp.sl.st.c - txn->rsp.som;
5424
5425 test->i = __strl2ui(ptr, len);
5426 test->flags = ACL_TEST_F_VOL_1ST;
5427 return 1;
5428}
5429
5430/* 4. Check on URL/URI. A pointer to the URI is stored. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005431static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005432acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
5433 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005434{
5435 struct http_txn *txn = l7;
5436
Willy Tarreaub6866442008-07-14 23:54:42 +02005437 if (!txn)
5438 return 0;
5439
Willy Tarreauc11416f2007-06-17 16:58:38 +02005440 if (txn->req.msg_state != HTTP_MSG_BODY)
5441 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005442
Willy Tarreauc11416f2007-06-17 16:58:38 +02005443 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5444 /* ensure the indexes are not affected */
5445 return 0;
5446
Willy Tarreau8797c062007-05-07 00:55:35 +02005447 test->len = txn->req.sl.rq.u_l;
5448 test->ptr = txn->req.sol + txn->req.sl.rq.u;
5449
Willy Tarreauf3d25982007-05-08 22:45:09 +02005450 /* we do not need to set READ_ONLY because the data is in a buffer */
5451 test->flags = ACL_TEST_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +02005452 return 1;
5453}
5454
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005455static int
5456acl_fetch_url_ip(struct proxy *px, struct session *l4, void *l7, int dir,
5457 struct acl_expr *expr, struct acl_test *test)
5458{
5459 struct http_txn *txn = l7;
5460
Willy Tarreaub6866442008-07-14 23:54:42 +02005461 if (!txn)
5462 return 0;
5463
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005464 if (txn->req.msg_state != HTTP_MSG_BODY)
5465 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005466
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005467 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5468 /* ensure the indexes are not affected */
5469 return 0;
5470
5471 /* Parse HTTP request */
5472 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5473 test->ptr = (void *)&((struct sockaddr_in *)&l4->srv_addr)->sin_addr;
5474 test->i = AF_INET;
5475
5476 /*
5477 * If we are parsing url in frontend space, we prepare backend stage
5478 * to not parse again the same url ! optimization lazyness...
5479 */
5480 if (px->options & PR_O_HTTP_PROXY)
5481 l4->flags |= SN_ADDR_SET;
5482
5483 test->flags = ACL_TEST_F_READ_ONLY;
5484 return 1;
5485}
5486
5487static int
5488acl_fetch_url_port(struct proxy *px, struct session *l4, void *l7, int dir,
5489 struct acl_expr *expr, struct acl_test *test)
5490{
5491 struct http_txn *txn = l7;
5492
Willy Tarreaub6866442008-07-14 23:54:42 +02005493 if (!txn)
5494 return 0;
5495
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005496 if (txn->req.msg_state != HTTP_MSG_BODY)
5497 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005498
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005499 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5500 /* ensure the indexes are not affected */
5501 return 0;
5502
5503 /* Same optimization as url_ip */
5504 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5505 test->i = ntohs(((struct sockaddr_in *)&l4->srv_addr)->sin_port);
5506
5507 if (px->options & PR_O_HTTP_PROXY)
5508 l4->flags |= SN_ADDR_SET;
5509
5510 test->flags = ACL_TEST_F_READ_ONLY;
5511 return 1;
5512}
5513
Willy Tarreauc11416f2007-06-17 16:58:38 +02005514/* 5. Check on HTTP header. A pointer to the beginning of the value is returned.
5515 * This generic function is used by both acl_fetch_chdr() and acl_fetch_shdr().
5516 */
Willy Tarreau33a7e692007-06-10 19:45:56 +02005517static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005518acl_fetch_hdr(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005519 struct acl_expr *expr, struct acl_test *test)
5520{
5521 struct http_txn *txn = l7;
5522 struct hdr_idx *idx = &txn->hdr_idx;
5523 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005524
Willy Tarreaub6866442008-07-14 23:54:42 +02005525 if (!txn)
5526 return 0;
5527
Willy Tarreau33a7e692007-06-10 19:45:56 +02005528 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5529 /* search for header from the beginning */
5530 ctx->idx = 0;
5531
Willy Tarreau33a7e692007-06-10 19:45:56 +02005532 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5533 test->flags |= ACL_TEST_F_FETCH_MORE;
5534 test->flags |= ACL_TEST_F_VOL_HDR;
5535 test->len = ctx->vlen;
5536 test->ptr = (char *)ctx->line + ctx->val;
5537 return 1;
5538 }
5539
5540 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5541 test->flags |= ACL_TEST_F_VOL_HDR;
5542 return 0;
5543}
5544
Willy Tarreau33a7e692007-06-10 19:45:56 +02005545static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005546acl_fetch_chdr(struct proxy *px, struct session *l4, void *l7, int dir,
5547 struct acl_expr *expr, struct acl_test *test)
5548{
5549 struct http_txn *txn = l7;
5550
Willy Tarreaub6866442008-07-14 23:54:42 +02005551 if (!txn)
5552 return 0;
5553
Willy Tarreauc11416f2007-06-17 16:58:38 +02005554 if (txn->req.msg_state != HTTP_MSG_BODY)
5555 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005556
Willy Tarreauc11416f2007-06-17 16:58:38 +02005557 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5558 /* ensure the indexes are not affected */
5559 return 0;
5560
5561 return acl_fetch_hdr(px, l4, txn, txn->req.sol, expr, test);
5562}
5563
5564static int
5565acl_fetch_shdr(struct proxy *px, struct session *l4, void *l7, int dir,
5566 struct acl_expr *expr, struct acl_test *test)
5567{
5568 struct http_txn *txn = l7;
5569
Willy Tarreaub6866442008-07-14 23:54:42 +02005570 if (!txn)
5571 return 0;
5572
Willy Tarreauc11416f2007-06-17 16:58:38 +02005573 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5574 return 0;
5575
5576 return acl_fetch_hdr(px, l4, txn, txn->rsp.sol, expr, test);
5577}
5578
5579/* 6. Check on HTTP header count. The number of occurrences is returned.
5580 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
5581 */
5582static int
5583acl_fetch_hdr_cnt(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005584 struct acl_expr *expr, struct acl_test *test)
5585{
5586 struct http_txn *txn = l7;
5587 struct hdr_idx *idx = &txn->hdr_idx;
5588 struct hdr_ctx ctx;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005589 int cnt;
Willy Tarreau8797c062007-05-07 00:55:35 +02005590
Willy Tarreaub6866442008-07-14 23:54:42 +02005591 if (!txn)
5592 return 0;
5593
Willy Tarreau33a7e692007-06-10 19:45:56 +02005594 ctx.idx = 0;
5595 cnt = 0;
5596 while (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, &ctx))
5597 cnt++;
5598
5599 test->i = cnt;
5600 test->flags = ACL_TEST_F_VOL_HDR;
5601 return 1;
5602}
5603
Willy Tarreauc11416f2007-06-17 16:58:38 +02005604static int
5605acl_fetch_chdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5606 struct acl_expr *expr, struct acl_test *test)
5607{
5608 struct http_txn *txn = l7;
5609
Willy Tarreaub6866442008-07-14 23:54:42 +02005610 if (!txn)
5611 return 0;
5612
Willy Tarreauc11416f2007-06-17 16:58:38 +02005613 if (txn->req.msg_state != HTTP_MSG_BODY)
5614 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005615
Willy Tarreauc11416f2007-06-17 16:58:38 +02005616 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5617 /* ensure the indexes are not affected */
5618 return 0;
5619
5620 return acl_fetch_hdr_cnt(px, l4, txn, txn->req.sol, expr, test);
5621}
5622
5623static int
5624acl_fetch_shdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5625 struct acl_expr *expr, struct acl_test *test)
5626{
5627 struct http_txn *txn = l7;
5628
Willy Tarreaub6866442008-07-14 23:54:42 +02005629 if (!txn)
5630 return 0;
5631
Willy Tarreauc11416f2007-06-17 16:58:38 +02005632 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5633 return 0;
5634
5635 return acl_fetch_hdr_cnt(px, l4, txn, txn->rsp.sol, expr, test);
5636}
5637
Willy Tarreau33a7e692007-06-10 19:45:56 +02005638/* 7. Check on HTTP header's integer value. The integer value is returned.
5639 * FIXME: the type is 'int', it may not be appropriate for everything.
Willy Tarreauc11416f2007-06-17 16:58:38 +02005640 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
Willy Tarreau33a7e692007-06-10 19:45:56 +02005641 */
5642static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005643acl_fetch_hdr_val(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005644 struct acl_expr *expr, struct acl_test *test)
5645{
5646 struct http_txn *txn = l7;
5647 struct hdr_idx *idx = &txn->hdr_idx;
5648 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005649
Willy Tarreaub6866442008-07-14 23:54:42 +02005650 if (!txn)
5651 return 0;
5652
Willy Tarreau33a7e692007-06-10 19:45:56 +02005653 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5654 /* search for header from the beginning */
5655 ctx->idx = 0;
5656
Willy Tarreau33a7e692007-06-10 19:45:56 +02005657 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5658 test->flags |= ACL_TEST_F_FETCH_MORE;
5659 test->flags |= ACL_TEST_F_VOL_HDR;
5660 test->i = strl2ic((char *)ctx->line + ctx->val, ctx->vlen);
5661 return 1;
5662 }
5663
5664 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5665 test->flags |= ACL_TEST_F_VOL_HDR;
5666 return 0;
5667}
5668
Willy Tarreauc11416f2007-06-17 16:58:38 +02005669static int
5670acl_fetch_chdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5671 struct acl_expr *expr, struct acl_test *test)
5672{
5673 struct http_txn *txn = l7;
5674
Willy Tarreaub6866442008-07-14 23:54:42 +02005675 if (!txn)
5676 return 0;
5677
Willy Tarreauc11416f2007-06-17 16:58:38 +02005678 if (txn->req.msg_state != HTTP_MSG_BODY)
5679 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005680
Willy Tarreauc11416f2007-06-17 16:58:38 +02005681 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5682 /* ensure the indexes are not affected */
5683 return 0;
5684
5685 return acl_fetch_hdr_val(px, l4, txn, txn->req.sol, expr, test);
5686}
5687
5688static int
5689acl_fetch_shdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5690 struct acl_expr *expr, struct acl_test *test)
5691{
5692 struct http_txn *txn = l7;
5693
Willy Tarreaub6866442008-07-14 23:54:42 +02005694 if (!txn)
5695 return 0;
5696
Willy Tarreauc11416f2007-06-17 16:58:38 +02005697 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5698 return 0;
5699
5700 return acl_fetch_hdr_val(px, l4, txn, txn->rsp.sol, expr, test);
5701}
5702
Willy Tarreau737b0c12007-06-10 21:28:46 +02005703/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at
5704 * the first '/' after the possible hostname, and ends before the possible '?'.
5705 */
5706static int
5707acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
5708 struct acl_expr *expr, struct acl_test *test)
5709{
5710 struct http_txn *txn = l7;
5711 char *ptr, *end;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005712
Willy Tarreaub6866442008-07-14 23:54:42 +02005713 if (!txn)
5714 return 0;
5715
Willy Tarreauc11416f2007-06-17 16:58:38 +02005716 if (txn->req.msg_state != HTTP_MSG_BODY)
5717 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005718
Willy Tarreauc11416f2007-06-17 16:58:38 +02005719 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5720 /* ensure the indexes are not affected */
5721 return 0;
5722
Willy Tarreau21d2af32008-02-14 20:25:24 +01005723 end = txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
5724 ptr = http_get_path(txn);
5725 if (!ptr)
Willy Tarreau737b0c12007-06-10 21:28:46 +02005726 return 0;
5727
5728 /* OK, we got the '/' ! */
5729 test->ptr = ptr;
5730
5731 while (ptr < end && *ptr != '?')
5732 ptr++;
5733
5734 test->len = ptr - test->ptr;
5735
5736 /* we do not need to set READ_ONLY because the data is in a buffer */
5737 test->flags = ACL_TEST_F_VOL_1ST;
5738 return 1;
5739}
5740
5741
Willy Tarreau8797c062007-05-07 00:55:35 +02005742
5743/************************************************************************/
5744/* All supported keywords must be declared here. */
5745/************************************************************************/
5746
5747/* Note: must not be declared <const> as its list will be overwritten */
5748static struct acl_kw_list acl_kws = {{ },{
5749 { "method", acl_parse_meth, acl_fetch_meth, acl_match_meth },
5750 { "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str },
5751 { "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str },
Willy Tarreauae8b7962007-06-09 23:10:04 +02005752 { "status", acl_parse_int, acl_fetch_stcode, acl_match_int },
Willy Tarreau8797c062007-05-07 00:55:35 +02005753
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005754 { "url", acl_parse_str, acl_fetch_url, acl_match_str },
5755 { "url_beg", acl_parse_str, acl_fetch_url, acl_match_beg },
5756 { "url_end", acl_parse_str, acl_fetch_url, acl_match_end },
5757 { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub },
5758 { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir },
5759 { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom },
5760 { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg },
5761 { "url_ip", acl_parse_ip, acl_fetch_url_ip, acl_match_ip },
5762 { "url_port", acl_parse_int, acl_fetch_url_port, acl_match_int },
Willy Tarreau8797c062007-05-07 00:55:35 +02005763
Willy Tarreauc11416f2007-06-17 16:58:38 +02005764 { "hdr", acl_parse_str, acl_fetch_chdr, acl_match_str },
5765 { "hdr_reg", acl_parse_reg, acl_fetch_chdr, acl_match_reg },
5766 { "hdr_beg", acl_parse_str, acl_fetch_chdr, acl_match_beg },
5767 { "hdr_end", acl_parse_str, acl_fetch_chdr, acl_match_end },
5768 { "hdr_sub", acl_parse_str, acl_fetch_chdr, acl_match_sub },
5769 { "hdr_dir", acl_parse_str, acl_fetch_chdr, acl_match_dir },
5770 { "hdr_dom", acl_parse_str, acl_fetch_chdr, acl_match_dom },
5771 { "hdr_cnt", acl_parse_int, acl_fetch_chdr_cnt,acl_match_int },
5772 { "hdr_val", acl_parse_int, acl_fetch_chdr_val,acl_match_int },
5773
5774 { "shdr", acl_parse_str, acl_fetch_shdr, acl_match_str },
5775 { "shdr_reg", acl_parse_reg, acl_fetch_shdr, acl_match_reg },
5776 { "shdr_beg", acl_parse_str, acl_fetch_shdr, acl_match_beg },
5777 { "shdr_end", acl_parse_str, acl_fetch_shdr, acl_match_end },
5778 { "shdr_sub", acl_parse_str, acl_fetch_shdr, acl_match_sub },
5779 { "shdr_dir", acl_parse_str, acl_fetch_shdr, acl_match_dir },
5780 { "shdr_dom", acl_parse_str, acl_fetch_shdr, acl_match_dom },
5781 { "shdr_cnt", acl_parse_int, acl_fetch_shdr_cnt,acl_match_int },
5782 { "shdr_val", acl_parse_int, acl_fetch_shdr_val,acl_match_int },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005783
5784 { "path", acl_parse_str, acl_fetch_path, acl_match_str },
5785 { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg },
5786 { "path_beg", acl_parse_str, acl_fetch_path, acl_match_beg },
5787 { "path_end", acl_parse_str, acl_fetch_path, acl_match_end },
5788 { "path_sub", acl_parse_str, acl_fetch_path, acl_match_sub },
5789 { "path_dir", acl_parse_str, acl_fetch_path, acl_match_dir },
5790 { "path_dom", acl_parse_str, acl_fetch_path, acl_match_dom },
5791
Willy Tarreauf3d25982007-05-08 22:45:09 +02005792 { NULL, NULL, NULL, NULL },
5793
5794#if 0
Willy Tarreau8797c062007-05-07 00:55:35 +02005795 { "line", acl_parse_str, acl_fetch_line, acl_match_str },
5796 { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg },
5797 { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg },
5798 { "line_end", acl_parse_str, acl_fetch_line, acl_match_end },
5799 { "line_sub", acl_parse_str, acl_fetch_line, acl_match_sub },
5800 { "line_dir", acl_parse_str, acl_fetch_line, acl_match_dir },
5801 { "line_dom", acl_parse_str, acl_fetch_line, acl_match_dom },
5802
Willy Tarreau8797c062007-05-07 00:55:35 +02005803 { "cook", acl_parse_str, acl_fetch_cook, acl_match_str },
5804 { "cook_reg", acl_parse_reg, acl_fetch_cook, acl_match_reg },
5805 { "cook_beg", acl_parse_str, acl_fetch_cook, acl_match_beg },
5806 { "cook_end", acl_parse_str, acl_fetch_cook, acl_match_end },
5807 { "cook_sub", acl_parse_str, acl_fetch_cook, acl_match_sub },
5808 { "cook_dir", acl_parse_str, acl_fetch_cook, acl_match_dir },
5809 { "cook_dom", acl_parse_str, acl_fetch_cook, acl_match_dom },
5810 { "cook_pst", acl_parse_none, acl_fetch_cook, acl_match_pst },
5811
5812 { "auth_user", acl_parse_str, acl_fetch_user, acl_match_str },
5813 { "auth_regex", acl_parse_reg, acl_fetch_user, acl_match_reg },
5814 { "auth_clear", acl_parse_str, acl_fetch_auth, acl_match_str },
5815 { "auth_md5", acl_parse_str, acl_fetch_auth, acl_match_md5 },
5816 { NULL, NULL, NULL, NULL },
5817#endif
5818}};
5819
5820
5821__attribute__((constructor))
5822static void __http_protocol_init(void)
5823{
5824 acl_register_keywords(&acl_kws);
5825}
5826
5827
Willy Tarreau58f10d72006-12-04 02:26:12 +01005828/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02005829 * Local variables:
5830 * c-indent-level: 8
5831 * c-basic-offset: 8
5832 * End:
5833 */