blob: 8a8bfffcab0d2fee50e948d4d575c67609c467f5 [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
Willy Tarreau6468d922008-08-03 19:15:35 +0200368static char *cli_stnames[6] = {"INS", "HDR", "DAT", "SHR", "SHW", "CLS" };
369static char *srv_stnames[8] = {"IDL", "ANA", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
Willy Tarreaubaaee002006-06-26 02:48:02 +0200370#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 Tarreau89edf5e2008-08-03 17:25:14 +0200548 buffer_shutw_done(t->req);
549 buffer_shutr_done(t->rep);
Willy Tarreau718f0ef2008-08-10 16:21:32 +0200550 t->rep->flags |= BF_MAY_FORWARD;
Willy Tarreau0f772532006-12-23 20:51:41 +0100551 if (status > 0 && msg) {
Willy Tarreau3bac9ff2007-03-18 17:31:28 +0100552 t->txn.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100553 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100554 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200555 }
556 if (!(t->flags & SN_ERR_MASK))
557 t->flags |= err;
558 if (!(t->flags & SN_FINST_MASK))
559 t->flags |= finst;
560}
561
Willy Tarreau80587432006-12-24 17:47:20 +0100562/* This function returns the appropriate error location for the given session
563 * and message.
564 */
565
566struct chunk *error_message(struct session *s, int msgnum)
567{
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200568 if (s->be->errmsg[msgnum].str)
569 return &s->be->errmsg[msgnum];
Willy Tarreau80587432006-12-24 17:47:20 +0100570 else if (s->fe->errmsg[msgnum].str)
571 return &s->fe->errmsg[msgnum];
572 else
573 return &http_err_chunks[msgnum];
574}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200575
Willy Tarreau53b6c742006-12-17 13:37:46 +0100576/*
577 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
578 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
579 */
580static http_meth_t find_http_meth(const char *str, const int len)
581{
582 unsigned char m;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100583 const struct http_method_desc *h;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100584
585 m = ((unsigned)*str - 'A');
586
587 if (m < 26) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100588 for (h = http_methods[m]; h->len > 0; h++) {
589 if (unlikely(h->len != len))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100590 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100591 if (likely(memcmp(str, h->text, h->len) == 0))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100592 return h->meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100593 };
594 return HTTP_METH_OTHER;
595 }
596 return HTTP_METH_NONE;
597
598}
599
Willy Tarreau21d2af32008-02-14 20:25:24 +0100600/* Parse the URI from the given transaction (which is assumed to be in request
601 * phase) and look for the "/" beginning the PATH. If not found, return NULL.
602 * It is returned otherwise.
603 */
604static char *
605http_get_path(struct http_txn *txn)
606{
607 char *ptr, *end;
608
609 ptr = txn->req.sol + txn->req.sl.rq.u;
610 end = ptr + txn->req.sl.rq.u_l;
611
612 if (ptr >= end)
613 return NULL;
614
615 /* RFC2616, par. 5.1.2 :
616 * Request-URI = "*" | absuri | abspath | authority
617 */
618
619 if (*ptr == '*')
620 return NULL;
621
622 if (isalpha((unsigned char)*ptr)) {
623 /* this is a scheme as described by RFC3986, par. 3.1 */
624 ptr++;
625 while (ptr < end &&
626 (isalnum((unsigned char)*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.'))
627 ptr++;
628 /* skip '://' */
629 if (ptr == end || *ptr++ != ':')
630 return NULL;
631 if (ptr == end || *ptr++ != '/')
632 return NULL;
633 if (ptr == end || *ptr++ != '/')
634 return NULL;
635 }
636 /* skip [user[:passwd]@]host[:[port]] */
637
638 while (ptr < end && *ptr != '/')
639 ptr++;
640
641 if (ptr == end)
642 return NULL;
643
644 /* OK, we got the '/' ! */
645 return ptr;
646}
647
Willy Tarreaubaaee002006-06-26 02:48:02 +0200648/* Processes the client and server jobs of a session task, then
649 * puts it back to the wait queue in a clean state, or
650 * cleans up its resources if it must be deleted. Returns
651 * the time the task accepts to wait, or TIME_ETERNITY for
652 * infinity.
653 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200654void process_session(struct task *t, int *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200655{
656 struct session *s = t->context;
657 int fsm_resync = 0;
658
659 do {
660 fsm_resync = 0;
661 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
662 fsm_resync |= process_cli(s);
663 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
664 fsm_resync |= process_srv(s);
665 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
666 } while (fsm_resync);
667
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200668 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100669
670 if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
671 session_process_counters(s);
672
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200673 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
674 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200675
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200676 t->expire = tick_first(tick_first(s->req->rex, s->req->wex),
677 tick_first(s->rep->rex, s->rep->wex));
678 t->expire = tick_first(t->expire, s->req->cex);
Willy Tarreau036fae02008-01-06 13:24:40 +0100679 if (s->cli_state == CL_STHEADERS)
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200680 t->expire = tick_first(t->expire, s->txn.exp);
Willy Tarreaub6866442008-07-14 23:54:42 +0200681 else if (s->cli_state == CL_STINSPECT)
682 t->expire = tick_first(t->expire, s->inspect_exp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200683
684 /* restore t to its place in the task list */
685 task_queue(t);
686
Willy Tarreaud825eef2007-05-12 22:35:00 +0200687 *next = t->expire;
688 return; /* nothing more to do */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200689 }
690
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100691 s->fe->feconn--;
692 if (s->flags & SN_BE_ASSIGNED)
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200693 s->be->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200694 actconn--;
695
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200696 if (unlikely((global.mode & MODE_DEBUG) &&
697 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200698 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100699 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200700 s->uniq_id, s->be->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100701 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200702 write(1, trash, len);
703 }
704
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200705 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100706 session_process_counters(s);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200707
708 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200709 if (s->logs.logwait &&
710 !(s->flags & SN_MONITOR) &&
Willy Tarreau42250582007-04-01 01:30:43 +0200711 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total)) {
712 if (s->fe->to_log & LW_REQ)
713 http_sess_log(s);
714 else
715 tcp_sess_log(s);
716 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200717
718 /* the task MUST not be in the run queue anymore */
719 task_delete(t);
720 session_free(s);
721 task_free(t);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200722 *next = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200723}
724
725
Willy Tarreau42250582007-04-01 01:30:43 +0200726extern const char sess_term_cond[8];
727extern const char sess_fin_state[8];
728extern const char *monthname[12];
729const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
730const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
731 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
732 unknown, Set-cookie Rewritten */
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200733struct pool_head *pool2_requri;
Willy Tarreau086b3b42007-05-13 21:45:51 +0200734struct pool_head *pool2_capture;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100735
Willy Tarreau42250582007-04-01 01:30:43 +0200736/*
737 * send a log for the session when we have enough info about it.
738 * Will not log if the frontend has no log defined.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100739 */
Willy Tarreau42250582007-04-01 01:30:43 +0200740static void http_sess_log(struct session *s)
741{
742 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
743 struct proxy *fe = s->fe;
744 struct proxy *be = s->be;
745 struct proxy *prx_log;
746 struct http_txn *txn = &s->txn;
747 int tolog;
748 char *uri, *h;
749 char *svid;
Willy Tarreaufe944602007-10-25 10:34:16 +0200750 struct tm tm;
Willy Tarreau42250582007-04-01 01:30:43 +0200751 static char tmpline[MAX_SYSLOG_LEN];
Willy Tarreau70089872008-06-13 21:12:51 +0200752 int t_request;
Willy Tarreau42250582007-04-01 01:30:43 +0200753 int hdr;
754
755 if (fe->logfac1 < 0 && fe->logfac2 < 0)
756 return;
757 prx_log = fe;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100758
Willy Tarreau42250582007-04-01 01:30:43 +0200759 if (s->cli_addr.ss_family == AF_INET)
760 inet_ntop(AF_INET,
761 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
762 pn, sizeof(pn));
763 else
764 inet_ntop(AF_INET6,
765 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
766 pn, sizeof(pn));
767
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200768 get_localtime(s->logs.accept_date.tv_sec, &tm);
Willy Tarreau42250582007-04-01 01:30:43 +0200769
770 /* FIXME: let's limit ourselves to frontend logging for now. */
771 tolog = fe->to_log;
772
773 h = tmpline;
774 if (fe->to_log & LW_REQHDR &&
775 txn->req.cap &&
776 (h < tmpline + sizeof(tmpline) - 10)) {
777 *(h++) = ' ';
778 *(h++) = '{';
779 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
780 if (hdr)
781 *(h++) = '|';
782 if (txn->req.cap[hdr] != NULL)
783 h = encode_string(h, tmpline + sizeof(tmpline) - 7,
784 '#', hdr_encode_map, txn->req.cap[hdr]);
785 }
786 *(h++) = '}';
787 }
788
789 if (fe->to_log & LW_RSPHDR &&
790 txn->rsp.cap &&
791 (h < tmpline + sizeof(tmpline) - 7)) {
792 *(h++) = ' ';
793 *(h++) = '{';
794 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
795 if (hdr)
796 *(h++) = '|';
797 if (txn->rsp.cap[hdr] != NULL)
798 h = encode_string(h, tmpline + sizeof(tmpline) - 4,
799 '#', hdr_encode_map, txn->rsp.cap[hdr]);
800 }
801 *(h++) = '}';
802 }
803
804 if (h < tmpline + sizeof(tmpline) - 4) {
805 *(h++) = ' ';
806 *(h++) = '"';
807 uri = txn->uri ? txn->uri : "<BADREQ>";
808 h = encode_string(h, tmpline + sizeof(tmpline) - 1,
809 '#', url_encode_map, uri);
810 *(h++) = '"';
811 }
812 *h = '\0';
813
814 svid = (tolog & LW_SVID) ?
815 (s->data_source != DATA_SRC_STATS) ?
816 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
817
Willy Tarreau70089872008-06-13 21:12:51 +0200818 t_request = -1;
819 if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
820 t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
821
Willy Tarreau42250582007-04-01 01:30:43 +0200822 send_log(prx_log, LOG_INFO,
823 "%s:%d [%02d/%s/%04d:%02d:%02d:%02d.%03d]"
824 " %s %s/%s %d/%d/%d/%d/%s%d %d %s%lld"
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100825 " %s %s %c%c%c%c %d/%d/%d/%d/%s%u %d/%d%s\n",
Willy Tarreau42250582007-04-01 01:30:43 +0200826 pn,
827 (s->cli_addr.ss_family == AF_INET) ?
828 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
829 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
Willy Tarreaufe944602007-10-25 10:34:16 +0200830 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200831 tm.tm_hour, tm.tm_min, tm.tm_sec, s->logs.accept_date.tv_usec/1000,
Willy Tarreau42250582007-04-01 01:30:43 +0200832 fe->id, be->id, svid,
Willy Tarreau70089872008-06-13 21:12:51 +0200833 t_request,
834 (s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1,
Willy Tarreau42250582007-04-01 01:30:43 +0200835 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
836 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
837 (tolog & LW_BYTES) ? "" : "+", s->logs.t_close,
838 txn->status,
Willy Tarreau8b3977f2008-01-18 11:16:32 +0100839 (tolog & LW_BYTES) ? "" : "+", s->logs.bytes_out,
Willy Tarreau42250582007-04-01 01:30:43 +0200840 txn->cli_cookie ? txn->cli_cookie : "-",
841 txn->srv_cookie ? txn->srv_cookie : "-",
842 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
843 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
844 (be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-',
845 (be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-',
846 actconn, fe->feconn, be->beconn, s->srv ? s->srv->cur_sess : 0,
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100847 (s->flags & SN_REDISP)?"+":"",
848 (s->conn_retries>0)?(be->conn_retries - s->conn_retries):be->conn_retries,
Willy Tarreau42250582007-04-01 01:30:43 +0200849 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
850
851 s->logs.logwait = 0;
852}
853
Willy Tarreau117f59e2007-03-04 18:17:17 +0100854
855/*
856 * Capture headers from message starting at <som> according to header list
857 * <cap_hdr>, and fill the <idx> structure appropriately.
858 */
859void capture_headers(char *som, struct hdr_idx *idx,
860 char **cap, struct cap_hdr *cap_hdr)
861{
862 char *eol, *sol, *col, *sov;
863 int cur_idx;
864 struct cap_hdr *h;
865 int len;
866
867 sol = som + hdr_idx_first_pos(idx);
868 cur_idx = hdr_idx_first_idx(idx);
869
870 while (cur_idx) {
871 eol = sol + idx->v[cur_idx].len;
872
873 col = sol;
874 while (col < eol && *col != ':')
875 col++;
876
877 sov = col + 1;
878 while (sov < eol && http_is_lws[(unsigned char)*sov])
879 sov++;
880
881 for (h = cap_hdr; h; h = h->next) {
882 if ((h->namelen == col - sol) &&
883 (strncasecmp(sol, h->name, h->namelen) == 0)) {
884 if (cap[h->index] == NULL)
885 cap[h->index] =
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200886 pool_alloc2(h->pool);
Willy Tarreau117f59e2007-03-04 18:17:17 +0100887
888 if (cap[h->index] == NULL) {
889 Alert("HTTP capture : out of memory.\n");
890 continue;
891 }
892
893 len = eol - sov;
894 if (len > h->len)
895 len = h->len;
896
897 memcpy(cap[h->index], sov, len);
898 cap[h->index][len]=0;
899 }
900 }
901 sol = eol + idx->v[cur_idx].cr + 1;
902 cur_idx = idx->v[cur_idx].next;
903 }
904}
905
906
Willy Tarreau42250582007-04-01 01:30:43 +0200907/* either we find an LF at <ptr> or we jump to <bad>.
908 */
909#define EXPECT_LF_HERE(ptr, bad) do { if (unlikely(*(ptr) != '\n')) goto bad; } while (0)
910
911/* plays with variables <ptr>, <end> and <state>. Jumps to <good> if OK,
912 * otherwise to <http_msg_ood> with <state> set to <st>.
913 */
914#define EAT_AND_JUMP_OR_RETURN(good, st) do { \
915 ptr++; \
916 if (likely(ptr < end)) \
917 goto good; \
918 else { \
919 state = (st); \
920 goto http_msg_ood; \
921 } \
922 } while (0)
923
924
Willy Tarreaubaaee002006-06-26 02:48:02 +0200925/*
Willy Tarreaua15645d2007-03-18 16:22:39 +0100926 * This function parses a status line between <ptr> and <end>, starting with
Willy Tarreau8973c702007-01-21 23:58:29 +0100927 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
928 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
929 * will give undefined results.
930 * Note that it is upon the caller's responsibility to ensure that ptr < end,
931 * and that msg->sol points to the beginning of the response.
932 * If a complete line is found (which implies that at least one CR or LF is
933 * found before <end>, the updated <ptr> is returned, otherwise NULL is
934 * returned indicating an incomplete line (which does not mean that parts have
935 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
936 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
937 * upon next call.
938 *
Willy Tarreau9cdde232007-05-02 20:58:19 +0200939 * This function was intentionally designed to be called from
Willy Tarreau8973c702007-01-21 23:58:29 +0100940 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
941 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +0200942 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreau8973c702007-01-21 23:58:29 +0100943 */
Willy Tarreaue69eada2008-01-27 00:34:10 +0100944const char *http_parse_stsline(struct http_msg *msg, const char *msg_buf,
945 unsigned int state, const char *ptr, const char *end,
946 char **ret_ptr, unsigned int *ret_state)
Willy Tarreau8973c702007-01-21 23:58:29 +0100947{
948 __label__
949 http_msg_rpver,
950 http_msg_rpver_sp,
951 http_msg_rpcode,
952 http_msg_rpcode_sp,
953 http_msg_rpreason,
954 http_msg_rpline_eol,
955 http_msg_ood, /* out of data */
956 http_msg_invalid;
957
958 switch (state) {
959 http_msg_rpver:
960 case HTTP_MSG_RPVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100961 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8973c702007-01-21 23:58:29 +0100962 EAT_AND_JUMP_OR_RETURN(http_msg_rpver, HTTP_MSG_RPVER);
963
964 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +0100965 msg->sl.st.v_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +0100966 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
967 }
968 goto http_msg_invalid;
969
970 http_msg_rpver_sp:
971 case HTTP_MSG_RPVER_SP:
972 if (likely(!HTTP_IS_LWS(*ptr))) {
973 msg->sl.st.c = ptr - msg_buf;
974 goto http_msg_rpcode;
975 }
976 if (likely(HTTP_IS_SPHT(*ptr)))
977 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
978 /* so it's a CR/LF, this is invalid */
979 goto http_msg_invalid;
980
981 http_msg_rpcode:
982 case HTTP_MSG_RPCODE:
983 if (likely(!HTTP_IS_LWS(*ptr)))
984 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode, HTTP_MSG_RPCODE);
985
986 if (likely(HTTP_IS_SPHT(*ptr))) {
987 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
988 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
989 }
990
991 /* so it's a CR/LF, so there is no reason phrase */
992 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
993 http_msg_rsp_reason:
994 /* FIXME: should we support HTTP responses without any reason phrase ? */
995 msg->sl.st.r = ptr - msg_buf;
996 msg->sl.st.r_l = 0;
997 goto http_msg_rpline_eol;
998
999 http_msg_rpcode_sp:
1000 case HTTP_MSG_RPCODE_SP:
1001 if (likely(!HTTP_IS_LWS(*ptr))) {
1002 msg->sl.st.r = ptr - msg_buf;
1003 goto http_msg_rpreason;
1004 }
1005 if (likely(HTTP_IS_SPHT(*ptr)))
1006 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1007 /* so it's a CR/LF, so there is no reason phrase */
1008 goto http_msg_rsp_reason;
1009
1010 http_msg_rpreason:
1011 case HTTP_MSG_RPREASON:
1012 if (likely(!HTTP_IS_CRLF(*ptr)))
1013 EAT_AND_JUMP_OR_RETURN(http_msg_rpreason, HTTP_MSG_RPREASON);
1014 msg->sl.st.r_l = (ptr - msg_buf) - msg->sl.st.r;
1015 http_msg_rpline_eol:
1016 /* We have seen the end of line. Note that we do not
1017 * necessarily have the \n yet, but at least we know that we
1018 * have EITHER \r OR \n, otherwise the response would not be
1019 * complete. We can then record the response length and return
1020 * to the caller which will be able to register it.
1021 */
1022 msg->sl.st.l = ptr - msg->sol;
1023 return ptr;
1024
1025#ifdef DEBUG_FULL
1026 default:
1027 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1028 exit(1);
1029#endif
1030 }
1031
1032 http_msg_ood:
1033 /* out of data */
1034 if (ret_state)
1035 *ret_state = state;
1036 if (ret_ptr)
1037 *ret_ptr = (char *)ptr;
1038 return NULL;
1039
1040 http_msg_invalid:
1041 /* invalid message */
1042 if (ret_state)
1043 *ret_state = HTTP_MSG_ERROR;
1044 return NULL;
1045}
1046
1047
1048/*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001049 * This function parses a request line between <ptr> and <end>, starting with
1050 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
1051 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
1052 * will give undefined results.
1053 * Note that it is upon the caller's responsibility to ensure that ptr < end,
1054 * and that msg->sol points to the beginning of the request.
1055 * If a complete line is found (which implies that at least one CR or LF is
1056 * found before <end>, the updated <ptr> is returned, otherwise NULL is
1057 * returned indicating an incomplete line (which does not mean that parts have
1058 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
1059 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
1060 * upon next call.
1061 *
Willy Tarreau9cdde232007-05-02 20:58:19 +02001062 * This function was intentionally designed to be called from
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001063 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
1064 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +02001065 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001066 */
Willy Tarreaue69eada2008-01-27 00:34:10 +01001067const char *http_parse_reqline(struct http_msg *msg, const char *msg_buf,
1068 unsigned int state, const char *ptr, const char *end,
1069 char **ret_ptr, unsigned int *ret_state)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001070{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001071 __label__
1072 http_msg_rqmeth,
1073 http_msg_rqmeth_sp,
1074 http_msg_rquri,
1075 http_msg_rquri_sp,
1076 http_msg_rqver,
1077 http_msg_rqline_eol,
1078 http_msg_ood, /* out of data */
1079 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001080
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001081 switch (state) {
1082 http_msg_rqmeth:
1083 case HTTP_MSG_RQMETH:
1084 if (likely(HTTP_IS_TOKEN(*ptr)))
1085 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth, HTTP_MSG_RQMETH);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001086
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001087 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001088 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001089 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1090 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001091
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001092 if (likely(HTTP_IS_CRLF(*ptr))) {
1093 /* HTTP 0.9 request */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001094 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001095 http_msg_req09_uri:
1096 msg->sl.rq.u = ptr - msg_buf;
1097 http_msg_req09_uri_e:
1098 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1099 http_msg_req09_ver:
1100 msg->sl.rq.v = ptr - msg_buf;
1101 msg->sl.rq.v_l = 0;
1102 goto http_msg_rqline_eol;
1103 }
1104 goto http_msg_invalid;
1105
1106 http_msg_rqmeth_sp:
1107 case HTTP_MSG_RQMETH_SP:
1108 if (likely(!HTTP_IS_LWS(*ptr))) {
1109 msg->sl.rq.u = ptr - msg_buf;
1110 goto http_msg_rquri;
1111 }
1112 if (likely(HTTP_IS_SPHT(*ptr)))
1113 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1114 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1115 goto http_msg_req09_uri;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001116
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001117 http_msg_rquri:
1118 case HTTP_MSG_RQURI:
1119 if (likely(!HTTP_IS_LWS(*ptr)))
1120 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001121
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001122 if (likely(HTTP_IS_SPHT(*ptr))) {
1123 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1124 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1125 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001126
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001127 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1128 goto http_msg_req09_uri_e;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001129
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001130 http_msg_rquri_sp:
1131 case HTTP_MSG_RQURI_SP:
1132 if (likely(!HTTP_IS_LWS(*ptr))) {
1133 msg->sl.rq.v = ptr - msg_buf;
1134 goto http_msg_rqver;
1135 }
1136 if (likely(HTTP_IS_SPHT(*ptr)))
1137 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1138 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1139 goto http_msg_req09_ver;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001140
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001141 http_msg_rqver:
1142 case HTTP_MSG_RQVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001143 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001144 EAT_AND_JUMP_OR_RETURN(http_msg_rqver, HTTP_MSG_RQVER);
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001145
1146 if (likely(HTTP_IS_CRLF(*ptr))) {
1147 msg->sl.rq.v_l = (ptr - msg_buf) - msg->sl.rq.v;
1148 http_msg_rqline_eol:
1149 /* We have seen the end of line. Note that we do not
1150 * necessarily have the \n yet, but at least we know that we
1151 * have EITHER \r OR \n, otherwise the request would not be
1152 * complete. We can then record the request length and return
1153 * to the caller which will be able to register it.
1154 */
1155 msg->sl.rq.l = ptr - msg->sol;
1156 return ptr;
1157 }
1158
1159 /* neither an HTTP_VER token nor a CRLF */
1160 goto http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001161
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001162#ifdef DEBUG_FULL
1163 default:
1164 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1165 exit(1);
1166#endif
1167 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001168
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001169 http_msg_ood:
1170 /* out of data */
1171 if (ret_state)
1172 *ret_state = state;
1173 if (ret_ptr)
1174 *ret_ptr = (char *)ptr;
1175 return NULL;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001176
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001177 http_msg_invalid:
1178 /* invalid message */
1179 if (ret_state)
1180 *ret_state = HTTP_MSG_ERROR;
1181 return NULL;
1182}
Willy Tarreau58f10d72006-12-04 02:26:12 +01001183
1184
Willy Tarreau8973c702007-01-21 23:58:29 +01001185/*
1186 * This function parses an HTTP message, either a request or a response,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001187 * depending on the initial msg->msg_state. It can be preempted everywhere
Willy Tarreau8973c702007-01-21 23:58:29 +01001188 * when data are missing and recalled at the exact same location with no
1189 * information loss. The header index is re-initialized when switching from
Willy Tarreau9cdde232007-05-02 20:58:19 +02001190 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH. It modifies msg->sol among other
1191 * fields.
Willy Tarreau8973c702007-01-21 23:58:29 +01001192 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001193void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx *idx)
1194{
1195 __label__
1196 http_msg_rqbefore,
1197 http_msg_rqbefore_cr,
1198 http_msg_rqmeth,
1199 http_msg_rqline_end,
1200 http_msg_hdr_first,
1201 http_msg_hdr_name,
1202 http_msg_hdr_l1_sp,
1203 http_msg_hdr_l1_lf,
1204 http_msg_hdr_l1_lws,
1205 http_msg_hdr_val,
1206 http_msg_hdr_l2_lf,
1207 http_msg_hdr_l2_lws,
1208 http_msg_complete_header,
1209 http_msg_last_lf,
1210 http_msg_ood, /* out of data */
1211 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001212
Willy Tarreaue69eada2008-01-27 00:34:10 +01001213 unsigned int state; /* updated only when leaving the FSM */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001214 register char *ptr, *end; /* request pointers, to avoid dereferences */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001215
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001216 state = msg->msg_state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001217 ptr = buf->lr;
1218 end = buf->r;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001219
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001220 if (unlikely(ptr >= end))
1221 goto http_msg_ood;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001222
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001223 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +01001224 /*
1225 * First, states that are specific to the response only.
1226 * We check them first so that request and headers are
1227 * closer to each other (accessed more often).
1228 */
1229 http_msg_rpbefore:
1230 case HTTP_MSG_RPBEFORE:
1231 if (likely(HTTP_IS_TOKEN(*ptr))) {
1232 if (likely(ptr == buf->data)) {
1233 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001234 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001235 } else {
1236#if PARSE_PRESERVE_EMPTY_LINES
1237 /* only skip empty leading lines, don't remove them */
1238 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001239 msg->som = ptr - buf->data;
Willy Tarreau8973c702007-01-21 23:58:29 +01001240#else
1241 /* Remove empty leading lines, as recommended by
1242 * RFC2616. This takes a lot of time because we
1243 * must move all the buffer backwards, but this
1244 * is rarely needed. The method above will be
1245 * cleaner when we'll be able to start sending
1246 * the request from any place in the buffer.
1247 */
1248 buf->lr = ptr;
1249 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001250 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001251 msg->sol = buf->data;
1252 ptr = buf->data;
1253 end = buf->r;
1254#endif
1255 }
1256 hdr_idx_init(idx);
1257 state = HTTP_MSG_RPVER;
1258 goto http_msg_rpver;
1259 }
1260
1261 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1262 goto http_msg_invalid;
1263
1264 if (unlikely(*ptr == '\n'))
1265 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1266 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore_cr, HTTP_MSG_RPBEFORE_CR);
1267 /* stop here */
1268
1269 http_msg_rpbefore_cr:
1270 case HTTP_MSG_RPBEFORE_CR:
1271 EXPECT_LF_HERE(ptr, http_msg_invalid);
1272 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1273 /* stop here */
1274
1275 http_msg_rpver:
1276 case HTTP_MSG_RPVER:
1277 case HTTP_MSG_RPVER_SP:
1278 case HTTP_MSG_RPCODE:
1279 case HTTP_MSG_RPCODE_SP:
1280 case HTTP_MSG_RPREASON:
Willy Tarreaua15645d2007-03-18 16:22:39 +01001281 ptr = (char *)http_parse_stsline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001282 &buf->lr, &msg->msg_state);
Willy Tarreau8973c702007-01-21 23:58:29 +01001283 if (unlikely(!ptr))
1284 return;
1285
1286 /* we have a full response and we know that we have either a CR
1287 * or an LF at <ptr>.
1288 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001289 //fprintf(stderr,"som=%d rq.l=%d *ptr=0x%02x\n", msg->som, msg->sl.st.l, *ptr);
Willy Tarreau8973c702007-01-21 23:58:29 +01001290 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
1291
1292 msg->sol = ptr;
1293 if (likely(*ptr == '\r'))
1294 EAT_AND_JUMP_OR_RETURN(http_msg_rpline_end, HTTP_MSG_RPLINE_END);
1295 goto http_msg_rpline_end;
1296
1297 http_msg_rpline_end:
1298 case HTTP_MSG_RPLINE_END:
1299 /* msg->sol must point to the first of CR or LF. */
1300 EXPECT_LF_HERE(ptr, http_msg_invalid);
1301 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
1302 /* stop here */
1303
1304 /*
1305 * Second, states that are specific to the request only
1306 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001307 http_msg_rqbefore:
1308 case HTTP_MSG_RQBEFORE:
1309 if (likely(HTTP_IS_TOKEN(*ptr))) {
1310 if (likely(ptr == buf->data)) {
1311 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001312 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001313 } else {
1314#if PARSE_PRESERVE_EMPTY_LINES
1315 /* only skip empty leading lines, don't remove them */
1316 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001317 msg->som = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001318#else
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001319 /* Remove empty leading lines, as recommended by
1320 * RFC2616. This takes a lot of time because we
1321 * must move all the buffer backwards, but this
1322 * is rarely needed. The method above will be
1323 * cleaner when we'll be able to start sending
1324 * the request from any place in the buffer.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001325 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001326 buf->lr = ptr;
1327 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001328 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001329 msg->sol = buf->data;
1330 ptr = buf->data;
1331 end = buf->r;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001332#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001333 }
Willy Tarreauf0d058e2007-01-25 12:03:42 +01001334 /* we will need this when keep-alive will be supported
1335 hdr_idx_init(idx);
1336 */
Willy Tarreau8973c702007-01-21 23:58:29 +01001337 state = HTTP_MSG_RQMETH;
1338 goto http_msg_rqmeth;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001339 }
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001340
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001341 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1342 goto http_msg_invalid;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001343
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001344 if (unlikely(*ptr == '\n'))
1345 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
1346 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore_cr, HTTP_MSG_RQBEFORE_CR);
Willy Tarreau8973c702007-01-21 23:58:29 +01001347 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001348
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001349 http_msg_rqbefore_cr:
1350 case HTTP_MSG_RQBEFORE_CR:
1351 EXPECT_LF_HERE(ptr, http_msg_invalid);
1352 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
Willy Tarreau8973c702007-01-21 23:58:29 +01001353 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001354
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001355 http_msg_rqmeth:
1356 case HTTP_MSG_RQMETH:
1357 case HTTP_MSG_RQMETH_SP:
1358 case HTTP_MSG_RQURI:
1359 case HTTP_MSG_RQURI_SP:
1360 case HTTP_MSG_RQVER:
1361 ptr = (char *)http_parse_reqline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001362 &buf->lr, &msg->msg_state);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001363 if (unlikely(!ptr))
1364 return;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001365
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001366 /* we have a full request and we know that we have either a CR
1367 * or an LF at <ptr>.
1368 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001369 //fprintf(stderr,"som=%d rq.l=%d *ptr=0x%02x\n", msg->som, msg->sl.rq.l, *ptr);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001370 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001371
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001372 msg->sol = ptr;
1373 if (likely(*ptr == '\r'))
1374 EAT_AND_JUMP_OR_RETURN(http_msg_rqline_end, HTTP_MSG_RQLINE_END);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001375 goto http_msg_rqline_end;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001376
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001377 http_msg_rqline_end:
1378 case HTTP_MSG_RQLINE_END:
1379 /* check for HTTP/0.9 request : no version information available.
1380 * msg->sol must point to the first of CR or LF.
1381 */
1382 if (unlikely(msg->sl.rq.v_l == 0))
1383 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001384
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001385 EXPECT_LF_HERE(ptr, http_msg_invalid);
1386 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
Willy Tarreau8973c702007-01-21 23:58:29 +01001387 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001388
Willy Tarreau8973c702007-01-21 23:58:29 +01001389 /*
1390 * Common states below
1391 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001392 http_msg_hdr_first:
1393 case HTTP_MSG_HDR_FIRST:
1394 msg->sol = ptr;
1395 if (likely(!HTTP_IS_CRLF(*ptr))) {
1396 goto http_msg_hdr_name;
1397 }
1398
1399 if (likely(*ptr == '\r'))
1400 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1401 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001402
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001403 http_msg_hdr_name:
1404 case HTTP_MSG_HDR_NAME:
1405 /* assumes msg->sol points to the first char */
1406 if (likely(HTTP_IS_TOKEN(*ptr)))
1407 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001408
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001409 if (likely(*ptr == ':')) {
1410 msg->col = ptr - buf->data;
1411 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
1412 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001413
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001414 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001415
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001416 http_msg_hdr_l1_sp:
1417 case HTTP_MSG_HDR_L1_SP:
1418 /* assumes msg->sol points to the first char and msg->col to the colon */
1419 if (likely(HTTP_IS_SPHT(*ptr)))
1420 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001421
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001422 /* header value can be basically anything except CR/LF */
1423 msg->sov = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001424
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001425 if (likely(!HTTP_IS_CRLF(*ptr))) {
1426 goto http_msg_hdr_val;
1427 }
1428
1429 if (likely(*ptr == '\r'))
1430 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lf, HTTP_MSG_HDR_L1_LF);
1431 goto http_msg_hdr_l1_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001432
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001433 http_msg_hdr_l1_lf:
1434 case HTTP_MSG_HDR_L1_LF:
1435 EXPECT_LF_HERE(ptr, http_msg_invalid);
1436 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lws, HTTP_MSG_HDR_L1_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001437
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001438 http_msg_hdr_l1_lws:
1439 case HTTP_MSG_HDR_L1_LWS:
1440 if (likely(HTTP_IS_SPHT(*ptr))) {
1441 /* replace HT,CR,LF with spaces */
1442 for (; buf->data+msg->sov < ptr; msg->sov++)
1443 buf->data[msg->sov] = ' ';
1444 goto http_msg_hdr_l1_sp;
1445 }
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001446 /* we had a header consisting only in spaces ! */
1447 msg->eol = buf->data + msg->sov;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001448 goto http_msg_complete_header;
1449
1450 http_msg_hdr_val:
1451 case HTTP_MSG_HDR_VAL:
1452 /* assumes msg->sol points to the first char, msg->col to the
1453 * colon, and msg->sov points to the first character of the
1454 * value.
1455 */
1456 if (likely(!HTTP_IS_CRLF(*ptr)))
1457 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001458
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001459 msg->eol = ptr;
1460 /* Note: we could also copy eol into ->eoh so that we have the
1461 * real header end in case it ends with lots of LWS, but is this
1462 * really needed ?
1463 */
1464 if (likely(*ptr == '\r'))
1465 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1466 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001467
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001468 http_msg_hdr_l2_lf:
1469 case HTTP_MSG_HDR_L2_LF:
1470 EXPECT_LF_HERE(ptr, http_msg_invalid);
1471 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001472
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001473 http_msg_hdr_l2_lws:
1474 case HTTP_MSG_HDR_L2_LWS:
1475 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1476 /* LWS: replace HT,CR,LF with spaces */
1477 for (; msg->eol < ptr; msg->eol++)
1478 *msg->eol = ' ';
1479 goto http_msg_hdr_val;
1480 }
1481 http_msg_complete_header:
1482 /*
1483 * It was a new header, so the last one is finished.
1484 * Assumes msg->sol points to the first char, msg->col to the
1485 * colon, msg->sov points to the first character of the value
1486 * and msg->eol to the first CR or LF so we know how the line
1487 * ends. We insert last header into the index.
1488 */
1489 /*
1490 fprintf(stderr,"registering %-2d bytes : ", msg->eol - msg->sol);
1491 write(2, msg->sol, msg->eol-msg->sol);
1492 fprintf(stderr,"\n");
1493 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001494
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001495 if (unlikely(hdr_idx_add(msg->eol - msg->sol, *msg->eol == '\r',
1496 idx, idx->tail) < 0))
1497 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001498
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001499 msg->sol = ptr;
1500 if (likely(!HTTP_IS_CRLF(*ptr))) {
1501 goto http_msg_hdr_name;
1502 }
1503
1504 if (likely(*ptr == '\r'))
1505 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1506 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001507
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001508 http_msg_last_lf:
1509 case HTTP_MSG_LAST_LF:
1510 /* Assumes msg->sol points to the first of either CR or LF */
1511 EXPECT_LF_HERE(ptr, http_msg_invalid);
1512 ptr++;
1513 buf->lr = ptr;
1514 msg->eoh = msg->sol - buf->data;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001515 msg->msg_state = HTTP_MSG_BODY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001516 return;
1517#ifdef DEBUG_FULL
1518 default:
1519 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1520 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001521#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001522 }
1523 http_msg_ood:
1524 /* out of data */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001525 msg->msg_state = state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001526 buf->lr = ptr;
1527 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001528
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001529 http_msg_invalid:
1530 /* invalid message */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001531 msg->msg_state = HTTP_MSG_ERROR;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001532 return;
1533}
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001534
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001535/*
1536 * manages the client FSM and its socket. BTW, it also tries to handle the
1537 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1538 * 0 else.
1539 */
1540int process_cli(struct session *t)
1541{
1542 int s = t->srv_state;
1543 int c = t->cli_state;
1544 struct buffer *req = t->req;
1545 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001546
Willy Tarreau6468d922008-08-03 19:15:35 +02001547 DPRINTF(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%u,%u\n",
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001548 cli_stnames[c], srv_stnames[s],
Willy Tarreauf161a342007-04-08 16:59:42 +02001549 EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
Willy Tarreau6468d922008-08-03 19:15:35 +02001550 req->rex, rep->wex);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001551
Willy Tarreaub6866442008-07-14 23:54:42 +02001552 if (c == CL_STINSPECT) {
1553 struct tcp_rule *rule;
1554 int partial;
1555
1556 /* We will abort if we encounter a read error. In theory,
1557 * we should not abort if we get a close, it might be
1558 * valid, also very unlikely. FIXME: we'll abort for now,
1559 * this will be easier to change later.
1560 */
1561 if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1562 t->inspect_exp = TICK_ETERNITY;
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001563 buffer_shutr_done(req);
1564 buffer_shutw_done(rep);
Willy Tarreaub6866442008-07-14 23:54:42 +02001565 fd_delete(t->cli_fd);
1566 t->cli_state = CL_STCLOSE;
1567 t->fe->failed_req++;
1568 if (!(t->flags & SN_ERR_MASK))
1569 t->flags |= SN_ERR_CLICL;
1570 if (!(t->flags & SN_FINST_MASK))
1571 t->flags |= SN_FINST_R;
1572 return 1;
1573 }
1574
1575 /* Abort if client read timeout has expired */
1576 else if (unlikely(tick_is_expired(req->rex, now_ms))) {
1577 t->inspect_exp = TICK_ETERNITY;
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001578 buffer_shutr_done(req);
1579 buffer_shutw_done(rep);
Willy Tarreaub6866442008-07-14 23:54:42 +02001580 fd_delete(t->cli_fd);
1581 t->cli_state = CL_STCLOSE;
1582 t->fe->failed_req++;
1583 if (!(t->flags & SN_ERR_MASK))
1584 t->flags |= SN_ERR_CLITO;
1585 if (!(t->flags & SN_FINST_MASK))
1586 t->flags |= SN_FINST_R;
1587 return 1;
1588 }
1589
1590 /* We don't know whether we have enough data, so must proceed
1591 * this way :
1592 * - iterate through all rules in their declaration order
1593 * - if one rule returns MISS, it means the inspect delay is
1594 * not over yet, then return immediately, otherwise consider
1595 * it as a non-match.
1596 * - if one rule returns OK, then return OK
1597 * - if one rule returns KO, then return KO
1598 */
1599
1600 if (tick_is_expired(t->inspect_exp, now_ms))
1601 partial = 0;
1602 else
1603 partial = ACL_PARTIAL;
1604
1605 list_for_each_entry(rule, &t->fe->tcp_req.inspect_rules, list) {
1606 int ret = ACL_PAT_PASS;
1607
1608 if (rule->cond) {
1609 ret = acl_exec_cond(rule->cond, t->fe, t, NULL, ACL_DIR_REQ | partial);
1610 if (ret == ACL_PAT_MISS) {
1611 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
1612 return 0;
1613 }
1614 ret = acl_pass(ret);
1615 if (rule->cond->pol == ACL_COND_UNLESS)
1616 ret = !ret;
1617 }
1618
1619 if (ret) {
1620 /* we have a matching rule. */
1621 if (rule->action == TCP_ACT_REJECT) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001622 buffer_shutr_done(req);
1623 buffer_shutw_done(rep);
Willy Tarreaub6866442008-07-14 23:54:42 +02001624 fd_delete(t->cli_fd);
1625 t->cli_state = CL_STCLOSE;
1626 t->fe->failed_req++;
1627 if (!(t->flags & SN_ERR_MASK))
1628 t->flags |= SN_ERR_PRXCOND;
1629 if (!(t->flags & SN_FINST_MASK))
1630 t->flags |= SN_FINST_R;
1631 t->inspect_exp = TICK_ETERNITY;
1632 return 1;
1633 }
1634 /* otherwise accept */
1635 break;
1636 }
1637 }
1638
1639 /* if we get there, it means we have no rule which matches, so
1640 * we apply the default accept.
1641 */
1642 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
1643 if (t->fe->mode == PR_MODE_HTTP) {
1644 t->cli_state = CL_STHEADERS;
1645 t->txn.exp = tick_add_ifset(now_ms, t->fe->timeout.httpreq);
1646 } else {
1647 t->cli_state = CL_STDATA;
Willy Tarreau718f0ef2008-08-10 16:21:32 +02001648 req->flags |= BF_MAY_CONNECT | BF_MAY_FORWARD;
Willy Tarreaub6866442008-07-14 23:54:42 +02001649 }
1650 t->inspect_exp = TICK_ETERNITY;
1651 return 1;
1652 }
1653 else if (c == CL_STHEADERS) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001654 /*
1655 * Now parse the partial (or complete) lines.
1656 * We will check the request syntax, and also join multi-line
1657 * headers. An index of all the lines will be elaborated while
1658 * parsing.
1659 *
Willy Tarreau8973c702007-01-21 23:58:29 +01001660 * For the parsing, we use a 28 states FSM.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001661 *
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001662 * Here is the information we currently have :
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001663 * req->data + req->som = beginning of request
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001664 * req->data + req->eoh = end of processed headers / start of current one
1665 * req->data + req->eol = end of current header or line (LF or CRLF)
1666 * req->lr = first non-visited byte
1667 * req->r = end of data
1668 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001669
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001670 int cur_idx;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001671 struct http_txn *txn = &t->txn;
1672 struct http_msg *msg = &txn->req;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001673 struct proxy *cur_proxy;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001674
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001675 if (likely(req->lr < req->r))
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001676 http_msg_analyzer(req, msg, &txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001677
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001678 /* 1: we might have to print this header in debug mode */
1679 if (unlikely((global.mode & MODE_DEBUG) &&
1680 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001681 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001682 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001683
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001684 sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001685 eol = sol + msg->sl.rq.l;
1686 debug_hdr("clireq", t, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001687
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001688 sol += hdr_idx_first_pos(&txn->hdr_idx);
1689 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001690
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001691 while (cur_idx) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001692 eol = sol + txn->hdr_idx.v[cur_idx].len;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001693 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001694 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
1695 cur_idx = txn->hdr_idx.v[cur_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001696 }
1697 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001698
Willy Tarreau58f10d72006-12-04 02:26:12 +01001699
1700 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001701 * Now we quickly check if we have found a full valid request.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001702 * If not so, we check the FD and buffer states before leaving.
1703 * A full request is indicated by the fact that we have seen
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001704 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
1705 * requests are checked first.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001706 *
1707 */
1708
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001709 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001710 /*
1711 * First, let's catch bad requests.
1712 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001713 if (unlikely(msg->msg_state == HTTP_MSG_ERROR))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001714 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001715
1716 /* 1: Since we are in header mode, if there's no space
1717 * left for headers, we won't be able to free more
1718 * later, so the session will never terminate. We
1719 * must terminate it now.
1720 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001721 if (unlikely(req->l >= req->rlim - req->data)) {
1722 /* FIXME: check if URI is set and return Status
1723 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001724 */
Willy Tarreau06619262006-12-17 08:37:22 +01001725 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001726 }
1727
1728 /* 2: have we encountered a read error or a close ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001729 else if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1730 /* read error, or last read : give up. */
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001731 buffer_shutr_done(req);
1732 buffer_shutw_done(rep);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001733 fd_delete(t->cli_fd);
1734 t->cli_state = CL_STCLOSE;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001735 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001736 if (!(t->flags & SN_ERR_MASK))
1737 t->flags |= SN_ERR_CLICL;
1738 if (!(t->flags & SN_FINST_MASK))
1739 t->flags |= SN_FINST_R;
1740 return 1;
1741 }
1742
1743 /* 3: has the read timeout expired ? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001744 else if (unlikely(tick_is_expired(req->rex, now_ms) ||
1745 tick_is_expired(txn->exp, now_ms))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001746 /* read timeout : give up with an error message. */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001747 txn->status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +01001748 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001749 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001750 if (!(t->flags & SN_ERR_MASK))
1751 t->flags |= SN_ERR_CLITO;
1752 if (!(t->flags & SN_FINST_MASK))
1753 t->flags |= SN_FINST_R;
1754 return 1;
1755 }
1756
1757 /* 4: do we need to re-enable the read socket ? */
Willy Tarreau66319382007-04-08 17:17:37 +02001758 else if (unlikely(EV_FD_COND_S(t->cli_fd, DIR_RD))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02001759 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreau58f10d72006-12-04 02:26:12 +01001760 * full. We cannot loop here since stream_sock_read will disable it only if
1761 * req->l == rlim-data
1762 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001763 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001764 }
1765 return t->cli_state != CL_STHEADERS;
1766 }
1767
1768
1769 /****************************************************************
1770 * More interesting part now : we know that we have a complete *
1771 * request which at least looks like HTTP. We have an indicator *
1772 * of each header's length, so we can parse them quickly. *
1773 ****************************************************************/
1774
Willy Tarreau9cdde232007-05-02 20:58:19 +02001775 /* ensure we keep this pointer to the beginning of the message */
1776 msg->sol = req->data + msg->som;
1777
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001778 /*
1779 * 1: identify the method
1780 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001781 txn->meth = find_http_meth(&req->data[msg->som], msg->sl.rq.m_l);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001782
1783 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001784 * 2: check if the URI matches the monitor_uri.
Willy Tarreau06619262006-12-17 08:37:22 +01001785 * We have to do this for every request which gets in, because
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001786 * the monitor-uri is defined by the frontend.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001787 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001788 if (unlikely((t->fe->monitor_uri_len != 0) &&
1789 (t->fe->monitor_uri_len == msg->sl.rq.u_l) &&
1790 !memcmp(&req->data[msg->sl.rq.u],
1791 t->fe->monitor_uri,
1792 t->fe->monitor_uri_len))) {
1793 /*
1794 * We have found the monitor URI
1795 */
Willy Tarreaub80c2302007-11-30 20:51:32 +01001796 struct acl_cond *cond;
1797 cur_proxy = t->fe;
1798
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001799 t->flags |= SN_MONITOR;
Willy Tarreaub80c2302007-11-30 20:51:32 +01001800
1801 /* Check if we want to fail this monitor request or not */
1802 list_for_each_entry(cond, &cur_proxy->mon_fail_cond, list) {
1803 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001804
1805 ret = acl_pass(ret);
Willy Tarreaub80c2302007-11-30 20:51:32 +01001806 if (cond->pol == ACL_COND_UNLESS)
1807 ret = !ret;
1808
1809 if (ret) {
1810 /* we fail this request, let's return 503 service unavail */
1811 txn->status = 503;
1812 client_retnclose(t, error_message(t, HTTP_ERR_503));
1813 goto return_prx_cond;
1814 }
1815 }
1816
1817 /* nothing to fail, let's reply normaly */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001818 txn->status = 200;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001819 client_retnclose(t, &http_200_chunk);
1820 goto return_prx_cond;
1821 }
1822
1823 /*
1824 * 3: Maybe we have to copy the original REQURI for the logs ?
1825 * Note: we cannot log anymore if the request has been
1826 * classified as invalid.
1827 */
1828 if (unlikely(t->logs.logwait & LW_REQ)) {
1829 /* we have a complete HTTP request that we must log */
Willy Tarreau332f8bf2007-05-13 21:36:56 +02001830 if ((txn->uri = pool_alloc2(pool2_requri)) != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001831 int urilen = msg->sl.rq.l;
1832
1833 if (urilen >= REQURI_LEN)
1834 urilen = REQURI_LEN - 1;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001835 memcpy(txn->uri, &req->data[msg->som], urilen);
1836 txn->uri[urilen] = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001837
1838 if (!(t->logs.logwait &= ~LW_REQ))
Willy Tarreau42250582007-04-01 01:30:43 +02001839 http_sess_log(t);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001840 } else {
1841 Alert("HTTP logging : out of memory.\n");
1842 }
1843 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001844
Willy Tarreau06619262006-12-17 08:37:22 +01001845
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001846 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
1847 if (unlikely(msg->sl.rq.v_l == 0)) {
1848 int delta;
1849 char *cur_end;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001850 msg->sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001851 cur_end = msg->sol + msg->sl.rq.l;
1852 delta = 0;
Willy Tarreau06619262006-12-17 08:37:22 +01001853
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001854 if (msg->sl.rq.u_l == 0) {
1855 /* if no URI was set, add "/" */
1856 delta = buffer_replace2(req, cur_end, cur_end, " /", 2);
1857 cur_end += delta;
1858 msg->eoh += delta;
Willy Tarreau06619262006-12-17 08:37:22 +01001859 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001860 /* add HTTP version */
1861 delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
1862 msg->eoh += delta;
1863 cur_end += delta;
1864 cur_end = (char *)http_parse_reqline(msg, req->data,
1865 HTTP_MSG_RQMETH,
1866 msg->sol, cur_end + 1,
1867 NULL, NULL);
1868 if (unlikely(!cur_end))
1869 goto return_bad_req;
1870
1871 /* we have a full HTTP/1.0 request now and we know that
1872 * we have either a CR or an LF at <ptr>.
1873 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001874 hdr_idx_set_start(&txn->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
Willy Tarreau58f10d72006-12-04 02:26:12 +01001875 }
1876
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001877
1878 /* 5: we may need to capture headers */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001879 if (unlikely((t->logs.logwait & LW_REQHDR) && t->fe->req_cap))
Willy Tarreau117f59e2007-03-04 18:17:17 +01001880 capture_headers(req->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001881 txn->req.cap, t->fe->req_cap);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001882
1883 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001884 * 6: we will have to evaluate the filters.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001885 * As opposed to version 1.2, now they will be evaluated in the
1886 * filters order and not in the header order. This means that
1887 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001888 *
1889 * We can now check whether we want to switch to another
1890 * backend, in which case we will re-check the backend's
1891 * filters and various options. In order to support 3-level
1892 * switching, here's how we should proceed :
1893 *
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001894 * a) run be.
Willy Tarreau830ff452006-12-17 19:31:23 +01001895 * if (switch) then switch ->be to the new backend.
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001896 * b) run be if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001897 * There cannot be any switch from there, so ->be cannot be
1898 * changed anymore.
1899 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001900 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001901 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001902 * The response path will be able to apply either ->be, or
1903 * ->be then ->fe filters in order to match the reverse of
1904 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001905 */
1906
Willy Tarreau06619262006-12-17 08:37:22 +01001907 do {
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001908 struct acl_cond *cond;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001909 struct redirect_rule *rule;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001910 struct proxy *rule_set = t->be;
Willy Tarreau830ff452006-12-17 19:31:23 +01001911 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001912
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001913 /* first check whether we have some ACLs set to redirect this request */
1914 list_for_each_entry(rule, &cur_proxy->redirect_rules, list) {
1915 int ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001916
1917 ret = acl_pass(ret);
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001918 if (rule->cond->pol == ACL_COND_UNLESS)
1919 ret = !ret;
1920
1921 if (ret) {
1922 struct chunk rdr = { trash, 0 };
1923 const char *msg_fmt;
1924
1925 /* build redirect message */
1926 switch(rule->code) {
1927 case 303:
1928 rdr.len = strlen(HTTP_303);
1929 msg_fmt = HTTP_303;
1930 break;
1931 case 301:
1932 rdr.len = strlen(HTTP_301);
1933 msg_fmt = HTTP_301;
1934 break;
1935 case 302:
1936 default:
1937 rdr.len = strlen(HTTP_302);
1938 msg_fmt = HTTP_302;
1939 break;
1940 }
1941
1942 if (unlikely(rdr.len > sizeof(trash)))
1943 goto return_bad_req;
1944 memcpy(rdr.str, msg_fmt, rdr.len);
1945
1946 switch(rule->type) {
1947 case REDIRECT_TYPE_PREFIX: {
1948 const char *path;
1949 int pathlen;
1950
1951 path = http_get_path(txn);
1952 /* build message using path */
1953 if (path) {
1954 pathlen = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
1955 } else {
1956 path = "/";
1957 pathlen = 1;
1958 }
1959
1960 if (rdr.len + rule->rdr_len + pathlen > sizeof(trash) - 4)
1961 goto return_bad_req;
1962
1963 /* add prefix */
1964 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1965 rdr.len += rule->rdr_len;
1966
1967 /* add path */
1968 memcpy(rdr.str + rdr.len, path, pathlen);
1969 rdr.len += pathlen;
1970 break;
1971 }
1972 case REDIRECT_TYPE_LOCATION:
1973 default:
1974 if (rdr.len + rule->rdr_len > sizeof(trash) - 4)
1975 goto return_bad_req;
1976
1977 /* add location */
1978 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1979 rdr.len += rule->rdr_len;
1980 break;
1981 }
1982
1983 /* add end of headers */
1984 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
1985 rdr.len += 4;
1986
1987 txn->status = rule->code;
1988 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02001989 t->logs.tv_request = now;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001990 client_retnclose(t, &rdr);
1991 goto return_prx_cond;
1992 }
1993 }
1994
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001995 /* first check whether we have some ACLs set to block this request */
1996 list_for_each_entry(cond, &cur_proxy->block_cond, list) {
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001997 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001998
1999 ret = acl_pass(ret);
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02002000 if (cond->pol == ACL_COND_UNLESS)
2001 ret = !ret;
2002
2003 if (ret) {
2004 txn->status = 403;
2005 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02002006 t->logs.tv_request = now;
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02002007 client_retnclose(t, error_message(t, HTTP_ERR_403));
2008 goto return_prx_cond;
2009 }
2010 }
2011
Willy Tarreau06619262006-12-17 08:37:22 +01002012 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01002013 if (rule_set->req_exp != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002014 if (apply_filters_to_request(t, req, rule_set->req_exp) < 0)
2015 goto return_bad_req;
Willy Tarreau53b6c742006-12-17 13:37:46 +01002016 }
2017
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002018 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
2019 /* to ensure correct connection accounting on
2020 * the backend, we count the connection for the
2021 * one managing the queue.
2022 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002023 t->be->beconn++;
2024 if (t->be->beconn > t->be->beconn_max)
2025 t->be->beconn_max = t->be->beconn;
2026 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002027 t->flags |= SN_BE_ASSIGNED;
2028 }
2029
Willy Tarreau06619262006-12-17 08:37:22 +01002030 /* has the request been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01002031 if (txn->flags & TX_CLDENY) {
Willy Tarreau06619262006-12-17 08:37:22 +01002032 /* no need to go further */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002033 txn->status = 403;
Willy Tarreau06619262006-12-17 08:37:22 +01002034 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02002035 t->logs.tv_request = now;
Willy Tarreau80587432006-12-24 17:47:20 +01002036 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01002037 goto return_prx_cond;
2038 }
2039
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002040 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002041 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002042 !(t->flags & SN_CONN_CLOSED)) {
2043 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002044 int cur_idx, old_idx, delta, val;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002045 struct hdr_idx_elem *cur_hdr;
Willy Tarreau06619262006-12-17 08:37:22 +01002046
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002047 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002048 old_idx = 0;
2049
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002050 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
2051 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002052 cur_ptr = cur_next;
2053 cur_end = cur_ptr + cur_hdr->len;
2054 cur_next = cur_end + cur_hdr->cr + 1;
2055
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002056 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
2057 if (val) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002058 /* 3 possibilities :
2059 * - we have already set Connection: close,
2060 * so we remove this line.
2061 * - we have not yet set Connection: close,
2062 * but this line indicates close. We leave
2063 * it untouched and set the flag.
2064 * - we have not yet set Connection: close,
2065 * and this line indicates non-close. We
2066 * replace it.
2067 */
2068 if (t->flags & SN_CONN_CLOSED) {
2069 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002070 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002071 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002072 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
2073 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002074 cur_hdr->len = 0;
2075 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002076 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
2077 delta = buffer_replace2(req, cur_ptr + val, cur_end,
2078 "close", 5);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002079 cur_next += delta;
2080 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002081 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002082 }
2083 t->flags |= SN_CONN_CLOSED;
2084 }
2085 }
2086 old_idx = cur_idx;
2087 }
Willy Tarreauf2f0ee82007-03-30 12:02:43 +02002088 }
2089 /* add request headers from the rule sets in the same order */
2090 for (cur_idx = 0; cur_idx < rule_set->nb_reqadd; cur_idx++) {
2091 if (unlikely(http_header_add_tail(req,
2092 &txn->req,
2093 &txn->hdr_idx,
2094 rule_set->req_add[cur_idx])) < 0)
2095 goto return_bad_req;
Willy Tarreau06619262006-12-17 08:37:22 +01002096 }
Willy Tarreaub2513902006-12-17 14:52:38 +01002097
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002098 /* check if stats URI was requested, and if an auth is needed */
Willy Tarreau0214c3a2007-01-07 13:47:30 +01002099 if (rule_set->uri_auth != NULL &&
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002100 (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)) {
Willy Tarreaub2513902006-12-17 14:52:38 +01002101 /* we have to check the URI and auth for this request */
2102 if (stats_check_uri_auth(t, rule_set))
2103 return 1;
2104 }
2105
Willy Tarreau55ea7572007-06-17 19:56:27 +02002106 /* now check whether we have some switching rules for this request */
2107 if (!(t->flags & SN_BE_ASSIGNED)) {
2108 struct switching_rule *rule;
2109
2110 list_for_each_entry(rule, &cur_proxy->switching_rules, list) {
2111 int ret;
2112
2113 ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02002114
2115 ret = acl_pass(ret);
Willy Tarreaua8cfa342008-07-09 11:23:31 +02002116 if (rule->cond->pol == ACL_COND_UNLESS)
Willy Tarreau55ea7572007-06-17 19:56:27 +02002117 ret = !ret;
2118
2119 if (ret) {
2120 t->be = rule->be.backend;
2121 t->be->beconn++;
2122 if (t->be->beconn > t->be->beconn_max)
2123 t->be->beconn_max = t->be->beconn;
2124 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002125
2126 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002127 t->rep->rto = t->req->wto = t->be->timeout.server;
2128 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002129 t->conn_retries = t->be->conn_retries;
Willy Tarreau55ea7572007-06-17 19:56:27 +02002130 t->flags |= SN_BE_ASSIGNED;
2131 break;
2132 }
2133 }
2134 }
2135
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002136 if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
2137 /* No backend was set, but there was a default
2138 * backend set in the frontend, so we use it and
2139 * loop again.
2140 */
2141 t->be = cur_proxy->defbe.be;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002142 t->be->beconn++;
2143 if (t->be->beconn > t->be->beconn_max)
2144 t->be->beconn_max = t->be->beconn;
2145 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002146
2147 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002148 t->rep->rto = t->req->wto = t->be->timeout.server;
2149 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002150 t->conn_retries = t->be->conn_retries;
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002151 t->flags |= SN_BE_ASSIGNED;
2152 }
2153 } while (t->be != cur_proxy); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01002154
Willy Tarreau58f10d72006-12-04 02:26:12 +01002155
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002156 if (!(t->flags & SN_BE_ASSIGNED)) {
2157 /* To ensure correct connection accounting on
2158 * the backend, we count the connection for the
2159 * one managing the queue.
2160 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002161 t->be->beconn++;
2162 if (t->be->beconn > t->be->beconn_max)
2163 t->be->beconn_max = t->be->beconn;
2164 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002165 t->flags |= SN_BE_ASSIGNED;
2166 }
2167
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002168 /*
2169 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01002170 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002171 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01002172 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01002173 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01002174
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01002175 /*
2176 * If HTTP PROXY is set we simply get remote server address
2177 * parsing incoming request.
2178 */
2179 if ((t->be->options & PR_O_HTTP_PROXY) && !(t->flags & SN_ADDR_SET)) {
2180 url2sa(req->data + msg->sl.rq.u, msg->sl.rq.u_l, &t->srv_addr);
2181 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002182
Willy Tarreau2a324282006-12-05 00:05:46 +01002183 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002184 * 7: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01002185 * so let's do the same now.
2186 */
2187
2188 /* It needs to look into the URI */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002189 if (t->be->appsession_name) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01002190 get_srv_from_appsession(t, &req->data[msg->som], msg->sl.rq.l);
Willy Tarreau06619262006-12-17 08:37:22 +01002191 }
2192
2193
2194 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002195 * 8: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01002196 * Note that doing so might move headers in the request, but
2197 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01002198 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01002199 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01002200 if ((t->be->cookie_name || t->be->appsession_name || t->be->capture_name)
2201 && !(txn->flags & (TX_CLDENY|TX_CLTARPIT)))
Willy Tarreau2a324282006-12-05 00:05:46 +01002202 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01002203
Willy Tarreau58f10d72006-12-04 02:26:12 +01002204
Willy Tarreau2a324282006-12-05 00:05:46 +01002205 /*
Willy Tarreaubb046ac2007-03-03 19:17:03 +01002206 * 9: add X-Forwarded-For if either the frontend or the backend
2207 * asks for it.
Willy Tarreau2a324282006-12-05 00:05:46 +01002208 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002209 if ((t->fe->options | t->be->options) & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002210 if (t->cli_addr.ss_family == AF_INET) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002211 /* Add an X-Forwarded-For header unless the source IP is
2212 * in the 'except' network range.
2213 */
2214 if ((!t->fe->except_mask.s_addr ||
2215 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->fe->except_mask.s_addr)
2216 != t->fe->except_net.s_addr) &&
2217 (!t->be->except_mask.s_addr ||
2218 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->be->except_mask.s_addr)
2219 != t->be->except_net.s_addr)) {
2220 int len;
2221 unsigned char *pn;
2222 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
Willy Tarreau45e73e32006-12-17 00:05:15 +01002223
Ross Westaf72a1d2008-08-03 10:51:45 +02002224 /* Note: we rely on the backend to get the header name to be used for
2225 * x-forwarded-for, because the header is really meant for the backends.
2226 * However, if the backend did not specify any option, we have to rely
2227 * on the frontend's header name.
2228 */
2229 if (t->be->fwdfor_hdr_len) {
2230 len = t->be->fwdfor_hdr_len;
2231 memcpy(trash, t->be->fwdfor_hdr_name, len);
2232 } else {
2233 len = t->fe->fwdfor_hdr_len;
2234 memcpy(trash, t->fe->fwdfor_hdr_name, len);
2235 }
2236 len += sprintf(trash + len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002237
Ross Westaf72a1d2008-08-03 10:51:45 +02002238 if (unlikely(http_header_add_tail2(req, &txn->req,
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002239 &txn->hdr_idx, trash, len)) < 0)
2240 goto return_bad_req;
2241 }
Willy Tarreau2a324282006-12-05 00:05:46 +01002242 }
2243 else if (t->cli_addr.ss_family == AF_INET6) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002244 /* FIXME: for the sake of completeness, we should also support
2245 * 'except' here, although it is mostly useless in this case.
2246 */
Willy Tarreau2a324282006-12-05 00:05:46 +01002247 int len;
2248 char pn[INET6_ADDRSTRLEN];
2249 inet_ntop(AF_INET6,
2250 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2251 pn, sizeof(pn));
Ross Westaf72a1d2008-08-03 10:51:45 +02002252
2253 /* Note: we rely on the backend to get the header name to be used for
2254 * x-forwarded-for, because the header is really meant for the backends.
2255 * However, if the backend did not specify any option, we have to rely
2256 * on the frontend's header name.
2257 */
2258 if (t->be->fwdfor_hdr_len) {
2259 len = t->be->fwdfor_hdr_len;
2260 memcpy(trash, t->be->fwdfor_hdr_name, len);
2261 } else {
2262 len = t->fe->fwdfor_hdr_len;
2263 memcpy(trash, t->fe->fwdfor_hdr_name, len);
2264 }
2265 len += sprintf(trash + len, ": %s", pn);
2266
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002267 if (unlikely(http_header_add_tail2(req, &txn->req,
2268 &txn->hdr_idx, trash, len)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002269 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01002270 }
2271 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002272
Willy Tarreau2a324282006-12-05 00:05:46 +01002273 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002274 * 10: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02002275 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaub2513902006-12-17 14:52:38 +01002276 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02002277 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002278 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02002279 if ((unlikely(msg->sl.rq.v_l != 8) ||
2280 unlikely(req->data[msg->som + msg->sl.rq.v + 7] != '0')) &&
2281 unlikely(http_header_add_tail2(req, &txn->req, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002282 "Connection: close", 17)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002283 goto return_bad_req;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002284 t->flags |= SN_CONN_CLOSED;
Willy Tarreaue15d9132006-12-14 22:26:42 +01002285 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002286 /* Before we switch to data, was assignment set in manage_client_side_cookie?
2287 * If not assigned, perhaps we are balancing on url_param, but this is a
2288 * POST; and the parameters are in the body, maybe scan there to find our server.
2289 * (unless headers overflowed the buffer?)
2290 */
2291 if (!(t->flags & (SN_ASSIGNED|SN_DIRECT)) &&
2292 t->txn.meth == HTTP_METH_POST && t->be->url_param_name != NULL &&
Willy Tarreaufb0528b2008-08-11 00:21:56 +02002293 t->be->url_param_post_limit != 0 && req->l < BUFSIZE &&
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002294 memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) {
2295 /* are there enough bytes here? total == l || r || rlim ?
2296 * len is unsigned, but eoh is int,
2297 * how many bytes of body have we received?
2298 * eoh is the first empty line of the header
2299 */
2300 /* already established CRLF or LF at eoh, move to start of message, find message length in buffer */
Willy Tarreaufb0528b2008-08-11 00:21:56 +02002301 unsigned long len = req->l - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1);
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002302
2303 /* If we have HTTP/1.1 and Expect: 100-continue, then abort.
2304 * We can't assume responsibility for the server's decision,
2305 * on this URI and header set. See rfc2616: 14.20, 8.2.3,
2306 * We also can't change our mind later, about which server to choose, so round robin.
2307 */
2308 if ((likely(msg->sl.rq.v_l == 8) && req->data[msg->som + msg->sl.rq.v + 7] == '1')) {
2309 struct hdr_ctx ctx;
2310 ctx.idx = 0;
2311 /* Expect is allowed in 1.1, look for it */
2312 http_find_header2("Expect", 6, msg->sol, &txn->hdr_idx, &ctx);
2313 if (ctx.idx != 0 &&
2314 unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val,"100-continue",12)==0))
2315 /* We can't reliablly stall and wait for data, because of
2316 * .NET clients that don't conform to rfc2616; so, no need for
2317 * the next block to check length expectations.
2318 * We could send 100 status back to the client, but then we need to
2319 * re-write headers, and send the message. And this isn't the right
2320 * place for that action.
2321 * TODO: support Expect elsewhere and delete this block.
2322 */
2323 goto end_check_maybe_wait_for_body;
2324 }
2325 if ( likely(len > t->be->url_param_post_limit) ) {
2326 /* nothing to do, we got enough */
2327 } else {
2328 /* limit implies we are supposed to need this many bytes
2329 * to find the parameter. Let's see how many bytes we can wait for.
2330 */
2331 long long hint = len;
2332 struct hdr_ctx ctx;
2333 ctx.idx = 0;
2334 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
2335 if (unlikely(ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",7)==0)) {
2336 t->srv_state = SV_STANALYZE;
2337 } else {
2338 ctx.idx = 0;
2339 http_find_header2("Content-Length", 14, msg->sol, &txn->hdr_idx, &ctx);
2340 /* now if we have a length, we'll take the hint */
2341 if ( ctx.idx ) {
2342 /* We have Content-Length */
2343 if ( strl2llrc(ctx.line+ctx.val,ctx.vlen, &hint) )
2344 hint = 0; /* parse failure, untrusted client */
2345 else {
2346 if ( hint > 0 )
2347 msg->hdr_content_len = hint;
2348 else
2349 hint = 0; /* bad client, sent negative length */
2350 }
2351 }
2352 /* but limited to what we care about, maybe we don't expect any entity data (hint == 0) */
2353 if ( t->be->url_param_post_limit < hint )
2354 hint = t->be->url_param_post_limit;
2355 /* now do we really need to buffer more data? */
2356 if ( len < hint )
2357 t->srv_state = SV_STANALYZE;
2358 /* else... There are no body bytes to wait for */
2359 }
2360 }
2361 }
2362 end_check_maybe_wait_for_body:
Willy Tarreaubaaee002006-06-26 02:48:02 +02002363
Willy Tarreau2a324282006-12-05 00:05:46 +01002364 /*************************************************************
2365 * OK, that's finished for the headers. We have done what we *
2366 * could. Let's switch to the DATA state. *
2367 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02002368
Willy Tarreau2a324282006-12-05 00:05:46 +01002369 t->cli_state = CL_STDATA;
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002370 req->flags |= BF_MAY_CONNECT | BF_MAY_FORWARD;
Willy Tarreaudc0a6a02008-08-03 20:38:13 +02002371
Willy Tarreau2a324282006-12-05 00:05:46 +01002372 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002373
Willy Tarreau70089872008-06-13 21:12:51 +02002374 t->logs.tv_request = now;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002375
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002376 if (!t->fe->timeout.client ||
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002377 (!(rep->flags & BF_MAY_FORWARD) && t->be->timeout.server)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002378 /* If the client has no timeout, or if the server is not ready yet,
2379 * and we know for sure that it can expire, then it's cleaner to
2380 * disable the timeout on the client side so that too low values
2381 * cannot make the sessions abort too early.
2382 *
2383 * FIXME-20050705: the server needs a way to re-enable this time-out
2384 * when it switches its state, otherwise a client can stay connected
2385 * indefinitely. This now seems to be OK.
2386 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002387 req->rex = TICK_ETERNITY;
Willy Tarreau2a324282006-12-05 00:05:46 +01002388 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002389
Willy Tarreau1fa31262007-12-03 00:36:16 +01002390 /* When a connection is tarpitted, we use the tarpit timeout,
2391 * which may be the same as the connect timeout if unspecified.
2392 * If unset, then set it to zero because we really want it to
2393 * eventually expire.
Willy Tarreau2a324282006-12-05 00:05:46 +01002394 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002395 if (txn->flags & TX_CLTARPIT) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002396 t->req->l = 0;
2397 /* flush the request so that we can drop the connection early
2398 * if the client closes first.
2399 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002400 req->cex = tick_add_ifset(now_ms, t->be->timeout.tarpit);
2401 if (!req->cex)
2402 req->cex = now_ms;
Willy Tarreau2a324282006-12-05 00:05:46 +01002403 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002404
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002405 /* OK let's go on with the BODY now */
Willy Tarreau06619262006-12-17 08:37:22 +01002406 goto process_data;
2407
2408 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002409 txn->req.msg_state = HTTP_MSG_ERROR;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002410 txn->status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01002411 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002412 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01002413 return_prx_cond:
2414 if (!(t->flags & SN_ERR_MASK))
2415 t->flags |= SN_ERR_PRXCOND;
2416 if (!(t->flags & SN_FINST_MASK))
2417 t->flags |= SN_FINST_R;
2418 return 1;
2419
Willy Tarreaubaaee002006-06-26 02:48:02 +02002420 }
2421 else if (c == CL_STDATA) {
2422 process_data:
2423 /* FIXME: this error handling is partly buggy because we always report
2424 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
2425 * or HEADER phase. BTW, it's not logical to expire the client while
2426 * we're waiting for the server to connect.
2427 */
2428 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002429 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002430 buffer_shutr_done(req);
2431 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002432 fd_delete(t->cli_fd);
2433 t->cli_state = CL_STCLOSE;
2434 if (!(t->flags & SN_ERR_MASK))
2435 t->flags |= SN_ERR_CLICL;
2436 if (!(t->flags & SN_FINST_MASK)) {
2437 if (t->pend_pos)
2438 t->flags |= SN_FINST_Q;
2439 else if (s == SV_STCONN)
2440 t->flags |= SN_FINST_C;
2441 else
2442 t->flags |= SN_FINST_D;
2443 }
2444 return 1;
2445 }
2446 /* last read, or end of server write */
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002447 else if (req->flags & (BF_READ_NULL | BF_SHUTW_STATUS)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002448 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002449 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002450 t->cli_state = CL_STSHUTR;
2451 return 1;
2452 }
2453 /* last server read and buffer empty */
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002454 else if (rep->flags & BF_SHUTR_STATUS && rep->l == 0) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002455 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002456 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002457 shutdown(t->cli_fd, SHUT_WR);
2458 /* We must ensure that the read part is still alive when switching
2459 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002460 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002461 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002462 t->cli_state = CL_STSHUTW;
2463 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2464 return 1;
2465 }
2466 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002467 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002468 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002469 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002470 t->cli_state = CL_STSHUTR;
2471 if (!(t->flags & SN_ERR_MASK))
2472 t->flags |= SN_ERR_CLITO;
2473 if (!(t->flags & SN_FINST_MASK)) {
2474 if (t->pend_pos)
2475 t->flags |= SN_FINST_Q;
2476 else if (s == SV_STCONN)
2477 t->flags |= SN_FINST_C;
2478 else
2479 t->flags |= SN_FINST_D;
2480 }
2481 return 1;
2482 }
2483 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002484 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002485 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002486 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002487 shutdown(t->cli_fd, SHUT_WR);
2488 /* We must ensure that the read part is still alive when switching
2489 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002490 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002491 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002492
2493 t->cli_state = CL_STSHUTW;
2494 if (!(t->flags & SN_ERR_MASK))
2495 t->flags |= SN_ERR_CLITO;
2496 if (!(t->flags & SN_FINST_MASK)) {
2497 if (t->pend_pos)
2498 t->flags |= SN_FINST_Q;
2499 else if (s == SV_STCONN)
2500 t->flags |= SN_FINST_C;
2501 else
2502 t->flags |= SN_FINST_D;
2503 }
2504 return 1;
2505 }
2506
2507 if (req->l >= req->rlim - req->data) {
2508 /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02002509 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002510 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002511 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002512 }
2513 } else {
2514 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002515 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002516 if (!t->fe->timeout.client ||
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002517 (!(rep->flags & BF_MAY_FORWARD) && t->be->timeout.server))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002518 /* If the client has no timeout, or if the server not ready yet, and we
2519 * know for sure that it can expire, then it's cleaner to disable the
2520 * timeout on the client side so that too low values cannot make the
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002521 * sessions abort too early. NB: we should only do this in HTTP states
2522 * before HEADERS.
Willy Tarreaubaaee002006-06-26 02:48:02 +02002523 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002524 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002525 else
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002526 req->rex = tick_add(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002527 }
2528 }
2529
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002530 /* we don't enable client write if the buffer is empty, nor if the server has to analyze it */
2531 if ((rep->l == 0) || !(rep->flags & BF_MAY_FORWARD)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002532 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2533 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002534 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002535 }
2536 } else {
2537 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002538 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2539 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002540 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
2541 if (rep->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002542 /* FIXME: to prevent the client from expiring read timeouts during writes,
2543 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002544 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002545 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002546 }
2547 }
2548 return 0; /* other cases change nothing */
2549 }
2550 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002551 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002552 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002553 fd_delete(t->cli_fd);
2554 t->cli_state = CL_STCLOSE;
2555 if (!(t->flags & SN_ERR_MASK))
2556 t->flags |= SN_ERR_CLICL;
2557 if (!(t->flags & SN_FINST_MASK)) {
2558 if (t->pend_pos)
2559 t->flags |= SN_FINST_Q;
2560 else if (s == SV_STCONN)
2561 t->flags |= SN_FINST_C;
2562 else
2563 t->flags |= SN_FINST_D;
2564 }
2565 return 1;
2566 }
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002567 else if ((rep->flags & BF_SHUTR_STATUS) && (rep->l == 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002568 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002569 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002570 fd_delete(t->cli_fd);
2571 t->cli_state = CL_STCLOSE;
2572 return 1;
2573 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002574 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002575 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002576 fd_delete(t->cli_fd);
2577 t->cli_state = CL_STCLOSE;
2578 if (!(t->flags & SN_ERR_MASK))
2579 t->flags |= SN_ERR_CLITO;
2580 if (!(t->flags & SN_FINST_MASK)) {
2581 if (t->pend_pos)
2582 t->flags |= SN_FINST_Q;
2583 else if (s == SV_STCONN)
2584 t->flags |= SN_FINST_C;
2585 else
2586 t->flags |= SN_FINST_D;
2587 }
2588 return 1;
2589 }
2590
2591 if (t->flags & SN_SELF_GEN) {
2592 produce_content(t);
2593 if (rep->l == 0) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002594 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002595 fd_delete(t->cli_fd);
2596 t->cli_state = CL_STCLOSE;
2597 return 1;
2598 }
2599 }
2600
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002601 if ((rep->l == 0) || !(rep->flags & BF_MAY_FORWARD)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002602 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2603 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002604 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002605 }
2606 } else {
2607 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002608 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2609 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002610 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002611 }
2612 }
2613 return 0;
2614 }
2615 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002616 if (req->flags & BF_READ_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002617 buffer_shutr_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002618 fd_delete(t->cli_fd);
2619 t->cli_state = CL_STCLOSE;
2620 if (!(t->flags & SN_ERR_MASK))
2621 t->flags |= SN_ERR_CLICL;
2622 if (!(t->flags & SN_FINST_MASK)) {
2623 if (t->pend_pos)
2624 t->flags |= SN_FINST_Q;
2625 else if (s == SV_STCONN)
2626 t->flags |= SN_FINST_C;
2627 else
2628 t->flags |= SN_FINST_D;
2629 }
2630 return 1;
2631 }
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002632 else if (req->flags & (BF_READ_NULL | BF_SHUTW_STATUS)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002633 buffer_shutr_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002634 fd_delete(t->cli_fd);
2635 t->cli_state = CL_STCLOSE;
2636 return 1;
2637 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002638 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002639 buffer_shutr_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002640 fd_delete(t->cli_fd);
2641 t->cli_state = CL_STCLOSE;
2642 if (!(t->flags & SN_ERR_MASK))
2643 t->flags |= SN_ERR_CLITO;
2644 if (!(t->flags & SN_FINST_MASK)) {
2645 if (t->pend_pos)
2646 t->flags |= SN_FINST_Q;
2647 else if (s == SV_STCONN)
2648 t->flags |= SN_FINST_C;
2649 else
2650 t->flags |= SN_FINST_D;
2651 }
2652 return 1;
2653 }
2654 else if (req->l >= req->rlim - req->data) {
2655 /* no room to read more data */
2656
2657 /* FIXME-20050705: is it possible for a client to maintain a session
2658 * after the timeout by sending more data after it receives a close ?
2659 */
2660
Willy Tarreau66319382007-04-08 17:17:37 +02002661 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002662 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002663 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002664 }
2665 } else {
2666 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002667 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002668 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002669 }
2670 }
2671 return 0;
2672 }
2673 else { /* CL_STCLOSE: nothing to do */
2674 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2675 int len;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002676 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 +02002677 write(1, trash, len);
2678 }
2679 return 0;
2680 }
2681 return 0;
2682}
2683
2684
2685/*
2686 * manages the server FSM and its socket. It returns 1 if a state has changed
2687 * (and a resync may be needed), 0 else.
2688 */
2689int process_srv(struct session *t)
2690{
2691 int s = t->srv_state;
Willy Tarreau3d300592007-03-18 18:34:41 +01002692 struct http_txn *txn = &t->txn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002693 struct buffer *req = t->req;
2694 struct buffer *rep = t->rep;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002695 int conn_err;
2696
Willy Tarreau6468d922008-08-03 19:15:35 +02002697 DPRINTF(stderr,"process_srv: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%u,%u\n",
Willy Tarreau9f1f24b2008-08-11 11:20:03 +02002698 cli_stnames[t->cli_state], srv_stnames[t->srv_state],
Willy Tarreau6468d922008-08-03 19:15:35 +02002699 EV_FD_ISSET(t->srv_fd, DIR_RD), EV_FD_ISSET(t->srv_fd, DIR_WR),
2700 rep->rex, req->wex);
Willy Tarreauee991362007-05-14 14:37:50 +02002701
Willy Tarreaubaaee002006-06-26 02:48:02 +02002702 if (s == SV_STIDLE) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002703 /* NOTE: The client processor may switch to SV_STANALYZE, which switches back SV_STIDLE.
2704 * This is logcially after CL_STHEADERS completed, CL_STDATA has started, but
2705 * we need to defer server selection until more data arrives, if possible.
2706 * This is rare, and only if balancing on parameter hash with values in the entity of a POST
2707 */
Willy Tarreaudc0a6a02008-08-03 20:38:13 +02002708 if ((rep->flags & BF_SHUTW_STATUS) ||
Willy Tarreau6468d922008-08-03 19:15:35 +02002709 ((req->flags & BF_SHUTR_STATUS) &&
2710 (req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002711 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002712 if (t->pend_pos)
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002713 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002714 /* note that this must not return any error because it would be able to
2715 * overwrite the client_retnclose() output.
2716 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002717 if (txn->flags & TX_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01002718 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02002719 else
Willy Tarreau0f772532006-12-23 20:51:41 +01002720 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 +02002721
2722 return 1;
2723 }
Willy Tarreaudc0a6a02008-08-03 20:38:13 +02002724 else if (req->flags & BF_MAY_CONNECT) {
2725 /* the client allows the server to connect */
Willy Tarreau3d300592007-03-18 18:34:41 +01002726 if (txn->flags & TX_CLTARPIT) {
Willy Tarreaub8750a82006-09-03 09:56:00 +02002727 /* This connection is being tarpitted. The CLIENT side has
2728 * already set the connect expiration date to the right
2729 * timeout. We just have to check that it has not expired.
2730 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002731 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreaub8750a82006-09-03 09:56:00 +02002732 return 0;
2733
2734 /* We will set the queue timer to the time spent, just for
2735 * logging purposes. We fake a 500 server error, so that the
2736 * attacker will not suspect his connection has been tarpitted.
2737 * It will not cause trouble to the logs because we can exclude
2738 * the tarpitted connections by filtering on the 'PT' status flags.
2739 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002740 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002741 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaub8750a82006-09-03 09:56:00 +02002742 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01002743 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02002744 return 1;
2745 }
2746
Willy Tarreaubaaee002006-06-26 02:48:02 +02002747 /* Right now, we will need to create a connection to the server.
2748 * We might already have tried, and got a connection pending, in
2749 * which case we will not do anything till it's pending. It's up
2750 * to any other session to release it and wake us up again.
2751 */
2752 if (t->pend_pos) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002753 if (!tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002754 return 0;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002755 } else {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002756 /* we've been waiting too long here */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002757 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002758 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002759 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01002760 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002761 if (t->srv)
2762 t->srv->failed_conns++;
Willy Tarreau50fd1e12007-12-10 15:25:35 +01002763 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002764 return 1;
2765 }
2766 }
2767
2768 do {
2769 /* first, get a connection */
Willy Tarreau21d2af32008-02-14 20:25:24 +01002770 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
2771 t->flags |= SN_REDIRECTABLE;
2772
Willy Tarreaubaaee002006-06-26 02:48:02 +02002773 if (srv_redispatch_connect(t))
2774 return t->srv_state != SV_STIDLE;
2775
Willy Tarreau21d2af32008-02-14 20:25:24 +01002776 if ((t->flags & SN_REDIRECTABLE) && t->srv && t->srv->rdr_len) {
2777 /* Server supporting redirection and it is possible.
2778 * Invalid requests are reported as such. It concerns all
2779 * the largest ones.
2780 */
2781 struct chunk rdr;
2782 char *path;
2783 int len;
2784
2785 /* 1: create the response header */
2786 rdr.len = strlen(HTTP_302);
2787 rdr.str = trash;
2788 memcpy(rdr.str, HTTP_302, rdr.len);
2789
2790 /* 2: add the server's prefix */
2791 if (rdr.len + t->srv->rdr_len > sizeof(trash))
2792 goto cancel_redir;
2793
2794 memcpy(rdr.str + rdr.len, t->srv->rdr_pfx, t->srv->rdr_len);
2795 rdr.len += t->srv->rdr_len;
2796
2797 /* 3: add the request URI */
2798 path = http_get_path(txn);
2799 if (!path)
2800 goto cancel_redir;
2801 len = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
2802 if (rdr.len + len > sizeof(trash) - 4) /* 4 for CRLF-CRLF */
2803 goto cancel_redir;
2804
2805 memcpy(rdr.str + rdr.len, path, len);
2806 rdr.len += len;
2807 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
2808 rdr.len += 4;
2809
2810 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C, 302, &rdr);
2811 /* FIXME: we should increase a counter of redirects per server and per backend. */
2812 if (t->srv)
2813 t->srv->cum_sess++;
2814 return 1;
2815 cancel_redir:
2816 txn->status = 400;
2817 t->fe->failed_req++;
2818 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C,
2819 400, error_message(t, HTTP_ERR_400));
2820 return 1;
2821 }
2822
Willy Tarreaubaaee002006-06-26 02:48:02 +02002823 /* try to (re-)connect to the server, and fail if we expire the
2824 * number of retries.
2825 */
2826 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002827 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002828 return t->srv_state != SV_STIDLE;
2829 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002830 } while (1);
2831 }
2832 }
2833 else if (s == SV_STCONN) { /* connection in progress */
Willy Tarreau6468d922008-08-03 19:15:35 +02002834 if ((rep->flags & BF_SHUTW_STATUS) ||
2835 ((req->flags & BF_SHUTR_STATUS) &&
2836 ((req->l == 0 && !(req->flags & BF_WRITE_STATUS)) ||
Willy Tarreauc9b654b2007-05-08 14:46:53 +02002837 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002838 req->cex = TICK_ETERNITY;
Willy Tarreauf899b942008-03-28 18:09:38 +01002839 if (!(t->flags & SN_CONN_TAR)) {
2840 /* if we are in turn-around, we have already closed the FD */
2841 fd_delete(t->srv_fd);
2842 if (t->srv) {
2843 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002844 sess_change_server(t, NULL);
Willy Tarreauf899b942008-03-28 18:09:38 +01002845 }
Willy Tarreau51406232008-03-10 22:04:20 +01002846 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002847
2848 /* note that this must not return any error because it would be able to
2849 * overwrite the client_retnclose() output.
2850 */
Willy Tarreau0f772532006-12-23 20:51:41 +01002851 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002852 return 1;
2853 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002854 if (!(req->flags & BF_WRITE_STATUS) && !tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002855 return 0; /* nothing changed */
2856 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002857 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002858 /* timeout, asynchronous connect error or first write error */
2859 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2860
Willy Tarreau541b5c22008-01-06 23:34:21 +01002861 if (t->flags & SN_CONN_TAR) {
2862 /* We are doing a turn-around waiting for a new connection attempt. */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002863 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreau541b5c22008-01-06 23:34:21 +01002864 return 0;
2865 t->flags &= ~SN_CONN_TAR;
2866 }
2867 else {
2868 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01002869 if (t->srv) {
Willy Tarreau541b5c22008-01-06 23:34:21 +01002870 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002871 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01002872 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002873
Willy Tarreau541b5c22008-01-06 23:34:21 +01002874 if (!(req->flags & BF_WRITE_STATUS))
2875 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
2876 else
2877 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
2878
2879 /* ensure that we have enough retries left */
2880 if (srv_count_retry_down(t, conn_err))
2881 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002882
Willy Tarreau541b5c22008-01-06 23:34:21 +01002883 if (req->flags & BF_WRITE_ERROR) {
2884 /* we encountered an immediate connection error, and we
2885 * will have to retry connecting to the same server, most
2886 * likely leading to the same result. To avoid this, we
2887 * fake a connection timeout to retry after a turn-around
2888 * time of 1 second. We will wait in the previous if block.
2889 */
2890 t->flags |= SN_CONN_TAR;
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002891 req->cex = tick_add(now_ms, MS_TO_TICKS(1000));
Willy Tarreau541b5c22008-01-06 23:34:21 +01002892 return 0;
2893 }
2894 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002895
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002896 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002897 /* We're on our last chance, and the REDISP option was specified.
2898 * We will ignore cookie and force to balance or use the dispatcher.
2899 */
2900 /* let's try to offer this slot to anybody */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002901 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02002902 process_srv_queue(t->srv);
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002903
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01002904 /* it's left to the dispatcher to choose a server */
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002905 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
Willy Tarreau7c669d72008-06-20 15:04:11 +02002906 t->prev_srv = t->srv;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002907
2908 /* first, get a connection */
2909 if (srv_redispatch_connect(t))
Willy Tarreau00559e72008-01-06 23:46:19 +01002910 return t->srv_state != SV_STCONN;
Krzysztof Piotr Oledzki626a19b2008-02-04 02:10:09 +01002911 } else {
2912 if (t->srv)
2913 t->srv->retries++;
2914 t->be->retries++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002915 }
2916
Willy Tarreaubaaee002006-06-26 02:48:02 +02002917 do {
2918 /* Now we will try to either reconnect to the same server or
2919 * connect to another server. If the connection gets queued
2920 * because all servers are saturated, then we will go back to
2921 * the SV_STIDLE state.
2922 */
2923 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002924 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002925 return t->srv_state != SV_STCONN;
2926 }
2927
2928 /* we need to redispatch the connection to another server */
2929 if (srv_redispatch_connect(t))
2930 return t->srv_state != SV_STCONN;
2931 } while (1);
2932 }
2933 else { /* no error or write 0 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002934 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002935
2936 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2937 if (req->l == 0) /* nothing to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002938 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002939 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002940 } else /* need the right to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002941 EV_FD_SET(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002942 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
2943 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002944 /* FIXME: to prevent the server from expiring read timeouts during writes,
2945 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002946 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002947 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002948 }
2949
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002950 if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreauf161a342007-04-08 16:59:42 +02002951 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002952 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002953 t->srv_state = SV_STDATA;
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002954 rep->flags |= BF_MAY_FORWARD;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002955 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
2956
2957 /* if the user wants to log as soon as possible, without counting
2958 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002959 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002960 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
Willy Tarreau42250582007-04-01 01:30:43 +02002961 tcp_sess_log(t);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002962 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002963#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002964 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002965 /* TCP splicing supported by both FE and BE */
2966 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2967 }
2968#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002969 }
2970 else {
2971 t->srv_state = SV_STHEADERS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002972 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002973 t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
2974 /* reset hdr_idx which was already initialized by the request.
2975 * right now, the http parser does it.
2976 * hdr_idx_init(&t->txn.hdr_idx);
2977 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002978 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002979 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002980 return 1;
2981 }
2982 }
2983 else if (s == SV_STHEADERS) { /* receiving server headers */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002984 /*
2985 * Now parse the partial (or complete) lines.
2986 * We will check the response syntax, and also join multi-line
2987 * headers. An index of all the lines will be elaborated while
2988 * parsing.
2989 *
2990 * For the parsing, we use a 28 states FSM.
2991 *
2992 * Here is the information we currently have :
2993 * rep->data + req->som = beginning of response
2994 * rep->data + req->eoh = end of processed headers / start of current one
2995 * rep->data + req->eol = end of current header or line (LF or CRLF)
2996 * rep->lr = first non-visited byte
2997 * rep->r = end of data
2998 */
2999
3000 int cur_idx;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003001 struct http_msg *msg = &txn->rsp;
3002 struct proxy *cur_proxy;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003003
Willy Tarreaua15645d2007-03-18 16:22:39 +01003004 if (likely(rep->lr < rep->r))
3005 http_msg_analyzer(rep, msg, &txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003006
Willy Tarreaua15645d2007-03-18 16:22:39 +01003007 /* 1: we might have to print this header in debug mode */
3008 if (unlikely((global.mode & MODE_DEBUG) &&
3009 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
3010 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
3011 char *eol, *sol;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003012
Willy Tarreaua15645d2007-03-18 16:22:39 +01003013 sol = rep->data + msg->som;
3014 eol = sol + msg->sl.rq.l;
3015 debug_hdr("srvrep", t, sol, eol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003016
Willy Tarreaua15645d2007-03-18 16:22:39 +01003017 sol += hdr_idx_first_pos(&txn->hdr_idx);
3018 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003019
Willy Tarreaua15645d2007-03-18 16:22:39 +01003020 while (cur_idx) {
3021 eol = sol + txn->hdr_idx.v[cur_idx].len;
3022 debug_hdr("srvhdr", t, sol, eol);
3023 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
3024 cur_idx = txn->hdr_idx.v[cur_idx].next;
3025 }
3026 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003027
Willy Tarreaubaaee002006-06-26 02:48:02 +02003028
Willy Tarreau66319382007-04-08 17:17:37 +02003029 if ((rep->l < rep->rlim - rep->data) && EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003030 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreaua15645d2007-03-18 16:22:39 +01003031 * full. We cannot loop here since stream_sock_read will disable it only if
3032 * rep->l == rlim-data
3033 */
Willy Tarreauce09c522008-08-11 10:35:07 +02003034 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003035 }
3036
3037
3038 /*
3039 * Now we quickly check if we have found a full valid response.
3040 * If not so, we check the FD and buffer states before leaving.
3041 * A full response is indicated by the fact that we have seen
3042 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
3043 * responses are checked first.
3044 *
3045 * Depending on whether the client is still there or not, we
3046 * may send an error response back or not. Note that normally
3047 * we should only check for HTTP status there, and check I/O
3048 * errors somewhere else.
3049 */
3050
3051 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
3052
3053 /* Invalid response, or read error or write error */
3054 if (unlikely((msg->msg_state == HTTP_MSG_ERROR) ||
3055 (req->flags & BF_WRITE_ERROR) ||
3056 (rep->flags & BF_READ_ERROR))) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003057 buffer_shutr_done(rep);
3058 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003059 fd_delete(t->srv_fd);
3060 if (t->srv) {
3061 t->srv->cur_sess--;
3062 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003063 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003064 }
3065 t->be->failed_resp++;
3066 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003067 txn->status = 502;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003068 client_return(t, error_message(t, HTTP_ERR_502));
3069 if (!(t->flags & SN_ERR_MASK))
3070 t->flags |= SN_ERR_SRVCL;
3071 if (!(t->flags & SN_FINST_MASK))
3072 t->flags |= SN_FINST_H;
3073 /* We used to have a free connection slot. Since we'll never use it,
3074 * we have to inform the server that it may be used by another session.
3075 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003076 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003077 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003078
Willy Tarreaua15645d2007-03-18 16:22:39 +01003079 return 1;
3080 }
3081
3082 /* end of client write or end of server read.
3083 * since we are in header mode, if there's no space left for headers, we
3084 * won't be able to free more later, so the session will never terminate.
3085 */
Willy Tarreau6468d922008-08-03 19:15:35 +02003086 else if (unlikely(rep->flags & (BF_READ_NULL | BF_SHUTW_STATUS) ||
Willy Tarreaua15645d2007-03-18 16:22:39 +01003087 rep->l >= rep->rlim - rep->data)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003088 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003089 buffer_shutr_done(rep);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003090 t->srv_state = SV_STSHUTR;
3091 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3092 return 1;
3093 }
3094
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003095 /* read timeout : return a 504 to the client. */
Willy Tarreauf161a342007-04-08 16:59:42 +02003096 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_RD) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003097 tick_is_expired(rep->rex, now_ms))) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003098 buffer_shutr_done(rep);
3099 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003100 fd_delete(t->srv_fd);
3101 if (t->srv) {
3102 t->srv->cur_sess--;
3103 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003104 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003105 }
3106 t->be->failed_resp++;
3107 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003108 txn->status = 504;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003109 client_return(t, error_message(t, HTTP_ERR_504));
3110 if (!(t->flags & SN_ERR_MASK))
3111 t->flags |= SN_ERR_SRVTO;
3112 if (!(t->flags & SN_FINST_MASK))
3113 t->flags |= SN_FINST_H;
3114 /* We used to have a free connection slot. Since we'll never use it,
3115 * we have to inform the server that it may be used by another session.
3116 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003117 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003118 process_srv_queue(t->srv);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003119 return 1;
3120 }
3121
3122 /* last client read and buffer empty */
3123 /* FIXME!!! here, we don't want to switch to SHUTW if the
3124 * client shuts read too early, because we may still have
3125 * some work to do on the headers.
3126 * The side-effect is that if the client completely closes its
3127 * connection during SV_STHEADER, the connection to the server
3128 * is kept until a response comes back or the timeout is reached.
3129 */
Willy Tarreau6468d922008-08-03 19:15:35 +02003130 else if (0 && /* we don't want to switch to shutw for now */
3131 unlikely(req->flags & BF_SHUTR_STATUS && (req->l == 0))) {
3132
Willy Tarreauf161a342007-04-08 16:59:42 +02003133 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003134 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003135
3136 /* We must ensure that the read part is still
3137 * alive when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003138 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003139 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003140
3141 shutdown(t->srv_fd, SHUT_WR);
3142 t->srv_state = SV_STSHUTW;
3143 return 1;
3144 }
3145
3146 /* write timeout */
3147 /* FIXME!!! here, we don't want to switch to SHUTW if the
3148 * client shuts read too early, because we may still have
3149 * some work to do on the headers.
3150 */
Willy Tarreauf161a342007-04-08 16:59:42 +02003151 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_WR) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003152 tick_is_expired(req->wex, now_ms))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003153 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003154 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003155 shutdown(t->srv_fd, SHUT_WR);
3156 /* We must ensure that the read part is still alive
3157 * when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003158 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003159 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003160
3161 t->srv_state = SV_STSHUTW;
3162 if (!(t->flags & SN_ERR_MASK))
3163 t->flags |= SN_ERR_SRVTO;
3164 if (!(t->flags & SN_FINST_MASK))
3165 t->flags |= SN_FINST_H;
3166 return 1;
3167 }
3168
3169 /*
3170 * And now the non-error cases.
3171 */
3172
3173 /* Data remaining in the request buffer.
3174 * This happens during the first pass here, and during
3175 * long posts.
3176 */
3177 else if (likely(req->l)) {
Willy Tarreau66319382007-04-08 17:17:37 +02003178 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3179 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003180 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3181 if (req->wex) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003182 /* FIXME: to prevent the server from expiring read timeouts during writes,
3183 * we refresh it. */
3184 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003185 }
3186 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003187 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003188
Willy Tarreaua15645d2007-03-18 16:22:39 +01003189 /* nothing left in the request buffer */
3190 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003191 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3192 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003193 req->wex = TICK_ETERNITY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003194 }
3195 }
3196
3197 return t->srv_state != SV_STHEADERS;
3198 }
3199
3200
3201 /*****************************************************************
3202 * More interesting part now : we know that we have a complete *
3203 * response which at least looks like HTTP. We have an indicator *
3204 * of each header's length, so we can parse them quickly. *
3205 ****************************************************************/
3206
Willy Tarreau9cdde232007-05-02 20:58:19 +02003207 /* ensure we keep this pointer to the beginning of the message */
3208 msg->sol = rep->data + msg->som;
3209
Willy Tarreaua15645d2007-03-18 16:22:39 +01003210 /*
3211 * 1: get the status code and check for cacheability.
3212 */
3213
3214 t->logs.logwait &= ~LW_RESP;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003215 txn->status = strl2ui(rep->data + msg->sl.st.c, msg->sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003216
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003217 switch (txn->status) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003218 case 200:
3219 case 203:
3220 case 206:
3221 case 300:
3222 case 301:
3223 case 410:
3224 /* RFC2616 @13.4:
3225 * "A response received with a status code of
3226 * 200, 203, 206, 300, 301 or 410 MAY be stored
3227 * by a cache (...) unless a cache-control
3228 * directive prohibits caching."
3229 *
3230 * RFC2616 @9.5: POST method :
3231 * "Responses to this method are not cacheable,
3232 * unless the response includes appropriate
3233 * Cache-Control or Expires header fields."
3234 */
3235 if (likely(txn->meth != HTTP_METH_POST) &&
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003236 (t->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
Willy Tarreau3d300592007-03-18 18:34:41 +01003237 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003238 break;
3239 default:
3240 break;
3241 }
3242
3243 /*
3244 * 2: we may need to capture headers
3245 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003246 if (unlikely((t->logs.logwait & LW_RSPHDR) && t->fe->rsp_cap))
Willy Tarreaua15645d2007-03-18 16:22:39 +01003247 capture_headers(rep->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003248 txn->rsp.cap, t->fe->rsp_cap);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003249
3250 /*
3251 * 3: we will have to evaluate the filters.
3252 * As opposed to version 1.2, now they will be evaluated in the
3253 * filters order and not in the header order. This means that
3254 * each filter has to be validated among all headers.
3255 *
3256 * Filters are tried with ->be first, then with ->fe if it is
3257 * different from ->be.
3258 */
3259
3260 t->flags &= ~SN_CONN_CLOSED; /* prepare for inspection */
3261
3262 cur_proxy = t->be;
3263 while (1) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003264 struct proxy *rule_set = cur_proxy;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003265
3266 /* try headers filters */
3267 if (rule_set->rsp_exp != NULL) {
3268 if (apply_filters_to_response(t, rep, rule_set->rsp_exp) < 0) {
3269 return_bad_resp:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003270 if (t->srv) {
3271 t->srv->cur_sess--;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003272 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003273 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003274 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003275 cur_proxy->failed_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003276 return_srv_prx_502:
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003277 buffer_shutr_done(rep);
3278 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003279 fd_delete(t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003280 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003281 txn->status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01003282 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003283 if (!(t->flags & SN_ERR_MASK))
3284 t->flags |= SN_ERR_PRXCOND;
3285 if (!(t->flags & SN_FINST_MASK))
3286 t->flags |= SN_FINST_H;
3287 /* We used to have a free connection slot. Since we'll never use it,
3288 * we have to inform the server that it may be used by another session.
3289 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003290 if (t->srv && may_dequeue_tasks(t->srv, cur_proxy))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003291 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003292 return 1;
3293 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003294 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003295
Willy Tarreaua15645d2007-03-18 16:22:39 +01003296 /* has the response been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01003297 if (txn->flags & TX_SVDENY) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003298 if (t->srv) {
3299 t->srv->cur_sess--;
3300 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003301 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003302 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003303 cur_proxy->denied_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003304 goto return_srv_prx_502;
3305 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003306
Willy Tarreaua15645d2007-03-18 16:22:39 +01003307 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003308 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01003309 !(t->flags & SN_CONN_CLOSED)) {
3310 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003311 int cur_idx, old_idx, delta, val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003312 struct hdr_idx_elem *cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003313
Willy Tarreaua15645d2007-03-18 16:22:39 +01003314 cur_next = rep->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
3315 old_idx = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003316
Willy Tarreaua15645d2007-03-18 16:22:39 +01003317 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
3318 cur_hdr = &txn->hdr_idx.v[cur_idx];
3319 cur_ptr = cur_next;
3320 cur_end = cur_ptr + cur_hdr->len;
3321 cur_next = cur_end + cur_hdr->cr + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003322
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003323 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
3324 if (val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003325 /* 3 possibilities :
3326 * - we have already set Connection: close,
3327 * so we remove this line.
3328 * - we have not yet set Connection: close,
3329 * but this line indicates close. We leave
3330 * it untouched and set the flag.
3331 * - we have not yet set Connection: close,
3332 * and this line indicates non-close. We
3333 * replace it.
3334 */
3335 if (t->flags & SN_CONN_CLOSED) {
3336 delta = buffer_replace2(rep, cur_ptr, cur_next, NULL, 0);
3337 txn->rsp.eoh += delta;
3338 cur_next += delta;
3339 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3340 txn->hdr_idx.used--;
3341 cur_hdr->len = 0;
3342 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003343 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
3344 delta = buffer_replace2(rep, cur_ptr + val, cur_end,
3345 "close", 5);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003346 cur_next += delta;
3347 cur_hdr->len += delta;
3348 txn->rsp.eoh += delta;
3349 }
3350 t->flags |= SN_CONN_CLOSED;
3351 }
3352 }
3353 old_idx = cur_idx;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003354 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003355 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003356
Willy Tarreaua15645d2007-03-18 16:22:39 +01003357 /* add response headers from the rule sets in the same order */
3358 for (cur_idx = 0; cur_idx < rule_set->nb_rspadd; cur_idx++) {
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003359 if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx,
3360 rule_set->rsp_add[cur_idx])) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003361 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003362 }
3363
Willy Tarreaua15645d2007-03-18 16:22:39 +01003364 /* check whether we're already working on the frontend */
3365 if (cur_proxy == t->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003366 break;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003367 cur_proxy = t->fe;
3368 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003369
Willy Tarreaua15645d2007-03-18 16:22:39 +01003370 /*
3371 * 4: check for server cookie.
3372 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003373 if (t->be->cookie_name || t->be->appsession_name || t->be->capture_name
3374 || (t->be->options & PR_O_CHK_CACHE))
3375 manage_server_side_cookies(t, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003376
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003377
Willy Tarreaua15645d2007-03-18 16:22:39 +01003378 /*
Willy Tarreau396d2c62007-11-04 19:30:00 +01003379 * 5: check for cache-control or pragma headers if required.
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003380 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003381 if ((t->be->options & (PR_O_COOK_NOC | PR_O_CHK_CACHE)) != 0)
3382 check_response_for_cacheability(t, rep);
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003383
3384 /*
3385 * 6: add server cookie in the response if needed
Willy Tarreaua15645d2007-03-18 16:22:39 +01003386 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003387 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
3388 (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003389 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003390
Willy Tarreaua15645d2007-03-18 16:22:39 +01003391 /* the server is known, it's not the one the client requested, we have to
3392 * insert a set-cookie here, except if we want to insert only on POST
3393 * requests and this one isn't. Note that servers which don't have cookies
3394 * (eg: some backup servers) will return a full cookie removal request.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003395 */
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003396 len = sprintf(trash, "Set-Cookie: %s=%s; path=/",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003397 t->be->cookie_name,
Willy Tarreaua15645d2007-03-18 16:22:39 +01003398 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003399
Krzysztof Piotr Oledzki1acf2172008-05-29 23:03:34 +02003400 if (t->be->cookie_domain)
3401 len += sprintf(trash+len, "; domain=%s", t->be->cookie_domain);
Krzysztof Piotr Oledzkiefe3b6f2008-05-23 23:49:32 +02003402
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003403 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3404 trash, len)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003405 goto return_bad_resp;
Willy Tarreau3d300592007-03-18 18:34:41 +01003406 txn->flags |= TX_SCK_INSERTED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003407
Willy Tarreaua15645d2007-03-18 16:22:39 +01003408 /* Here, we will tell an eventual cache on the client side that we don't
3409 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3410 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3411 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3412 */
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003413 if ((t->be->options & PR_O_COOK_NOC) && (txn->flags & TX_CACHEABLE)) {
3414
3415 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
3416
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003417 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3418 "Cache-control: private", 22)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003419 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003420 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003421 }
3422
3423
3424 /*
Willy Tarreaua15645d2007-03-18 16:22:39 +01003425 * 7: check if result will be cacheable with a cookie.
3426 * We'll block the response if security checks have caught
3427 * nasty things such as a cacheable cookie.
3428 */
Willy Tarreau3d300592007-03-18 18:34:41 +01003429 if (((txn->flags & (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) ==
3430 (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003431 (t->be->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003432
Willy Tarreaua15645d2007-03-18 16:22:39 +01003433 /* we're in presence of a cacheable response containing
3434 * a set-cookie header. We'll block it as requested by
3435 * the 'checkcache' option, and send an alert.
3436 */
3437 if (t->srv) {
3438 t->srv->cur_sess--;
3439 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003440 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003441 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003442 t->be->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003443
Willy Tarreaua15645d2007-03-18 16:22:39 +01003444 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003445 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003446 send_log(t->be, LOG_ALERT,
3447 "Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003448 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003449 goto return_srv_prx_502;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003450 }
3451
Willy Tarreaua15645d2007-03-18 16:22:39 +01003452 /*
3453 * 8: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02003454 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003455 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02003456 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003457 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02003458 if ((unlikely(msg->sl.st.v_l != 8) ||
3459 unlikely(req->data[msg->som + 7] != '0')) &&
3460 unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003461 "Connection: close", 17)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003462 goto return_bad_resp;
3463 t->flags |= SN_CONN_CLOSED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003464 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003465
Willy Tarreaubaaee002006-06-26 02:48:02 +02003466
Willy Tarreaua15645d2007-03-18 16:22:39 +01003467 /*************************************************************
3468 * OK, that's finished for the headers. We have done what we *
3469 * could. Let's switch to the DATA state. *
3470 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02003471
Willy Tarreaua15645d2007-03-18 16:22:39 +01003472 t->srv_state = SV_STDATA;
Willy Tarreau718f0ef2008-08-10 16:21:32 +02003473 rep->flags |= BF_MAY_FORWARD;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003474 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02003475 t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003476
3477 /* client connection already closed or option 'forceclose' required :
3478 * we close the server's outgoing connection right now.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003479 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003480 if ((req->l == 0) &&
Willy Tarreau6468d922008-08-03 19:15:35 +02003481 (req->flags & BF_SHUTR_STATUS || t->be->options & PR_O_FORCE_CLO)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003482 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003483 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003484
3485 /* We must ensure that the read part is still alive when switching
3486 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003487 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003488 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003489
Willy Tarreaua15645d2007-03-18 16:22:39 +01003490 shutdown(t->srv_fd, SHUT_WR);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003491 t->srv_state = SV_STSHUTW;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003492 }
3493
Willy Tarreaua15645d2007-03-18 16:22:39 +01003494#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003495 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003496 /* TCP splicing supported by both FE and BE */
3497 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003498 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003499#endif
3500 /* if the user wants to log as soon as possible, without counting
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003501 * bytes from the server, then this is the right moment. We have
3502 * to temporarily assign bytes_out to log what we currently have.
3503 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003504 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
3505 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreau8b3977f2008-01-18 11:16:32 +01003506 t->logs.bytes_out = txn->rsp.eoh;
Willy Tarreau42250582007-04-01 01:30:43 +02003507 if (t->fe->to_log & LW_REQ)
3508 http_sess_log(t);
3509 else
3510 tcp_sess_log(t);
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003511 t->logs.bytes_out = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003512 }
3513
Willy Tarreaua15645d2007-03-18 16:22:39 +01003514 /* Note: we must not try to cheat by jumping directly to DATA,
3515 * otherwise we would not let the client side wake up.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003516 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003517
3518 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003519 }
3520 else if (s == SV_STDATA) {
3521 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003522 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003523 buffer_shutr_done(rep);
3524 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003525 fd_delete(t->srv_fd);
3526 if (t->srv) {
3527 t->srv->cur_sess--;
3528 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003529 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003530 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003531 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003532 t->srv_state = SV_STCLOSE;
3533 if (!(t->flags & SN_ERR_MASK))
3534 t->flags |= SN_ERR_SRVCL;
3535 if (!(t->flags & SN_FINST_MASK))
3536 t->flags |= SN_FINST_D;
3537 /* We used to have a free connection slot. Since we'll never use it,
3538 * we have to inform the server that it may be used by another session.
3539 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003540 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003541 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003542
3543 return 1;
3544 }
3545 /* last read, or end of client write */
Willy Tarreau6468d922008-08-03 19:15:35 +02003546 else if (rep->flags & (BF_READ_NULL | BF_SHUTW_STATUS)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003547 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003548 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003549 t->srv_state = SV_STSHUTR;
3550 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3551 return 1;
3552 }
3553 /* end of client read and no more data to send */
Willy Tarreau6468d922008-08-03 19:15:35 +02003554 else if (req->flags & BF_SHUTR_STATUS && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003555 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003556 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003557 shutdown(t->srv_fd, SHUT_WR);
3558 /* We must ensure that the read part is still alive when switching
3559 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003560 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003561 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003562
3563 t->srv_state = SV_STSHUTW;
3564 return 1;
3565 }
3566 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003567 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003568 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003569 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003570 t->srv_state = SV_STSHUTR;
3571 if (!(t->flags & SN_ERR_MASK))
3572 t->flags |= SN_ERR_SRVTO;
3573 if (!(t->flags & SN_FINST_MASK))
3574 t->flags |= SN_FINST_D;
3575 return 1;
3576 }
3577 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003578 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003579 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003580 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003581 shutdown(t->srv_fd, SHUT_WR);
3582 /* We must ensure that the read part is still alive when switching
3583 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003584 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003585 rep->cex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003586 t->srv_state = SV_STSHUTW;
3587 if (!(t->flags & SN_ERR_MASK))
3588 t->flags |= SN_ERR_SRVTO;
3589 if (!(t->flags & SN_FINST_MASK))
3590 t->flags |= SN_FINST_D;
3591 return 1;
3592 }
3593
3594 /* recompute request time-outs */
3595 if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003596 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3597 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003598 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003599 }
3600 }
3601 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau66319382007-04-08 17:17:37 +02003602 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3603 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003604 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3605 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003606 /* FIXME: to prevent the server from expiring read timeouts during writes,
3607 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02003608 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003609 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003610 }
3611 }
3612
3613 /* recompute response time-outs */
3614 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003615 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003616 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003617 }
3618 }
3619 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003620 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003621 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003622 }
3623 }
3624
3625 return 0; /* other cases change nothing */
3626 }
3627 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003628 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003629 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003630 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003631 fd_delete(t->srv_fd);
3632 if (t->srv) {
3633 t->srv->cur_sess--;
3634 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003635 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003636 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003637 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003638 //close(t->srv_fd);
3639 t->srv_state = SV_STCLOSE;
3640 if (!(t->flags & SN_ERR_MASK))
3641 t->flags |= SN_ERR_SRVCL;
3642 if (!(t->flags & SN_FINST_MASK))
3643 t->flags |= SN_FINST_D;
3644 /* We used to have a free connection slot. Since we'll never use it,
3645 * we have to inform the server that it may be used by another session.
3646 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003647 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003648 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003649
3650 return 1;
3651 }
Willy Tarreau6468d922008-08-03 19:15:35 +02003652 else if (req->flags & BF_SHUTR_STATUS && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003653 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003654 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003655 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003656 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003657 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003658 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003659 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003660 //close(t->srv_fd);
3661 t->srv_state = SV_STCLOSE;
3662 /* We used to have a free connection slot. Since we'll never use it,
3663 * we have to inform the server that it may be used by another session.
3664 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003665 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003666 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003667
3668 return 1;
3669 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003670 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003671 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003672 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003673 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003674 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003675 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003676 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003677 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003678 //close(t->srv_fd);
3679 t->srv_state = SV_STCLOSE;
3680 if (!(t->flags & SN_ERR_MASK))
3681 t->flags |= SN_ERR_SRVTO;
3682 if (!(t->flags & SN_FINST_MASK))
3683 t->flags |= SN_FINST_D;
3684 /* We used to have a free connection slot. Since we'll never use it,
3685 * we have to inform the server that it may be used by another session.
3686 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003687 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003688 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003689
3690 return 1;
3691 }
3692 else if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003693 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3694 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003695 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003696 }
3697 }
3698 else { /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02003699 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3700 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003701 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003702 }
3703 }
3704 return 0;
3705 }
3706 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003707 if (rep->flags & BF_READ_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003708 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003709 buffer_shutr_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003710 fd_delete(t->srv_fd);
3711 if (t->srv) {
3712 t->srv->cur_sess--;
3713 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003714 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003715 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003716 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003717 //close(t->srv_fd);
3718 t->srv_state = SV_STCLOSE;
3719 if (!(t->flags & SN_ERR_MASK))
3720 t->flags |= SN_ERR_SRVCL;
3721 if (!(t->flags & SN_FINST_MASK))
3722 t->flags |= SN_FINST_D;
3723 /* We used to have a free connection slot. Since we'll never use it,
3724 * we have to inform the server that it may be used by another session.
3725 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003726 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003727 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003728
3729 return 1;
3730 }
Willy Tarreau6468d922008-08-03 19:15:35 +02003731 else if (rep->flags & (BF_READ_NULL | BF_SHUTW_STATUS)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003732 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003733 buffer_shutr_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003734 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003735 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003736 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003737 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003738 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003739 //close(t->srv_fd);
3740 t->srv_state = SV_STCLOSE;
3741 /* We used to have a free connection slot. Since we'll never use it,
3742 * we have to inform the server that it may be used by another session.
3743 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003744 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003745 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003746
3747 return 1;
3748 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003749 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003750 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003751 buffer_shutr_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003752 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003753 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003754 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003755 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003756 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003757 //close(t->srv_fd);
3758 t->srv_state = SV_STCLOSE;
3759 if (!(t->flags & SN_ERR_MASK))
3760 t->flags |= SN_ERR_SRVTO;
3761 if (!(t->flags & SN_FINST_MASK))
3762 t->flags |= SN_FINST_D;
3763 /* We used to have a free connection slot. Since we'll never use it,
3764 * we have to inform the server that it may be used by another session.
3765 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003766 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003767 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003768
3769 return 1;
3770 }
3771 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003772 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003773 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003774 }
3775 }
3776 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003777 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003778 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003779 }
3780 }
3781 return 0;
3782 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003783 else if (s == SV_STANALYZE){
3784 /* this server state is set by the client to study the body for server assignment */
3785
3786 /* Have we been through this long enough to timeout? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003787 if (!tick_is_expired(req->rex, now_ms)) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003788 /* balance url_param check_post should have been the only to get into this.
3789 * just wait for data, check to compare how much
3790 */
3791 struct http_msg * msg = &t->txn.req;
3792 unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 :msg->eoh + 1;
Willy Tarreaufb0528b2008-08-11 00:21:56 +02003793 unsigned long len = req->l - body;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003794 long long limit = t->be->url_param_post_limit;
3795 struct hdr_ctx ctx;
3796 ctx.idx = 0;
3797 /* now if we have a length, we'll take the hint */
3798 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
3799 if ( ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",ctx.vlen)==0) {
3800 unsigned int chunk = 0;
Willy Tarreaufb0528b2008-08-11 00:21:56 +02003801 while ( body < req->l && !HTTP_IS_CRLF(msg->sol[body])) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003802 char c = msg->sol[body];
3803 if (ishex(c)) {
3804 unsigned int hex = toupper(c) - '0';
3805 if ( hex > 9 )
3806 hex -= 'A' - '9' - 1;
3807 chunk = (chunk << 4) | hex;
3808 }
3809 else break;
3810 body++;
3811 len--;
3812 }
Willy Tarreaufb0528b2008-08-11 00:21:56 +02003813 if ( body + 2 >= req->l )
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003814 return 0; /* end of buffer? data missing! */
3815
3816 if ( memcmp(msg->sol+body, "\r\n", 2) != 0 )
3817 return 0; /* chunked encoding len ends with CRLF, and we don't have it yet */
3818
3819 /* if we support more then one chunk here, we have to do it again when assigning server
3820 1. how much entity data do we have? new var
3821 2. should save entity_start, entity_cursor, elen & rlen in req; so we don't repeat scanning here
3822 3. test if elen > limit, or set new limit to elen if 0 (end of entity found)
3823 */
3824
3825 if ( chunk < limit )
3826 limit = chunk; /* only reading one chunk */
3827 } else {
3828 if ( msg->hdr_content_len < limit )
3829 limit = msg->hdr_content_len;
3830 }
3831 if ( len < limit )
3832 return 0;
3833 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003834 t->srv_state = SV_STIDLE;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003835 return 1;
3836 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003837 else { /* SV_STCLOSE : nothing to do */
3838 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
3839 int len;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003840 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003841 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003842 write(1, trash, len);
3843 }
3844 return 0;
3845 }
3846 return 0;
3847}
3848
3849
3850/*
3851 * Produces data for the session <s> depending on its source. Expects to be
3852 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3853 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3854 * session, which it uses to keep on being called when there is free space in
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003855 * the buffer, or simply by letting an empty buffer upon return. It returns 1
Willy Tarreaubaaee002006-06-26 02:48:02 +02003856 * if it changes the session state from CL_STSHUTR, otherwise 0.
3857 */
3858int produce_content(struct session *s)
3859{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003860 if (s->data_source == DATA_SRC_NONE) {
3861 s->flags &= ~SN_SELF_GEN;
3862 return 1;
3863 }
3864 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003865 /* dump server statistics */
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01003866 int ret = stats_dump_http(s, s->be->uri_auth);
Willy Tarreau91861262007-10-17 17:06:05 +02003867 if (ret >= 0)
3868 return ret;
3869 /* -1 indicates an error */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003870 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003871
Willy Tarreau91861262007-10-17 17:06:05 +02003872 /* unknown data source or internal error */
3873 s->txn.status = 500;
3874 client_retnclose(s, error_message(s, HTTP_ERR_500));
3875 if (!(s->flags & SN_ERR_MASK))
3876 s->flags |= SN_ERR_PRXCOND;
3877 if (!(s->flags & SN_FINST_MASK))
3878 s->flags |= SN_FINST_R;
3879 s->flags &= ~SN_SELF_GEN;
3880 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003881}
3882
3883
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003884/* Iterate the same filter through all request headers.
3885 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003886 * Since it can manage the switch to another backend, it updates the per-proxy
3887 * DENY stats.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003888 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003889int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003890{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003891 char term;
3892 char *cur_ptr, *cur_end, *cur_next;
3893 int cur_idx, old_idx, last_hdr;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003894 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003895 struct hdr_idx_elem *cur_hdr;
3896 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003897
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003898 last_hdr = 0;
3899
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003900 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003901 old_idx = 0;
3902
3903 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01003904 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003905 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003906 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003907 (exp->action == ACT_ALLOW ||
3908 exp->action == ACT_DENY ||
3909 exp->action == ACT_TARPIT))
3910 return 0;
3911
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003912 cur_idx = txn->hdr_idx.v[old_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003913 if (!cur_idx)
3914 break;
3915
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003916 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003917 cur_ptr = cur_next;
3918 cur_end = cur_ptr + cur_hdr->len;
3919 cur_next = cur_end + cur_hdr->cr + 1;
3920
3921 /* Now we have one header between cur_ptr and cur_end,
3922 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003923 */
3924
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003925 /* The annoying part is that pattern matching needs
3926 * that we modify the contents to null-terminate all
3927 * strings before testing them.
3928 */
3929
3930 term = *cur_end;
3931 *cur_end = '\0';
3932
3933 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3934 switch (exp->action) {
3935 case ACT_SETBE:
3936 /* It is not possible to jump a second time.
3937 * FIXME: should we return an HTTP/500 here so that
3938 * the admin knows there's a problem ?
3939 */
3940 if (t->be != t->fe)
3941 break;
3942
3943 /* Swithing Proxy */
3944 t->be = (struct proxy *) exp->replace;
3945
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003946 /* right now, the backend switch is not overly complicated
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003947 * because we have associated req_cap and rsp_cap to the
3948 * frontend, and the beconn will be updated later.
3949 */
3950
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003951 t->rep->rto = t->req->wto = t->be->timeout.server;
3952 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02003953 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003954 last_hdr = 1;
3955 break;
3956
3957 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003958 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003959 last_hdr = 1;
3960 break;
3961
3962 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003963 txn->flags |= TX_CLDENY;
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_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003969 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003970 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003971 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003972 break;
3973
3974 case ACT_REPLACE:
3975 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3976 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3977 /* FIXME: if the user adds a newline in the replacement, the
3978 * index will not be recalculated for now, and the new line
3979 * will not be counted as a new header.
3980 */
3981
3982 cur_end += delta;
3983 cur_next += delta;
3984 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003985 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003986 break;
3987
3988 case ACT_REMOVE:
3989 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3990 cur_next += delta;
3991
3992 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003993 txn->req.eoh += delta;
3994 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3995 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003996 cur_hdr->len = 0;
3997 cur_end = NULL; /* null-term has been rewritten */
3998 break;
3999
4000 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004001 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004002 if (cur_end)
4003 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004004
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004005 /* keep the link from this header to next one in case of later
4006 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004007 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004008 old_idx = cur_idx;
4009 }
4010 return 0;
4011}
4012
4013
4014/* Apply the filter to the request line.
4015 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4016 * or -1 if a replacement resulted in an invalid request line.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004017 * Since it can manage the switch to another backend, it updates the per-proxy
4018 * DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004019 */
4020int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
4021{
4022 char term;
4023 char *cur_ptr, *cur_end;
4024 int done;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004025 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004026 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004027
Willy Tarreau58f10d72006-12-04 02:26:12 +01004028
Willy Tarreau3d300592007-03-18 18:34:41 +01004029 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004030 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004031 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004032 (exp->action == ACT_ALLOW ||
4033 exp->action == ACT_DENY ||
4034 exp->action == ACT_TARPIT))
4035 return 0;
4036 else if (exp->action == ACT_REMOVE)
4037 return 0;
4038
4039 done = 0;
4040
Willy Tarreau9cdde232007-05-02 20:58:19 +02004041 cur_ptr = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004042 cur_end = cur_ptr + txn->req.sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004043
4044 /* Now we have the request line between cur_ptr and cur_end */
4045
4046 /* The annoying part is that pattern matching needs
4047 * that we modify the contents to null-terminate all
4048 * strings before testing them.
4049 */
4050
4051 term = *cur_end;
4052 *cur_end = '\0';
4053
4054 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4055 switch (exp->action) {
4056 case ACT_SETBE:
4057 /* It is not possible to jump a second time.
4058 * FIXME: should we return an HTTP/500 here so that
4059 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01004060 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004061 if (t->be != t->fe)
4062 break;
4063
4064 /* Swithing Proxy */
4065 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004066
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004067 /* right now, the backend switch is not too much complicated
4068 * because we have associated req_cap and rsp_cap to the
4069 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004070 */
4071
Willy Tarreaud7c30f92007-12-03 01:38:36 +01004072 t->rep->rto = t->req->wto = t->be->timeout.server;
4073 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02004074 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004075 done = 1;
4076 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004077
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004078 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004079 txn->flags |= TX_CLALLOW;
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_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004084 txn->flags |= TX_CLDENY;
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_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01004090 txn->flags |= TX_CLTARPIT;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004091 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004092 done = 1;
4093 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004094
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004095 case ACT_REPLACE:
4096 *cur_end = term; /* restore the string terminator */
4097 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4098 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
4099 /* FIXME: if the user adds a newline in the replacement, the
4100 * index will not be recalculated for now, and the new line
4101 * will not be counted as a new header.
4102 */
Willy Tarreaua496b602006-12-17 23:15:24 +01004103
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004104 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004105 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01004106
Willy Tarreau9cdde232007-05-02 20:58:19 +02004107 txn->req.sol = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004108 cur_end = (char *)http_parse_reqline(&txn->req, req->data,
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004109 HTTP_MSG_RQMETH,
4110 cur_ptr, cur_end + 1,
4111 NULL, NULL);
4112 if (unlikely(!cur_end))
4113 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01004114
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004115 /* we have a full request and we know that we have either a CR
4116 * or an LF at <ptr>.
4117 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004118 txn->meth = find_http_meth(cur_ptr, txn->req.sl.rq.m_l);
4119 hdr_idx_set_start(&txn->hdr_idx, txn->req.sl.rq.l, *cur_end == '\r');
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004120 /* there is no point trying this regex on headers */
4121 return 1;
4122 }
4123 }
4124 *cur_end = term; /* restore the string terminator */
4125 return done;
4126}
Willy Tarreau97de6242006-12-27 17:18:38 +01004127
Willy Tarreau58f10d72006-12-04 02:26:12 +01004128
Willy Tarreau58f10d72006-12-04 02:26:12 +01004129
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004130/*
4131 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
4132 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
Willy Tarreaua15645d2007-03-18 16:22:39 +01004133 * unparsable request. Since it can manage the switch to another backend, it
4134 * updates the per-proxy DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004135 */
4136int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
4137{
Willy Tarreau3d300592007-03-18 18:34:41 +01004138 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004139 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004140 while (exp && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004141 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004142
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004143 /*
4144 * The interleaving of transformations and verdicts
4145 * makes it difficult to decide to continue or stop
4146 * the evaluation.
4147 */
4148
Willy Tarreau3d300592007-03-18 18:34:41 +01004149 if ((txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004150 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4151 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
4152 exp = exp->next;
4153 continue;
4154 }
4155
4156 /* Apply the filter to the request line. */
4157 ret = apply_filter_to_req_line(t, req, exp);
4158 if (unlikely(ret < 0))
4159 return -1;
4160
4161 if (likely(ret == 0)) {
4162 /* The filter did not match the request, it can be
4163 * iterated through all headers.
4164 */
4165 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004166 }
4167 exp = exp->next;
4168 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004169 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004170}
4171
4172
Willy Tarreaua15645d2007-03-18 16:22:39 +01004173
Willy Tarreau58f10d72006-12-04 02:26:12 +01004174/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004175 * Manage client-side cookie. It can impact performance by about 2% so it is
4176 * desirable to call it only when needed.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004177 */
4178void manage_client_side_cookies(struct session *t, struct buffer *req)
4179{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004180 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004181 char *p1, *p2, *p3, *p4;
4182 char *del_colon, *del_cookie, *colon;
4183 int app_cookies;
4184
4185 appsess *asession_temp = NULL;
4186 appsess local_asession;
4187
4188 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004189 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004190
Willy Tarreau2a324282006-12-05 00:05:46 +01004191 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004192 * we start with the start line.
4193 */
Willy Tarreau83969f42007-01-22 08:55:47 +01004194 old_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004195 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004196
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004197 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004198 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004199 int val;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004200
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004201 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01004202 cur_ptr = cur_next;
4203 cur_end = cur_ptr + cur_hdr->len;
4204 cur_next = cur_end + cur_hdr->cr + 1;
4205
4206 /* We have one full header between cur_ptr and cur_end, and the
4207 * next header starts at cur_next. We're only interested in
4208 * "Cookie:" headers.
4209 */
4210
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004211 val = http_header_match2(cur_ptr, cur_end, "Cookie", 6);
4212 if (!val) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004213 old_idx = cur_idx;
4214 continue;
4215 }
4216
4217 /* Now look for cookies. Conforming to RFC2109, we have to support
4218 * attributes whose name begin with a '$', and associate them with
4219 * the right cookie, if we want to delete this cookie.
4220 * So there are 3 cases for each cookie read :
4221 * 1) it's a special attribute, beginning with a '$' : ignore it.
4222 * 2) it's a server id cookie that we *MAY* want to delete : save
4223 * some pointers on it (last semi-colon, beginning of cookie...)
4224 * 3) it's an application cookie : we *MAY* have to delete a previous
4225 * "special" cookie.
4226 * At the end of loop, if a "special" cookie remains, we may have to
4227 * remove it. If no application cookie persists in the header, we
4228 * *MUST* delete it
4229 */
4230
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004231 colon = p1 = cur_ptr + val; /* first non-space char after 'Cookie:' */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004232
Willy Tarreau58f10d72006-12-04 02:26:12 +01004233 /* del_cookie == NULL => nothing to be deleted */
4234 del_colon = del_cookie = NULL;
4235 app_cookies = 0;
4236
4237 while (p1 < cur_end) {
4238 /* skip spaces and colons, but keep an eye on these ones */
4239 while (p1 < cur_end) {
4240 if (*p1 == ';' || *p1 == ',')
4241 colon = p1;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004242 else if (!isspace((unsigned char)*p1))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004243 break;
4244 p1++;
4245 }
4246
4247 if (p1 == cur_end)
4248 break;
4249
4250 /* p1 is at the beginning of the cookie name */
4251 p2 = p1;
4252 while (p2 < cur_end && *p2 != '=')
4253 p2++;
4254
4255 if (p2 == cur_end)
4256 break;
4257
4258 p3 = p2 + 1; /* skips the '=' sign */
4259 if (p3 == cur_end)
4260 break;
4261
4262 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004263 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';' && *p4 != ',')
Willy Tarreau58f10d72006-12-04 02:26:12 +01004264 p4++;
4265
4266 /* here, we have the cookie name between p1 and p2,
4267 * and its value between p3 and p4.
4268 * we can process it :
4269 *
4270 * Cookie: NAME=VALUE;
4271 * | || || |
4272 * | || || +--> p4
4273 * | || |+-------> p3
4274 * | || +--------> p2
4275 * | |+------------> p1
4276 * | +-------------> colon
4277 * +--------------------> cur_ptr
4278 */
4279
4280 if (*p1 == '$') {
4281 /* skip this one */
4282 }
4283 else {
4284 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004285 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004286 txn->cli_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004287 (p4 - p1 >= t->fe->capture_namelen) &&
4288 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004289 int log_len = p4 - p1;
4290
Willy Tarreau086b3b42007-05-13 21:45:51 +02004291 if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004292 Alert("HTTP logging : out of memory.\n");
4293 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004294 if (log_len > t->fe->capture_len)
4295 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004296 memcpy(txn->cli_cookie, p1, log_len);
4297 txn->cli_cookie[log_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004298 }
4299 }
4300
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004301 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4302 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004303 /* Cool... it's the right one */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004304 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004305 char *delim;
4306
4307 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4308 * have the server ID betweek p3 and delim, and the original cookie between
4309 * delim+1 and p4. Otherwise, delim==p4 :
4310 *
4311 * Cookie: NAME=SRV~VALUE;
4312 * | || || | |
4313 * | || || | +--> p4
4314 * | || || +--------> delim
4315 * | || |+-----------> p3
4316 * | || +------------> p2
4317 * | |+----------------> p1
4318 * | +-----------------> colon
4319 * +------------------------> cur_ptr
4320 */
4321
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004322 if (t->be->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004323 for (delim = p3; delim < p4; delim++)
4324 if (*delim == COOKIE_DELIM)
4325 break;
4326 }
4327 else
4328 delim = p4;
4329
4330
4331 /* Here, we'll look for the first running server which supports the cookie.
4332 * This allows to share a same cookie between several servers, for example
4333 * to dedicate backup servers to specific servers only.
4334 * However, to prevent clients from sticking to cookie-less backup server
4335 * when they have incidentely learned an empty cookie, we simply ignore
4336 * empty cookies and mark them as invalid.
4337 */
4338 if (delim == p3)
4339 srv = NULL;
4340
4341 while (srv) {
Willy Tarreau92f2ab12007-02-02 22:14:47 +01004342 if (srv->cookie && (srv->cklen == delim - p3) &&
4343 !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004344 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004345 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004346 txn->flags &= ~TX_CK_MASK;
4347 txn->flags |= TX_CK_VALID;
4348 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004349 t->srv = srv;
4350 break;
4351 } else {
4352 /* we found a server, but it's down */
Willy Tarreau3d300592007-03-18 18:34:41 +01004353 txn->flags &= ~TX_CK_MASK;
4354 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004355 }
4356 }
4357 srv = srv->next;
4358 }
4359
Willy Tarreau3d300592007-03-18 18:34:41 +01004360 if (!srv && !(txn->flags & TX_CK_DOWN)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004361 /* no server matched this cookie */
Willy Tarreau3d300592007-03-18 18:34:41 +01004362 txn->flags &= ~TX_CK_MASK;
4363 txn->flags |= TX_CK_INVALID;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004364 }
4365
4366 /* depending on the cookie mode, we may have to either :
4367 * - delete the complete cookie if we're in insert+indirect mode, so that
4368 * the server never sees it ;
4369 * - remove the server id from the cookie value, and tag the cookie as an
4370 * application cookie so that it does not get accidentely removed later,
4371 * if we're in cookie prefix mode
4372 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004373 if ((t->be->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004374 int delta; /* negative */
4375
4376 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
4377 p4 += delta;
4378 cur_end += delta;
4379 cur_next += delta;
4380 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004381 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004382
4383 del_cookie = del_colon = NULL;
4384 app_cookies++; /* protect the header from deletion */
4385 }
4386 else if (del_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004387 (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 +01004388 del_cookie = p1;
4389 del_colon = colon;
4390 }
4391 } else {
4392 /* now we know that we must keep this cookie since it's
4393 * not ours. But if we wanted to delete our cookie
4394 * earlier, we cannot remove the complete header, but we
4395 * can remove the previous block itself.
4396 */
4397 app_cookies++;
4398
4399 if (del_cookie != NULL) {
4400 int delta; /* negative */
4401
4402 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
4403 p4 += delta;
4404 cur_end += delta;
4405 cur_next += delta;
4406 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004407 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004408 del_cookie = del_colon = NULL;
4409 }
4410 }
4411
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004412 if ((t->be->appsession_name != NULL) &&
4413 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004414 /* first, let's see if the cookie is our appcookie*/
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004415
Willy Tarreau58f10d72006-12-04 02:26:12 +01004416 /* Cool... it's the right one */
4417
4418 asession_temp = &local_asession;
4419
Willy Tarreau63963c62007-05-13 21:29:55 +02004420 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004421 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4422 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4423 return;
4424 }
4425
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004426 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4427 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004428 asession_temp->serverid = NULL;
Willy Tarreau51041c72007-09-09 21:56:53 +02004429
Willy Tarreau58f10d72006-12-04 02:26:12 +01004430 /* only do insert, if lookup fails */
Willy Tarreau51041c72007-09-09 21:56:53 +02004431 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4432 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004433 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004434 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004435 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004436 Alert("Not enough memory process_cli():asession:calloc().\n");
4437 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4438 return;
4439 }
4440
4441 asession_temp->sessid = local_asession.sessid;
4442 asession_temp->serverid = local_asession.serverid;
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004443 asession_temp->request_count = 0;
Willy Tarreau51041c72007-09-09 21:56:53 +02004444 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004445 } else {
4446 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004447 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004448 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004449 if (asession_temp->serverid == NULL) {
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004450 /* TODO redispatch request */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004451 Alert("Found Application Session without matching server.\n");
4452 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004453 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004454 while (srv) {
4455 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004456 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004457 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004458 txn->flags &= ~TX_CK_MASK;
4459 txn->flags |= TX_CK_VALID;
4460 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004461 t->srv = srv;
4462 break;
4463 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01004464 txn->flags &= ~TX_CK_MASK;
4465 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004466 }
4467 }
4468 srv = srv->next;
4469 }/* end while(srv) */
4470 }/* end else if server == NULL */
4471
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004472 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004473 asession_temp->request_count++;
4474#if defined(DEBUG_HASH)
4475 Alert("manage_client_side_cookies\n");
4476 appsession_hash_dump(&(t->be->htbl_proxy));
4477#endif
Willy Tarreau58f10d72006-12-04 02:26:12 +01004478 }/* end if ((t->proxy->appsession_name != NULL) ... */
4479 }
4480
4481 /* we'll have to look for another cookie ... */
4482 p1 = p4;
4483 } /* while (p1 < cur_end) */
4484
4485 /* There's no more cookie on this line.
4486 * We may have marked the last one(s) for deletion.
4487 * We must do this now in two ways :
4488 * - if there is no app cookie, we simply delete the header ;
4489 * - if there are app cookies, we must delete the end of the
4490 * string properly, including the colon/semi-colon before
4491 * the cookie name.
4492 */
4493 if (del_cookie != NULL) {
4494 int delta;
4495 if (app_cookies) {
4496 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
4497 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004498 cur_hdr->len += delta;
4499 } else {
4500 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004501
4502 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004503 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4504 txn->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004505 cur_hdr->len = 0;
4506 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01004507 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004508 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004509 }
4510
4511 /* keep the link from this header to next one */
4512 old_idx = cur_idx;
4513 } /* end of cookie processing on this header */
4514}
4515
4516
Willy Tarreaua15645d2007-03-18 16:22:39 +01004517/* Iterate the same filter through all response headers contained in <rtr>.
4518 * Returns 1 if this filter can be stopped upon return, otherwise 0.
4519 */
4520int apply_filter_to_resp_headers(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4521{
4522 char term;
4523 char *cur_ptr, *cur_end, *cur_next;
4524 int cur_idx, old_idx, last_hdr;
4525 struct http_txn *txn = &t->txn;
4526 struct hdr_idx_elem *cur_hdr;
4527 int len, delta;
4528
4529 last_hdr = 0;
4530
4531 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4532 old_idx = 0;
4533
4534 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004535 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004536 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004537 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004538 (exp->action == ACT_ALLOW ||
4539 exp->action == ACT_DENY))
4540 return 0;
4541
4542 cur_idx = txn->hdr_idx.v[old_idx].next;
4543 if (!cur_idx)
4544 break;
4545
4546 cur_hdr = &txn->hdr_idx.v[cur_idx];
4547 cur_ptr = cur_next;
4548 cur_end = cur_ptr + cur_hdr->len;
4549 cur_next = cur_end + cur_hdr->cr + 1;
4550
4551 /* Now we have one header between cur_ptr and cur_end,
4552 * and the next header starts at cur_next.
4553 */
4554
4555 /* The annoying part is that pattern matching needs
4556 * that we modify the contents to null-terminate all
4557 * strings before testing them.
4558 */
4559
4560 term = *cur_end;
4561 *cur_end = '\0';
4562
4563 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4564 switch (exp->action) {
4565 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004566 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004567 last_hdr = 1;
4568 break;
4569
4570 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004571 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004572 last_hdr = 1;
4573 break;
4574
4575 case ACT_REPLACE:
4576 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4577 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4578 /* FIXME: if the user adds a newline in the replacement, the
4579 * index will not be recalculated for now, and the new line
4580 * will not be counted as a new header.
4581 */
4582
4583 cur_end += delta;
4584 cur_next += delta;
4585 cur_hdr->len += delta;
4586 txn->rsp.eoh += delta;
4587 break;
4588
4589 case ACT_REMOVE:
4590 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4591 cur_next += delta;
4592
4593 /* FIXME: this should be a separate function */
4594 txn->rsp.eoh += delta;
4595 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4596 txn->hdr_idx.used--;
4597 cur_hdr->len = 0;
4598 cur_end = NULL; /* null-term has been rewritten */
4599 break;
4600
4601 }
4602 }
4603 if (cur_end)
4604 *cur_end = term; /* restore the string terminator */
4605
4606 /* keep the link from this header to next one in case of later
4607 * removal of next header.
4608 */
4609 old_idx = cur_idx;
4610 }
4611 return 0;
4612}
4613
4614
4615/* Apply the filter to the status line in the response buffer <rtr>.
4616 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4617 * or -1 if a replacement resulted in an invalid status line.
4618 */
4619int apply_filter_to_sts_line(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4620{
4621 char term;
4622 char *cur_ptr, *cur_end;
4623 int done;
4624 struct http_txn *txn = &t->txn;
4625 int len, delta;
4626
4627
Willy Tarreau3d300592007-03-18 18:34:41 +01004628 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004629 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004630 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004631 (exp->action == ACT_ALLOW ||
4632 exp->action == ACT_DENY))
4633 return 0;
4634 else if (exp->action == ACT_REMOVE)
4635 return 0;
4636
4637 done = 0;
4638
Willy Tarreau9cdde232007-05-02 20:58:19 +02004639 cur_ptr = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004640 cur_end = cur_ptr + txn->rsp.sl.rq.l;
4641
4642 /* Now we have the status line between cur_ptr and cur_end */
4643
4644 /* The annoying part is that pattern matching needs
4645 * that we modify the contents to null-terminate all
4646 * strings before testing them.
4647 */
4648
4649 term = *cur_end;
4650 *cur_end = '\0';
4651
4652 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4653 switch (exp->action) {
4654 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004655 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004656 done = 1;
4657 break;
4658
4659 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004660 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004661 done = 1;
4662 break;
4663
4664 case ACT_REPLACE:
4665 *cur_end = term; /* restore the string terminator */
4666 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4667 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4668 /* FIXME: if the user adds a newline in the replacement, the
4669 * index will not be recalculated for now, and the new line
4670 * will not be counted as a new header.
4671 */
4672
4673 txn->rsp.eoh += delta;
4674 cur_end += delta;
4675
Willy Tarreau9cdde232007-05-02 20:58:19 +02004676 txn->rsp.sol = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004677 cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data,
Willy Tarreau02785762007-04-03 14:45:44 +02004678 HTTP_MSG_RPVER,
Willy Tarreaua15645d2007-03-18 16:22:39 +01004679 cur_ptr, cur_end + 1,
4680 NULL, NULL);
4681 if (unlikely(!cur_end))
4682 return -1;
4683
4684 /* we have a full respnse and we know that we have either a CR
4685 * or an LF at <ptr>.
4686 */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004687 txn->status = strl2ui(rtr->data + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004688 hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.rq.l, *cur_end == '\r');
4689 /* there is no point trying this regex on headers */
4690 return 1;
4691 }
4692 }
4693 *cur_end = term; /* restore the string terminator */
4694 return done;
4695}
4696
4697
4698
4699/*
4700 * Apply all the resp filters <exp> to all headers in buffer <rtr> of session <t>.
4701 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
4702 * unparsable response.
4703 */
4704int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4705{
Willy Tarreau3d300592007-03-18 18:34:41 +01004706 struct http_txn *txn = &t->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004707 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004708 while (exp && !(txn->flags & TX_SVDENY)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004709 int ret;
4710
4711 /*
4712 * The interleaving of transformations and verdicts
4713 * makes it difficult to decide to continue or stop
4714 * the evaluation.
4715 */
4716
Willy Tarreau3d300592007-03-18 18:34:41 +01004717 if ((txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004718 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4719 exp->action == ACT_PASS)) {
4720 exp = exp->next;
4721 continue;
4722 }
4723
4724 /* Apply the filter to the status line. */
4725 ret = apply_filter_to_sts_line(t, rtr, exp);
4726 if (unlikely(ret < 0))
4727 return -1;
4728
4729 if (likely(ret == 0)) {
4730 /* The filter did not match the response, it can be
4731 * iterated through all headers.
4732 */
4733 apply_filter_to_resp_headers(t, rtr, exp);
4734 }
4735 exp = exp->next;
4736 }
4737 return 0;
4738}
4739
4740
4741
4742/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004743 * Manage server-side cookies. It can impact performance by about 2% so it is
4744 * desirable to call it only when needed.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004745 */
4746void manage_server_side_cookies(struct session *t, struct buffer *rtr)
4747{
4748 struct http_txn *txn = &t->txn;
4749 char *p1, *p2, *p3, *p4;
4750
4751 appsess *asession_temp = NULL;
4752 appsess local_asession;
4753
4754 char *cur_ptr, *cur_end, *cur_next;
4755 int cur_idx, old_idx, delta;
4756
Willy Tarreaua15645d2007-03-18 16:22:39 +01004757 /* Iterate through the headers.
4758 * we start with the start line.
4759 */
4760 old_idx = 0;
4761 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4762
4763 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
4764 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004765 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004766
4767 cur_hdr = &txn->hdr_idx.v[cur_idx];
4768 cur_ptr = cur_next;
4769 cur_end = cur_ptr + cur_hdr->len;
4770 cur_next = cur_end + cur_hdr->cr + 1;
4771
4772 /* We have one full header between cur_ptr and cur_end, and the
4773 * next header starts at cur_next. We're only interested in
4774 * "Cookie:" headers.
4775 */
4776
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004777 val = http_header_match2(cur_ptr, cur_end, "Set-Cookie", 10);
4778 if (!val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004779 old_idx = cur_idx;
4780 continue;
4781 }
4782
4783 /* OK, right now we know we have a set-cookie at cur_ptr */
Willy Tarreau3d300592007-03-18 18:34:41 +01004784 txn->flags |= TX_SCK_ANY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004785
4786
4787 /* maybe we only wanted to see if there was a set-cookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004788 if (t->be->cookie_name == NULL &&
4789 t->be->appsession_name == NULL &&
4790 t->be->capture_name == NULL)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004791 return;
4792
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004793 p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004794
4795 while (p1 < cur_end) { /* in fact, we'll break after the first cookie */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004796 if (p1 == cur_end || *p1 == ';') /* end of cookie */
4797 break;
4798
4799 /* p1 is at the beginning of the cookie name */
4800 p2 = p1;
4801
4802 while (p2 < cur_end && *p2 != '=' && *p2 != ';')
4803 p2++;
4804
4805 if (p2 == cur_end || *p2 == ';') /* next cookie */
4806 break;
4807
4808 p3 = p2 + 1; /* skip the '=' sign */
4809 if (p3 == cur_end)
4810 break;
4811
4812 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004813 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';')
Willy Tarreaua15645d2007-03-18 16:22:39 +01004814 p4++;
4815
4816 /* here, we have the cookie name between p1 and p2,
4817 * and its value between p3 and p4.
4818 * we can process it.
4819 */
4820
4821 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004822 if (t->be->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004823 txn->srv_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004824 (p4 - p1 >= t->be->capture_namelen) &&
4825 memcmp(p1, t->be->capture_name, t->be->capture_namelen) == 0) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004826 int log_len = p4 - p1;
4827
Willy Tarreau086b3b42007-05-13 21:45:51 +02004828 if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004829 Alert("HTTP logging : out of memory.\n");
4830 }
4831
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004832 if (log_len > t->be->capture_len)
4833 log_len = t->be->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004834 memcpy(txn->srv_cookie, p1, log_len);
4835 txn->srv_cookie[log_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004836 }
4837
4838 /* now check if we need to process it for persistence */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004839 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4840 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004841 /* Cool... it's the right one */
Willy Tarreau3d300592007-03-18 18:34:41 +01004842 txn->flags |= TX_SCK_SEEN;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004843
4844 /* If the cookie is in insert mode on a known server, we'll delete
4845 * this occurrence because we'll insert another one later.
4846 * We'll delete it too if the "indirect" option is set and we're in
4847 * a direct access. */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004848 if (((t->srv) && (t->be->options & PR_O_COOK_INS)) ||
4849 ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004850 /* this header must be deleted */
4851 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4852 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4853 txn->hdr_idx.used--;
4854 cur_hdr->len = 0;
4855 cur_next += delta;
4856 txn->rsp.eoh += delta;
4857
Willy Tarreau3d300592007-03-18 18:34:41 +01004858 txn->flags |= TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004859 }
4860 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004861 (t->be->options & PR_O_COOK_RW)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004862 /* replace bytes p3->p4 with the cookie name associated
4863 * with this server since we know it.
4864 */
4865 delta = buffer_replace2(rtr, p3, p4, t->srv->cookie, t->srv->cklen);
4866 cur_hdr->len += delta;
4867 cur_next += delta;
4868 txn->rsp.eoh += delta;
4869
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 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004873 (t->be->options & PR_O_COOK_PFX)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004874 /* insert the cookie name associated with this server
4875 * before existing cookie, and insert a delimitor between them..
4876 */
4877 delta = buffer_replace2(rtr, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4878 cur_hdr->len += delta;
4879 cur_next += delta;
4880 txn->rsp.eoh += delta;
4881
4882 p3[t->srv->cklen] = COOKIE_DELIM;
Willy Tarreau3d300592007-03-18 18:34:41 +01004883 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004884 }
4885 }
4886 /* next, let's see if the cookie is our appcookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004887 else if ((t->be->appsession_name != NULL) &&
4888 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004889
4890 /* Cool... it's the right one */
4891
4892 size_t server_id_len = strlen(t->srv->id) + 1;
4893 asession_temp = &local_asession;
4894
Willy Tarreau63963c62007-05-13 21:29:55 +02004895 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004896 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4897 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4898 return;
4899 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004900 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4901 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004902 asession_temp->serverid = NULL;
4903
4904 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01004905 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4906 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004907 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004908 Alert("Not enough Memory process_srv():asession:calloc().\n");
4909 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
4910 return;
4911 }
4912 asession_temp->sessid = local_asession.sessid;
4913 asession_temp->serverid = local_asession.serverid;
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004914 asession_temp->request_count = 0;
Willy Tarreau51041c72007-09-09 21:56:53 +02004915 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
4916 } else {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004917 /* free wasted memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004918 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau51041c72007-09-09 21:56:53 +02004919 }
4920
Willy Tarreaua15645d2007-03-18 16:22:39 +01004921 if (asession_temp->serverid == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004922 if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004923 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4924 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4925 return;
4926 }
4927 asession_temp->serverid[0] = '\0';
4928 }
4929
4930 if (asession_temp->serverid[0] == '\0')
4931 memcpy(asession_temp->serverid, t->srv->id, server_id_len);
4932
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004933 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004934 asession_temp->request_count++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004935#if defined(DEBUG_HASH)
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004936 Alert("manage_server_side_cookies\n");
Willy Tarreau51041c72007-09-09 21:56:53 +02004937 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreaua15645d2007-03-18 16:22:39 +01004938#endif
4939 }/* end if ((t->proxy->appsession_name != NULL) ... */
4940 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4941 } /* we're now at the end of the cookie value */
4942
4943 /* keep the link from this header to next one */
4944 old_idx = cur_idx;
4945 } /* end of cookie processing on this header */
4946}
4947
4948
4949
4950/*
4951 * Check if response is cacheable or not. Updates t->flags.
4952 */
4953void check_response_for_cacheability(struct session *t, struct buffer *rtr)
4954{
4955 struct http_txn *txn = &t->txn;
4956 char *p1, *p2;
4957
4958 char *cur_ptr, *cur_end, *cur_next;
4959 int cur_idx;
4960
Willy Tarreau5df51872007-11-25 16:20:08 +01004961 if (!(txn->flags & TX_CACHEABLE))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004962 return;
4963
4964 /* Iterate through the headers.
4965 * we start with the start line.
4966 */
4967 cur_idx = 0;
4968 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4969
4970 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
4971 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004972 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004973
4974 cur_hdr = &txn->hdr_idx.v[cur_idx];
4975 cur_ptr = cur_next;
4976 cur_end = cur_ptr + cur_hdr->len;
4977 cur_next = cur_end + cur_hdr->cr + 1;
4978
4979 /* We have one full header between cur_ptr and cur_end, and the
4980 * next header starts at cur_next. We're only interested in
4981 * "Cookie:" headers.
4982 */
4983
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004984 val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
4985 if (val) {
4986 if ((cur_end - (cur_ptr + val) >= 8) &&
4987 strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
4988 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
4989 return;
4990 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01004991 }
4992
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004993 val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
4994 if (!val)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004995 continue;
4996
4997 /* OK, right now we know we have a cache-control header at cur_ptr */
4998
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004999 p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01005000
5001 if (p1 >= cur_end) /* no more info */
5002 continue;
5003
5004 /* p1 is at the beginning of the value */
5005 p2 = p1;
5006
Willy Tarreau8f8e6452007-06-17 21:51:38 +02005007 while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((unsigned char)*p2))
Willy Tarreaua15645d2007-03-18 16:22:39 +01005008 p2++;
5009
5010 /* we have a complete value between p1 and p2 */
5011 if (p2 < cur_end && *p2 == '=') {
5012 /* we have something of the form no-cache="set-cookie" */
5013 if ((cur_end - p1 >= 21) &&
5014 strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0
5015 && (p1[20] == '"' || p1[20] == ','))
Willy Tarreau3d300592007-03-18 18:34:41 +01005016 txn->flags &= ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005017 continue;
5018 }
5019
5020 /* OK, so we know that either p2 points to the end of string or to a comma */
5021 if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) ||
5022 ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) ||
5023 ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) ||
5024 ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005025 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005026 return;
5027 }
5028
5029 if ((p2 - p1 == 6) && strncasecmp(p1, "public", 6) == 0) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005030 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005031 continue;
5032 }
5033 }
5034}
5035
5036
Willy Tarreau58f10d72006-12-04 02:26:12 +01005037/*
5038 * Try to retrieve a known appsession in the URI, then the associated server.
5039 * If the server is found, it's assigned to the session.
5040 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005041void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01005042{
Willy Tarreau3d300592007-03-18 18:34:41 +01005043 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005044 appsess *asession_temp = NULL;
5045 appsess local_asession;
5046 char *request_line;
5047
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005048 if (t->be->appsession_name == NULL ||
Willy Tarreaub326fcc2007-03-03 13:54:32 +01005049 (t->txn.meth != HTTP_METH_GET && t->txn.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005050 (request_line = memchr(begin, ';', len)) == NULL ||
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005051 ((1 + t->be->appsession_name_len + 1 + t->be->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01005052 return;
5053
5054 /* skip ';' */
5055 request_line++;
5056
5057 /* look if we have a jsessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005058 if (strncasecmp(request_line, t->be->appsession_name, t->be->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01005059 return;
5060
5061 /* skip jsessionid= */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005062 request_line += t->be->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005063
5064 /* First try if we already have an appsession */
5065 asession_temp = &local_asession;
5066
Willy Tarreau63963c62007-05-13 21:29:55 +02005067 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005068 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
5069 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
5070 return;
5071 }
5072
5073 /* Copy the sessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005074 memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
5075 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005076 asession_temp->serverid = NULL;
5077
5078 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01005079 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
5080 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02005081 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005082 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005083 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005084 Alert("Not enough memory process_cli():asession:calloc().\n");
5085 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
5086 return;
5087 }
5088 asession_temp->sessid = local_asession.sessid;
5089 asession_temp->serverid = local_asession.serverid;
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02005090 asession_temp->request_count=0;
Willy Tarreau51041c72007-09-09 21:56:53 +02005091 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005092 }
5093 else {
5094 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005095 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005096 }
Willy Tarreau51041c72007-09-09 21:56:53 +02005097
Willy Tarreau0c303ee2008-07-07 00:09:58 +02005098 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005099 asession_temp->request_count++;
Willy Tarreau51041c72007-09-09 21:56:53 +02005100
Willy Tarreau58f10d72006-12-04 02:26:12 +01005101#if defined(DEBUG_HASH)
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02005102 Alert("get_srv_from_appsession\n");
Willy Tarreau51041c72007-09-09 21:56:53 +02005103 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreau58f10d72006-12-04 02:26:12 +01005104#endif
5105 if (asession_temp->serverid == NULL) {
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02005106 /* TODO redispatch request */
Willy Tarreau58f10d72006-12-04 02:26:12 +01005107 Alert("Found Application Session without matching server.\n");
5108 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005109 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005110 while (srv) {
5111 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005112 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005113 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01005114 txn->flags &= ~TX_CK_MASK;
5115 txn->flags |= TX_CK_VALID;
5116 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005117 t->srv = srv;
5118 break;
5119 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01005120 txn->flags &= ~TX_CK_MASK;
5121 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005122 }
5123 }
5124 srv = srv->next;
5125 }
5126 }
5127}
5128
5129
Willy Tarreaub2513902006-12-17 14:52:38 +01005130/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005131 * In a GET or HEAD request, check if the requested URI matches the stats uri
5132 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01005133 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005134 * It is assumed that the request is either a HEAD or GET and that the
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005135 * t->be->uri_auth field is valid. An HTTP/401 response may be sent, or
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005136 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01005137 *
5138 * Returns 1 if the session's state changes, otherwise 0.
5139 */
5140int stats_check_uri_auth(struct session *t, struct proxy *backend)
5141{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005142 struct http_txn *txn = &t->txn;
Willy Tarreaub2513902006-12-17 14:52:38 +01005143 struct uri_auth *uri_auth = backend->uri_auth;
5144 struct user_auth *user;
5145 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005146 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01005147
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005148 memset(&t->data_ctx.stats, 0, sizeof(t->data_ctx.stats));
5149
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005150 /* check URI size */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005151 if (uri_auth->uri_len > txn->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01005152 return 0;
5153
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005154 h = t->req->data + txn->req.sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005155
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005156 /* the URI is in h */
5157 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01005158 return 0;
5159
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005160 h += uri_auth->uri_len;
5161 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 3) {
5162 if (memcmp(h, ";up", 3) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005163 t->data_ctx.stats.flags |= STAT_HIDE_DOWN;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005164 break;
5165 }
5166 h++;
5167 }
5168
5169 if (uri_auth->refresh) {
5170 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5171 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 10) {
5172 if (memcmp(h, ";norefresh", 10) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005173 t->data_ctx.stats.flags |= STAT_NO_REFRESH;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005174 break;
5175 }
5176 h++;
5177 }
5178 }
5179
Willy Tarreau55bb8452007-10-17 18:44:57 +02005180 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5181 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 4) {
5182 if (memcmp(h, ";csv", 4) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005183 t->data_ctx.stats.flags |= STAT_FMT_CSV;
Willy Tarreau55bb8452007-10-17 18:44:57 +02005184 break;
5185 }
5186 h++;
5187 }
5188
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005189 t->data_ctx.stats.flags |= STAT_SHOW_STAT | STAT_SHOW_INFO;
5190
Willy Tarreaub2513902006-12-17 14:52:38 +01005191 /* we are in front of a interceptable URI. Let's check
5192 * if there's an authentication and if it's valid.
5193 */
5194 user = uri_auth->users;
5195 if (!user) {
5196 /* no user auth required, it's OK */
5197 authenticated = 1;
5198 } else {
5199 authenticated = 0;
5200
5201 /* a user list is defined, we have to check.
5202 * skip 21 chars for "Authorization: Basic ".
5203 */
5204
5205 /* FIXME: this should move to an earlier place */
5206 cur_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005207 h = t->req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
5208 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
5209 int len = txn->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005210 if (len > 14 &&
5211 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005212 txn->auth_hdr.str = h;
5213 txn->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005214 break;
5215 }
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005216 h += len + txn->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01005217 }
5218
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005219 if (txn->auth_hdr.len < 21 ||
5220 memcmp(txn->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01005221 user = NULL;
5222
5223 while (user) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005224 if ((txn->auth_hdr.len == user->user_len + 14 + 7)
5225 && !memcmp(txn->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01005226 user->user_pwd, user->user_len)) {
5227 authenticated = 1;
5228 break;
5229 }
5230 user = user->next;
5231 }
5232 }
5233
5234 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01005235 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01005236
5237 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01005238 msg.str = trash;
5239 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005240 txn->status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01005241 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01005242 if (!(t->flags & SN_ERR_MASK))
5243 t->flags |= SN_ERR_PRXCOND;
5244 if (!(t->flags & SN_FINST_MASK))
5245 t->flags |= SN_FINST_R;
5246 return 1;
5247 }
5248
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005249 /* The request is valid, the user is authenticated. Let's start sending
Willy Tarreaub2513902006-12-17 14:52:38 +01005250 * data.
5251 */
Willy Tarreau284c7b32008-06-29 16:38:43 +02005252 EV_FD_CLR(t->cli_fd, DIR_RD);
5253 buffer_shutr(t->req);
5254 buffer_shutr(t->rep);
Willy Tarreaub2513902006-12-17 14:52:38 +01005255 t->cli_state = CL_STSHUTR;
5256 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau70089872008-06-13 21:12:51 +02005257 t->logs.tv_request = now;
Willy Tarreaub2513902006-12-17 14:52:38 +01005258 t->data_source = DATA_SRC_STATS;
5259 t->data_state = DATA_ST_INIT;
Willy Tarreau91e99932008-06-30 07:51:00 +02005260 t->task->nice = -32; /* small boost for HTTP statistics */
Willy Tarreaub2513902006-12-17 14:52:38 +01005261 produce_content(t);
5262 return 1;
5263}
5264
5265
Willy Tarreaubaaee002006-06-26 02:48:02 +02005266/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01005267 * Print a debug line with a header
5268 */
5269void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
5270{
5271 int len, max;
5272 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
5273 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
5274 max = end - start;
5275 UBOUND(max, sizeof(trash) - len - 1);
5276 len += strlcpy2(trash + len, start, max + 1);
5277 trash[len++] = '\n';
5278 write(1, trash, len);
5279}
5280
5281
Willy Tarreau8797c062007-05-07 00:55:35 +02005282/************************************************************************/
5283/* The code below is dedicated to ACL parsing and matching */
5284/************************************************************************/
5285
5286
5287
5288
5289/* 1. Check on METHOD
5290 * We use the pre-parsed method if it is known, and store its number as an
5291 * integer. If it is unknown, we use the pointer and the length.
5292 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005293static int acl_parse_meth(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005294{
5295 int len, meth;
5296
Willy Tarreauae8b7962007-06-09 23:10:04 +02005297 len = strlen(*text);
5298 meth = find_http_meth(*text, len);
Willy Tarreau8797c062007-05-07 00:55:35 +02005299
5300 pattern->val.i = meth;
5301 if (meth == HTTP_METH_OTHER) {
Willy Tarreauae8b7962007-06-09 23:10:04 +02005302 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005303 if (!pattern->ptr.str)
5304 return 0;
5305 pattern->len = len;
5306 }
5307 return 1;
5308}
5309
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005310static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005311acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
5312 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005313{
5314 int meth;
5315 struct http_txn *txn = l7;
5316
Willy Tarreaub6866442008-07-14 23:54:42 +02005317 if (!txn)
5318 return 0;
5319
Willy Tarreauc11416f2007-06-17 16:58:38 +02005320 if (txn->req.msg_state != HTTP_MSG_BODY)
5321 return 0;
5322
Willy Tarreau8797c062007-05-07 00:55:35 +02005323 meth = txn->meth;
5324 test->i = meth;
5325 if (meth == HTTP_METH_OTHER) {
Willy Tarreauc11416f2007-06-17 16:58:38 +02005326 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5327 /* ensure the indexes are not affected */
5328 return 0;
Willy Tarreau8797c062007-05-07 00:55:35 +02005329 test->len = txn->req.sl.rq.m_l;
5330 test->ptr = txn->req.sol;
5331 }
5332 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5333 return 1;
5334}
5335
5336static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
5337{
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005338 int icase;
5339
Willy Tarreau8797c062007-05-07 00:55:35 +02005340 if (test->i != pattern->val.i)
Willy Tarreau11382812008-07-09 16:18:21 +02005341 return ACL_PAT_FAIL;
Willy Tarreau8797c062007-05-07 00:55:35 +02005342
5343 if (test->i != HTTP_METH_OTHER)
Willy Tarreau11382812008-07-09 16:18:21 +02005344 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005345
5346 /* Other method, we must compare the strings */
5347 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +02005348 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005349
5350 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
5351 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) != 0) ||
5352 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +02005353 return ACL_PAT_FAIL;
5354 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005355}
5356
5357/* 2. Check on Request/Status Version
5358 * We simply compare strings here.
5359 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005360static int acl_parse_ver(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005361{
Willy Tarreauae8b7962007-06-09 23:10:04 +02005362 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005363 if (!pattern->ptr.str)
5364 return 0;
Willy Tarreauae8b7962007-06-09 23:10:04 +02005365 pattern->len = strlen(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005366 return 1;
5367}
5368
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005369static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005370acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
5371 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005372{
5373 struct http_txn *txn = l7;
5374 char *ptr;
5375 int len;
5376
Willy Tarreaub6866442008-07-14 23:54:42 +02005377 if (!txn)
5378 return 0;
5379
Willy Tarreauc11416f2007-06-17 16:58:38 +02005380 if (txn->req.msg_state != HTTP_MSG_BODY)
5381 return 0;
5382
Willy Tarreau8797c062007-05-07 00:55:35 +02005383 len = txn->req.sl.rq.v_l;
5384 ptr = txn->req.sol + txn->req.sl.rq.v - txn->req.som;
5385
5386 while ((len-- > 0) && (*ptr++ != '/'));
5387 if (len <= 0)
5388 return 0;
5389
5390 test->ptr = ptr;
5391 test->len = len;
5392
5393 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5394 return 1;
5395}
5396
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005397static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005398acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
5399 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005400{
5401 struct http_txn *txn = l7;
5402 char *ptr;
5403 int len;
5404
Willy Tarreaub6866442008-07-14 23:54:42 +02005405 if (!txn)
5406 return 0;
5407
Willy Tarreauc11416f2007-06-17 16:58:38 +02005408 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5409 return 0;
5410
Willy Tarreau8797c062007-05-07 00:55:35 +02005411 len = txn->rsp.sl.st.v_l;
5412 ptr = txn->rsp.sol;
5413
5414 while ((len-- > 0) && (*ptr++ != '/'));
5415 if (len <= 0)
5416 return 0;
5417
5418 test->ptr = ptr;
5419 test->len = len;
5420
5421 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5422 return 1;
5423}
5424
5425/* 3. Check on Status Code. We manipulate integers here. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005426static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005427acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, int dir,
5428 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005429{
5430 struct http_txn *txn = l7;
5431 char *ptr;
5432 int len;
5433
Willy Tarreaub6866442008-07-14 23:54:42 +02005434 if (!txn)
5435 return 0;
5436
Willy Tarreauc11416f2007-06-17 16:58:38 +02005437 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5438 return 0;
5439
Willy Tarreau8797c062007-05-07 00:55:35 +02005440 len = txn->rsp.sl.st.c_l;
5441 ptr = txn->rsp.sol + txn->rsp.sl.st.c - txn->rsp.som;
5442
5443 test->i = __strl2ui(ptr, len);
5444 test->flags = ACL_TEST_F_VOL_1ST;
5445 return 1;
5446}
5447
5448/* 4. Check on URL/URI. A pointer to the URI is stored. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005449static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005450acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
5451 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005452{
5453 struct http_txn *txn = l7;
5454
Willy Tarreaub6866442008-07-14 23:54:42 +02005455 if (!txn)
5456 return 0;
5457
Willy Tarreauc11416f2007-06-17 16:58:38 +02005458 if (txn->req.msg_state != HTTP_MSG_BODY)
5459 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005460
Willy Tarreauc11416f2007-06-17 16:58:38 +02005461 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5462 /* ensure the indexes are not affected */
5463 return 0;
5464
Willy Tarreau8797c062007-05-07 00:55:35 +02005465 test->len = txn->req.sl.rq.u_l;
5466 test->ptr = txn->req.sol + txn->req.sl.rq.u;
5467
Willy Tarreauf3d25982007-05-08 22:45:09 +02005468 /* we do not need to set READ_ONLY because the data is in a buffer */
5469 test->flags = ACL_TEST_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +02005470 return 1;
5471}
5472
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005473static int
5474acl_fetch_url_ip(struct proxy *px, struct session *l4, void *l7, int dir,
5475 struct acl_expr *expr, struct acl_test *test)
5476{
5477 struct http_txn *txn = l7;
5478
Willy Tarreaub6866442008-07-14 23:54:42 +02005479 if (!txn)
5480 return 0;
5481
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005482 if (txn->req.msg_state != HTTP_MSG_BODY)
5483 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005484
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005485 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5486 /* ensure the indexes are not affected */
5487 return 0;
5488
5489 /* Parse HTTP request */
5490 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5491 test->ptr = (void *)&((struct sockaddr_in *)&l4->srv_addr)->sin_addr;
5492 test->i = AF_INET;
5493
5494 /*
5495 * If we are parsing url in frontend space, we prepare backend stage
5496 * to not parse again the same url ! optimization lazyness...
5497 */
5498 if (px->options & PR_O_HTTP_PROXY)
5499 l4->flags |= SN_ADDR_SET;
5500
5501 test->flags = ACL_TEST_F_READ_ONLY;
5502 return 1;
5503}
5504
5505static int
5506acl_fetch_url_port(struct proxy *px, struct session *l4, void *l7, int dir,
5507 struct acl_expr *expr, struct acl_test *test)
5508{
5509 struct http_txn *txn = l7;
5510
Willy Tarreaub6866442008-07-14 23:54:42 +02005511 if (!txn)
5512 return 0;
5513
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005514 if (txn->req.msg_state != HTTP_MSG_BODY)
5515 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005516
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005517 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5518 /* ensure the indexes are not affected */
5519 return 0;
5520
5521 /* Same optimization as url_ip */
5522 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5523 test->i = ntohs(((struct sockaddr_in *)&l4->srv_addr)->sin_port);
5524
5525 if (px->options & PR_O_HTTP_PROXY)
5526 l4->flags |= SN_ADDR_SET;
5527
5528 test->flags = ACL_TEST_F_READ_ONLY;
5529 return 1;
5530}
5531
Willy Tarreauc11416f2007-06-17 16:58:38 +02005532/* 5. Check on HTTP header. A pointer to the beginning of the value is returned.
5533 * This generic function is used by both acl_fetch_chdr() and acl_fetch_shdr().
5534 */
Willy Tarreau33a7e692007-06-10 19:45:56 +02005535static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005536acl_fetch_hdr(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005537 struct acl_expr *expr, struct acl_test *test)
5538{
5539 struct http_txn *txn = l7;
5540 struct hdr_idx *idx = &txn->hdr_idx;
5541 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005542
Willy Tarreaub6866442008-07-14 23:54:42 +02005543 if (!txn)
5544 return 0;
5545
Willy Tarreau33a7e692007-06-10 19:45:56 +02005546 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5547 /* search for header from the beginning */
5548 ctx->idx = 0;
5549
Willy Tarreau33a7e692007-06-10 19:45:56 +02005550 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5551 test->flags |= ACL_TEST_F_FETCH_MORE;
5552 test->flags |= ACL_TEST_F_VOL_HDR;
5553 test->len = ctx->vlen;
5554 test->ptr = (char *)ctx->line + ctx->val;
5555 return 1;
5556 }
5557
5558 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5559 test->flags |= ACL_TEST_F_VOL_HDR;
5560 return 0;
5561}
5562
Willy Tarreau33a7e692007-06-10 19:45:56 +02005563static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005564acl_fetch_chdr(struct proxy *px, struct session *l4, void *l7, int dir,
5565 struct acl_expr *expr, struct acl_test *test)
5566{
5567 struct http_txn *txn = l7;
5568
Willy Tarreaub6866442008-07-14 23:54:42 +02005569 if (!txn)
5570 return 0;
5571
Willy Tarreauc11416f2007-06-17 16:58:38 +02005572 if (txn->req.msg_state != HTTP_MSG_BODY)
5573 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005574
Willy Tarreauc11416f2007-06-17 16:58:38 +02005575 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5576 /* ensure the indexes are not affected */
5577 return 0;
5578
5579 return acl_fetch_hdr(px, l4, txn, txn->req.sol, expr, test);
5580}
5581
5582static int
5583acl_fetch_shdr(struct proxy *px, struct session *l4, void *l7, int dir,
5584 struct acl_expr *expr, struct acl_test *test)
5585{
5586 struct http_txn *txn = l7;
5587
Willy Tarreaub6866442008-07-14 23:54:42 +02005588 if (!txn)
5589 return 0;
5590
Willy Tarreauc11416f2007-06-17 16:58:38 +02005591 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5592 return 0;
5593
5594 return acl_fetch_hdr(px, l4, txn, txn->rsp.sol, expr, test);
5595}
5596
5597/* 6. Check on HTTP header count. The number of occurrences is returned.
5598 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
5599 */
5600static int
5601acl_fetch_hdr_cnt(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005602 struct acl_expr *expr, struct acl_test *test)
5603{
5604 struct http_txn *txn = l7;
5605 struct hdr_idx *idx = &txn->hdr_idx;
5606 struct hdr_ctx ctx;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005607 int cnt;
Willy Tarreau8797c062007-05-07 00:55:35 +02005608
Willy Tarreaub6866442008-07-14 23:54:42 +02005609 if (!txn)
5610 return 0;
5611
Willy Tarreau33a7e692007-06-10 19:45:56 +02005612 ctx.idx = 0;
5613 cnt = 0;
5614 while (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, &ctx))
5615 cnt++;
5616
5617 test->i = cnt;
5618 test->flags = ACL_TEST_F_VOL_HDR;
5619 return 1;
5620}
5621
Willy Tarreauc11416f2007-06-17 16:58:38 +02005622static int
5623acl_fetch_chdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5624 struct acl_expr *expr, struct acl_test *test)
5625{
5626 struct http_txn *txn = l7;
5627
Willy Tarreaub6866442008-07-14 23:54:42 +02005628 if (!txn)
5629 return 0;
5630
Willy Tarreauc11416f2007-06-17 16:58:38 +02005631 if (txn->req.msg_state != HTTP_MSG_BODY)
5632 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005633
Willy Tarreauc11416f2007-06-17 16:58:38 +02005634 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5635 /* ensure the indexes are not affected */
5636 return 0;
5637
5638 return acl_fetch_hdr_cnt(px, l4, txn, txn->req.sol, expr, test);
5639}
5640
5641static int
5642acl_fetch_shdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5643 struct acl_expr *expr, struct acl_test *test)
5644{
5645 struct http_txn *txn = l7;
5646
Willy Tarreaub6866442008-07-14 23:54:42 +02005647 if (!txn)
5648 return 0;
5649
Willy Tarreauc11416f2007-06-17 16:58:38 +02005650 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5651 return 0;
5652
5653 return acl_fetch_hdr_cnt(px, l4, txn, txn->rsp.sol, expr, test);
5654}
5655
Willy Tarreau33a7e692007-06-10 19:45:56 +02005656/* 7. Check on HTTP header's integer value. The integer value is returned.
5657 * FIXME: the type is 'int', it may not be appropriate for everything.
Willy Tarreauc11416f2007-06-17 16:58:38 +02005658 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
Willy Tarreau33a7e692007-06-10 19:45:56 +02005659 */
5660static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005661acl_fetch_hdr_val(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005662 struct acl_expr *expr, struct acl_test *test)
5663{
5664 struct http_txn *txn = l7;
5665 struct hdr_idx *idx = &txn->hdr_idx;
5666 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005667
Willy Tarreaub6866442008-07-14 23:54:42 +02005668 if (!txn)
5669 return 0;
5670
Willy Tarreau33a7e692007-06-10 19:45:56 +02005671 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5672 /* search for header from the beginning */
5673 ctx->idx = 0;
5674
Willy Tarreau33a7e692007-06-10 19:45:56 +02005675 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5676 test->flags |= ACL_TEST_F_FETCH_MORE;
5677 test->flags |= ACL_TEST_F_VOL_HDR;
5678 test->i = strl2ic((char *)ctx->line + ctx->val, ctx->vlen);
5679 return 1;
5680 }
5681
5682 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5683 test->flags |= ACL_TEST_F_VOL_HDR;
5684 return 0;
5685}
5686
Willy Tarreauc11416f2007-06-17 16:58:38 +02005687static int
5688acl_fetch_chdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5689 struct acl_expr *expr, struct acl_test *test)
5690{
5691 struct http_txn *txn = l7;
5692
Willy Tarreaub6866442008-07-14 23:54:42 +02005693 if (!txn)
5694 return 0;
5695
Willy Tarreauc11416f2007-06-17 16:58:38 +02005696 if (txn->req.msg_state != HTTP_MSG_BODY)
5697 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005698
Willy Tarreauc11416f2007-06-17 16:58:38 +02005699 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5700 /* ensure the indexes are not affected */
5701 return 0;
5702
5703 return acl_fetch_hdr_val(px, l4, txn, txn->req.sol, expr, test);
5704}
5705
5706static int
5707acl_fetch_shdr_val(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
Willy Tarreaub6866442008-07-14 23:54:42 +02005712 if (!txn)
5713 return 0;
5714
Willy Tarreauc11416f2007-06-17 16:58:38 +02005715 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5716 return 0;
5717
5718 return acl_fetch_hdr_val(px, l4, txn, txn->rsp.sol, expr, test);
5719}
5720
Willy Tarreau737b0c12007-06-10 21:28:46 +02005721/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at
5722 * the first '/' after the possible hostname, and ends before the possible '?'.
5723 */
5724static int
5725acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
5726 struct acl_expr *expr, struct acl_test *test)
5727{
5728 struct http_txn *txn = l7;
5729 char *ptr, *end;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005730
Willy Tarreaub6866442008-07-14 23:54:42 +02005731 if (!txn)
5732 return 0;
5733
Willy Tarreauc11416f2007-06-17 16:58:38 +02005734 if (txn->req.msg_state != HTTP_MSG_BODY)
5735 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005736
Willy Tarreauc11416f2007-06-17 16:58:38 +02005737 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5738 /* ensure the indexes are not affected */
5739 return 0;
5740
Willy Tarreau21d2af32008-02-14 20:25:24 +01005741 end = txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
5742 ptr = http_get_path(txn);
5743 if (!ptr)
Willy Tarreau737b0c12007-06-10 21:28:46 +02005744 return 0;
5745
5746 /* OK, we got the '/' ! */
5747 test->ptr = ptr;
5748
5749 while (ptr < end && *ptr != '?')
5750 ptr++;
5751
5752 test->len = ptr - test->ptr;
5753
5754 /* we do not need to set READ_ONLY because the data is in a buffer */
5755 test->flags = ACL_TEST_F_VOL_1ST;
5756 return 1;
5757}
5758
5759
Willy Tarreau8797c062007-05-07 00:55:35 +02005760
5761/************************************************************************/
5762/* All supported keywords must be declared here. */
5763/************************************************************************/
5764
5765/* Note: must not be declared <const> as its list will be overwritten */
5766static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005767 { "method", acl_parse_meth, acl_fetch_meth, acl_match_meth, ACL_USE_L7REQ_PERMANENT },
5768 { "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5769 { "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str, ACL_USE_L7RTR_VOLATILE },
5770 { "status", acl_parse_int, acl_fetch_stcode, acl_match_int, ACL_USE_L7RTR_PERMANENT },
Willy Tarreau8797c062007-05-07 00:55:35 +02005771
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005772 { "url", acl_parse_str, acl_fetch_url, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5773 { "url_beg", acl_parse_str, acl_fetch_url, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5774 { "url_end", acl_parse_str, acl_fetch_url, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5775 { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5776 { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5777 { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
5778 { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5779 { "url_ip", acl_parse_ip, acl_fetch_url_ip, acl_match_ip, ACL_USE_L7REQ_VOLATILE },
5780 { "url_port", acl_parse_int, acl_fetch_url_port, acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau8797c062007-05-07 00:55:35 +02005781
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005782 /* note: we should set hdr* to use ACL_USE_HDR_VOLATILE, and chdr* to use L7REQ_VOLATILE */
5783 { "hdr", acl_parse_str, acl_fetch_chdr, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5784 { "hdr_reg", acl_parse_reg, acl_fetch_chdr, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5785 { "hdr_beg", acl_parse_str, acl_fetch_chdr, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5786 { "hdr_end", acl_parse_str, acl_fetch_chdr, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5787 { "hdr_sub", acl_parse_str, acl_fetch_chdr, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5788 { "hdr_dir", acl_parse_str, acl_fetch_chdr, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5789 { "hdr_dom", acl_parse_str, acl_fetch_chdr, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
5790 { "hdr_cnt", acl_parse_int, acl_fetch_chdr_cnt,acl_match_int, ACL_USE_L7REQ_VOLATILE },
5791 { "hdr_val", acl_parse_int, acl_fetch_chdr_val,acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreauc11416f2007-06-17 16:58:38 +02005792
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005793 { "shdr", acl_parse_str, acl_fetch_shdr, acl_match_str, ACL_USE_L7RTR_VOLATILE },
5794 { "shdr_reg", acl_parse_reg, acl_fetch_shdr, acl_match_reg, ACL_USE_L7RTR_VOLATILE },
5795 { "shdr_beg", acl_parse_str, acl_fetch_shdr, acl_match_beg, ACL_USE_L7RTR_VOLATILE },
5796 { "shdr_end", acl_parse_str, acl_fetch_shdr, acl_match_end, ACL_USE_L7RTR_VOLATILE },
5797 { "shdr_sub", acl_parse_str, acl_fetch_shdr, acl_match_sub, ACL_USE_L7RTR_VOLATILE },
5798 { "shdr_dir", acl_parse_str, acl_fetch_shdr, acl_match_dir, ACL_USE_L7RTR_VOLATILE },
5799 { "shdr_dom", acl_parse_str, acl_fetch_shdr, acl_match_dom, ACL_USE_L7RTR_VOLATILE },
5800 { "shdr_cnt", acl_parse_int, acl_fetch_shdr_cnt,acl_match_int, ACL_USE_L7RTR_VOLATILE },
5801 { "shdr_val", acl_parse_int, acl_fetch_shdr_val,acl_match_int, ACL_USE_L7RTR_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005802
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005803 { "path", acl_parse_str, acl_fetch_path, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5804 { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5805 { "path_beg", acl_parse_str, acl_fetch_path, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5806 { "path_end", acl_parse_str, acl_fetch_path, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5807 { "path_sub", acl_parse_str, acl_fetch_path, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5808 { "path_dir", acl_parse_str, acl_fetch_path, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5809 { "path_dom", acl_parse_str, acl_fetch_path, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005810
Willy Tarreauf3d25982007-05-08 22:45:09 +02005811 { NULL, NULL, NULL, NULL },
5812
5813#if 0
Willy Tarreau8797c062007-05-07 00:55:35 +02005814 { "line", acl_parse_str, acl_fetch_line, acl_match_str },
5815 { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg },
5816 { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg },
5817 { "line_end", acl_parse_str, acl_fetch_line, acl_match_end },
5818 { "line_sub", acl_parse_str, acl_fetch_line, acl_match_sub },
5819 { "line_dir", acl_parse_str, acl_fetch_line, acl_match_dir },
5820 { "line_dom", acl_parse_str, acl_fetch_line, acl_match_dom },
5821
Willy Tarreau8797c062007-05-07 00:55:35 +02005822 { "cook", acl_parse_str, acl_fetch_cook, acl_match_str },
5823 { "cook_reg", acl_parse_reg, acl_fetch_cook, acl_match_reg },
5824 { "cook_beg", acl_parse_str, acl_fetch_cook, acl_match_beg },
5825 { "cook_end", acl_parse_str, acl_fetch_cook, acl_match_end },
5826 { "cook_sub", acl_parse_str, acl_fetch_cook, acl_match_sub },
5827 { "cook_dir", acl_parse_str, acl_fetch_cook, acl_match_dir },
5828 { "cook_dom", acl_parse_str, acl_fetch_cook, acl_match_dom },
5829 { "cook_pst", acl_parse_none, acl_fetch_cook, acl_match_pst },
5830
5831 { "auth_user", acl_parse_str, acl_fetch_user, acl_match_str },
5832 { "auth_regex", acl_parse_reg, acl_fetch_user, acl_match_reg },
5833 { "auth_clear", acl_parse_str, acl_fetch_auth, acl_match_str },
5834 { "auth_md5", acl_parse_str, acl_fetch_auth, acl_match_md5 },
5835 { NULL, NULL, NULL, NULL },
5836#endif
5837}};
5838
5839
5840__attribute__((constructor))
5841static void __http_protocol_init(void)
5842{
5843 acl_register_keywords(&acl_kws);
5844}
5845
5846
Willy Tarreau58f10d72006-12-04 02:26:12 +01005847/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02005848 * Local variables:
5849 * c-indent-level: 8
5850 * c-basic-offset: 8
5851 * End:
5852 */