blob: 42f253189fb575fd3caa083fc914f343bdd4c297 [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 Tarreau0f772532006-12-23 20:51:41 +0100550 if (status > 0 && msg) {
Willy Tarreau3bac9ff2007-03-18 17:31:28 +0100551 t->txn.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100552 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100553 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200554 }
555 if (!(t->flags & SN_ERR_MASK))
556 t->flags |= err;
557 if (!(t->flags & SN_FINST_MASK))
558 t->flags |= finst;
559}
560
Willy Tarreau80587432006-12-24 17:47:20 +0100561/* This function returns the appropriate error location for the given session
562 * and message.
563 */
564
565struct chunk *error_message(struct session *s, int msgnum)
566{
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200567 if (s->be->errmsg[msgnum].str)
568 return &s->be->errmsg[msgnum];
Willy Tarreau80587432006-12-24 17:47:20 +0100569 else if (s->fe->errmsg[msgnum].str)
570 return &s->fe->errmsg[msgnum];
571 else
572 return &http_err_chunks[msgnum];
573}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200574
Willy Tarreau53b6c742006-12-17 13:37:46 +0100575/*
576 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
577 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
578 */
579static http_meth_t find_http_meth(const char *str, const int len)
580{
581 unsigned char m;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100582 const struct http_method_desc *h;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100583
584 m = ((unsigned)*str - 'A');
585
586 if (m < 26) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100587 for (h = http_methods[m]; h->len > 0; h++) {
588 if (unlikely(h->len != len))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100589 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100590 if (likely(memcmp(str, h->text, h->len) == 0))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100591 return h->meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100592 };
593 return HTTP_METH_OTHER;
594 }
595 return HTTP_METH_NONE;
596
597}
598
Willy Tarreau21d2af32008-02-14 20:25:24 +0100599/* Parse the URI from the given transaction (which is assumed to be in request
600 * phase) and look for the "/" beginning the PATH. If not found, return NULL.
601 * It is returned otherwise.
602 */
603static char *
604http_get_path(struct http_txn *txn)
605{
606 char *ptr, *end;
607
608 ptr = txn->req.sol + txn->req.sl.rq.u;
609 end = ptr + txn->req.sl.rq.u_l;
610
611 if (ptr >= end)
612 return NULL;
613
614 /* RFC2616, par. 5.1.2 :
615 * Request-URI = "*" | absuri | abspath | authority
616 */
617
618 if (*ptr == '*')
619 return NULL;
620
621 if (isalpha((unsigned char)*ptr)) {
622 /* this is a scheme as described by RFC3986, par. 3.1 */
623 ptr++;
624 while (ptr < end &&
625 (isalnum((unsigned char)*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.'))
626 ptr++;
627 /* skip '://' */
628 if (ptr == end || *ptr++ != ':')
629 return NULL;
630 if (ptr == end || *ptr++ != '/')
631 return NULL;
632 if (ptr == end || *ptr++ != '/')
633 return NULL;
634 }
635 /* skip [user[:passwd]@]host[:[port]] */
636
637 while (ptr < end && *ptr != '/')
638 ptr++;
639
640 if (ptr == end)
641 return NULL;
642
643 /* OK, we got the '/' ! */
644 return ptr;
645}
646
Willy Tarreaubaaee002006-06-26 02:48:02 +0200647/* Processes the client and server jobs of a session task, then
648 * puts it back to the wait queue in a clean state, or
649 * cleans up its resources if it must be deleted. Returns
650 * the time the task accepts to wait, or TIME_ETERNITY for
651 * infinity.
652 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200653void process_session(struct task *t, int *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200654{
655 struct session *s = t->context;
656 int fsm_resync = 0;
657
658 do {
659 fsm_resync = 0;
660 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
661 fsm_resync |= process_cli(s);
662 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
663 fsm_resync |= process_srv(s);
664 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
665 } while (fsm_resync);
666
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200667 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100668
669 if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
670 session_process_counters(s);
671
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200672 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
673 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200674
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200675 t->expire = tick_first(tick_first(s->req->rex, s->req->wex),
676 tick_first(s->rep->rex, s->rep->wex));
677 t->expire = tick_first(t->expire, s->req->cex);
Willy Tarreau036fae02008-01-06 13:24:40 +0100678 if (s->cli_state == CL_STHEADERS)
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200679 t->expire = tick_first(t->expire, s->txn.exp);
Willy Tarreaub6866442008-07-14 23:54:42 +0200680 else if (s->cli_state == CL_STINSPECT)
681 t->expire = tick_first(t->expire, s->inspect_exp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200682
683 /* restore t to its place in the task list */
684 task_queue(t);
685
Willy Tarreaud825eef2007-05-12 22:35:00 +0200686 *next = t->expire;
687 return; /* nothing more to do */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200688 }
689
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100690 s->fe->feconn--;
691 if (s->flags & SN_BE_ASSIGNED)
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200692 s->be->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200693 actconn--;
694
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200695 if (unlikely((global.mode & MODE_DEBUG) &&
696 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200697 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100698 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200699 s->uniq_id, s->be->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100700 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200701 write(1, trash, len);
702 }
703
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200704 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100705 session_process_counters(s);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200706
707 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200708 if (s->logs.logwait &&
709 !(s->flags & SN_MONITOR) &&
Willy Tarreau42250582007-04-01 01:30:43 +0200710 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total)) {
711 if (s->fe->to_log & LW_REQ)
712 http_sess_log(s);
713 else
714 tcp_sess_log(s);
715 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200716
717 /* the task MUST not be in the run queue anymore */
718 task_delete(t);
719 session_free(s);
720 task_free(t);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200721 *next = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200722}
723
724
Willy Tarreau42250582007-04-01 01:30:43 +0200725extern const char sess_term_cond[8];
726extern const char sess_fin_state[8];
727extern const char *monthname[12];
728const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
729const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
730 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
731 unknown, Set-cookie Rewritten */
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200732struct pool_head *pool2_requri;
Willy Tarreau086b3b42007-05-13 21:45:51 +0200733struct pool_head *pool2_capture;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100734
Willy Tarreau42250582007-04-01 01:30:43 +0200735/*
736 * send a log for the session when we have enough info about it.
737 * Will not log if the frontend has no log defined.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100738 */
Willy Tarreau42250582007-04-01 01:30:43 +0200739static void http_sess_log(struct session *s)
740{
741 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
742 struct proxy *fe = s->fe;
743 struct proxy *be = s->be;
744 struct proxy *prx_log;
745 struct http_txn *txn = &s->txn;
746 int tolog;
747 char *uri, *h;
748 char *svid;
Willy Tarreaufe944602007-10-25 10:34:16 +0200749 struct tm tm;
Willy Tarreau42250582007-04-01 01:30:43 +0200750 static char tmpline[MAX_SYSLOG_LEN];
Willy Tarreau70089872008-06-13 21:12:51 +0200751 int t_request;
Willy Tarreau42250582007-04-01 01:30:43 +0200752 int hdr;
753
754 if (fe->logfac1 < 0 && fe->logfac2 < 0)
755 return;
756 prx_log = fe;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100757
Willy Tarreau42250582007-04-01 01:30:43 +0200758 if (s->cli_addr.ss_family == AF_INET)
759 inet_ntop(AF_INET,
760 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
761 pn, sizeof(pn));
762 else
763 inet_ntop(AF_INET6,
764 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
765 pn, sizeof(pn));
766
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200767 get_localtime(s->logs.accept_date.tv_sec, &tm);
Willy Tarreau42250582007-04-01 01:30:43 +0200768
769 /* FIXME: let's limit ourselves to frontend logging for now. */
770 tolog = fe->to_log;
771
772 h = tmpline;
773 if (fe->to_log & LW_REQHDR &&
774 txn->req.cap &&
775 (h < tmpline + sizeof(tmpline) - 10)) {
776 *(h++) = ' ';
777 *(h++) = '{';
778 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
779 if (hdr)
780 *(h++) = '|';
781 if (txn->req.cap[hdr] != NULL)
782 h = encode_string(h, tmpline + sizeof(tmpline) - 7,
783 '#', hdr_encode_map, txn->req.cap[hdr]);
784 }
785 *(h++) = '}';
786 }
787
788 if (fe->to_log & LW_RSPHDR &&
789 txn->rsp.cap &&
790 (h < tmpline + sizeof(tmpline) - 7)) {
791 *(h++) = ' ';
792 *(h++) = '{';
793 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
794 if (hdr)
795 *(h++) = '|';
796 if (txn->rsp.cap[hdr] != NULL)
797 h = encode_string(h, tmpline + sizeof(tmpline) - 4,
798 '#', hdr_encode_map, txn->rsp.cap[hdr]);
799 }
800 *(h++) = '}';
801 }
802
803 if (h < tmpline + sizeof(tmpline) - 4) {
804 *(h++) = ' ';
805 *(h++) = '"';
806 uri = txn->uri ? txn->uri : "<BADREQ>";
807 h = encode_string(h, tmpline + sizeof(tmpline) - 1,
808 '#', url_encode_map, uri);
809 *(h++) = '"';
810 }
811 *h = '\0';
812
813 svid = (tolog & LW_SVID) ?
814 (s->data_source != DATA_SRC_STATS) ?
815 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
816
Willy Tarreau70089872008-06-13 21:12:51 +0200817 t_request = -1;
818 if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
819 t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
820
Willy Tarreau42250582007-04-01 01:30:43 +0200821 send_log(prx_log, LOG_INFO,
822 "%s:%d [%02d/%s/%04d:%02d:%02d:%02d.%03d]"
823 " %s %s/%s %d/%d/%d/%d/%s%d %d %s%lld"
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100824 " %s %s %c%c%c%c %d/%d/%d/%d/%s%u %d/%d%s\n",
Willy Tarreau42250582007-04-01 01:30:43 +0200825 pn,
826 (s->cli_addr.ss_family == AF_INET) ?
827 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
828 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
Willy Tarreaufe944602007-10-25 10:34:16 +0200829 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200830 tm.tm_hour, tm.tm_min, tm.tm_sec, s->logs.accept_date.tv_usec/1000,
Willy Tarreau42250582007-04-01 01:30:43 +0200831 fe->id, be->id, svid,
Willy Tarreau70089872008-06-13 21:12:51 +0200832 t_request,
833 (s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1,
Willy Tarreau42250582007-04-01 01:30:43 +0200834 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
835 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
836 (tolog & LW_BYTES) ? "" : "+", s->logs.t_close,
837 txn->status,
Willy Tarreau8b3977f2008-01-18 11:16:32 +0100838 (tolog & LW_BYTES) ? "" : "+", s->logs.bytes_out,
Willy Tarreau42250582007-04-01 01:30:43 +0200839 txn->cli_cookie ? txn->cli_cookie : "-",
840 txn->srv_cookie ? txn->srv_cookie : "-",
841 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
842 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
843 (be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-',
844 (be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-',
845 actconn, fe->feconn, be->beconn, s->srv ? s->srv->cur_sess : 0,
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100846 (s->flags & SN_REDISP)?"+":"",
847 (s->conn_retries>0)?(be->conn_retries - s->conn_retries):be->conn_retries,
Willy Tarreau42250582007-04-01 01:30:43 +0200848 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
849
850 s->logs.logwait = 0;
851}
852
Willy Tarreau117f59e2007-03-04 18:17:17 +0100853
854/*
855 * Capture headers from message starting at <som> according to header list
856 * <cap_hdr>, and fill the <idx> structure appropriately.
857 */
858void capture_headers(char *som, struct hdr_idx *idx,
859 char **cap, struct cap_hdr *cap_hdr)
860{
861 char *eol, *sol, *col, *sov;
862 int cur_idx;
863 struct cap_hdr *h;
864 int len;
865
866 sol = som + hdr_idx_first_pos(idx);
867 cur_idx = hdr_idx_first_idx(idx);
868
869 while (cur_idx) {
870 eol = sol + idx->v[cur_idx].len;
871
872 col = sol;
873 while (col < eol && *col != ':')
874 col++;
875
876 sov = col + 1;
877 while (sov < eol && http_is_lws[(unsigned char)*sov])
878 sov++;
879
880 for (h = cap_hdr; h; h = h->next) {
881 if ((h->namelen == col - sol) &&
882 (strncasecmp(sol, h->name, h->namelen) == 0)) {
883 if (cap[h->index] == NULL)
884 cap[h->index] =
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200885 pool_alloc2(h->pool);
Willy Tarreau117f59e2007-03-04 18:17:17 +0100886
887 if (cap[h->index] == NULL) {
888 Alert("HTTP capture : out of memory.\n");
889 continue;
890 }
891
892 len = eol - sov;
893 if (len > h->len)
894 len = h->len;
895
896 memcpy(cap[h->index], sov, len);
897 cap[h->index][len]=0;
898 }
899 }
900 sol = eol + idx->v[cur_idx].cr + 1;
901 cur_idx = idx->v[cur_idx].next;
902 }
903}
904
905
Willy Tarreau42250582007-04-01 01:30:43 +0200906/* either we find an LF at <ptr> or we jump to <bad>.
907 */
908#define EXPECT_LF_HERE(ptr, bad) do { if (unlikely(*(ptr) != '\n')) goto bad; } while (0)
909
910/* plays with variables <ptr>, <end> and <state>. Jumps to <good> if OK,
911 * otherwise to <http_msg_ood> with <state> set to <st>.
912 */
913#define EAT_AND_JUMP_OR_RETURN(good, st) do { \
914 ptr++; \
915 if (likely(ptr < end)) \
916 goto good; \
917 else { \
918 state = (st); \
919 goto http_msg_ood; \
920 } \
921 } while (0)
922
923
Willy Tarreaubaaee002006-06-26 02:48:02 +0200924/*
Willy Tarreaua15645d2007-03-18 16:22:39 +0100925 * This function parses a status line between <ptr> and <end>, starting with
Willy Tarreau8973c702007-01-21 23:58:29 +0100926 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
927 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
928 * will give undefined results.
929 * Note that it is upon the caller's responsibility to ensure that ptr < end,
930 * and that msg->sol points to the beginning of the response.
931 * If a complete line is found (which implies that at least one CR or LF is
932 * found before <end>, the updated <ptr> is returned, otherwise NULL is
933 * returned indicating an incomplete line (which does not mean that parts have
934 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
935 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
936 * upon next call.
937 *
Willy Tarreau9cdde232007-05-02 20:58:19 +0200938 * This function was intentionally designed to be called from
Willy Tarreau8973c702007-01-21 23:58:29 +0100939 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
940 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +0200941 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreau8973c702007-01-21 23:58:29 +0100942 */
Willy Tarreaue69eada2008-01-27 00:34:10 +0100943const char *http_parse_stsline(struct http_msg *msg, const char *msg_buf,
944 unsigned int state, const char *ptr, const char *end,
945 char **ret_ptr, unsigned int *ret_state)
Willy Tarreau8973c702007-01-21 23:58:29 +0100946{
947 __label__
948 http_msg_rpver,
949 http_msg_rpver_sp,
950 http_msg_rpcode,
951 http_msg_rpcode_sp,
952 http_msg_rpreason,
953 http_msg_rpline_eol,
954 http_msg_ood, /* out of data */
955 http_msg_invalid;
956
957 switch (state) {
958 http_msg_rpver:
959 case HTTP_MSG_RPVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100960 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8973c702007-01-21 23:58:29 +0100961 EAT_AND_JUMP_OR_RETURN(http_msg_rpver, HTTP_MSG_RPVER);
962
963 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +0100964 msg->sl.st.v_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +0100965 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
966 }
967 goto http_msg_invalid;
968
969 http_msg_rpver_sp:
970 case HTTP_MSG_RPVER_SP:
971 if (likely(!HTTP_IS_LWS(*ptr))) {
972 msg->sl.st.c = ptr - msg_buf;
973 goto http_msg_rpcode;
974 }
975 if (likely(HTTP_IS_SPHT(*ptr)))
976 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
977 /* so it's a CR/LF, this is invalid */
978 goto http_msg_invalid;
979
980 http_msg_rpcode:
981 case HTTP_MSG_RPCODE:
982 if (likely(!HTTP_IS_LWS(*ptr)))
983 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode, HTTP_MSG_RPCODE);
984
985 if (likely(HTTP_IS_SPHT(*ptr))) {
986 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
987 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
988 }
989
990 /* so it's a CR/LF, so there is no reason phrase */
991 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
992 http_msg_rsp_reason:
993 /* FIXME: should we support HTTP responses without any reason phrase ? */
994 msg->sl.st.r = ptr - msg_buf;
995 msg->sl.st.r_l = 0;
996 goto http_msg_rpline_eol;
997
998 http_msg_rpcode_sp:
999 case HTTP_MSG_RPCODE_SP:
1000 if (likely(!HTTP_IS_LWS(*ptr))) {
1001 msg->sl.st.r = ptr - msg_buf;
1002 goto http_msg_rpreason;
1003 }
1004 if (likely(HTTP_IS_SPHT(*ptr)))
1005 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1006 /* so it's a CR/LF, so there is no reason phrase */
1007 goto http_msg_rsp_reason;
1008
1009 http_msg_rpreason:
1010 case HTTP_MSG_RPREASON:
1011 if (likely(!HTTP_IS_CRLF(*ptr)))
1012 EAT_AND_JUMP_OR_RETURN(http_msg_rpreason, HTTP_MSG_RPREASON);
1013 msg->sl.st.r_l = (ptr - msg_buf) - msg->sl.st.r;
1014 http_msg_rpline_eol:
1015 /* We have seen the end of line. Note that we do not
1016 * necessarily have the \n yet, but at least we know that we
1017 * have EITHER \r OR \n, otherwise the response would not be
1018 * complete. We can then record the response length and return
1019 * to the caller which will be able to register it.
1020 */
1021 msg->sl.st.l = ptr - msg->sol;
1022 return ptr;
1023
1024#ifdef DEBUG_FULL
1025 default:
1026 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1027 exit(1);
1028#endif
1029 }
1030
1031 http_msg_ood:
1032 /* out of data */
1033 if (ret_state)
1034 *ret_state = state;
1035 if (ret_ptr)
1036 *ret_ptr = (char *)ptr;
1037 return NULL;
1038
1039 http_msg_invalid:
1040 /* invalid message */
1041 if (ret_state)
1042 *ret_state = HTTP_MSG_ERROR;
1043 return NULL;
1044}
1045
1046
1047/*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001048 * This function parses a request line between <ptr> and <end>, starting with
1049 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
1050 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
1051 * will give undefined results.
1052 * Note that it is upon the caller's responsibility to ensure that ptr < end,
1053 * and that msg->sol points to the beginning of the request.
1054 * If a complete line is found (which implies that at least one CR or LF is
1055 * found before <end>, the updated <ptr> is returned, otherwise NULL is
1056 * returned indicating an incomplete line (which does not mean that parts have
1057 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
1058 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
1059 * upon next call.
1060 *
Willy Tarreau9cdde232007-05-02 20:58:19 +02001061 * This function was intentionally designed to be called from
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001062 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
1063 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +02001064 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001065 */
Willy Tarreaue69eada2008-01-27 00:34:10 +01001066const char *http_parse_reqline(struct http_msg *msg, const char *msg_buf,
1067 unsigned int state, const char *ptr, const char *end,
1068 char **ret_ptr, unsigned int *ret_state)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001069{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001070 __label__
1071 http_msg_rqmeth,
1072 http_msg_rqmeth_sp,
1073 http_msg_rquri,
1074 http_msg_rquri_sp,
1075 http_msg_rqver,
1076 http_msg_rqline_eol,
1077 http_msg_ood, /* out of data */
1078 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001079
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001080 switch (state) {
1081 http_msg_rqmeth:
1082 case HTTP_MSG_RQMETH:
1083 if (likely(HTTP_IS_TOKEN(*ptr)))
1084 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth, HTTP_MSG_RQMETH);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001085
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001086 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001087 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001088 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1089 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001090
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001091 if (likely(HTTP_IS_CRLF(*ptr))) {
1092 /* HTTP 0.9 request */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001093 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001094 http_msg_req09_uri:
1095 msg->sl.rq.u = ptr - msg_buf;
1096 http_msg_req09_uri_e:
1097 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1098 http_msg_req09_ver:
1099 msg->sl.rq.v = ptr - msg_buf;
1100 msg->sl.rq.v_l = 0;
1101 goto http_msg_rqline_eol;
1102 }
1103 goto http_msg_invalid;
1104
1105 http_msg_rqmeth_sp:
1106 case HTTP_MSG_RQMETH_SP:
1107 if (likely(!HTTP_IS_LWS(*ptr))) {
1108 msg->sl.rq.u = ptr - msg_buf;
1109 goto http_msg_rquri;
1110 }
1111 if (likely(HTTP_IS_SPHT(*ptr)))
1112 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1113 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1114 goto http_msg_req09_uri;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001115
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001116 http_msg_rquri:
1117 case HTTP_MSG_RQURI:
1118 if (likely(!HTTP_IS_LWS(*ptr)))
1119 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001120
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001121 if (likely(HTTP_IS_SPHT(*ptr))) {
1122 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1123 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1124 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001125
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001126 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1127 goto http_msg_req09_uri_e;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001128
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001129 http_msg_rquri_sp:
1130 case HTTP_MSG_RQURI_SP:
1131 if (likely(!HTTP_IS_LWS(*ptr))) {
1132 msg->sl.rq.v = ptr - msg_buf;
1133 goto http_msg_rqver;
1134 }
1135 if (likely(HTTP_IS_SPHT(*ptr)))
1136 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1137 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1138 goto http_msg_req09_ver;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001139
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001140 http_msg_rqver:
1141 case HTTP_MSG_RQVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001142 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001143 EAT_AND_JUMP_OR_RETURN(http_msg_rqver, HTTP_MSG_RQVER);
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001144
1145 if (likely(HTTP_IS_CRLF(*ptr))) {
1146 msg->sl.rq.v_l = (ptr - msg_buf) - msg->sl.rq.v;
1147 http_msg_rqline_eol:
1148 /* We have seen the end of line. Note that we do not
1149 * necessarily have the \n yet, but at least we know that we
1150 * have EITHER \r OR \n, otherwise the request would not be
1151 * complete. We can then record the request length and return
1152 * to the caller which will be able to register it.
1153 */
1154 msg->sl.rq.l = ptr - msg->sol;
1155 return ptr;
1156 }
1157
1158 /* neither an HTTP_VER token nor a CRLF */
1159 goto http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001160
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001161#ifdef DEBUG_FULL
1162 default:
1163 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1164 exit(1);
1165#endif
1166 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001167
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001168 http_msg_ood:
1169 /* out of data */
1170 if (ret_state)
1171 *ret_state = state;
1172 if (ret_ptr)
1173 *ret_ptr = (char *)ptr;
1174 return NULL;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001175
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001176 http_msg_invalid:
1177 /* invalid message */
1178 if (ret_state)
1179 *ret_state = HTTP_MSG_ERROR;
1180 return NULL;
1181}
Willy Tarreau58f10d72006-12-04 02:26:12 +01001182
1183
Willy Tarreau8973c702007-01-21 23:58:29 +01001184/*
1185 * This function parses an HTTP message, either a request or a response,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001186 * depending on the initial msg->msg_state. It can be preempted everywhere
Willy Tarreau8973c702007-01-21 23:58:29 +01001187 * when data are missing and recalled at the exact same location with no
1188 * information loss. The header index is re-initialized when switching from
Willy Tarreau9cdde232007-05-02 20:58:19 +02001189 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH. It modifies msg->sol among other
1190 * fields.
Willy Tarreau8973c702007-01-21 23:58:29 +01001191 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001192void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx *idx)
1193{
1194 __label__
1195 http_msg_rqbefore,
1196 http_msg_rqbefore_cr,
1197 http_msg_rqmeth,
1198 http_msg_rqline_end,
1199 http_msg_hdr_first,
1200 http_msg_hdr_name,
1201 http_msg_hdr_l1_sp,
1202 http_msg_hdr_l1_lf,
1203 http_msg_hdr_l1_lws,
1204 http_msg_hdr_val,
1205 http_msg_hdr_l2_lf,
1206 http_msg_hdr_l2_lws,
1207 http_msg_complete_header,
1208 http_msg_last_lf,
1209 http_msg_ood, /* out of data */
1210 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001211
Willy Tarreaue69eada2008-01-27 00:34:10 +01001212 unsigned int state; /* updated only when leaving the FSM */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001213 register char *ptr, *end; /* request pointers, to avoid dereferences */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001214
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001215 state = msg->msg_state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001216 ptr = buf->lr;
1217 end = buf->r;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001218
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001219 if (unlikely(ptr >= end))
1220 goto http_msg_ood;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001221
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001222 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +01001223 /*
1224 * First, states that are specific to the response only.
1225 * We check them first so that request and headers are
1226 * closer to each other (accessed more often).
1227 */
1228 http_msg_rpbefore:
1229 case HTTP_MSG_RPBEFORE:
1230 if (likely(HTTP_IS_TOKEN(*ptr))) {
1231 if (likely(ptr == buf->data)) {
1232 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001233 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001234 } else {
1235#if PARSE_PRESERVE_EMPTY_LINES
1236 /* only skip empty leading lines, don't remove them */
1237 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001238 msg->som = ptr - buf->data;
Willy Tarreau8973c702007-01-21 23:58:29 +01001239#else
1240 /* Remove empty leading lines, as recommended by
1241 * RFC2616. This takes a lot of time because we
1242 * must move all the buffer backwards, but this
1243 * is rarely needed. The method above will be
1244 * cleaner when we'll be able to start sending
1245 * the request from any place in the buffer.
1246 */
1247 buf->lr = ptr;
1248 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001249 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001250 msg->sol = buf->data;
1251 ptr = buf->data;
1252 end = buf->r;
1253#endif
1254 }
1255 hdr_idx_init(idx);
1256 state = HTTP_MSG_RPVER;
1257 goto http_msg_rpver;
1258 }
1259
1260 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1261 goto http_msg_invalid;
1262
1263 if (unlikely(*ptr == '\n'))
1264 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1265 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore_cr, HTTP_MSG_RPBEFORE_CR);
1266 /* stop here */
1267
1268 http_msg_rpbefore_cr:
1269 case HTTP_MSG_RPBEFORE_CR:
1270 EXPECT_LF_HERE(ptr, http_msg_invalid);
1271 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1272 /* stop here */
1273
1274 http_msg_rpver:
1275 case HTTP_MSG_RPVER:
1276 case HTTP_MSG_RPVER_SP:
1277 case HTTP_MSG_RPCODE:
1278 case HTTP_MSG_RPCODE_SP:
1279 case HTTP_MSG_RPREASON:
Willy Tarreaua15645d2007-03-18 16:22:39 +01001280 ptr = (char *)http_parse_stsline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001281 &buf->lr, &msg->msg_state);
Willy Tarreau8973c702007-01-21 23:58:29 +01001282 if (unlikely(!ptr))
1283 return;
1284
1285 /* we have a full response and we know that we have either a CR
1286 * or an LF at <ptr>.
1287 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001288 //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 +01001289 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
1290
1291 msg->sol = ptr;
1292 if (likely(*ptr == '\r'))
1293 EAT_AND_JUMP_OR_RETURN(http_msg_rpline_end, HTTP_MSG_RPLINE_END);
1294 goto http_msg_rpline_end;
1295
1296 http_msg_rpline_end:
1297 case HTTP_MSG_RPLINE_END:
1298 /* msg->sol must point to the first of CR or LF. */
1299 EXPECT_LF_HERE(ptr, http_msg_invalid);
1300 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
1301 /* stop here */
1302
1303 /*
1304 * Second, states that are specific to the request only
1305 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001306 http_msg_rqbefore:
1307 case HTTP_MSG_RQBEFORE:
1308 if (likely(HTTP_IS_TOKEN(*ptr))) {
1309 if (likely(ptr == buf->data)) {
1310 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001311 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001312 } else {
1313#if PARSE_PRESERVE_EMPTY_LINES
1314 /* only skip empty leading lines, don't remove them */
1315 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001316 msg->som = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001317#else
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001318 /* Remove empty leading lines, as recommended by
1319 * RFC2616. This takes a lot of time because we
1320 * must move all the buffer backwards, but this
1321 * is rarely needed. The method above will be
1322 * cleaner when we'll be able to start sending
1323 * the request from any place in the buffer.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001324 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001325 buf->lr = ptr;
1326 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001327 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001328 msg->sol = buf->data;
1329 ptr = buf->data;
1330 end = buf->r;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001331#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001332 }
Willy Tarreauf0d058e2007-01-25 12:03:42 +01001333 /* we will need this when keep-alive will be supported
1334 hdr_idx_init(idx);
1335 */
Willy Tarreau8973c702007-01-21 23:58:29 +01001336 state = HTTP_MSG_RQMETH;
1337 goto http_msg_rqmeth;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001338 }
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001339
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001340 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1341 goto http_msg_invalid;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001342
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001343 if (unlikely(*ptr == '\n'))
1344 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
1345 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore_cr, HTTP_MSG_RQBEFORE_CR);
Willy Tarreau8973c702007-01-21 23:58:29 +01001346 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001347
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001348 http_msg_rqbefore_cr:
1349 case HTTP_MSG_RQBEFORE_CR:
1350 EXPECT_LF_HERE(ptr, http_msg_invalid);
1351 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
Willy Tarreau8973c702007-01-21 23:58:29 +01001352 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001353
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001354 http_msg_rqmeth:
1355 case HTTP_MSG_RQMETH:
1356 case HTTP_MSG_RQMETH_SP:
1357 case HTTP_MSG_RQURI:
1358 case HTTP_MSG_RQURI_SP:
1359 case HTTP_MSG_RQVER:
1360 ptr = (char *)http_parse_reqline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001361 &buf->lr, &msg->msg_state);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001362 if (unlikely(!ptr))
1363 return;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001364
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001365 /* we have a full request and we know that we have either a CR
1366 * or an LF at <ptr>.
1367 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001368 //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 +01001369 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001370
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001371 msg->sol = ptr;
1372 if (likely(*ptr == '\r'))
1373 EAT_AND_JUMP_OR_RETURN(http_msg_rqline_end, HTTP_MSG_RQLINE_END);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001374 goto http_msg_rqline_end;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001375
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001376 http_msg_rqline_end:
1377 case HTTP_MSG_RQLINE_END:
1378 /* check for HTTP/0.9 request : no version information available.
1379 * msg->sol must point to the first of CR or LF.
1380 */
1381 if (unlikely(msg->sl.rq.v_l == 0))
1382 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001383
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001384 EXPECT_LF_HERE(ptr, http_msg_invalid);
1385 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
Willy Tarreau8973c702007-01-21 23:58:29 +01001386 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001387
Willy Tarreau8973c702007-01-21 23:58:29 +01001388 /*
1389 * Common states below
1390 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001391 http_msg_hdr_first:
1392 case HTTP_MSG_HDR_FIRST:
1393 msg->sol = ptr;
1394 if (likely(!HTTP_IS_CRLF(*ptr))) {
1395 goto http_msg_hdr_name;
1396 }
1397
1398 if (likely(*ptr == '\r'))
1399 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1400 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001401
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001402 http_msg_hdr_name:
1403 case HTTP_MSG_HDR_NAME:
1404 /* assumes msg->sol points to the first char */
1405 if (likely(HTTP_IS_TOKEN(*ptr)))
1406 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001407
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001408 if (likely(*ptr == ':')) {
1409 msg->col = ptr - buf->data;
1410 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
1411 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001412
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001413 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001414
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001415 http_msg_hdr_l1_sp:
1416 case HTTP_MSG_HDR_L1_SP:
1417 /* assumes msg->sol points to the first char and msg->col to the colon */
1418 if (likely(HTTP_IS_SPHT(*ptr)))
1419 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001420
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001421 /* header value can be basically anything except CR/LF */
1422 msg->sov = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001423
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001424 if (likely(!HTTP_IS_CRLF(*ptr))) {
1425 goto http_msg_hdr_val;
1426 }
1427
1428 if (likely(*ptr == '\r'))
1429 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lf, HTTP_MSG_HDR_L1_LF);
1430 goto http_msg_hdr_l1_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001431
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001432 http_msg_hdr_l1_lf:
1433 case HTTP_MSG_HDR_L1_LF:
1434 EXPECT_LF_HERE(ptr, http_msg_invalid);
1435 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lws, HTTP_MSG_HDR_L1_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001436
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001437 http_msg_hdr_l1_lws:
1438 case HTTP_MSG_HDR_L1_LWS:
1439 if (likely(HTTP_IS_SPHT(*ptr))) {
1440 /* replace HT,CR,LF with spaces */
1441 for (; buf->data+msg->sov < ptr; msg->sov++)
1442 buf->data[msg->sov] = ' ';
1443 goto http_msg_hdr_l1_sp;
1444 }
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001445 /* we had a header consisting only in spaces ! */
1446 msg->eol = buf->data + msg->sov;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001447 goto http_msg_complete_header;
1448
1449 http_msg_hdr_val:
1450 case HTTP_MSG_HDR_VAL:
1451 /* assumes msg->sol points to the first char, msg->col to the
1452 * colon, and msg->sov points to the first character of the
1453 * value.
1454 */
1455 if (likely(!HTTP_IS_CRLF(*ptr)))
1456 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001457
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001458 msg->eol = ptr;
1459 /* Note: we could also copy eol into ->eoh so that we have the
1460 * real header end in case it ends with lots of LWS, but is this
1461 * really needed ?
1462 */
1463 if (likely(*ptr == '\r'))
1464 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1465 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001466
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001467 http_msg_hdr_l2_lf:
1468 case HTTP_MSG_HDR_L2_LF:
1469 EXPECT_LF_HERE(ptr, http_msg_invalid);
1470 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001471
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001472 http_msg_hdr_l2_lws:
1473 case HTTP_MSG_HDR_L2_LWS:
1474 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1475 /* LWS: replace HT,CR,LF with spaces */
1476 for (; msg->eol < ptr; msg->eol++)
1477 *msg->eol = ' ';
1478 goto http_msg_hdr_val;
1479 }
1480 http_msg_complete_header:
1481 /*
1482 * It was a new header, so the last one is finished.
1483 * Assumes msg->sol points to the first char, msg->col to the
1484 * colon, msg->sov points to the first character of the value
1485 * and msg->eol to the first CR or LF so we know how the line
1486 * ends. We insert last header into the index.
1487 */
1488 /*
1489 fprintf(stderr,"registering %-2d bytes : ", msg->eol - msg->sol);
1490 write(2, msg->sol, msg->eol-msg->sol);
1491 fprintf(stderr,"\n");
1492 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001493
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001494 if (unlikely(hdr_idx_add(msg->eol - msg->sol, *msg->eol == '\r',
1495 idx, idx->tail) < 0))
1496 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001497
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001498 msg->sol = ptr;
1499 if (likely(!HTTP_IS_CRLF(*ptr))) {
1500 goto http_msg_hdr_name;
1501 }
1502
1503 if (likely(*ptr == '\r'))
1504 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1505 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001506
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001507 http_msg_last_lf:
1508 case HTTP_MSG_LAST_LF:
1509 /* Assumes msg->sol points to the first of either CR or LF */
1510 EXPECT_LF_HERE(ptr, http_msg_invalid);
1511 ptr++;
1512 buf->lr = ptr;
1513 msg->eoh = msg->sol - buf->data;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001514 msg->msg_state = HTTP_MSG_BODY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001515 return;
1516#ifdef DEBUG_FULL
1517 default:
1518 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1519 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001520#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001521 }
1522 http_msg_ood:
1523 /* out of data */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001524 msg->msg_state = state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001525 buf->lr = ptr;
1526 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001527
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001528 http_msg_invalid:
1529 /* invalid message */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001530 msg->msg_state = HTTP_MSG_ERROR;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001531 return;
1532}
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001533
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001534/*
1535 * manages the client FSM and its socket. BTW, it also tries to handle the
1536 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1537 * 0 else.
1538 */
1539int process_cli(struct session *t)
1540{
1541 int s = t->srv_state;
1542 int c = t->cli_state;
1543 struct buffer *req = t->req;
1544 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001545
Willy Tarreau6468d922008-08-03 19:15:35 +02001546 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 +01001547 cli_stnames[c], srv_stnames[s],
Willy Tarreauf161a342007-04-08 16:59:42 +02001548 EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
Willy Tarreau6468d922008-08-03 19:15:35 +02001549 req->rex, rep->wex);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001550
Willy Tarreaub6866442008-07-14 23:54:42 +02001551 if (c == CL_STINSPECT) {
1552 struct tcp_rule *rule;
1553 int partial;
1554
1555 /* We will abort if we encounter a read error. In theory,
1556 * we should not abort if we get a close, it might be
1557 * valid, also very unlikely. FIXME: we'll abort for now,
1558 * this will be easier to change later.
1559 */
1560 if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1561 t->inspect_exp = TICK_ETERNITY;
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001562 buffer_shutr_done(req);
1563 buffer_shutw_done(rep);
Willy Tarreaub6866442008-07-14 23:54:42 +02001564 fd_delete(t->cli_fd);
1565 t->cli_state = CL_STCLOSE;
1566 t->fe->failed_req++;
1567 if (!(t->flags & SN_ERR_MASK))
1568 t->flags |= SN_ERR_CLICL;
1569 if (!(t->flags & SN_FINST_MASK))
1570 t->flags |= SN_FINST_R;
1571 return 1;
1572 }
1573
1574 /* Abort if client read timeout has expired */
1575 else if (unlikely(tick_is_expired(req->rex, now_ms))) {
1576 t->inspect_exp = TICK_ETERNITY;
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001577 buffer_shutr_done(req);
1578 buffer_shutw_done(rep);
Willy Tarreaub6866442008-07-14 23:54:42 +02001579 fd_delete(t->cli_fd);
1580 t->cli_state = CL_STCLOSE;
1581 t->fe->failed_req++;
1582 if (!(t->flags & SN_ERR_MASK))
1583 t->flags |= SN_ERR_CLITO;
1584 if (!(t->flags & SN_FINST_MASK))
1585 t->flags |= SN_FINST_R;
1586 return 1;
1587 }
1588
1589 /* We don't know whether we have enough data, so must proceed
1590 * this way :
1591 * - iterate through all rules in their declaration order
1592 * - if one rule returns MISS, it means the inspect delay is
1593 * not over yet, then return immediately, otherwise consider
1594 * it as a non-match.
1595 * - if one rule returns OK, then return OK
1596 * - if one rule returns KO, then return KO
1597 */
1598
1599 if (tick_is_expired(t->inspect_exp, now_ms))
1600 partial = 0;
1601 else
1602 partial = ACL_PARTIAL;
1603
1604 list_for_each_entry(rule, &t->fe->tcp_req.inspect_rules, list) {
1605 int ret = ACL_PAT_PASS;
1606
1607 if (rule->cond) {
1608 ret = acl_exec_cond(rule->cond, t->fe, t, NULL, ACL_DIR_REQ | partial);
1609 if (ret == ACL_PAT_MISS) {
1610 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
1611 return 0;
1612 }
1613 ret = acl_pass(ret);
1614 if (rule->cond->pol == ACL_COND_UNLESS)
1615 ret = !ret;
1616 }
1617
1618 if (ret) {
1619 /* we have a matching rule. */
1620 if (rule->action == TCP_ACT_REJECT) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001621 buffer_shutr_done(req);
1622 buffer_shutw_done(rep);
Willy Tarreaub6866442008-07-14 23:54:42 +02001623 fd_delete(t->cli_fd);
1624 t->cli_state = CL_STCLOSE;
1625 t->fe->failed_req++;
1626 if (!(t->flags & SN_ERR_MASK))
1627 t->flags |= SN_ERR_PRXCOND;
1628 if (!(t->flags & SN_FINST_MASK))
1629 t->flags |= SN_FINST_R;
1630 t->inspect_exp = TICK_ETERNITY;
1631 return 1;
1632 }
1633 /* otherwise accept */
1634 break;
1635 }
1636 }
1637
1638 /* if we get there, it means we have no rule which matches, so
1639 * we apply the default accept.
1640 */
1641 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
1642 if (t->fe->mode == PR_MODE_HTTP) {
1643 t->cli_state = CL_STHEADERS;
1644 t->txn.exp = tick_add_ifset(now_ms, t->fe->timeout.httpreq);
1645 } else {
1646 t->cli_state = CL_STDATA;
1647 }
1648 t->inspect_exp = TICK_ETERNITY;
1649 return 1;
1650 }
1651 else if (c == CL_STHEADERS) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001652 /*
1653 * Now parse the partial (or complete) lines.
1654 * We will check the request syntax, and also join multi-line
1655 * headers. An index of all the lines will be elaborated while
1656 * parsing.
1657 *
Willy Tarreau8973c702007-01-21 23:58:29 +01001658 * For the parsing, we use a 28 states FSM.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001659 *
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001660 * Here is the information we currently have :
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001661 * req->data + req->som = beginning of request
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001662 * req->data + req->eoh = end of processed headers / start of current one
1663 * req->data + req->eol = end of current header or line (LF or CRLF)
1664 * req->lr = first non-visited byte
1665 * req->r = end of data
1666 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001667
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001668 int cur_idx;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001669 struct http_txn *txn = &t->txn;
1670 struct http_msg *msg = &txn->req;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001671 struct proxy *cur_proxy;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001672
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001673 if (likely(req->lr < req->r))
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001674 http_msg_analyzer(req, msg, &txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001675
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001676 /* 1: we might have to print this header in debug mode */
1677 if (unlikely((global.mode & MODE_DEBUG) &&
1678 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001679 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001680 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001681
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001682 sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001683 eol = sol + msg->sl.rq.l;
1684 debug_hdr("clireq", t, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001685
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001686 sol += hdr_idx_first_pos(&txn->hdr_idx);
1687 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001688
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001689 while (cur_idx) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001690 eol = sol + txn->hdr_idx.v[cur_idx].len;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001691 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001692 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
1693 cur_idx = txn->hdr_idx.v[cur_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001694 }
1695 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001696
Willy Tarreau58f10d72006-12-04 02:26:12 +01001697
1698 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001699 * Now we quickly check if we have found a full valid request.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001700 * If not so, we check the FD and buffer states before leaving.
1701 * A full request is indicated by the fact that we have seen
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001702 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
1703 * requests are checked first.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001704 *
1705 */
1706
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001707 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001708 /*
1709 * First, let's catch bad requests.
1710 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001711 if (unlikely(msg->msg_state == HTTP_MSG_ERROR))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001712 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001713
1714 /* 1: Since we are in header mode, if there's no space
1715 * left for headers, we won't be able to free more
1716 * later, so the session will never terminate. We
1717 * must terminate it now.
1718 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001719 if (unlikely(req->l >= req->rlim - req->data)) {
1720 /* FIXME: check if URI is set and return Status
1721 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001722 */
Willy Tarreau06619262006-12-17 08:37:22 +01001723 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001724 }
1725
1726 /* 2: have we encountered a read error or a close ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001727 else if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1728 /* read error, or last read : give up. */
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001729 buffer_shutr_done(req);
1730 buffer_shutw_done(rep);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001731 fd_delete(t->cli_fd);
1732 t->cli_state = CL_STCLOSE;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001733 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001734 if (!(t->flags & SN_ERR_MASK))
1735 t->flags |= SN_ERR_CLICL;
1736 if (!(t->flags & SN_FINST_MASK))
1737 t->flags |= SN_FINST_R;
1738 return 1;
1739 }
1740
1741 /* 3: has the read timeout expired ? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001742 else if (unlikely(tick_is_expired(req->rex, now_ms) ||
1743 tick_is_expired(txn->exp, now_ms))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001744 /* read timeout : give up with an error message. */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001745 txn->status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +01001746 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001747 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001748 if (!(t->flags & SN_ERR_MASK))
1749 t->flags |= SN_ERR_CLITO;
1750 if (!(t->flags & SN_FINST_MASK))
1751 t->flags |= SN_FINST_R;
1752 return 1;
1753 }
1754
1755 /* 4: do we need to re-enable the read socket ? */
Willy Tarreau66319382007-04-08 17:17:37 +02001756 else if (unlikely(EV_FD_COND_S(t->cli_fd, DIR_RD))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02001757 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreau58f10d72006-12-04 02:26:12 +01001758 * full. We cannot loop here since stream_sock_read will disable it only if
1759 * req->l == rlim-data
1760 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001761 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001762 }
1763 return t->cli_state != CL_STHEADERS;
1764 }
1765
1766
1767 /****************************************************************
1768 * More interesting part now : we know that we have a complete *
1769 * request which at least looks like HTTP. We have an indicator *
1770 * of each header's length, so we can parse them quickly. *
1771 ****************************************************************/
1772
Willy Tarreau9cdde232007-05-02 20:58:19 +02001773 /* ensure we keep this pointer to the beginning of the message */
1774 msg->sol = req->data + msg->som;
1775
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001776 /*
1777 * 1: identify the method
1778 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001779 txn->meth = find_http_meth(&req->data[msg->som], msg->sl.rq.m_l);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001780
1781 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001782 * 2: check if the URI matches the monitor_uri.
Willy Tarreau06619262006-12-17 08:37:22 +01001783 * We have to do this for every request which gets in, because
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001784 * the monitor-uri is defined by the frontend.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001785 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001786 if (unlikely((t->fe->monitor_uri_len != 0) &&
1787 (t->fe->monitor_uri_len == msg->sl.rq.u_l) &&
1788 !memcmp(&req->data[msg->sl.rq.u],
1789 t->fe->monitor_uri,
1790 t->fe->monitor_uri_len))) {
1791 /*
1792 * We have found the monitor URI
1793 */
Willy Tarreaub80c2302007-11-30 20:51:32 +01001794 struct acl_cond *cond;
1795 cur_proxy = t->fe;
1796
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001797 t->flags |= SN_MONITOR;
Willy Tarreaub80c2302007-11-30 20:51:32 +01001798
1799 /* Check if we want to fail this monitor request or not */
1800 list_for_each_entry(cond, &cur_proxy->mon_fail_cond, list) {
1801 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001802
1803 ret = acl_pass(ret);
Willy Tarreaub80c2302007-11-30 20:51:32 +01001804 if (cond->pol == ACL_COND_UNLESS)
1805 ret = !ret;
1806
1807 if (ret) {
1808 /* we fail this request, let's return 503 service unavail */
1809 txn->status = 503;
1810 client_retnclose(t, error_message(t, HTTP_ERR_503));
1811 goto return_prx_cond;
1812 }
1813 }
1814
1815 /* nothing to fail, let's reply normaly */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001816 txn->status = 200;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001817 client_retnclose(t, &http_200_chunk);
1818 goto return_prx_cond;
1819 }
1820
1821 /*
1822 * 3: Maybe we have to copy the original REQURI for the logs ?
1823 * Note: we cannot log anymore if the request has been
1824 * classified as invalid.
1825 */
1826 if (unlikely(t->logs.logwait & LW_REQ)) {
1827 /* we have a complete HTTP request that we must log */
Willy Tarreau332f8bf2007-05-13 21:36:56 +02001828 if ((txn->uri = pool_alloc2(pool2_requri)) != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001829 int urilen = msg->sl.rq.l;
1830
1831 if (urilen >= REQURI_LEN)
1832 urilen = REQURI_LEN - 1;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001833 memcpy(txn->uri, &req->data[msg->som], urilen);
1834 txn->uri[urilen] = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001835
1836 if (!(t->logs.logwait &= ~LW_REQ))
Willy Tarreau42250582007-04-01 01:30:43 +02001837 http_sess_log(t);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001838 } else {
1839 Alert("HTTP logging : out of memory.\n");
1840 }
1841 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001842
Willy Tarreau06619262006-12-17 08:37:22 +01001843
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001844 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
1845 if (unlikely(msg->sl.rq.v_l == 0)) {
1846 int delta;
1847 char *cur_end;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001848 msg->sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001849 cur_end = msg->sol + msg->sl.rq.l;
1850 delta = 0;
Willy Tarreau06619262006-12-17 08:37:22 +01001851
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001852 if (msg->sl.rq.u_l == 0) {
1853 /* if no URI was set, add "/" */
1854 delta = buffer_replace2(req, cur_end, cur_end, " /", 2);
1855 cur_end += delta;
1856 msg->eoh += delta;
Willy Tarreau06619262006-12-17 08:37:22 +01001857 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001858 /* add HTTP version */
1859 delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
1860 msg->eoh += delta;
1861 cur_end += delta;
1862 cur_end = (char *)http_parse_reqline(msg, req->data,
1863 HTTP_MSG_RQMETH,
1864 msg->sol, cur_end + 1,
1865 NULL, NULL);
1866 if (unlikely(!cur_end))
1867 goto return_bad_req;
1868
1869 /* we have a full HTTP/1.0 request now and we know that
1870 * we have either a CR or an LF at <ptr>.
1871 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001872 hdr_idx_set_start(&txn->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
Willy Tarreau58f10d72006-12-04 02:26:12 +01001873 }
1874
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001875
1876 /* 5: we may need to capture headers */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001877 if (unlikely((t->logs.logwait & LW_REQHDR) && t->fe->req_cap))
Willy Tarreau117f59e2007-03-04 18:17:17 +01001878 capture_headers(req->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001879 txn->req.cap, t->fe->req_cap);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001880
1881 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001882 * 6: we will have to evaluate the filters.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001883 * As opposed to version 1.2, now they will be evaluated in the
1884 * filters order and not in the header order. This means that
1885 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001886 *
1887 * We can now check whether we want to switch to another
1888 * backend, in which case we will re-check the backend's
1889 * filters and various options. In order to support 3-level
1890 * switching, here's how we should proceed :
1891 *
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001892 * a) run be.
Willy Tarreau830ff452006-12-17 19:31:23 +01001893 * if (switch) then switch ->be to the new backend.
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001894 * b) run be if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001895 * There cannot be any switch from there, so ->be cannot be
1896 * changed anymore.
1897 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001898 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001899 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001900 * The response path will be able to apply either ->be, or
1901 * ->be then ->fe filters in order to match the reverse of
1902 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001903 */
1904
Willy Tarreau06619262006-12-17 08:37:22 +01001905 do {
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001906 struct acl_cond *cond;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001907 struct redirect_rule *rule;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001908 struct proxy *rule_set = t->be;
Willy Tarreau830ff452006-12-17 19:31:23 +01001909 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001910
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001911 /* first check whether we have some ACLs set to redirect this request */
1912 list_for_each_entry(rule, &cur_proxy->redirect_rules, list) {
1913 int ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001914
1915 ret = acl_pass(ret);
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001916 if (rule->cond->pol == ACL_COND_UNLESS)
1917 ret = !ret;
1918
1919 if (ret) {
1920 struct chunk rdr = { trash, 0 };
1921 const char *msg_fmt;
1922
1923 /* build redirect message */
1924 switch(rule->code) {
1925 case 303:
1926 rdr.len = strlen(HTTP_303);
1927 msg_fmt = HTTP_303;
1928 break;
1929 case 301:
1930 rdr.len = strlen(HTTP_301);
1931 msg_fmt = HTTP_301;
1932 break;
1933 case 302:
1934 default:
1935 rdr.len = strlen(HTTP_302);
1936 msg_fmt = HTTP_302;
1937 break;
1938 }
1939
1940 if (unlikely(rdr.len > sizeof(trash)))
1941 goto return_bad_req;
1942 memcpy(rdr.str, msg_fmt, rdr.len);
1943
1944 switch(rule->type) {
1945 case REDIRECT_TYPE_PREFIX: {
1946 const char *path;
1947 int pathlen;
1948
1949 path = http_get_path(txn);
1950 /* build message using path */
1951 if (path) {
1952 pathlen = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
1953 } else {
1954 path = "/";
1955 pathlen = 1;
1956 }
1957
1958 if (rdr.len + rule->rdr_len + pathlen > sizeof(trash) - 4)
1959 goto return_bad_req;
1960
1961 /* add prefix */
1962 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1963 rdr.len += rule->rdr_len;
1964
1965 /* add path */
1966 memcpy(rdr.str + rdr.len, path, pathlen);
1967 rdr.len += pathlen;
1968 break;
1969 }
1970 case REDIRECT_TYPE_LOCATION:
1971 default:
1972 if (rdr.len + rule->rdr_len > sizeof(trash) - 4)
1973 goto return_bad_req;
1974
1975 /* add location */
1976 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1977 rdr.len += rule->rdr_len;
1978 break;
1979 }
1980
1981 /* add end of headers */
1982 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
1983 rdr.len += 4;
1984
1985 txn->status = rule->code;
1986 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02001987 t->logs.tv_request = now;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001988 client_retnclose(t, &rdr);
1989 goto return_prx_cond;
1990 }
1991 }
1992
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001993 /* first check whether we have some ACLs set to block this request */
1994 list_for_each_entry(cond, &cur_proxy->block_cond, list) {
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001995 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001996
1997 ret = acl_pass(ret);
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001998 if (cond->pol == ACL_COND_UNLESS)
1999 ret = !ret;
2000
2001 if (ret) {
2002 txn->status = 403;
2003 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02002004 t->logs.tv_request = now;
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02002005 client_retnclose(t, error_message(t, HTTP_ERR_403));
2006 goto return_prx_cond;
2007 }
2008 }
2009
Willy Tarreau06619262006-12-17 08:37:22 +01002010 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01002011 if (rule_set->req_exp != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002012 if (apply_filters_to_request(t, req, rule_set->req_exp) < 0)
2013 goto return_bad_req;
Willy Tarreau53b6c742006-12-17 13:37:46 +01002014 }
2015
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002016 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
2017 /* to ensure correct connection accounting on
2018 * the backend, we count the connection for the
2019 * one managing the queue.
2020 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002021 t->be->beconn++;
2022 if (t->be->beconn > t->be->beconn_max)
2023 t->be->beconn_max = t->be->beconn;
2024 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002025 t->flags |= SN_BE_ASSIGNED;
2026 }
2027
Willy Tarreau06619262006-12-17 08:37:22 +01002028 /* has the request been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01002029 if (txn->flags & TX_CLDENY) {
Willy Tarreau06619262006-12-17 08:37:22 +01002030 /* no need to go further */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002031 txn->status = 403;
Willy Tarreau06619262006-12-17 08:37:22 +01002032 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02002033 t->logs.tv_request = now;
Willy Tarreau80587432006-12-24 17:47:20 +01002034 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01002035 goto return_prx_cond;
2036 }
2037
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002038 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002039 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002040 !(t->flags & SN_CONN_CLOSED)) {
2041 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002042 int cur_idx, old_idx, delta, val;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002043 struct hdr_idx_elem *cur_hdr;
Willy Tarreau06619262006-12-17 08:37:22 +01002044
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002045 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002046 old_idx = 0;
2047
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002048 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
2049 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002050 cur_ptr = cur_next;
2051 cur_end = cur_ptr + cur_hdr->len;
2052 cur_next = cur_end + cur_hdr->cr + 1;
2053
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002054 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
2055 if (val) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002056 /* 3 possibilities :
2057 * - we have already set Connection: close,
2058 * so we remove this line.
2059 * - we have not yet set Connection: close,
2060 * but this line indicates close. We leave
2061 * it untouched and set the flag.
2062 * - we have not yet set Connection: close,
2063 * and this line indicates non-close. We
2064 * replace it.
2065 */
2066 if (t->flags & SN_CONN_CLOSED) {
2067 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002068 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002069 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002070 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
2071 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002072 cur_hdr->len = 0;
2073 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002074 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
2075 delta = buffer_replace2(req, cur_ptr + val, cur_end,
2076 "close", 5);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002077 cur_next += delta;
2078 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002079 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002080 }
2081 t->flags |= SN_CONN_CLOSED;
2082 }
2083 }
2084 old_idx = cur_idx;
2085 }
Willy Tarreauf2f0ee82007-03-30 12:02:43 +02002086 }
2087 /* add request headers from the rule sets in the same order */
2088 for (cur_idx = 0; cur_idx < rule_set->nb_reqadd; cur_idx++) {
2089 if (unlikely(http_header_add_tail(req,
2090 &txn->req,
2091 &txn->hdr_idx,
2092 rule_set->req_add[cur_idx])) < 0)
2093 goto return_bad_req;
Willy Tarreau06619262006-12-17 08:37:22 +01002094 }
Willy Tarreaub2513902006-12-17 14:52:38 +01002095
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002096 /* check if stats URI was requested, and if an auth is needed */
Willy Tarreau0214c3a2007-01-07 13:47:30 +01002097 if (rule_set->uri_auth != NULL &&
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002098 (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)) {
Willy Tarreaub2513902006-12-17 14:52:38 +01002099 /* we have to check the URI and auth for this request */
2100 if (stats_check_uri_auth(t, rule_set))
2101 return 1;
2102 }
2103
Willy Tarreau55ea7572007-06-17 19:56:27 +02002104 /* now check whether we have some switching rules for this request */
2105 if (!(t->flags & SN_BE_ASSIGNED)) {
2106 struct switching_rule *rule;
2107
2108 list_for_each_entry(rule, &cur_proxy->switching_rules, list) {
2109 int ret;
2110
2111 ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02002112
2113 ret = acl_pass(ret);
Willy Tarreaua8cfa342008-07-09 11:23:31 +02002114 if (rule->cond->pol == ACL_COND_UNLESS)
Willy Tarreau55ea7572007-06-17 19:56:27 +02002115 ret = !ret;
2116
2117 if (ret) {
2118 t->be = rule->be.backend;
2119 t->be->beconn++;
2120 if (t->be->beconn > t->be->beconn_max)
2121 t->be->beconn_max = t->be->beconn;
2122 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002123
2124 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002125 t->rep->rto = t->req->wto = t->be->timeout.server;
2126 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002127 t->conn_retries = t->be->conn_retries;
Willy Tarreau55ea7572007-06-17 19:56:27 +02002128 t->flags |= SN_BE_ASSIGNED;
2129 break;
2130 }
2131 }
2132 }
2133
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002134 if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
2135 /* No backend was set, but there was a default
2136 * backend set in the frontend, so we use it and
2137 * loop again.
2138 */
2139 t->be = cur_proxy->defbe.be;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002140 t->be->beconn++;
2141 if (t->be->beconn > t->be->beconn_max)
2142 t->be->beconn_max = t->be->beconn;
2143 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002144
2145 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002146 t->rep->rto = t->req->wto = t->be->timeout.server;
2147 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002148 t->conn_retries = t->be->conn_retries;
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002149 t->flags |= SN_BE_ASSIGNED;
2150 }
2151 } while (t->be != cur_proxy); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01002152
Willy Tarreau58f10d72006-12-04 02:26:12 +01002153
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002154 if (!(t->flags & SN_BE_ASSIGNED)) {
2155 /* To ensure correct connection accounting on
2156 * the backend, we count the connection for the
2157 * one managing the queue.
2158 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002159 t->be->beconn++;
2160 if (t->be->beconn > t->be->beconn_max)
2161 t->be->beconn_max = t->be->beconn;
2162 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002163 t->flags |= SN_BE_ASSIGNED;
2164 }
2165
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002166 /*
2167 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01002168 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002169 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01002170 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01002171 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01002172
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01002173 /*
2174 * If HTTP PROXY is set we simply get remote server address
2175 * parsing incoming request.
2176 */
2177 if ((t->be->options & PR_O_HTTP_PROXY) && !(t->flags & SN_ADDR_SET)) {
2178 url2sa(req->data + msg->sl.rq.u, msg->sl.rq.u_l, &t->srv_addr);
2179 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002180
Willy Tarreau2a324282006-12-05 00:05:46 +01002181 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002182 * 7: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01002183 * so let's do the same now.
2184 */
2185
2186 /* It needs to look into the URI */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002187 if (t->be->appsession_name) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01002188 get_srv_from_appsession(t, &req->data[msg->som], msg->sl.rq.l);
Willy Tarreau06619262006-12-17 08:37:22 +01002189 }
2190
2191
2192 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002193 * 8: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01002194 * Note that doing so might move headers in the request, but
2195 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01002196 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01002197 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01002198 if ((t->be->cookie_name || t->be->appsession_name || t->be->capture_name)
2199 && !(txn->flags & (TX_CLDENY|TX_CLTARPIT)))
Willy Tarreau2a324282006-12-05 00:05:46 +01002200 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01002201
Willy Tarreau58f10d72006-12-04 02:26:12 +01002202
Willy Tarreau2a324282006-12-05 00:05:46 +01002203 /*
Willy Tarreaubb046ac2007-03-03 19:17:03 +01002204 * 9: add X-Forwarded-For if either the frontend or the backend
2205 * asks for it.
Willy Tarreau2a324282006-12-05 00:05:46 +01002206 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002207 if ((t->fe->options | t->be->options) & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002208 if (t->cli_addr.ss_family == AF_INET) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002209 /* Add an X-Forwarded-For header unless the source IP is
2210 * in the 'except' network range.
2211 */
2212 if ((!t->fe->except_mask.s_addr ||
2213 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->fe->except_mask.s_addr)
2214 != t->fe->except_net.s_addr) &&
2215 (!t->be->except_mask.s_addr ||
2216 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->be->except_mask.s_addr)
2217 != t->be->except_net.s_addr)) {
2218 int len;
2219 unsigned char *pn;
2220 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
Willy Tarreau45e73e32006-12-17 00:05:15 +01002221
Ross Westaf72a1d2008-08-03 10:51:45 +02002222 /* Note: we rely on the backend to get the header name to be used for
2223 * x-forwarded-for, because the header is really meant for the backends.
2224 * However, if the backend did not specify any option, we have to rely
2225 * on the frontend's header name.
2226 */
2227 if (t->be->fwdfor_hdr_len) {
2228 len = t->be->fwdfor_hdr_len;
2229 memcpy(trash, t->be->fwdfor_hdr_name, len);
2230 } else {
2231 len = t->fe->fwdfor_hdr_len;
2232 memcpy(trash, t->fe->fwdfor_hdr_name, len);
2233 }
2234 len += sprintf(trash + len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002235
Ross Westaf72a1d2008-08-03 10:51:45 +02002236 if (unlikely(http_header_add_tail2(req, &txn->req,
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002237 &txn->hdr_idx, trash, len)) < 0)
2238 goto return_bad_req;
2239 }
Willy Tarreau2a324282006-12-05 00:05:46 +01002240 }
2241 else if (t->cli_addr.ss_family == AF_INET6) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002242 /* FIXME: for the sake of completeness, we should also support
2243 * 'except' here, although it is mostly useless in this case.
2244 */
Willy Tarreau2a324282006-12-05 00:05:46 +01002245 int len;
2246 char pn[INET6_ADDRSTRLEN];
2247 inet_ntop(AF_INET6,
2248 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2249 pn, sizeof(pn));
Ross Westaf72a1d2008-08-03 10:51:45 +02002250
2251 /* Note: we rely on the backend to get the header name to be used for
2252 * x-forwarded-for, because the header is really meant for the backends.
2253 * However, if the backend did not specify any option, we have to rely
2254 * on the frontend's header name.
2255 */
2256 if (t->be->fwdfor_hdr_len) {
2257 len = t->be->fwdfor_hdr_len;
2258 memcpy(trash, t->be->fwdfor_hdr_name, len);
2259 } else {
2260 len = t->fe->fwdfor_hdr_len;
2261 memcpy(trash, t->fe->fwdfor_hdr_name, len);
2262 }
2263 len += sprintf(trash + len, ": %s", pn);
2264
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002265 if (unlikely(http_header_add_tail2(req, &txn->req,
2266 &txn->hdr_idx, trash, len)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002267 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01002268 }
2269 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002270
Willy Tarreau2a324282006-12-05 00:05:46 +01002271 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002272 * 10: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02002273 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaub2513902006-12-17 14:52:38 +01002274 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02002275 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002276 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02002277 if ((unlikely(msg->sl.rq.v_l != 8) ||
2278 unlikely(req->data[msg->som + msg->sl.rq.v + 7] != '0')) &&
2279 unlikely(http_header_add_tail2(req, &txn->req, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002280 "Connection: close", 17)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002281 goto return_bad_req;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002282 t->flags |= SN_CONN_CLOSED;
Willy Tarreaue15d9132006-12-14 22:26:42 +01002283 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002284 /* Before we switch to data, was assignment set in manage_client_side_cookie?
2285 * If not assigned, perhaps we are balancing on url_param, but this is a
2286 * POST; and the parameters are in the body, maybe scan there to find our server.
2287 * (unless headers overflowed the buffer?)
2288 */
2289 if (!(t->flags & (SN_ASSIGNED|SN_DIRECT)) &&
2290 t->txn.meth == HTTP_METH_POST && t->be->url_param_name != NULL &&
2291 t->be->url_param_post_limit != 0 && req->total < BUFSIZE &&
2292 memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) {
2293 /* are there enough bytes here? total == l || r || rlim ?
2294 * len is unsigned, but eoh is int,
2295 * how many bytes of body have we received?
2296 * eoh is the first empty line of the header
2297 */
2298 /* already established CRLF or LF at eoh, move to start of message, find message length in buffer */
2299 unsigned long len = req->total - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1);
2300
2301 /* If we have HTTP/1.1 and Expect: 100-continue, then abort.
2302 * We can't assume responsibility for the server's decision,
2303 * on this URI and header set. See rfc2616: 14.20, 8.2.3,
2304 * We also can't change our mind later, about which server to choose, so round robin.
2305 */
2306 if ((likely(msg->sl.rq.v_l == 8) && req->data[msg->som + msg->sl.rq.v + 7] == '1')) {
2307 struct hdr_ctx ctx;
2308 ctx.idx = 0;
2309 /* Expect is allowed in 1.1, look for it */
2310 http_find_header2("Expect", 6, msg->sol, &txn->hdr_idx, &ctx);
2311 if (ctx.idx != 0 &&
2312 unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val,"100-continue",12)==0))
2313 /* We can't reliablly stall and wait for data, because of
2314 * .NET clients that don't conform to rfc2616; so, no need for
2315 * the next block to check length expectations.
2316 * We could send 100 status back to the client, but then we need to
2317 * re-write headers, and send the message. And this isn't the right
2318 * place for that action.
2319 * TODO: support Expect elsewhere and delete this block.
2320 */
2321 goto end_check_maybe_wait_for_body;
2322 }
2323 if ( likely(len > t->be->url_param_post_limit) ) {
2324 /* nothing to do, we got enough */
2325 } else {
2326 /* limit implies we are supposed to need this many bytes
2327 * to find the parameter. Let's see how many bytes we can wait for.
2328 */
2329 long long hint = len;
2330 struct hdr_ctx ctx;
2331 ctx.idx = 0;
2332 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
2333 if (unlikely(ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",7)==0)) {
2334 t->srv_state = SV_STANALYZE;
2335 } else {
2336 ctx.idx = 0;
2337 http_find_header2("Content-Length", 14, msg->sol, &txn->hdr_idx, &ctx);
2338 /* now if we have a length, we'll take the hint */
2339 if ( ctx.idx ) {
2340 /* We have Content-Length */
2341 if ( strl2llrc(ctx.line+ctx.val,ctx.vlen, &hint) )
2342 hint = 0; /* parse failure, untrusted client */
2343 else {
2344 if ( hint > 0 )
2345 msg->hdr_content_len = hint;
2346 else
2347 hint = 0; /* bad client, sent negative length */
2348 }
2349 }
2350 /* but limited to what we care about, maybe we don't expect any entity data (hint == 0) */
2351 if ( t->be->url_param_post_limit < hint )
2352 hint = t->be->url_param_post_limit;
2353 /* now do we really need to buffer more data? */
2354 if ( len < hint )
2355 t->srv_state = SV_STANALYZE;
2356 /* else... There are no body bytes to wait for */
2357 }
2358 }
2359 }
2360 end_check_maybe_wait_for_body:
Willy Tarreaubaaee002006-06-26 02:48:02 +02002361
Willy Tarreau2a324282006-12-05 00:05:46 +01002362 /*************************************************************
2363 * OK, that's finished for the headers. We have done what we *
2364 * could. Let's switch to the DATA state. *
2365 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02002366
Willy Tarreau2a324282006-12-05 00:05:46 +01002367 t->cli_state = CL_STDATA;
2368 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002369
Willy Tarreau70089872008-06-13 21:12:51 +02002370 t->logs.tv_request = now;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002371
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002372 if (!t->fe->timeout.client ||
2373 (t->srv_state < SV_STDATA && t->be->timeout.server)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002374 /* If the client has no timeout, or if the server is not ready yet,
2375 * and we know for sure that it can expire, then it's cleaner to
2376 * disable the timeout on the client side so that too low values
2377 * cannot make the sessions abort too early.
2378 *
2379 * FIXME-20050705: the server needs a way to re-enable this time-out
2380 * when it switches its state, otherwise a client can stay connected
2381 * indefinitely. This now seems to be OK.
2382 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002383 req->rex = TICK_ETERNITY;
Willy Tarreau2a324282006-12-05 00:05:46 +01002384 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002385
Willy Tarreau1fa31262007-12-03 00:36:16 +01002386 /* When a connection is tarpitted, we use the tarpit timeout,
2387 * which may be the same as the connect timeout if unspecified.
2388 * If unset, then set it to zero because we really want it to
2389 * eventually expire.
Willy Tarreau2a324282006-12-05 00:05:46 +01002390 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002391 if (txn->flags & TX_CLTARPIT) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002392 t->req->l = 0;
2393 /* flush the request so that we can drop the connection early
2394 * if the client closes first.
2395 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002396 req->cex = tick_add_ifset(now_ms, t->be->timeout.tarpit);
2397 if (!req->cex)
2398 req->cex = now_ms;
Willy Tarreau2a324282006-12-05 00:05:46 +01002399 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002400
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002401 /* OK let's go on with the BODY now */
Willy Tarreau06619262006-12-17 08:37:22 +01002402 goto process_data;
2403
2404 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002405 txn->req.msg_state = HTTP_MSG_ERROR;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002406 txn->status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01002407 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002408 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01002409 return_prx_cond:
2410 if (!(t->flags & SN_ERR_MASK))
2411 t->flags |= SN_ERR_PRXCOND;
2412 if (!(t->flags & SN_FINST_MASK))
2413 t->flags |= SN_FINST_R;
2414 return 1;
2415
Willy Tarreaubaaee002006-06-26 02:48:02 +02002416 }
2417 else if (c == CL_STDATA) {
2418 process_data:
2419 /* FIXME: this error handling is partly buggy because we always report
2420 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
2421 * or HEADER phase. BTW, it's not logical to expire the client while
2422 * we're waiting for the server to connect.
2423 */
2424 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002425 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002426 buffer_shutr_done(req);
2427 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002428 fd_delete(t->cli_fd);
2429 t->cli_state = CL_STCLOSE;
2430 if (!(t->flags & SN_ERR_MASK))
2431 t->flags |= SN_ERR_CLICL;
2432 if (!(t->flags & SN_FINST_MASK)) {
2433 if (t->pend_pos)
2434 t->flags |= SN_FINST_Q;
2435 else if (s == SV_STCONN)
2436 t->flags |= SN_FINST_C;
2437 else
2438 t->flags |= SN_FINST_D;
2439 }
2440 return 1;
2441 }
2442 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002443 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002444 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002445 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002446 t->cli_state = CL_STSHUTR;
2447 return 1;
2448 }
2449 /* last server read and buffer empty */
2450 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002451 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002452 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002453 shutdown(t->cli_fd, SHUT_WR);
2454 /* We must ensure that the read part is still alive when switching
2455 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002456 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002457 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002458 t->cli_state = CL_STSHUTW;
2459 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2460 return 1;
2461 }
2462 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002463 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002464 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002465 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002466 t->cli_state = CL_STSHUTR;
2467 if (!(t->flags & SN_ERR_MASK))
2468 t->flags |= SN_ERR_CLITO;
2469 if (!(t->flags & SN_FINST_MASK)) {
2470 if (t->pend_pos)
2471 t->flags |= SN_FINST_Q;
2472 else if (s == SV_STCONN)
2473 t->flags |= SN_FINST_C;
2474 else
2475 t->flags |= SN_FINST_D;
2476 }
2477 return 1;
2478 }
2479 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002480 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002481 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002482 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002483 shutdown(t->cli_fd, SHUT_WR);
2484 /* We must ensure that the read part is still alive when switching
2485 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002486 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002487 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002488
2489 t->cli_state = CL_STSHUTW;
2490 if (!(t->flags & SN_ERR_MASK))
2491 t->flags |= SN_ERR_CLITO;
2492 if (!(t->flags & SN_FINST_MASK)) {
2493 if (t->pend_pos)
2494 t->flags |= SN_FINST_Q;
2495 else if (s == SV_STCONN)
2496 t->flags |= SN_FINST_C;
2497 else
2498 t->flags |= SN_FINST_D;
2499 }
2500 return 1;
2501 }
2502
2503 if (req->l >= req->rlim - req->data) {
2504 /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02002505 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002506 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002507 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002508 }
2509 } else {
2510 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002511 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002512 if (!t->fe->timeout.client ||
2513 (t->srv_state < SV_STDATA && t->be->timeout.server))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002514 /* If the client has no timeout, or if the server not ready yet, and we
2515 * know for sure that it can expire, then it's cleaner to disable the
2516 * timeout on the client side so that too low values cannot make the
2517 * sessions abort too early.
2518 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002519 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002520 else
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002521 req->rex = tick_add(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002522 }
2523 }
2524
2525 if ((rep->l == 0) ||
2526 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002527 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2528 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002529 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002530 }
2531 } else {
2532 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002533 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2534 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002535 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
2536 if (rep->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002537 /* FIXME: to prevent the client from expiring read timeouts during writes,
2538 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002539 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002540 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002541 }
2542 }
2543 return 0; /* other cases change nothing */
2544 }
2545 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002546 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002547 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002548 fd_delete(t->cli_fd);
2549 t->cli_state = CL_STCLOSE;
2550 if (!(t->flags & SN_ERR_MASK))
2551 t->flags |= SN_ERR_CLICL;
2552 if (!(t->flags & SN_FINST_MASK)) {
2553 if (t->pend_pos)
2554 t->flags |= SN_FINST_Q;
2555 else if (s == SV_STCONN)
2556 t->flags |= SN_FINST_C;
2557 else
2558 t->flags |= SN_FINST_D;
2559 }
2560 return 1;
2561 }
2562 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
2563 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002564 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002565 fd_delete(t->cli_fd);
2566 t->cli_state = CL_STCLOSE;
2567 return 1;
2568 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002569 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002570 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002571 fd_delete(t->cli_fd);
2572 t->cli_state = CL_STCLOSE;
2573 if (!(t->flags & SN_ERR_MASK))
2574 t->flags |= SN_ERR_CLITO;
2575 if (!(t->flags & SN_FINST_MASK)) {
2576 if (t->pend_pos)
2577 t->flags |= SN_FINST_Q;
2578 else if (s == SV_STCONN)
2579 t->flags |= SN_FINST_C;
2580 else
2581 t->flags |= SN_FINST_D;
2582 }
2583 return 1;
2584 }
2585
2586 if (t->flags & SN_SELF_GEN) {
2587 produce_content(t);
2588 if (rep->l == 0) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002589 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002590 fd_delete(t->cli_fd);
2591 t->cli_state = CL_STCLOSE;
2592 return 1;
2593 }
2594 }
2595
2596 if ((rep->l == 0)
2597 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002598 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2599 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002600 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002601 }
2602 } else {
2603 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002604 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2605 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002606 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002607 }
2608 }
2609 return 0;
2610 }
2611 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002612 if (req->flags & BF_READ_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002613 buffer_shutr_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002614 fd_delete(t->cli_fd);
2615 t->cli_state = CL_STCLOSE;
2616 if (!(t->flags & SN_ERR_MASK))
2617 t->flags |= SN_ERR_CLICL;
2618 if (!(t->flags & SN_FINST_MASK)) {
2619 if (t->pend_pos)
2620 t->flags |= SN_FINST_Q;
2621 else if (s == SV_STCONN)
2622 t->flags |= SN_FINST_C;
2623 else
2624 t->flags |= SN_FINST_D;
2625 }
2626 return 1;
2627 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002628 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002629 buffer_shutr_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002630 fd_delete(t->cli_fd);
2631 t->cli_state = CL_STCLOSE;
2632 return 1;
2633 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002634 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002635 buffer_shutr_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002636 fd_delete(t->cli_fd);
2637 t->cli_state = CL_STCLOSE;
2638 if (!(t->flags & SN_ERR_MASK))
2639 t->flags |= SN_ERR_CLITO;
2640 if (!(t->flags & SN_FINST_MASK)) {
2641 if (t->pend_pos)
2642 t->flags |= SN_FINST_Q;
2643 else if (s == SV_STCONN)
2644 t->flags |= SN_FINST_C;
2645 else
2646 t->flags |= SN_FINST_D;
2647 }
2648 return 1;
2649 }
2650 else if (req->l >= req->rlim - req->data) {
2651 /* no room to read more data */
2652
2653 /* FIXME-20050705: is it possible for a client to maintain a session
2654 * after the timeout by sending more data after it receives a close ?
2655 */
2656
Willy Tarreau66319382007-04-08 17:17:37 +02002657 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002658 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002659 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002660 }
2661 } else {
2662 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002663 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002664 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002665 }
2666 }
2667 return 0;
2668 }
2669 else { /* CL_STCLOSE: nothing to do */
2670 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2671 int len;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002672 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 +02002673 write(1, trash, len);
2674 }
2675 return 0;
2676 }
2677 return 0;
2678}
2679
2680
2681/*
2682 * manages the server FSM and its socket. It returns 1 if a state has changed
2683 * (and a resync may be needed), 0 else.
2684 */
2685int process_srv(struct session *t)
2686{
2687 int s = t->srv_state;
2688 int c = t->cli_state;
Willy Tarreau3d300592007-03-18 18:34:41 +01002689 struct http_txn *txn = &t->txn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002690 struct buffer *req = t->req;
2691 struct buffer *rep = t->rep;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002692 int conn_err;
2693
Willy Tarreau6468d922008-08-03 19:15:35 +02002694 DPRINTF(stderr,"process_srv: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%u,%u\n",
2695 cli_stnames[c], srv_stnames[s],
2696 EV_FD_ISSET(t->srv_fd, DIR_RD), EV_FD_ISSET(t->srv_fd, DIR_WR),
2697 rep->rex, req->wex);
Willy Tarreauee991362007-05-14 14:37:50 +02002698
2699#if 0
2700 fprintf(stderr,"%s:%d fe->clito=%d.%d, fe->conto=%d.%d, fe->srvto=%d.%d\n",
2701 __FUNCTION__, __LINE__,
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002702 t->fe->timeout.client.tv_sec, t->fe->timeout.client.tv_usec,
2703 t->fe->timeout.connect.tv_sec, t->fe->timeout.connect.tv_usec,
2704 t->fe->timeout.server.tv_sec, t->fe->timeout.server.tv_usec);
Willy Tarreauee991362007-05-14 14:37:50 +02002705 fprintf(stderr,"%s:%d be->clito=%d.%d, be->conto=%d.%d, be->srvto=%d.%d\n",
2706 __FUNCTION__, __LINE__,
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002707 t->be->timeout.client.tv_sec, t->be->timeout.client.tv_usec,
2708 t->be->timeout.connect.tv_sec, t->be->timeout.connect.tv_usec,
2709 t->be->timeout.server.tv_sec, t->be->timeout.server.tv_usec);
Willy Tarreauee991362007-05-14 14:37:50 +02002710
2711 fprintf(stderr,"%s:%d req->cto=%d.%d, req->rto=%d.%d, req->wto=%d.%d\n",
2712 __FUNCTION__, __LINE__,
2713 req->cto.tv_sec, req->cto.tv_usec,
2714 req->rto.tv_sec, req->rto.tv_usec,
2715 req->wto.tv_sec, req->wto.tv_usec);
2716
2717 fprintf(stderr,"%s:%d rep->cto=%d.%d, rep->rto=%d.%d, rep->wto=%d.%d\n",
2718 __FUNCTION__, __LINE__,
2719 rep->cto.tv_sec, rep->cto.tv_usec,
2720 rep->rto.tv_sec, rep->rto.tv_usec,
2721 rep->wto.tv_sec, rep->wto.tv_usec);
2722#endif
2723
Willy Tarreaubaaee002006-06-26 02:48:02 +02002724 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
Willy Tarreauf161a342007-04-08 16:59:42 +02002725 //EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
2726 //EV_FD_ISSET(t->srv_fd, DIR_RD), EV_FD_ISSET(t->srv_fd, DIR_WR)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002727 //);
2728 if (s == SV_STIDLE) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002729 /* NOTE: The client processor may switch to SV_STANALYZE, which switches back SV_STIDLE.
2730 * This is logcially after CL_STHEADERS completed, CL_STDATA has started, but
2731 * we need to defer server selection until more data arrives, if possible.
2732 * This is rare, and only if balancing on parameter hash with values in the entity of a POST
2733 */
Willy Tarreaub6866442008-07-14 23:54:42 +02002734 if (c == CL_STHEADERS || c == CL_STINSPECT)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002735 return 0; /* stay in idle, waiting for data to reach the client side */
Willy Tarreau6468d922008-08-03 19:15:35 +02002736 else if ((rep->flags & BF_SHUTW_STATUS) ||
2737 ((req->flags & BF_SHUTR_STATUS) &&
2738 (req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002739 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002740 if (t->pend_pos)
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002741 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002742 /* note that this must not return any error because it would be able to
2743 * overwrite the client_retnclose() output.
2744 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002745 if (txn->flags & TX_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01002746 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02002747 else
Willy Tarreau0f772532006-12-23 20:51:41 +01002748 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 +02002749
2750 return 1;
2751 }
2752 else {
Willy Tarreau3d300592007-03-18 18:34:41 +01002753 if (txn->flags & TX_CLTARPIT) {
Willy Tarreaub8750a82006-09-03 09:56:00 +02002754 /* This connection is being tarpitted. The CLIENT side has
2755 * already set the connect expiration date to the right
2756 * timeout. We just have to check that it has not expired.
2757 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002758 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreaub8750a82006-09-03 09:56:00 +02002759 return 0;
2760
2761 /* We will set the queue timer to the time spent, just for
2762 * logging purposes. We fake a 500 server error, so that the
2763 * attacker will not suspect his connection has been tarpitted.
2764 * It will not cause trouble to the logs because we can exclude
2765 * the tarpitted connections by filtering on the 'PT' status flags.
2766 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002767 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002768 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaub8750a82006-09-03 09:56:00 +02002769 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01002770 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02002771 return 1;
2772 }
2773
Willy Tarreaubaaee002006-06-26 02:48:02 +02002774 /* Right now, we will need to create a connection to the server.
2775 * We might already have tried, and got a connection pending, in
2776 * which case we will not do anything till it's pending. It's up
2777 * to any other session to release it and wake us up again.
2778 */
2779 if (t->pend_pos) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002780 if (!tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002781 return 0;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002782 } else {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002783 /* we've been waiting too long here */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002784 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002785 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002786 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01002787 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002788 if (t->srv)
2789 t->srv->failed_conns++;
Willy Tarreau50fd1e12007-12-10 15:25:35 +01002790 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002791 return 1;
2792 }
2793 }
2794
2795 do {
2796 /* first, get a connection */
Willy Tarreau21d2af32008-02-14 20:25:24 +01002797 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
2798 t->flags |= SN_REDIRECTABLE;
2799
Willy Tarreaubaaee002006-06-26 02:48:02 +02002800 if (srv_redispatch_connect(t))
2801 return t->srv_state != SV_STIDLE;
2802
Willy Tarreau21d2af32008-02-14 20:25:24 +01002803 if ((t->flags & SN_REDIRECTABLE) && t->srv && t->srv->rdr_len) {
2804 /* Server supporting redirection and it is possible.
2805 * Invalid requests are reported as such. It concerns all
2806 * the largest ones.
2807 */
2808 struct chunk rdr;
2809 char *path;
2810 int len;
2811
2812 /* 1: create the response header */
2813 rdr.len = strlen(HTTP_302);
2814 rdr.str = trash;
2815 memcpy(rdr.str, HTTP_302, rdr.len);
2816
2817 /* 2: add the server's prefix */
2818 if (rdr.len + t->srv->rdr_len > sizeof(trash))
2819 goto cancel_redir;
2820
2821 memcpy(rdr.str + rdr.len, t->srv->rdr_pfx, t->srv->rdr_len);
2822 rdr.len += t->srv->rdr_len;
2823
2824 /* 3: add the request URI */
2825 path = http_get_path(txn);
2826 if (!path)
2827 goto cancel_redir;
2828 len = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
2829 if (rdr.len + len > sizeof(trash) - 4) /* 4 for CRLF-CRLF */
2830 goto cancel_redir;
2831
2832 memcpy(rdr.str + rdr.len, path, len);
2833 rdr.len += len;
2834 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
2835 rdr.len += 4;
2836
2837 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C, 302, &rdr);
2838 /* FIXME: we should increase a counter of redirects per server and per backend. */
2839 if (t->srv)
2840 t->srv->cum_sess++;
2841 return 1;
2842 cancel_redir:
2843 txn->status = 400;
2844 t->fe->failed_req++;
2845 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C,
2846 400, error_message(t, HTTP_ERR_400));
2847 return 1;
2848 }
2849
Willy Tarreaubaaee002006-06-26 02:48:02 +02002850 /* try to (re-)connect to the server, and fail if we expire the
2851 * number of retries.
2852 */
2853 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002854 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002855 return t->srv_state != SV_STIDLE;
2856 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002857 } while (1);
2858 }
2859 }
2860 else if (s == SV_STCONN) { /* connection in progress */
Willy Tarreau6468d922008-08-03 19:15:35 +02002861 if ((rep->flags & BF_SHUTW_STATUS) ||
2862 ((req->flags & BF_SHUTR_STATUS) &&
2863 ((req->l == 0 && !(req->flags & BF_WRITE_STATUS)) ||
Willy Tarreauc9b654b2007-05-08 14:46:53 +02002864 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002865 req->cex = TICK_ETERNITY;
Willy Tarreauf899b942008-03-28 18:09:38 +01002866 if (!(t->flags & SN_CONN_TAR)) {
2867 /* if we are in turn-around, we have already closed the FD */
2868 fd_delete(t->srv_fd);
2869 if (t->srv) {
2870 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002871 sess_change_server(t, NULL);
Willy Tarreauf899b942008-03-28 18:09:38 +01002872 }
Willy Tarreau51406232008-03-10 22:04:20 +01002873 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002874
2875 /* note that this must not return any error because it would be able to
2876 * overwrite the client_retnclose() output.
2877 */
Willy Tarreau0f772532006-12-23 20:51:41 +01002878 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002879 return 1;
2880 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002881 if (!(req->flags & BF_WRITE_STATUS) && !tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002882 return 0; /* nothing changed */
2883 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002884 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002885 /* timeout, asynchronous connect error or first write error */
2886 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2887
Willy Tarreau541b5c22008-01-06 23:34:21 +01002888 if (t->flags & SN_CONN_TAR) {
2889 /* We are doing a turn-around waiting for a new connection attempt. */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002890 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreau541b5c22008-01-06 23:34:21 +01002891 return 0;
2892 t->flags &= ~SN_CONN_TAR;
2893 }
2894 else {
2895 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01002896 if (t->srv) {
Willy Tarreau541b5c22008-01-06 23:34:21 +01002897 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002898 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01002899 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002900
Willy Tarreau541b5c22008-01-06 23:34:21 +01002901 if (!(req->flags & BF_WRITE_STATUS))
2902 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
2903 else
2904 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
2905
2906 /* ensure that we have enough retries left */
2907 if (srv_count_retry_down(t, conn_err))
2908 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002909
Willy Tarreau541b5c22008-01-06 23:34:21 +01002910 if (req->flags & BF_WRITE_ERROR) {
2911 /* we encountered an immediate connection error, and we
2912 * will have to retry connecting to the same server, most
2913 * likely leading to the same result. To avoid this, we
2914 * fake a connection timeout to retry after a turn-around
2915 * time of 1 second. We will wait in the previous if block.
2916 */
2917 t->flags |= SN_CONN_TAR;
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002918 req->cex = tick_add(now_ms, MS_TO_TICKS(1000));
Willy Tarreau541b5c22008-01-06 23:34:21 +01002919 return 0;
2920 }
2921 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002922
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002923 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002924 /* We're on our last chance, and the REDISP option was specified.
2925 * We will ignore cookie and force to balance or use the dispatcher.
2926 */
2927 /* let's try to offer this slot to anybody */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002928 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02002929 process_srv_queue(t->srv);
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002930
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01002931 /* it's left to the dispatcher to choose a server */
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002932 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
Willy Tarreau7c669d72008-06-20 15:04:11 +02002933 t->prev_srv = t->srv;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002934
2935 /* first, get a connection */
2936 if (srv_redispatch_connect(t))
Willy Tarreau00559e72008-01-06 23:46:19 +01002937 return t->srv_state != SV_STCONN;
Krzysztof Piotr Oledzki626a19b2008-02-04 02:10:09 +01002938 } else {
2939 if (t->srv)
2940 t->srv->retries++;
2941 t->be->retries++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002942 }
2943
Willy Tarreaubaaee002006-06-26 02:48:02 +02002944 do {
2945 /* Now we will try to either reconnect to the same server or
2946 * connect to another server. If the connection gets queued
2947 * because all servers are saturated, then we will go back to
2948 * the SV_STIDLE state.
2949 */
2950 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002951 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002952 return t->srv_state != SV_STCONN;
2953 }
2954
2955 /* we need to redispatch the connection to another server */
2956 if (srv_redispatch_connect(t))
2957 return t->srv_state != SV_STCONN;
2958 } while (1);
2959 }
2960 else { /* no error or write 0 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002961 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002962
2963 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2964 if (req->l == 0) /* nothing to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002965 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002966 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002967 } else /* need the right to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002968 EV_FD_SET(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002969 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
2970 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002971 /* FIXME: to prevent the server from expiring read timeouts during writes,
2972 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002973 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002974 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002975 }
2976
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002977 if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreauf161a342007-04-08 16:59:42 +02002978 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002979 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002980 t->srv_state = SV_STDATA;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002981 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
2982
2983 /* if the user wants to log as soon as possible, without counting
2984 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002985 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002986 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
Willy Tarreau42250582007-04-01 01:30:43 +02002987 tcp_sess_log(t);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002988 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002989#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002990 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002991 /* TCP splicing supported by both FE and BE */
2992 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2993 }
2994#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002995 }
2996 else {
2997 t->srv_state = SV_STHEADERS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002998 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002999 t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
3000 /* reset hdr_idx which was already initialized by the request.
3001 * right now, the http parser does it.
3002 * hdr_idx_init(&t->txn.hdr_idx);
3003 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003004 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003005 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003006 return 1;
3007 }
3008 }
3009 else if (s == SV_STHEADERS) { /* receiving server headers */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003010 /*
3011 * Now parse the partial (or complete) lines.
3012 * We will check the response syntax, and also join multi-line
3013 * headers. An index of all the lines will be elaborated while
3014 * parsing.
3015 *
3016 * For the parsing, we use a 28 states FSM.
3017 *
3018 * Here is the information we currently have :
3019 * rep->data + req->som = beginning of response
3020 * rep->data + req->eoh = end of processed headers / start of current one
3021 * rep->data + req->eol = end of current header or line (LF or CRLF)
3022 * rep->lr = first non-visited byte
3023 * rep->r = end of data
3024 */
3025
3026 int cur_idx;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003027 struct http_msg *msg = &txn->rsp;
3028 struct proxy *cur_proxy;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003029
Willy Tarreaua15645d2007-03-18 16:22:39 +01003030 if (likely(rep->lr < rep->r))
3031 http_msg_analyzer(rep, msg, &txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003032
Willy Tarreaua15645d2007-03-18 16:22:39 +01003033 /* 1: we might have to print this header in debug mode */
3034 if (unlikely((global.mode & MODE_DEBUG) &&
3035 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
3036 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
3037 char *eol, *sol;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003038
Willy Tarreaua15645d2007-03-18 16:22:39 +01003039 sol = rep->data + msg->som;
3040 eol = sol + msg->sl.rq.l;
3041 debug_hdr("srvrep", t, sol, eol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003042
Willy Tarreaua15645d2007-03-18 16:22:39 +01003043 sol += hdr_idx_first_pos(&txn->hdr_idx);
3044 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003045
Willy Tarreaua15645d2007-03-18 16:22:39 +01003046 while (cur_idx) {
3047 eol = sol + txn->hdr_idx.v[cur_idx].len;
3048 debug_hdr("srvhdr", t, sol, eol);
3049 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
3050 cur_idx = txn->hdr_idx.v[cur_idx].next;
3051 }
3052 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003053
Willy Tarreaubaaee002006-06-26 02:48:02 +02003054
Willy Tarreau66319382007-04-08 17:17:37 +02003055 if ((rep->l < rep->rlim - rep->data) && EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003056 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreaua15645d2007-03-18 16:22:39 +01003057 * full. We cannot loop here since stream_sock_read will disable it only if
3058 * rep->l == rlim-data
3059 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003060 req->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003061 }
3062
3063
3064 /*
3065 * Now we quickly check if we have found a full valid response.
3066 * If not so, we check the FD and buffer states before leaving.
3067 * A full response is indicated by the fact that we have seen
3068 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
3069 * responses are checked first.
3070 *
3071 * Depending on whether the client is still there or not, we
3072 * may send an error response back or not. Note that normally
3073 * we should only check for HTTP status there, and check I/O
3074 * errors somewhere else.
3075 */
3076
3077 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
3078
3079 /* Invalid response, or read error or write error */
3080 if (unlikely((msg->msg_state == HTTP_MSG_ERROR) ||
3081 (req->flags & BF_WRITE_ERROR) ||
3082 (rep->flags & BF_READ_ERROR))) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003083 buffer_shutr_done(rep);
3084 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003085 fd_delete(t->srv_fd);
3086 if (t->srv) {
3087 t->srv->cur_sess--;
3088 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003089 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003090 }
3091 t->be->failed_resp++;
3092 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003093 txn->status = 502;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003094 client_return(t, error_message(t, HTTP_ERR_502));
3095 if (!(t->flags & SN_ERR_MASK))
3096 t->flags |= SN_ERR_SRVCL;
3097 if (!(t->flags & SN_FINST_MASK))
3098 t->flags |= SN_FINST_H;
3099 /* We used to have a free connection slot. Since we'll never use it,
3100 * we have to inform the server that it may be used by another session.
3101 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003102 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003103 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003104
Willy Tarreaua15645d2007-03-18 16:22:39 +01003105 return 1;
3106 }
3107
3108 /* end of client write or end of server read.
3109 * since we are in header mode, if there's no space left for headers, we
3110 * won't be able to free more later, so the session will never terminate.
3111 */
Willy Tarreau6468d922008-08-03 19:15:35 +02003112 else if (unlikely(rep->flags & (BF_READ_NULL | BF_SHUTW_STATUS) ||
Willy Tarreaua15645d2007-03-18 16:22:39 +01003113 rep->l >= rep->rlim - rep->data)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003114 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003115 buffer_shutr_done(rep);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003116 t->srv_state = SV_STSHUTR;
3117 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3118 return 1;
3119 }
3120
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003121 /* read timeout : return a 504 to the client. */
Willy Tarreauf161a342007-04-08 16:59:42 +02003122 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_RD) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003123 tick_is_expired(rep->rex, now_ms))) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003124 buffer_shutr_done(rep);
3125 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003126 fd_delete(t->srv_fd);
3127 if (t->srv) {
3128 t->srv->cur_sess--;
3129 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003130 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003131 }
3132 t->be->failed_resp++;
3133 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003134 txn->status = 504;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003135 client_return(t, error_message(t, HTTP_ERR_504));
3136 if (!(t->flags & SN_ERR_MASK))
3137 t->flags |= SN_ERR_SRVTO;
3138 if (!(t->flags & SN_FINST_MASK))
3139 t->flags |= SN_FINST_H;
3140 /* We used to have a free connection slot. Since we'll never use it,
3141 * we have to inform the server that it may be used by another session.
3142 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003143 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003144 process_srv_queue(t->srv);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003145 return 1;
3146 }
3147
3148 /* last client read and buffer empty */
3149 /* FIXME!!! here, we don't want to switch to SHUTW if the
3150 * client shuts read too early, because we may still have
3151 * some work to do on the headers.
3152 * The side-effect is that if the client completely closes its
3153 * connection during SV_STHEADER, the connection to the server
3154 * is kept until a response comes back or the timeout is reached.
3155 */
Willy Tarreau6468d922008-08-03 19:15:35 +02003156 else if (0 && /* we don't want to switch to shutw for now */
3157 unlikely(req->flags & BF_SHUTR_STATUS && (req->l == 0))) {
3158
Willy Tarreauf161a342007-04-08 16:59:42 +02003159 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003160 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003161
3162 /* We must ensure that the read part is still
3163 * alive when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003164 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003165 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003166
3167 shutdown(t->srv_fd, SHUT_WR);
3168 t->srv_state = SV_STSHUTW;
3169 return 1;
3170 }
3171
3172 /* write timeout */
3173 /* FIXME!!! here, we don't want to switch to SHUTW if the
3174 * client shuts read too early, because we may still have
3175 * some work to do on the headers.
3176 */
Willy Tarreauf161a342007-04-08 16:59:42 +02003177 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_WR) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003178 tick_is_expired(req->wex, now_ms))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003179 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003180 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003181 shutdown(t->srv_fd, SHUT_WR);
3182 /* We must ensure that the read part is still alive
3183 * when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003184 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003185 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003186
3187 t->srv_state = SV_STSHUTW;
3188 if (!(t->flags & SN_ERR_MASK))
3189 t->flags |= SN_ERR_SRVTO;
3190 if (!(t->flags & SN_FINST_MASK))
3191 t->flags |= SN_FINST_H;
3192 return 1;
3193 }
3194
3195 /*
3196 * And now the non-error cases.
3197 */
3198
3199 /* Data remaining in the request buffer.
3200 * This happens during the first pass here, and during
3201 * long posts.
3202 */
3203 else if (likely(req->l)) {
Willy Tarreau66319382007-04-08 17:17:37 +02003204 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3205 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003206 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3207 if (req->wex) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003208 /* FIXME: to prevent the server from expiring read timeouts during writes,
3209 * we refresh it. */
3210 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003211 }
3212 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003213 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003214
Willy Tarreaua15645d2007-03-18 16:22:39 +01003215 /* nothing left in the request buffer */
3216 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003217 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3218 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003219 req->wex = TICK_ETERNITY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003220 }
3221 }
3222
3223 return t->srv_state != SV_STHEADERS;
3224 }
3225
3226
3227 /*****************************************************************
3228 * More interesting part now : we know that we have a complete *
3229 * response which at least looks like HTTP. We have an indicator *
3230 * of each header's length, so we can parse them quickly. *
3231 ****************************************************************/
3232
Willy Tarreau9cdde232007-05-02 20:58:19 +02003233 /* ensure we keep this pointer to the beginning of the message */
3234 msg->sol = rep->data + msg->som;
3235
Willy Tarreaua15645d2007-03-18 16:22:39 +01003236 /*
3237 * 1: get the status code and check for cacheability.
3238 */
3239
3240 t->logs.logwait &= ~LW_RESP;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003241 txn->status = strl2ui(rep->data + msg->sl.st.c, msg->sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003242
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003243 switch (txn->status) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003244 case 200:
3245 case 203:
3246 case 206:
3247 case 300:
3248 case 301:
3249 case 410:
3250 /* RFC2616 @13.4:
3251 * "A response received with a status code of
3252 * 200, 203, 206, 300, 301 or 410 MAY be stored
3253 * by a cache (...) unless a cache-control
3254 * directive prohibits caching."
3255 *
3256 * RFC2616 @9.5: POST method :
3257 * "Responses to this method are not cacheable,
3258 * unless the response includes appropriate
3259 * Cache-Control or Expires header fields."
3260 */
3261 if (likely(txn->meth != HTTP_METH_POST) &&
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003262 (t->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
Willy Tarreau3d300592007-03-18 18:34:41 +01003263 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003264 break;
3265 default:
3266 break;
3267 }
3268
3269 /*
3270 * 2: we may need to capture headers
3271 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003272 if (unlikely((t->logs.logwait & LW_RSPHDR) && t->fe->rsp_cap))
Willy Tarreaua15645d2007-03-18 16:22:39 +01003273 capture_headers(rep->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003274 txn->rsp.cap, t->fe->rsp_cap);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003275
3276 /*
3277 * 3: we will have to evaluate the filters.
3278 * As opposed to version 1.2, now they will be evaluated in the
3279 * filters order and not in the header order. This means that
3280 * each filter has to be validated among all headers.
3281 *
3282 * Filters are tried with ->be first, then with ->fe if it is
3283 * different from ->be.
3284 */
3285
3286 t->flags &= ~SN_CONN_CLOSED; /* prepare for inspection */
3287
3288 cur_proxy = t->be;
3289 while (1) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003290 struct proxy *rule_set = cur_proxy;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003291
3292 /* try headers filters */
3293 if (rule_set->rsp_exp != NULL) {
3294 if (apply_filters_to_response(t, rep, rule_set->rsp_exp) < 0) {
3295 return_bad_resp:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003296 if (t->srv) {
3297 t->srv->cur_sess--;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003298 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003299 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003300 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003301 cur_proxy->failed_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003302 return_srv_prx_502:
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003303 buffer_shutr_done(rep);
3304 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003305 fd_delete(t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003306 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003307 txn->status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01003308 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003309 if (!(t->flags & SN_ERR_MASK))
3310 t->flags |= SN_ERR_PRXCOND;
3311 if (!(t->flags & SN_FINST_MASK))
3312 t->flags |= SN_FINST_H;
3313 /* We used to have a free connection slot. Since we'll never use it,
3314 * we have to inform the server that it may be used by another session.
3315 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003316 if (t->srv && may_dequeue_tasks(t->srv, cur_proxy))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003317 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003318 return 1;
3319 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003320 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003321
Willy Tarreaua15645d2007-03-18 16:22:39 +01003322 /* has the response been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01003323 if (txn->flags & TX_SVDENY) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003324 if (t->srv) {
3325 t->srv->cur_sess--;
3326 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003327 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003328 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003329 cur_proxy->denied_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003330 goto return_srv_prx_502;
3331 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003332
Willy Tarreaua15645d2007-03-18 16:22:39 +01003333 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003334 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01003335 !(t->flags & SN_CONN_CLOSED)) {
3336 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003337 int cur_idx, old_idx, delta, val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003338 struct hdr_idx_elem *cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003339
Willy Tarreaua15645d2007-03-18 16:22:39 +01003340 cur_next = rep->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
3341 old_idx = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003342
Willy Tarreaua15645d2007-03-18 16:22:39 +01003343 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
3344 cur_hdr = &txn->hdr_idx.v[cur_idx];
3345 cur_ptr = cur_next;
3346 cur_end = cur_ptr + cur_hdr->len;
3347 cur_next = cur_end + cur_hdr->cr + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003348
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003349 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
3350 if (val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003351 /* 3 possibilities :
3352 * - we have already set Connection: close,
3353 * so we remove this line.
3354 * - we have not yet set Connection: close,
3355 * but this line indicates close. We leave
3356 * it untouched and set the flag.
3357 * - we have not yet set Connection: close,
3358 * and this line indicates non-close. We
3359 * replace it.
3360 */
3361 if (t->flags & SN_CONN_CLOSED) {
3362 delta = buffer_replace2(rep, cur_ptr, cur_next, NULL, 0);
3363 txn->rsp.eoh += delta;
3364 cur_next += delta;
3365 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3366 txn->hdr_idx.used--;
3367 cur_hdr->len = 0;
3368 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003369 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
3370 delta = buffer_replace2(rep, cur_ptr + val, cur_end,
3371 "close", 5);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003372 cur_next += delta;
3373 cur_hdr->len += delta;
3374 txn->rsp.eoh += delta;
3375 }
3376 t->flags |= SN_CONN_CLOSED;
3377 }
3378 }
3379 old_idx = cur_idx;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003380 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003381 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003382
Willy Tarreaua15645d2007-03-18 16:22:39 +01003383 /* add response headers from the rule sets in the same order */
3384 for (cur_idx = 0; cur_idx < rule_set->nb_rspadd; cur_idx++) {
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003385 if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx,
3386 rule_set->rsp_add[cur_idx])) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003387 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003388 }
3389
Willy Tarreaua15645d2007-03-18 16:22:39 +01003390 /* check whether we're already working on the frontend */
3391 if (cur_proxy == t->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003392 break;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003393 cur_proxy = t->fe;
3394 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003395
Willy Tarreaua15645d2007-03-18 16:22:39 +01003396 /*
3397 * 4: check for server cookie.
3398 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003399 if (t->be->cookie_name || t->be->appsession_name || t->be->capture_name
3400 || (t->be->options & PR_O_CHK_CACHE))
3401 manage_server_side_cookies(t, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003402
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003403
Willy Tarreaua15645d2007-03-18 16:22:39 +01003404 /*
Willy Tarreau396d2c62007-11-04 19:30:00 +01003405 * 5: check for cache-control or pragma headers if required.
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003406 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003407 if ((t->be->options & (PR_O_COOK_NOC | PR_O_CHK_CACHE)) != 0)
3408 check_response_for_cacheability(t, rep);
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003409
3410 /*
3411 * 6: add server cookie in the response if needed
Willy Tarreaua15645d2007-03-18 16:22:39 +01003412 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003413 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
3414 (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003415 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003416
Willy Tarreaua15645d2007-03-18 16:22:39 +01003417 /* the server is known, it's not the one the client requested, we have to
3418 * insert a set-cookie here, except if we want to insert only on POST
3419 * requests and this one isn't. Note that servers which don't have cookies
3420 * (eg: some backup servers) will return a full cookie removal request.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003421 */
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003422 len = sprintf(trash, "Set-Cookie: %s=%s; path=/",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003423 t->be->cookie_name,
Willy Tarreaua15645d2007-03-18 16:22:39 +01003424 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003425
Krzysztof Piotr Oledzki1acf2172008-05-29 23:03:34 +02003426 if (t->be->cookie_domain)
3427 len += sprintf(trash+len, "; domain=%s", t->be->cookie_domain);
Krzysztof Piotr Oledzkiefe3b6f2008-05-23 23:49:32 +02003428
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003429 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3430 trash, len)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003431 goto return_bad_resp;
Willy Tarreau3d300592007-03-18 18:34:41 +01003432 txn->flags |= TX_SCK_INSERTED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003433
Willy Tarreaua15645d2007-03-18 16:22:39 +01003434 /* Here, we will tell an eventual cache on the client side that we don't
3435 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3436 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3437 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3438 */
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003439 if ((t->be->options & PR_O_COOK_NOC) && (txn->flags & TX_CACHEABLE)) {
3440
3441 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
3442
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003443 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3444 "Cache-control: private", 22)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003445 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003446 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003447 }
3448
3449
3450 /*
Willy Tarreaua15645d2007-03-18 16:22:39 +01003451 * 7: check if result will be cacheable with a cookie.
3452 * We'll block the response if security checks have caught
3453 * nasty things such as a cacheable cookie.
3454 */
Willy Tarreau3d300592007-03-18 18:34:41 +01003455 if (((txn->flags & (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) ==
3456 (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003457 (t->be->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003458
Willy Tarreaua15645d2007-03-18 16:22:39 +01003459 /* we're in presence of a cacheable response containing
3460 * a set-cookie header. We'll block it as requested by
3461 * the 'checkcache' option, and send an alert.
3462 */
3463 if (t->srv) {
3464 t->srv->cur_sess--;
3465 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003466 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003467 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003468 t->be->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003469
Willy Tarreaua15645d2007-03-18 16:22:39 +01003470 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003471 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003472 send_log(t->be, LOG_ALERT,
3473 "Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003474 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003475 goto return_srv_prx_502;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003476 }
3477
Willy Tarreaua15645d2007-03-18 16:22:39 +01003478 /*
3479 * 8: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02003480 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003481 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02003482 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003483 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02003484 if ((unlikely(msg->sl.st.v_l != 8) ||
3485 unlikely(req->data[msg->som + 7] != '0')) &&
3486 unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003487 "Connection: close", 17)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003488 goto return_bad_resp;
3489 t->flags |= SN_CONN_CLOSED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003490 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003491
Willy Tarreaubaaee002006-06-26 02:48:02 +02003492
Willy Tarreaua15645d2007-03-18 16:22:39 +01003493 /*************************************************************
3494 * OK, that's finished for the headers. We have done what we *
3495 * could. Let's switch to the DATA state. *
3496 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02003497
Willy Tarreaua15645d2007-03-18 16:22:39 +01003498 t->srv_state = SV_STDATA;
3499 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02003500 t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003501
3502 /* client connection already closed or option 'forceclose' required :
3503 * we close the server's outgoing connection right now.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003504 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003505 if ((req->l == 0) &&
Willy Tarreau6468d922008-08-03 19:15:35 +02003506 (req->flags & BF_SHUTR_STATUS || t->be->options & PR_O_FORCE_CLO)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003507 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003508 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003509
3510 /* We must ensure that the read part is still alive when switching
3511 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003512 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003513 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003514
Willy Tarreaua15645d2007-03-18 16:22:39 +01003515 shutdown(t->srv_fd, SHUT_WR);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003516 t->srv_state = SV_STSHUTW;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003517 }
3518
Willy Tarreaua15645d2007-03-18 16:22:39 +01003519#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003520 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003521 /* TCP splicing supported by both FE and BE */
3522 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003523 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003524#endif
3525 /* if the user wants to log as soon as possible, without counting
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003526 * bytes from the server, then this is the right moment. We have
3527 * to temporarily assign bytes_out to log what we currently have.
3528 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003529 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
3530 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreau8b3977f2008-01-18 11:16:32 +01003531 t->logs.bytes_out = txn->rsp.eoh;
Willy Tarreau42250582007-04-01 01:30:43 +02003532 if (t->fe->to_log & LW_REQ)
3533 http_sess_log(t);
3534 else
3535 tcp_sess_log(t);
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003536 t->logs.bytes_out = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003537 }
3538
Willy Tarreaua15645d2007-03-18 16:22:39 +01003539 /* Note: we must not try to cheat by jumping directly to DATA,
3540 * otherwise we would not let the client side wake up.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003541 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003542
3543 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003544 }
3545 else if (s == SV_STDATA) {
3546 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003547 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003548 buffer_shutr_done(rep);
3549 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003550 fd_delete(t->srv_fd);
3551 if (t->srv) {
3552 t->srv->cur_sess--;
3553 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003554 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003555 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003556 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003557 t->srv_state = SV_STCLOSE;
3558 if (!(t->flags & SN_ERR_MASK))
3559 t->flags |= SN_ERR_SRVCL;
3560 if (!(t->flags & SN_FINST_MASK))
3561 t->flags |= SN_FINST_D;
3562 /* We used to have a free connection slot. Since we'll never use it,
3563 * we have to inform the server that it may be used by another session.
3564 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003565 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003566 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003567
3568 return 1;
3569 }
3570 /* last read, or end of client write */
Willy Tarreau6468d922008-08-03 19:15:35 +02003571 else if (rep->flags & (BF_READ_NULL | BF_SHUTW_STATUS)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003572 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003573 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003574 t->srv_state = SV_STSHUTR;
3575 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3576 return 1;
3577 }
3578 /* end of client read and no more data to send */
Willy Tarreau6468d922008-08-03 19:15:35 +02003579 else if (req->flags & BF_SHUTR_STATUS && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003580 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003581 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003582 shutdown(t->srv_fd, SHUT_WR);
3583 /* We must ensure that the read part is still alive when switching
3584 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003585 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003586 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003587
3588 t->srv_state = SV_STSHUTW;
3589 return 1;
3590 }
3591 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003592 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003593 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003594 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003595 t->srv_state = SV_STSHUTR;
3596 if (!(t->flags & SN_ERR_MASK))
3597 t->flags |= SN_ERR_SRVTO;
3598 if (!(t->flags & SN_FINST_MASK))
3599 t->flags |= SN_FINST_D;
3600 return 1;
3601 }
3602 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003603 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003604 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003605 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003606 shutdown(t->srv_fd, SHUT_WR);
3607 /* We must ensure that the read part is still alive when switching
3608 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003609 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003610 rep->cex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003611 t->srv_state = SV_STSHUTW;
3612 if (!(t->flags & SN_ERR_MASK))
3613 t->flags |= SN_ERR_SRVTO;
3614 if (!(t->flags & SN_FINST_MASK))
3615 t->flags |= SN_FINST_D;
3616 return 1;
3617 }
3618
3619 /* recompute request time-outs */
3620 if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003621 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3622 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003623 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003624 }
3625 }
3626 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau66319382007-04-08 17:17:37 +02003627 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3628 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003629 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3630 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003631 /* FIXME: to prevent the server from expiring read timeouts during writes,
3632 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02003633 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003634 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003635 }
3636 }
3637
3638 /* recompute response time-outs */
3639 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003640 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003641 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003642 }
3643 }
3644 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003645 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003646 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003647 }
3648 }
3649
3650 return 0; /* other cases change nothing */
3651 }
3652 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003653 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003654 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003655 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003656 fd_delete(t->srv_fd);
3657 if (t->srv) {
3658 t->srv->cur_sess--;
3659 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003660 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003661 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003662 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003663 //close(t->srv_fd);
3664 t->srv_state = SV_STCLOSE;
3665 if (!(t->flags & SN_ERR_MASK))
3666 t->flags |= SN_ERR_SRVCL;
3667 if (!(t->flags & SN_FINST_MASK))
3668 t->flags |= SN_FINST_D;
3669 /* We used to have a free connection slot. Since we'll never use it,
3670 * we have to inform the server that it may be used by another session.
3671 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003672 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003673 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003674
3675 return 1;
3676 }
Willy Tarreau6468d922008-08-03 19:15:35 +02003677 else if (req->flags & BF_SHUTR_STATUS && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003678 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003679 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003680 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003681 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003682 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003683 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003684 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003685 //close(t->srv_fd);
3686 t->srv_state = SV_STCLOSE;
3687 /* We used to have a free connection slot. Since we'll never use it,
3688 * we have to inform the server that it may be used by another session.
3689 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003690 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003691 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003692
3693 return 1;
3694 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003695 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003696 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003697 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003698 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003699 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003700 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003701 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003702 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003703 //close(t->srv_fd);
3704 t->srv_state = SV_STCLOSE;
3705 if (!(t->flags & SN_ERR_MASK))
3706 t->flags |= SN_ERR_SRVTO;
3707 if (!(t->flags & SN_FINST_MASK))
3708 t->flags |= SN_FINST_D;
3709 /* We used to have a free connection slot. Since we'll never use it,
3710 * we have to inform the server that it may be used by another session.
3711 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003712 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003713 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003714
3715 return 1;
3716 }
3717 else if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003718 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3719 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003720 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003721 }
3722 }
3723 else { /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02003724 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3725 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003726 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003727 }
3728 }
3729 return 0;
3730 }
3731 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003732 if (rep->flags & BF_READ_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003733 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003734 buffer_shutr_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003735 fd_delete(t->srv_fd);
3736 if (t->srv) {
3737 t->srv->cur_sess--;
3738 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003739 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003740 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003741 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003742 //close(t->srv_fd);
3743 t->srv_state = SV_STCLOSE;
3744 if (!(t->flags & SN_ERR_MASK))
3745 t->flags |= SN_ERR_SRVCL;
3746 if (!(t->flags & SN_FINST_MASK))
3747 t->flags |= SN_FINST_D;
3748 /* We used to have a free connection slot. Since we'll never use it,
3749 * we have to inform the server that it may be used by another session.
3750 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003751 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003752 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003753
3754 return 1;
3755 }
Willy Tarreau6468d922008-08-03 19:15:35 +02003756 else if (rep->flags & (BF_READ_NULL | BF_SHUTW_STATUS)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003757 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003758 buffer_shutr_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003759 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003760 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003761 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003762 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003763 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003764 //close(t->srv_fd);
3765 t->srv_state = SV_STCLOSE;
3766 /* We used to have a free connection slot. Since we'll never use it,
3767 * we have to inform the server that it may be used by another session.
3768 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003769 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003770 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003771
3772 return 1;
3773 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003774 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003775 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003776 buffer_shutr_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003777 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003778 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003779 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003780 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003781 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003782 //close(t->srv_fd);
3783 t->srv_state = SV_STCLOSE;
3784 if (!(t->flags & SN_ERR_MASK))
3785 t->flags |= SN_ERR_SRVTO;
3786 if (!(t->flags & SN_FINST_MASK))
3787 t->flags |= SN_FINST_D;
3788 /* We used to have a free connection slot. Since we'll never use it,
3789 * we have to inform the server that it may be used by another session.
3790 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003791 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003792 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003793
3794 return 1;
3795 }
3796 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003797 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003798 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003799 }
3800 }
3801 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003802 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003803 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003804 }
3805 }
3806 return 0;
3807 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003808 else if (s == SV_STANALYZE){
3809 /* this server state is set by the client to study the body for server assignment */
3810
3811 /* Have we been through this long enough to timeout? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003812 if (!tick_is_expired(req->rex, now_ms)) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003813 /* balance url_param check_post should have been the only to get into this.
3814 * just wait for data, check to compare how much
3815 */
3816 struct http_msg * msg = &t->txn.req;
3817 unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 :msg->eoh + 1;
3818 unsigned long len = req->total - body;
3819 long long limit = t->be->url_param_post_limit;
3820 struct hdr_ctx ctx;
3821 ctx.idx = 0;
3822 /* now if we have a length, we'll take the hint */
3823 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
3824 if ( ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",ctx.vlen)==0) {
3825 unsigned int chunk = 0;
3826 while ( body < req->total && !HTTP_IS_CRLF(msg->sol[body])) {
3827 char c = msg->sol[body];
3828 if (ishex(c)) {
3829 unsigned int hex = toupper(c) - '0';
3830 if ( hex > 9 )
3831 hex -= 'A' - '9' - 1;
3832 chunk = (chunk << 4) | hex;
3833 }
3834 else break;
3835 body++;
3836 len--;
3837 }
3838 if ( body == req->total )
3839 return 0; /* end of buffer? data missing! */
3840
3841 if ( memcmp(msg->sol+body, "\r\n", 2) != 0 )
3842 return 0; /* chunked encoding len ends with CRLF, and we don't have it yet */
3843
3844 /* if we support more then one chunk here, we have to do it again when assigning server
3845 1. how much entity data do we have? new var
3846 2. should save entity_start, entity_cursor, elen & rlen in req; so we don't repeat scanning here
3847 3. test if elen > limit, or set new limit to elen if 0 (end of entity found)
3848 */
3849
3850 if ( chunk < limit )
3851 limit = chunk; /* only reading one chunk */
3852 } else {
3853 if ( msg->hdr_content_len < limit )
3854 limit = msg->hdr_content_len;
3855 }
3856 if ( len < limit )
3857 return 0;
3858 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003859 t->srv_state = SV_STIDLE;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003860 return 1;
3861 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003862 else { /* SV_STCLOSE : nothing to do */
3863 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
3864 int len;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003865 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003866 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003867 write(1, trash, len);
3868 }
3869 return 0;
3870 }
3871 return 0;
3872}
3873
3874
3875/*
3876 * Produces data for the session <s> depending on its source. Expects to be
3877 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3878 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3879 * session, which it uses to keep on being called when there is free space in
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003880 * the buffer, or simply by letting an empty buffer upon return. It returns 1
Willy Tarreaubaaee002006-06-26 02:48:02 +02003881 * if it changes the session state from CL_STSHUTR, otherwise 0.
3882 */
3883int produce_content(struct session *s)
3884{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003885 if (s->data_source == DATA_SRC_NONE) {
3886 s->flags &= ~SN_SELF_GEN;
3887 return 1;
3888 }
3889 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003890 /* dump server statistics */
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01003891 int ret = stats_dump_http(s, s->be->uri_auth);
Willy Tarreau91861262007-10-17 17:06:05 +02003892 if (ret >= 0)
3893 return ret;
3894 /* -1 indicates an error */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003895 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003896
Willy Tarreau91861262007-10-17 17:06:05 +02003897 /* unknown data source or internal error */
3898 s->txn.status = 500;
3899 client_retnclose(s, error_message(s, HTTP_ERR_500));
3900 if (!(s->flags & SN_ERR_MASK))
3901 s->flags |= SN_ERR_PRXCOND;
3902 if (!(s->flags & SN_FINST_MASK))
3903 s->flags |= SN_FINST_R;
3904 s->flags &= ~SN_SELF_GEN;
3905 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003906}
3907
3908
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003909/* Iterate the same filter through all request headers.
3910 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003911 * Since it can manage the switch to another backend, it updates the per-proxy
3912 * DENY stats.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003913 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003914int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003915{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003916 char term;
3917 char *cur_ptr, *cur_end, *cur_next;
3918 int cur_idx, old_idx, last_hdr;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003919 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003920 struct hdr_idx_elem *cur_hdr;
3921 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003922
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003923 last_hdr = 0;
3924
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003925 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003926 old_idx = 0;
3927
3928 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01003929 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003930 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003931 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003932 (exp->action == ACT_ALLOW ||
3933 exp->action == ACT_DENY ||
3934 exp->action == ACT_TARPIT))
3935 return 0;
3936
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003937 cur_idx = txn->hdr_idx.v[old_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003938 if (!cur_idx)
3939 break;
3940
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003941 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003942 cur_ptr = cur_next;
3943 cur_end = cur_ptr + cur_hdr->len;
3944 cur_next = cur_end + cur_hdr->cr + 1;
3945
3946 /* Now we have one header between cur_ptr and cur_end,
3947 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003948 */
3949
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003950 /* The annoying part is that pattern matching needs
3951 * that we modify the contents to null-terminate all
3952 * strings before testing them.
3953 */
3954
3955 term = *cur_end;
3956 *cur_end = '\0';
3957
3958 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3959 switch (exp->action) {
3960 case ACT_SETBE:
3961 /* It is not possible to jump a second time.
3962 * FIXME: should we return an HTTP/500 here so that
3963 * the admin knows there's a problem ?
3964 */
3965 if (t->be != t->fe)
3966 break;
3967
3968 /* Swithing Proxy */
3969 t->be = (struct proxy *) exp->replace;
3970
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003971 /* right now, the backend switch is not overly complicated
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003972 * because we have associated req_cap and rsp_cap to the
3973 * frontend, and the beconn will be updated later.
3974 */
3975
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003976 t->rep->rto = t->req->wto = t->be->timeout.server;
3977 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02003978 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003979 last_hdr = 1;
3980 break;
3981
3982 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003983 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003984 last_hdr = 1;
3985 break;
3986
3987 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003988 txn->flags |= TX_CLDENY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003989 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003990 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003991 break;
3992
3993 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003994 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003995 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003996 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003997 break;
3998
3999 case ACT_REPLACE:
4000 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4001 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
4002 /* FIXME: if the user adds a newline in the replacement, the
4003 * index will not be recalculated for now, and the new line
4004 * will not be counted as a new header.
4005 */
4006
4007 cur_end += delta;
4008 cur_next += delta;
4009 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004010 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004011 break;
4012
4013 case ACT_REMOVE:
4014 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
4015 cur_next += delta;
4016
4017 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004018 txn->req.eoh += delta;
4019 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4020 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004021 cur_hdr->len = 0;
4022 cur_end = NULL; /* null-term has been rewritten */
4023 break;
4024
4025 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004026 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004027 if (cur_end)
4028 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004029
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004030 /* keep the link from this header to next one in case of later
4031 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004032 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004033 old_idx = cur_idx;
4034 }
4035 return 0;
4036}
4037
4038
4039/* Apply the filter to the request line.
4040 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4041 * or -1 if a replacement resulted in an invalid request line.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004042 * Since it can manage the switch to another backend, it updates the per-proxy
4043 * DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004044 */
4045int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
4046{
4047 char term;
4048 char *cur_ptr, *cur_end;
4049 int done;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004050 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004051 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004052
Willy Tarreau58f10d72006-12-04 02:26:12 +01004053
Willy Tarreau3d300592007-03-18 18:34:41 +01004054 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004055 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004056 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004057 (exp->action == ACT_ALLOW ||
4058 exp->action == ACT_DENY ||
4059 exp->action == ACT_TARPIT))
4060 return 0;
4061 else if (exp->action == ACT_REMOVE)
4062 return 0;
4063
4064 done = 0;
4065
Willy Tarreau9cdde232007-05-02 20:58:19 +02004066 cur_ptr = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004067 cur_end = cur_ptr + txn->req.sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004068
4069 /* Now we have the request line between cur_ptr and cur_end */
4070
4071 /* The annoying part is that pattern matching needs
4072 * that we modify the contents to null-terminate all
4073 * strings before testing them.
4074 */
4075
4076 term = *cur_end;
4077 *cur_end = '\0';
4078
4079 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4080 switch (exp->action) {
4081 case ACT_SETBE:
4082 /* It is not possible to jump a second time.
4083 * FIXME: should we return an HTTP/500 here so that
4084 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01004085 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004086 if (t->be != t->fe)
4087 break;
4088
4089 /* Swithing Proxy */
4090 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004091
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004092 /* right now, the backend switch is not too much complicated
4093 * because we have associated req_cap and rsp_cap to the
4094 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004095 */
4096
Willy Tarreaud7c30f92007-12-03 01:38:36 +01004097 t->rep->rto = t->req->wto = t->be->timeout.server;
4098 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02004099 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004100 done = 1;
4101 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004102
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004103 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004104 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004105 done = 1;
4106 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004107
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004108 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004109 txn->flags |= TX_CLDENY;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004110 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004111 done = 1;
4112 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004113
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004114 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01004115 txn->flags |= TX_CLTARPIT;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004116 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004117 done = 1;
4118 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004119
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004120 case ACT_REPLACE:
4121 *cur_end = term; /* restore the string terminator */
4122 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4123 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
4124 /* FIXME: if the user adds a newline in the replacement, the
4125 * index will not be recalculated for now, and the new line
4126 * will not be counted as a new header.
4127 */
Willy Tarreaua496b602006-12-17 23:15:24 +01004128
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004129 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004130 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01004131
Willy Tarreau9cdde232007-05-02 20:58:19 +02004132 txn->req.sol = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004133 cur_end = (char *)http_parse_reqline(&txn->req, req->data,
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004134 HTTP_MSG_RQMETH,
4135 cur_ptr, cur_end + 1,
4136 NULL, NULL);
4137 if (unlikely(!cur_end))
4138 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01004139
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004140 /* we have a full request and we know that we have either a CR
4141 * or an LF at <ptr>.
4142 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004143 txn->meth = find_http_meth(cur_ptr, txn->req.sl.rq.m_l);
4144 hdr_idx_set_start(&txn->hdr_idx, txn->req.sl.rq.l, *cur_end == '\r');
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004145 /* there is no point trying this regex on headers */
4146 return 1;
4147 }
4148 }
4149 *cur_end = term; /* restore the string terminator */
4150 return done;
4151}
Willy Tarreau97de6242006-12-27 17:18:38 +01004152
Willy Tarreau58f10d72006-12-04 02:26:12 +01004153
Willy Tarreau58f10d72006-12-04 02:26:12 +01004154
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004155/*
4156 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
4157 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
Willy Tarreaua15645d2007-03-18 16:22:39 +01004158 * unparsable request. Since it can manage the switch to another backend, it
4159 * updates the per-proxy DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004160 */
4161int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
4162{
Willy Tarreau3d300592007-03-18 18:34:41 +01004163 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004164 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004165 while (exp && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004166 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004167
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004168 /*
4169 * The interleaving of transformations and verdicts
4170 * makes it difficult to decide to continue or stop
4171 * the evaluation.
4172 */
4173
Willy Tarreau3d300592007-03-18 18:34:41 +01004174 if ((txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004175 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4176 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
4177 exp = exp->next;
4178 continue;
4179 }
4180
4181 /* Apply the filter to the request line. */
4182 ret = apply_filter_to_req_line(t, req, exp);
4183 if (unlikely(ret < 0))
4184 return -1;
4185
4186 if (likely(ret == 0)) {
4187 /* The filter did not match the request, it can be
4188 * iterated through all headers.
4189 */
4190 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004191 }
4192 exp = exp->next;
4193 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004194 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004195}
4196
4197
Willy Tarreaua15645d2007-03-18 16:22:39 +01004198
Willy Tarreau58f10d72006-12-04 02:26:12 +01004199/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004200 * Manage client-side cookie. It can impact performance by about 2% so it is
4201 * desirable to call it only when needed.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004202 */
4203void manage_client_side_cookies(struct session *t, struct buffer *req)
4204{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004205 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004206 char *p1, *p2, *p3, *p4;
4207 char *del_colon, *del_cookie, *colon;
4208 int app_cookies;
4209
4210 appsess *asession_temp = NULL;
4211 appsess local_asession;
4212
4213 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004214 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004215
Willy Tarreau2a324282006-12-05 00:05:46 +01004216 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004217 * we start with the start line.
4218 */
Willy Tarreau83969f42007-01-22 08:55:47 +01004219 old_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004220 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004221
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004222 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004223 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004224 int val;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004225
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004226 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01004227 cur_ptr = cur_next;
4228 cur_end = cur_ptr + cur_hdr->len;
4229 cur_next = cur_end + cur_hdr->cr + 1;
4230
4231 /* We have one full header between cur_ptr and cur_end, and the
4232 * next header starts at cur_next. We're only interested in
4233 * "Cookie:" headers.
4234 */
4235
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004236 val = http_header_match2(cur_ptr, cur_end, "Cookie", 6);
4237 if (!val) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004238 old_idx = cur_idx;
4239 continue;
4240 }
4241
4242 /* Now look for cookies. Conforming to RFC2109, we have to support
4243 * attributes whose name begin with a '$', and associate them with
4244 * the right cookie, if we want to delete this cookie.
4245 * So there are 3 cases for each cookie read :
4246 * 1) it's a special attribute, beginning with a '$' : ignore it.
4247 * 2) it's a server id cookie that we *MAY* want to delete : save
4248 * some pointers on it (last semi-colon, beginning of cookie...)
4249 * 3) it's an application cookie : we *MAY* have to delete a previous
4250 * "special" cookie.
4251 * At the end of loop, if a "special" cookie remains, we may have to
4252 * remove it. If no application cookie persists in the header, we
4253 * *MUST* delete it
4254 */
4255
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004256 colon = p1 = cur_ptr + val; /* first non-space char after 'Cookie:' */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004257
Willy Tarreau58f10d72006-12-04 02:26:12 +01004258 /* del_cookie == NULL => nothing to be deleted */
4259 del_colon = del_cookie = NULL;
4260 app_cookies = 0;
4261
4262 while (p1 < cur_end) {
4263 /* skip spaces and colons, but keep an eye on these ones */
4264 while (p1 < cur_end) {
4265 if (*p1 == ';' || *p1 == ',')
4266 colon = p1;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004267 else if (!isspace((unsigned char)*p1))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004268 break;
4269 p1++;
4270 }
4271
4272 if (p1 == cur_end)
4273 break;
4274
4275 /* p1 is at the beginning of the cookie name */
4276 p2 = p1;
4277 while (p2 < cur_end && *p2 != '=')
4278 p2++;
4279
4280 if (p2 == cur_end)
4281 break;
4282
4283 p3 = p2 + 1; /* skips the '=' sign */
4284 if (p3 == cur_end)
4285 break;
4286
4287 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004288 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';' && *p4 != ',')
Willy Tarreau58f10d72006-12-04 02:26:12 +01004289 p4++;
4290
4291 /* here, we have the cookie name between p1 and p2,
4292 * and its value between p3 and p4.
4293 * we can process it :
4294 *
4295 * Cookie: NAME=VALUE;
4296 * | || || |
4297 * | || || +--> p4
4298 * | || |+-------> p3
4299 * | || +--------> p2
4300 * | |+------------> p1
4301 * | +-------------> colon
4302 * +--------------------> cur_ptr
4303 */
4304
4305 if (*p1 == '$') {
4306 /* skip this one */
4307 }
4308 else {
4309 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004310 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004311 txn->cli_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004312 (p4 - p1 >= t->fe->capture_namelen) &&
4313 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004314 int log_len = p4 - p1;
4315
Willy Tarreau086b3b42007-05-13 21:45:51 +02004316 if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004317 Alert("HTTP logging : out of memory.\n");
4318 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004319 if (log_len > t->fe->capture_len)
4320 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004321 memcpy(txn->cli_cookie, p1, log_len);
4322 txn->cli_cookie[log_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004323 }
4324 }
4325
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004326 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4327 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004328 /* Cool... it's the right one */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004329 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004330 char *delim;
4331
4332 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4333 * have the server ID betweek p3 and delim, and the original cookie between
4334 * delim+1 and p4. Otherwise, delim==p4 :
4335 *
4336 * Cookie: NAME=SRV~VALUE;
4337 * | || || | |
4338 * | || || | +--> p4
4339 * | || || +--------> delim
4340 * | || |+-----------> p3
4341 * | || +------------> p2
4342 * | |+----------------> p1
4343 * | +-----------------> colon
4344 * +------------------------> cur_ptr
4345 */
4346
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004347 if (t->be->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004348 for (delim = p3; delim < p4; delim++)
4349 if (*delim == COOKIE_DELIM)
4350 break;
4351 }
4352 else
4353 delim = p4;
4354
4355
4356 /* Here, we'll look for the first running server which supports the cookie.
4357 * This allows to share a same cookie between several servers, for example
4358 * to dedicate backup servers to specific servers only.
4359 * However, to prevent clients from sticking to cookie-less backup server
4360 * when they have incidentely learned an empty cookie, we simply ignore
4361 * empty cookies and mark them as invalid.
4362 */
4363 if (delim == p3)
4364 srv = NULL;
4365
4366 while (srv) {
Willy Tarreau92f2ab12007-02-02 22:14:47 +01004367 if (srv->cookie && (srv->cklen == delim - p3) &&
4368 !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004369 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004370 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004371 txn->flags &= ~TX_CK_MASK;
4372 txn->flags |= TX_CK_VALID;
4373 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004374 t->srv = srv;
4375 break;
4376 } else {
4377 /* we found a server, but it's down */
Willy Tarreau3d300592007-03-18 18:34:41 +01004378 txn->flags &= ~TX_CK_MASK;
4379 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004380 }
4381 }
4382 srv = srv->next;
4383 }
4384
Willy Tarreau3d300592007-03-18 18:34:41 +01004385 if (!srv && !(txn->flags & TX_CK_DOWN)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004386 /* no server matched this cookie */
Willy Tarreau3d300592007-03-18 18:34:41 +01004387 txn->flags &= ~TX_CK_MASK;
4388 txn->flags |= TX_CK_INVALID;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004389 }
4390
4391 /* depending on the cookie mode, we may have to either :
4392 * - delete the complete cookie if we're in insert+indirect mode, so that
4393 * the server never sees it ;
4394 * - remove the server id from the cookie value, and tag the cookie as an
4395 * application cookie so that it does not get accidentely removed later,
4396 * if we're in cookie prefix mode
4397 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004398 if ((t->be->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004399 int delta; /* negative */
4400
4401 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
4402 p4 += delta;
4403 cur_end += delta;
4404 cur_next += delta;
4405 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004406 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004407
4408 del_cookie = del_colon = NULL;
4409 app_cookies++; /* protect the header from deletion */
4410 }
4411 else if (del_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004412 (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 +01004413 del_cookie = p1;
4414 del_colon = colon;
4415 }
4416 } else {
4417 /* now we know that we must keep this cookie since it's
4418 * not ours. But if we wanted to delete our cookie
4419 * earlier, we cannot remove the complete header, but we
4420 * can remove the previous block itself.
4421 */
4422 app_cookies++;
4423
4424 if (del_cookie != NULL) {
4425 int delta; /* negative */
4426
4427 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
4428 p4 += delta;
4429 cur_end += delta;
4430 cur_next += delta;
4431 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004432 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004433 del_cookie = del_colon = NULL;
4434 }
4435 }
4436
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004437 if ((t->be->appsession_name != NULL) &&
4438 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004439 /* first, let's see if the cookie is our appcookie*/
4440
4441 /* Cool... it's the right one */
4442
4443 asession_temp = &local_asession;
4444
Willy Tarreau63963c62007-05-13 21:29:55 +02004445 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004446 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4447 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4448 return;
4449 }
4450
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004451 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4452 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004453 asession_temp->serverid = NULL;
Willy Tarreau51041c72007-09-09 21:56:53 +02004454
Willy Tarreau58f10d72006-12-04 02:26:12 +01004455 /* only do insert, if lookup fails */
Willy Tarreau51041c72007-09-09 21:56:53 +02004456 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4457 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004458 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004459 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004460 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004461 Alert("Not enough memory process_cli():asession:calloc().\n");
4462 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4463 return;
4464 }
4465
4466 asession_temp->sessid = local_asession.sessid;
4467 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004468 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004469 } else {
4470 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004471 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004472 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004473 if (asession_temp->serverid == NULL) {
4474 Alert("Found Application Session without matching server.\n");
4475 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004476 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004477 while (srv) {
4478 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004479 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004480 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004481 txn->flags &= ~TX_CK_MASK;
4482 txn->flags |= TX_CK_VALID;
4483 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004484 t->srv = srv;
4485 break;
4486 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01004487 txn->flags &= ~TX_CK_MASK;
4488 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004489 }
4490 }
4491 srv = srv->next;
4492 }/* end while(srv) */
4493 }/* end else if server == NULL */
4494
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004495 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004496 }/* end if ((t->proxy->appsession_name != NULL) ... */
4497 }
4498
4499 /* we'll have to look for another cookie ... */
4500 p1 = p4;
4501 } /* while (p1 < cur_end) */
4502
4503 /* There's no more cookie on this line.
4504 * We may have marked the last one(s) for deletion.
4505 * We must do this now in two ways :
4506 * - if there is no app cookie, we simply delete the header ;
4507 * - if there are app cookies, we must delete the end of the
4508 * string properly, including the colon/semi-colon before
4509 * the cookie name.
4510 */
4511 if (del_cookie != NULL) {
4512 int delta;
4513 if (app_cookies) {
4514 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
4515 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004516 cur_hdr->len += delta;
4517 } else {
4518 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004519
4520 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004521 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4522 txn->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004523 cur_hdr->len = 0;
4524 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01004525 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004526 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004527 }
4528
4529 /* keep the link from this header to next one */
4530 old_idx = cur_idx;
4531 } /* end of cookie processing on this header */
4532}
4533
4534
Willy Tarreaua15645d2007-03-18 16:22:39 +01004535/* Iterate the same filter through all response headers contained in <rtr>.
4536 * Returns 1 if this filter can be stopped upon return, otherwise 0.
4537 */
4538int apply_filter_to_resp_headers(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4539{
4540 char term;
4541 char *cur_ptr, *cur_end, *cur_next;
4542 int cur_idx, old_idx, last_hdr;
4543 struct http_txn *txn = &t->txn;
4544 struct hdr_idx_elem *cur_hdr;
4545 int len, delta;
4546
4547 last_hdr = 0;
4548
4549 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4550 old_idx = 0;
4551
4552 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004553 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004554 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004555 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004556 (exp->action == ACT_ALLOW ||
4557 exp->action == ACT_DENY))
4558 return 0;
4559
4560 cur_idx = txn->hdr_idx.v[old_idx].next;
4561 if (!cur_idx)
4562 break;
4563
4564 cur_hdr = &txn->hdr_idx.v[cur_idx];
4565 cur_ptr = cur_next;
4566 cur_end = cur_ptr + cur_hdr->len;
4567 cur_next = cur_end + cur_hdr->cr + 1;
4568
4569 /* Now we have one header between cur_ptr and cur_end,
4570 * and the next header starts at cur_next.
4571 */
4572
4573 /* The annoying part is that pattern matching needs
4574 * that we modify the contents to null-terminate all
4575 * strings before testing them.
4576 */
4577
4578 term = *cur_end;
4579 *cur_end = '\0';
4580
4581 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4582 switch (exp->action) {
4583 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004584 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004585 last_hdr = 1;
4586 break;
4587
4588 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004589 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004590 last_hdr = 1;
4591 break;
4592
4593 case ACT_REPLACE:
4594 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4595 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4596 /* FIXME: if the user adds a newline in the replacement, the
4597 * index will not be recalculated for now, and the new line
4598 * will not be counted as a new header.
4599 */
4600
4601 cur_end += delta;
4602 cur_next += delta;
4603 cur_hdr->len += delta;
4604 txn->rsp.eoh += delta;
4605 break;
4606
4607 case ACT_REMOVE:
4608 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4609 cur_next += delta;
4610
4611 /* FIXME: this should be a separate function */
4612 txn->rsp.eoh += delta;
4613 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4614 txn->hdr_idx.used--;
4615 cur_hdr->len = 0;
4616 cur_end = NULL; /* null-term has been rewritten */
4617 break;
4618
4619 }
4620 }
4621 if (cur_end)
4622 *cur_end = term; /* restore the string terminator */
4623
4624 /* keep the link from this header to next one in case of later
4625 * removal of next header.
4626 */
4627 old_idx = cur_idx;
4628 }
4629 return 0;
4630}
4631
4632
4633/* Apply the filter to the status line in the response buffer <rtr>.
4634 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4635 * or -1 if a replacement resulted in an invalid status line.
4636 */
4637int apply_filter_to_sts_line(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4638{
4639 char term;
4640 char *cur_ptr, *cur_end;
4641 int done;
4642 struct http_txn *txn = &t->txn;
4643 int len, delta;
4644
4645
Willy Tarreau3d300592007-03-18 18:34:41 +01004646 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004647 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004648 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004649 (exp->action == ACT_ALLOW ||
4650 exp->action == ACT_DENY))
4651 return 0;
4652 else if (exp->action == ACT_REMOVE)
4653 return 0;
4654
4655 done = 0;
4656
Willy Tarreau9cdde232007-05-02 20:58:19 +02004657 cur_ptr = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004658 cur_end = cur_ptr + txn->rsp.sl.rq.l;
4659
4660 /* Now we have the status line between cur_ptr and cur_end */
4661
4662 /* The annoying part is that pattern matching needs
4663 * that we modify the contents to null-terminate all
4664 * strings before testing them.
4665 */
4666
4667 term = *cur_end;
4668 *cur_end = '\0';
4669
4670 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4671 switch (exp->action) {
4672 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004673 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004674 done = 1;
4675 break;
4676
4677 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004678 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004679 done = 1;
4680 break;
4681
4682 case ACT_REPLACE:
4683 *cur_end = term; /* restore the string terminator */
4684 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4685 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4686 /* FIXME: if the user adds a newline in the replacement, the
4687 * index will not be recalculated for now, and the new line
4688 * will not be counted as a new header.
4689 */
4690
4691 txn->rsp.eoh += delta;
4692 cur_end += delta;
4693
Willy Tarreau9cdde232007-05-02 20:58:19 +02004694 txn->rsp.sol = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004695 cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data,
Willy Tarreau02785762007-04-03 14:45:44 +02004696 HTTP_MSG_RPVER,
Willy Tarreaua15645d2007-03-18 16:22:39 +01004697 cur_ptr, cur_end + 1,
4698 NULL, NULL);
4699 if (unlikely(!cur_end))
4700 return -1;
4701
4702 /* we have a full respnse and we know that we have either a CR
4703 * or an LF at <ptr>.
4704 */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004705 txn->status = strl2ui(rtr->data + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004706 hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.rq.l, *cur_end == '\r');
4707 /* there is no point trying this regex on headers */
4708 return 1;
4709 }
4710 }
4711 *cur_end = term; /* restore the string terminator */
4712 return done;
4713}
4714
4715
4716
4717/*
4718 * Apply all the resp filters <exp> to all headers in buffer <rtr> of session <t>.
4719 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
4720 * unparsable response.
4721 */
4722int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4723{
Willy Tarreau3d300592007-03-18 18:34:41 +01004724 struct http_txn *txn = &t->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004725 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004726 while (exp && !(txn->flags & TX_SVDENY)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004727 int ret;
4728
4729 /*
4730 * The interleaving of transformations and verdicts
4731 * makes it difficult to decide to continue or stop
4732 * the evaluation.
4733 */
4734
Willy Tarreau3d300592007-03-18 18:34:41 +01004735 if ((txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004736 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4737 exp->action == ACT_PASS)) {
4738 exp = exp->next;
4739 continue;
4740 }
4741
4742 /* Apply the filter to the status line. */
4743 ret = apply_filter_to_sts_line(t, rtr, exp);
4744 if (unlikely(ret < 0))
4745 return -1;
4746
4747 if (likely(ret == 0)) {
4748 /* The filter did not match the response, it can be
4749 * iterated through all headers.
4750 */
4751 apply_filter_to_resp_headers(t, rtr, exp);
4752 }
4753 exp = exp->next;
4754 }
4755 return 0;
4756}
4757
4758
4759
4760/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004761 * Manage server-side cookies. It can impact performance by about 2% so it is
4762 * desirable to call it only when needed.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004763 */
4764void manage_server_side_cookies(struct session *t, struct buffer *rtr)
4765{
4766 struct http_txn *txn = &t->txn;
4767 char *p1, *p2, *p3, *p4;
4768
4769 appsess *asession_temp = NULL;
4770 appsess local_asession;
4771
4772 char *cur_ptr, *cur_end, *cur_next;
4773 int cur_idx, old_idx, delta;
4774
Willy Tarreaua15645d2007-03-18 16:22:39 +01004775 /* Iterate through the headers.
4776 * we start with the start line.
4777 */
4778 old_idx = 0;
4779 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4780
4781 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
4782 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004783 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004784
4785 cur_hdr = &txn->hdr_idx.v[cur_idx];
4786 cur_ptr = cur_next;
4787 cur_end = cur_ptr + cur_hdr->len;
4788 cur_next = cur_end + cur_hdr->cr + 1;
4789
4790 /* We have one full header between cur_ptr and cur_end, and the
4791 * next header starts at cur_next. We're only interested in
4792 * "Cookie:" headers.
4793 */
4794
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004795 val = http_header_match2(cur_ptr, cur_end, "Set-Cookie", 10);
4796 if (!val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004797 old_idx = cur_idx;
4798 continue;
4799 }
4800
4801 /* OK, right now we know we have a set-cookie at cur_ptr */
Willy Tarreau3d300592007-03-18 18:34:41 +01004802 txn->flags |= TX_SCK_ANY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004803
4804
4805 /* maybe we only wanted to see if there was a set-cookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004806 if (t->be->cookie_name == NULL &&
4807 t->be->appsession_name == NULL &&
4808 t->be->capture_name == NULL)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004809 return;
4810
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004811 p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004812
4813 while (p1 < cur_end) { /* in fact, we'll break after the first cookie */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004814 if (p1 == cur_end || *p1 == ';') /* end of cookie */
4815 break;
4816
4817 /* p1 is at the beginning of the cookie name */
4818 p2 = p1;
4819
4820 while (p2 < cur_end && *p2 != '=' && *p2 != ';')
4821 p2++;
4822
4823 if (p2 == cur_end || *p2 == ';') /* next cookie */
4824 break;
4825
4826 p3 = p2 + 1; /* skip the '=' sign */
4827 if (p3 == cur_end)
4828 break;
4829
4830 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004831 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';')
Willy Tarreaua15645d2007-03-18 16:22:39 +01004832 p4++;
4833
4834 /* here, we have the cookie name between p1 and p2,
4835 * and its value between p3 and p4.
4836 * we can process it.
4837 */
4838
4839 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004840 if (t->be->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004841 txn->srv_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004842 (p4 - p1 >= t->be->capture_namelen) &&
4843 memcmp(p1, t->be->capture_name, t->be->capture_namelen) == 0) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004844 int log_len = p4 - p1;
4845
Willy Tarreau086b3b42007-05-13 21:45:51 +02004846 if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004847 Alert("HTTP logging : out of memory.\n");
4848 }
4849
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004850 if (log_len > t->be->capture_len)
4851 log_len = t->be->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004852 memcpy(txn->srv_cookie, p1, log_len);
4853 txn->srv_cookie[log_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004854 }
4855
4856 /* now check if we need to process it for persistence */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004857 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4858 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004859 /* Cool... it's the right one */
Willy Tarreau3d300592007-03-18 18:34:41 +01004860 txn->flags |= TX_SCK_SEEN;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004861
4862 /* If the cookie is in insert mode on a known server, we'll delete
4863 * this occurrence because we'll insert another one later.
4864 * We'll delete it too if the "indirect" option is set and we're in
4865 * a direct access. */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004866 if (((t->srv) && (t->be->options & PR_O_COOK_INS)) ||
4867 ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004868 /* this header must be deleted */
4869 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4870 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4871 txn->hdr_idx.used--;
4872 cur_hdr->len = 0;
4873 cur_next += delta;
4874 txn->rsp.eoh += delta;
4875
Willy Tarreau3d300592007-03-18 18:34:41 +01004876 txn->flags |= TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004877 }
4878 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004879 (t->be->options & PR_O_COOK_RW)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004880 /* replace bytes p3->p4 with the cookie name associated
4881 * with this server since we know it.
4882 */
4883 delta = buffer_replace2(rtr, p3, p4, t->srv->cookie, t->srv->cklen);
4884 cur_hdr->len += delta;
4885 cur_next += delta;
4886 txn->rsp.eoh += delta;
4887
Willy Tarreau3d300592007-03-18 18:34:41 +01004888 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004889 }
4890 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004891 (t->be->options & PR_O_COOK_PFX)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004892 /* insert the cookie name associated with this server
4893 * before existing cookie, and insert a delimitor between them..
4894 */
4895 delta = buffer_replace2(rtr, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4896 cur_hdr->len += delta;
4897 cur_next += delta;
4898 txn->rsp.eoh += delta;
4899
4900 p3[t->srv->cklen] = COOKIE_DELIM;
Willy Tarreau3d300592007-03-18 18:34:41 +01004901 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004902 }
4903 }
4904 /* next, let's see if the cookie is our appcookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004905 else if ((t->be->appsession_name != NULL) &&
4906 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004907
4908 /* Cool... it's the right one */
4909
4910 size_t server_id_len = strlen(t->srv->id) + 1;
4911 asession_temp = &local_asession;
4912
Willy Tarreau63963c62007-05-13 21:29:55 +02004913 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004914 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4915 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4916 return;
4917 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004918 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4919 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004920 asession_temp->serverid = NULL;
4921
4922 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01004923 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4924 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004925 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004926 Alert("Not enough Memory process_srv():asession:calloc().\n");
4927 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
4928 return;
4929 }
4930 asession_temp->sessid = local_asession.sessid;
4931 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004932 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
4933 } else {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004934 /* free wasted memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004935 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau51041c72007-09-09 21:56:53 +02004936 }
4937
Willy Tarreaua15645d2007-03-18 16:22:39 +01004938 if (asession_temp->serverid == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004939 if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004940 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4941 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4942 return;
4943 }
4944 asession_temp->serverid[0] = '\0';
4945 }
4946
4947 if (asession_temp->serverid[0] == '\0')
4948 memcpy(asession_temp->serverid, t->srv->id, server_id_len);
4949
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004950 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004951
4952#if defined(DEBUG_HASH)
Willy Tarreau51041c72007-09-09 21:56:53 +02004953 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreaua15645d2007-03-18 16:22:39 +01004954#endif
4955 }/* end if ((t->proxy->appsession_name != NULL) ... */
4956 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4957 } /* we're now at the end of the cookie value */
4958
4959 /* keep the link from this header to next one */
4960 old_idx = cur_idx;
4961 } /* end of cookie processing on this header */
4962}
4963
4964
4965
4966/*
4967 * Check if response is cacheable or not. Updates t->flags.
4968 */
4969void check_response_for_cacheability(struct session *t, struct buffer *rtr)
4970{
4971 struct http_txn *txn = &t->txn;
4972 char *p1, *p2;
4973
4974 char *cur_ptr, *cur_end, *cur_next;
4975 int cur_idx;
4976
Willy Tarreau5df51872007-11-25 16:20:08 +01004977 if (!(txn->flags & TX_CACHEABLE))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004978 return;
4979
4980 /* Iterate through the headers.
4981 * we start with the start line.
4982 */
4983 cur_idx = 0;
4984 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4985
4986 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
4987 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004988 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004989
4990 cur_hdr = &txn->hdr_idx.v[cur_idx];
4991 cur_ptr = cur_next;
4992 cur_end = cur_ptr + cur_hdr->len;
4993 cur_next = cur_end + cur_hdr->cr + 1;
4994
4995 /* We have one full header between cur_ptr and cur_end, and the
4996 * next header starts at cur_next. We're only interested in
4997 * "Cookie:" headers.
4998 */
4999
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005000 val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
5001 if (val) {
5002 if ((cur_end - (cur_ptr + val) >= 8) &&
5003 strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
5004 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
5005 return;
5006 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01005007 }
5008
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005009 val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
5010 if (!val)
Willy Tarreaua15645d2007-03-18 16:22:39 +01005011 continue;
5012
5013 /* OK, right now we know we have a cache-control header at cur_ptr */
5014
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005015 p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01005016
5017 if (p1 >= cur_end) /* no more info */
5018 continue;
5019
5020 /* p1 is at the beginning of the value */
5021 p2 = p1;
5022
Willy Tarreau8f8e6452007-06-17 21:51:38 +02005023 while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((unsigned char)*p2))
Willy Tarreaua15645d2007-03-18 16:22:39 +01005024 p2++;
5025
5026 /* we have a complete value between p1 and p2 */
5027 if (p2 < cur_end && *p2 == '=') {
5028 /* we have something of the form no-cache="set-cookie" */
5029 if ((cur_end - p1 >= 21) &&
5030 strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0
5031 && (p1[20] == '"' || p1[20] == ','))
Willy Tarreau3d300592007-03-18 18:34:41 +01005032 txn->flags &= ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005033 continue;
5034 }
5035
5036 /* OK, so we know that either p2 points to the end of string or to a comma */
5037 if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) ||
5038 ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) ||
5039 ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) ||
5040 ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005041 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005042 return;
5043 }
5044
5045 if ((p2 - p1 == 6) && strncasecmp(p1, "public", 6) == 0) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005046 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005047 continue;
5048 }
5049 }
5050}
5051
5052
Willy Tarreau58f10d72006-12-04 02:26:12 +01005053/*
5054 * Try to retrieve a known appsession in the URI, then the associated server.
5055 * If the server is found, it's assigned to the session.
5056 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005057void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01005058{
Willy Tarreau3d300592007-03-18 18:34:41 +01005059 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005060 appsess *asession_temp = NULL;
5061 appsess local_asession;
5062 char *request_line;
5063
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005064 if (t->be->appsession_name == NULL ||
Willy Tarreaub326fcc2007-03-03 13:54:32 +01005065 (t->txn.meth != HTTP_METH_GET && t->txn.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005066 (request_line = memchr(begin, ';', len)) == NULL ||
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005067 ((1 + t->be->appsession_name_len + 1 + t->be->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01005068 return;
5069
5070 /* skip ';' */
5071 request_line++;
5072
5073 /* look if we have a jsessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005074 if (strncasecmp(request_line, t->be->appsession_name, t->be->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01005075 return;
5076
5077 /* skip jsessionid= */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005078 request_line += t->be->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005079
5080 /* First try if we already have an appsession */
5081 asession_temp = &local_asession;
5082
Willy Tarreau63963c62007-05-13 21:29:55 +02005083 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005084 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
5085 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
5086 return;
5087 }
5088
5089 /* Copy the sessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005090 memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
5091 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005092 asession_temp->serverid = NULL;
5093
5094 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01005095 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
5096 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02005097 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005098 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005099 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005100 Alert("Not enough memory process_cli():asession:calloc().\n");
5101 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
5102 return;
5103 }
5104 asession_temp->sessid = local_asession.sessid;
5105 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02005106 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005107 }
5108 else {
5109 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005110 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005111 }
Willy Tarreau51041c72007-09-09 21:56:53 +02005112
Willy Tarreau0c303ee2008-07-07 00:09:58 +02005113 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005114 asession_temp->request_count++;
Willy Tarreau51041c72007-09-09 21:56:53 +02005115
Willy Tarreau58f10d72006-12-04 02:26:12 +01005116#if defined(DEBUG_HASH)
Willy Tarreau51041c72007-09-09 21:56:53 +02005117 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreau58f10d72006-12-04 02:26:12 +01005118#endif
5119 if (asession_temp->serverid == NULL) {
5120 Alert("Found Application Session without matching server.\n");
5121 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005122 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005123 while (srv) {
5124 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005125 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005126 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01005127 txn->flags &= ~TX_CK_MASK;
5128 txn->flags |= TX_CK_VALID;
5129 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005130 t->srv = srv;
5131 break;
5132 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01005133 txn->flags &= ~TX_CK_MASK;
5134 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005135 }
5136 }
5137 srv = srv->next;
5138 }
5139 }
5140}
5141
5142
Willy Tarreaub2513902006-12-17 14:52:38 +01005143/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005144 * In a GET or HEAD request, check if the requested URI matches the stats uri
5145 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01005146 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005147 * It is assumed that the request is either a HEAD or GET and that the
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005148 * t->be->uri_auth field is valid. An HTTP/401 response may be sent, or
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005149 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01005150 *
5151 * Returns 1 if the session's state changes, otherwise 0.
5152 */
5153int stats_check_uri_auth(struct session *t, struct proxy *backend)
5154{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005155 struct http_txn *txn = &t->txn;
Willy Tarreaub2513902006-12-17 14:52:38 +01005156 struct uri_auth *uri_auth = backend->uri_auth;
5157 struct user_auth *user;
5158 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005159 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01005160
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005161 memset(&t->data_ctx.stats, 0, sizeof(t->data_ctx.stats));
5162
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005163 /* check URI size */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005164 if (uri_auth->uri_len > txn->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01005165 return 0;
5166
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005167 h = t->req->data + txn->req.sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005168
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005169 /* the URI is in h */
5170 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01005171 return 0;
5172
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005173 h += uri_auth->uri_len;
5174 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 3) {
5175 if (memcmp(h, ";up", 3) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005176 t->data_ctx.stats.flags |= STAT_HIDE_DOWN;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005177 break;
5178 }
5179 h++;
5180 }
5181
5182 if (uri_auth->refresh) {
5183 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5184 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 10) {
5185 if (memcmp(h, ";norefresh", 10) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005186 t->data_ctx.stats.flags |= STAT_NO_REFRESH;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005187 break;
5188 }
5189 h++;
5190 }
5191 }
5192
Willy Tarreau55bb8452007-10-17 18:44:57 +02005193 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5194 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 4) {
5195 if (memcmp(h, ";csv", 4) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005196 t->data_ctx.stats.flags |= STAT_FMT_CSV;
Willy Tarreau55bb8452007-10-17 18:44:57 +02005197 break;
5198 }
5199 h++;
5200 }
5201
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005202 t->data_ctx.stats.flags |= STAT_SHOW_STAT | STAT_SHOW_INFO;
5203
Willy Tarreaub2513902006-12-17 14:52:38 +01005204 /* we are in front of a interceptable URI. Let's check
5205 * if there's an authentication and if it's valid.
5206 */
5207 user = uri_auth->users;
5208 if (!user) {
5209 /* no user auth required, it's OK */
5210 authenticated = 1;
5211 } else {
5212 authenticated = 0;
5213
5214 /* a user list is defined, we have to check.
5215 * skip 21 chars for "Authorization: Basic ".
5216 */
5217
5218 /* FIXME: this should move to an earlier place */
5219 cur_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005220 h = t->req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
5221 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
5222 int len = txn->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005223 if (len > 14 &&
5224 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005225 txn->auth_hdr.str = h;
5226 txn->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005227 break;
5228 }
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005229 h += len + txn->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01005230 }
5231
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005232 if (txn->auth_hdr.len < 21 ||
5233 memcmp(txn->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01005234 user = NULL;
5235
5236 while (user) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005237 if ((txn->auth_hdr.len == user->user_len + 14 + 7)
5238 && !memcmp(txn->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01005239 user->user_pwd, user->user_len)) {
5240 authenticated = 1;
5241 break;
5242 }
5243 user = user->next;
5244 }
5245 }
5246
5247 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01005248 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01005249
5250 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01005251 msg.str = trash;
5252 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005253 txn->status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01005254 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01005255 if (!(t->flags & SN_ERR_MASK))
5256 t->flags |= SN_ERR_PRXCOND;
5257 if (!(t->flags & SN_FINST_MASK))
5258 t->flags |= SN_FINST_R;
5259 return 1;
5260 }
5261
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005262 /* The request is valid, the user is authenticated. Let's start sending
Willy Tarreaub2513902006-12-17 14:52:38 +01005263 * data.
5264 */
Willy Tarreau284c7b32008-06-29 16:38:43 +02005265 EV_FD_CLR(t->cli_fd, DIR_RD);
5266 buffer_shutr(t->req);
5267 buffer_shutr(t->rep);
Willy Tarreaub2513902006-12-17 14:52:38 +01005268 t->cli_state = CL_STSHUTR;
5269 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau70089872008-06-13 21:12:51 +02005270 t->logs.tv_request = now;
Willy Tarreaub2513902006-12-17 14:52:38 +01005271 t->data_source = DATA_SRC_STATS;
5272 t->data_state = DATA_ST_INIT;
Willy Tarreau91e99932008-06-30 07:51:00 +02005273 t->task->nice = -32; /* small boost for HTTP statistics */
Willy Tarreaub2513902006-12-17 14:52:38 +01005274 produce_content(t);
5275 return 1;
5276}
5277
5278
Willy Tarreaubaaee002006-06-26 02:48:02 +02005279/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01005280 * Print a debug line with a header
5281 */
5282void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
5283{
5284 int len, max;
5285 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
5286 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
5287 max = end - start;
5288 UBOUND(max, sizeof(trash) - len - 1);
5289 len += strlcpy2(trash + len, start, max + 1);
5290 trash[len++] = '\n';
5291 write(1, trash, len);
5292}
5293
5294
Willy Tarreau8797c062007-05-07 00:55:35 +02005295/************************************************************************/
5296/* The code below is dedicated to ACL parsing and matching */
5297/************************************************************************/
5298
5299
5300
5301
5302/* 1. Check on METHOD
5303 * We use the pre-parsed method if it is known, and store its number as an
5304 * integer. If it is unknown, we use the pointer and the length.
5305 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005306static int acl_parse_meth(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005307{
5308 int len, meth;
5309
Willy Tarreauae8b7962007-06-09 23:10:04 +02005310 len = strlen(*text);
5311 meth = find_http_meth(*text, len);
Willy Tarreau8797c062007-05-07 00:55:35 +02005312
5313 pattern->val.i = meth;
5314 if (meth == HTTP_METH_OTHER) {
Willy Tarreauae8b7962007-06-09 23:10:04 +02005315 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005316 if (!pattern->ptr.str)
5317 return 0;
5318 pattern->len = len;
5319 }
5320 return 1;
5321}
5322
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005323static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005324acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
5325 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005326{
5327 int meth;
5328 struct http_txn *txn = l7;
5329
Willy Tarreaub6866442008-07-14 23:54:42 +02005330 if (!txn)
5331 return 0;
5332
Willy Tarreauc11416f2007-06-17 16:58:38 +02005333 if (txn->req.msg_state != HTTP_MSG_BODY)
5334 return 0;
5335
Willy Tarreau8797c062007-05-07 00:55:35 +02005336 meth = txn->meth;
5337 test->i = meth;
5338 if (meth == HTTP_METH_OTHER) {
Willy Tarreauc11416f2007-06-17 16:58:38 +02005339 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5340 /* ensure the indexes are not affected */
5341 return 0;
Willy Tarreau8797c062007-05-07 00:55:35 +02005342 test->len = txn->req.sl.rq.m_l;
5343 test->ptr = txn->req.sol;
5344 }
5345 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5346 return 1;
5347}
5348
5349static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
5350{
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005351 int icase;
5352
Willy Tarreau8797c062007-05-07 00:55:35 +02005353 if (test->i != pattern->val.i)
Willy Tarreau11382812008-07-09 16:18:21 +02005354 return ACL_PAT_FAIL;
Willy Tarreau8797c062007-05-07 00:55:35 +02005355
5356 if (test->i != HTTP_METH_OTHER)
Willy Tarreau11382812008-07-09 16:18:21 +02005357 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005358
5359 /* Other method, we must compare the strings */
5360 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +02005361 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005362
5363 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
5364 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) != 0) ||
5365 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +02005366 return ACL_PAT_FAIL;
5367 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005368}
5369
5370/* 2. Check on Request/Status Version
5371 * We simply compare strings here.
5372 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005373static int acl_parse_ver(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005374{
Willy Tarreauae8b7962007-06-09 23:10:04 +02005375 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005376 if (!pattern->ptr.str)
5377 return 0;
Willy Tarreauae8b7962007-06-09 23:10:04 +02005378 pattern->len = strlen(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005379 return 1;
5380}
5381
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005382static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005383acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
5384 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005385{
5386 struct http_txn *txn = l7;
5387 char *ptr;
5388 int len;
5389
Willy Tarreaub6866442008-07-14 23:54:42 +02005390 if (!txn)
5391 return 0;
5392
Willy Tarreauc11416f2007-06-17 16:58:38 +02005393 if (txn->req.msg_state != HTTP_MSG_BODY)
5394 return 0;
5395
Willy Tarreau8797c062007-05-07 00:55:35 +02005396 len = txn->req.sl.rq.v_l;
5397 ptr = txn->req.sol + txn->req.sl.rq.v - txn->req.som;
5398
5399 while ((len-- > 0) && (*ptr++ != '/'));
5400 if (len <= 0)
5401 return 0;
5402
5403 test->ptr = ptr;
5404 test->len = len;
5405
5406 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5407 return 1;
5408}
5409
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005410static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005411acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
5412 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005413{
5414 struct http_txn *txn = l7;
5415 char *ptr;
5416 int len;
5417
Willy Tarreaub6866442008-07-14 23:54:42 +02005418 if (!txn)
5419 return 0;
5420
Willy Tarreauc11416f2007-06-17 16:58:38 +02005421 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5422 return 0;
5423
Willy Tarreau8797c062007-05-07 00:55:35 +02005424 len = txn->rsp.sl.st.v_l;
5425 ptr = txn->rsp.sol;
5426
5427 while ((len-- > 0) && (*ptr++ != '/'));
5428 if (len <= 0)
5429 return 0;
5430
5431 test->ptr = ptr;
5432 test->len = len;
5433
5434 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5435 return 1;
5436}
5437
5438/* 3. Check on Status Code. We manipulate integers here. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005439static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005440acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, int dir,
5441 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005442{
5443 struct http_txn *txn = l7;
5444 char *ptr;
5445 int len;
5446
Willy Tarreaub6866442008-07-14 23:54:42 +02005447 if (!txn)
5448 return 0;
5449
Willy Tarreauc11416f2007-06-17 16:58:38 +02005450 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5451 return 0;
5452
Willy Tarreau8797c062007-05-07 00:55:35 +02005453 len = txn->rsp.sl.st.c_l;
5454 ptr = txn->rsp.sol + txn->rsp.sl.st.c - txn->rsp.som;
5455
5456 test->i = __strl2ui(ptr, len);
5457 test->flags = ACL_TEST_F_VOL_1ST;
5458 return 1;
5459}
5460
5461/* 4. Check on URL/URI. A pointer to the URI is stored. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005462static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005463acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
5464 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005465{
5466 struct http_txn *txn = l7;
5467
Willy Tarreaub6866442008-07-14 23:54:42 +02005468 if (!txn)
5469 return 0;
5470
Willy Tarreauc11416f2007-06-17 16:58:38 +02005471 if (txn->req.msg_state != HTTP_MSG_BODY)
5472 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005473
Willy Tarreauc11416f2007-06-17 16:58:38 +02005474 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5475 /* ensure the indexes are not affected */
5476 return 0;
5477
Willy Tarreau8797c062007-05-07 00:55:35 +02005478 test->len = txn->req.sl.rq.u_l;
5479 test->ptr = txn->req.sol + txn->req.sl.rq.u;
5480
Willy Tarreauf3d25982007-05-08 22:45:09 +02005481 /* we do not need to set READ_ONLY because the data is in a buffer */
5482 test->flags = ACL_TEST_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +02005483 return 1;
5484}
5485
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005486static int
5487acl_fetch_url_ip(struct proxy *px, struct session *l4, void *l7, int dir,
5488 struct acl_expr *expr, struct acl_test *test)
5489{
5490 struct http_txn *txn = l7;
5491
Willy Tarreaub6866442008-07-14 23:54:42 +02005492 if (!txn)
5493 return 0;
5494
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005495 if (txn->req.msg_state != HTTP_MSG_BODY)
5496 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005497
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005498 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5499 /* ensure the indexes are not affected */
5500 return 0;
5501
5502 /* Parse HTTP request */
5503 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5504 test->ptr = (void *)&((struct sockaddr_in *)&l4->srv_addr)->sin_addr;
5505 test->i = AF_INET;
5506
5507 /*
5508 * If we are parsing url in frontend space, we prepare backend stage
5509 * to not parse again the same url ! optimization lazyness...
5510 */
5511 if (px->options & PR_O_HTTP_PROXY)
5512 l4->flags |= SN_ADDR_SET;
5513
5514 test->flags = ACL_TEST_F_READ_ONLY;
5515 return 1;
5516}
5517
5518static int
5519acl_fetch_url_port(struct proxy *px, struct session *l4, void *l7, int dir,
5520 struct acl_expr *expr, struct acl_test *test)
5521{
5522 struct http_txn *txn = l7;
5523
Willy Tarreaub6866442008-07-14 23:54:42 +02005524 if (!txn)
5525 return 0;
5526
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005527 if (txn->req.msg_state != HTTP_MSG_BODY)
5528 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005529
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005530 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5531 /* ensure the indexes are not affected */
5532 return 0;
5533
5534 /* Same optimization as url_ip */
5535 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5536 test->i = ntohs(((struct sockaddr_in *)&l4->srv_addr)->sin_port);
5537
5538 if (px->options & PR_O_HTTP_PROXY)
5539 l4->flags |= SN_ADDR_SET;
5540
5541 test->flags = ACL_TEST_F_READ_ONLY;
5542 return 1;
5543}
5544
Willy Tarreauc11416f2007-06-17 16:58:38 +02005545/* 5. Check on HTTP header. A pointer to the beginning of the value is returned.
5546 * This generic function is used by both acl_fetch_chdr() and acl_fetch_shdr().
5547 */
Willy Tarreau33a7e692007-06-10 19:45:56 +02005548static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005549acl_fetch_hdr(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005550 struct acl_expr *expr, struct acl_test *test)
5551{
5552 struct http_txn *txn = l7;
5553 struct hdr_idx *idx = &txn->hdr_idx;
5554 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005555
Willy Tarreaub6866442008-07-14 23:54:42 +02005556 if (!txn)
5557 return 0;
5558
Willy Tarreau33a7e692007-06-10 19:45:56 +02005559 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5560 /* search for header from the beginning */
5561 ctx->idx = 0;
5562
Willy Tarreau33a7e692007-06-10 19:45:56 +02005563 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5564 test->flags |= ACL_TEST_F_FETCH_MORE;
5565 test->flags |= ACL_TEST_F_VOL_HDR;
5566 test->len = ctx->vlen;
5567 test->ptr = (char *)ctx->line + ctx->val;
5568 return 1;
5569 }
5570
5571 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5572 test->flags |= ACL_TEST_F_VOL_HDR;
5573 return 0;
5574}
5575
Willy Tarreau33a7e692007-06-10 19:45:56 +02005576static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005577acl_fetch_chdr(struct proxy *px, struct session *l4, void *l7, int dir,
5578 struct acl_expr *expr, struct acl_test *test)
5579{
5580 struct http_txn *txn = l7;
5581
Willy Tarreaub6866442008-07-14 23:54:42 +02005582 if (!txn)
5583 return 0;
5584
Willy Tarreauc11416f2007-06-17 16:58:38 +02005585 if (txn->req.msg_state != HTTP_MSG_BODY)
5586 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005587
Willy Tarreauc11416f2007-06-17 16:58:38 +02005588 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5589 /* ensure the indexes are not affected */
5590 return 0;
5591
5592 return acl_fetch_hdr(px, l4, txn, txn->req.sol, expr, test);
5593}
5594
5595static int
5596acl_fetch_shdr(struct proxy *px, struct session *l4, void *l7, int dir,
5597 struct acl_expr *expr, struct acl_test *test)
5598{
5599 struct http_txn *txn = l7;
5600
Willy Tarreaub6866442008-07-14 23:54:42 +02005601 if (!txn)
5602 return 0;
5603
Willy Tarreauc11416f2007-06-17 16:58:38 +02005604 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5605 return 0;
5606
5607 return acl_fetch_hdr(px, l4, txn, txn->rsp.sol, expr, test);
5608}
5609
5610/* 6. Check on HTTP header count. The number of occurrences is returned.
5611 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
5612 */
5613static int
5614acl_fetch_hdr_cnt(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005615 struct acl_expr *expr, struct acl_test *test)
5616{
5617 struct http_txn *txn = l7;
5618 struct hdr_idx *idx = &txn->hdr_idx;
5619 struct hdr_ctx ctx;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005620 int cnt;
Willy Tarreau8797c062007-05-07 00:55:35 +02005621
Willy Tarreaub6866442008-07-14 23:54:42 +02005622 if (!txn)
5623 return 0;
5624
Willy Tarreau33a7e692007-06-10 19:45:56 +02005625 ctx.idx = 0;
5626 cnt = 0;
5627 while (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, &ctx))
5628 cnt++;
5629
5630 test->i = cnt;
5631 test->flags = ACL_TEST_F_VOL_HDR;
5632 return 1;
5633}
5634
Willy Tarreauc11416f2007-06-17 16:58:38 +02005635static int
5636acl_fetch_chdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5637 struct acl_expr *expr, struct acl_test *test)
5638{
5639 struct http_txn *txn = l7;
5640
Willy Tarreaub6866442008-07-14 23:54:42 +02005641 if (!txn)
5642 return 0;
5643
Willy Tarreauc11416f2007-06-17 16:58:38 +02005644 if (txn->req.msg_state != HTTP_MSG_BODY)
5645 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005646
Willy Tarreauc11416f2007-06-17 16:58:38 +02005647 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5648 /* ensure the indexes are not affected */
5649 return 0;
5650
5651 return acl_fetch_hdr_cnt(px, l4, txn, txn->req.sol, expr, test);
5652}
5653
5654static int
5655acl_fetch_shdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5656 struct acl_expr *expr, struct acl_test *test)
5657{
5658 struct http_txn *txn = l7;
5659
Willy Tarreaub6866442008-07-14 23:54:42 +02005660 if (!txn)
5661 return 0;
5662
Willy Tarreauc11416f2007-06-17 16:58:38 +02005663 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5664 return 0;
5665
5666 return acl_fetch_hdr_cnt(px, l4, txn, txn->rsp.sol, expr, test);
5667}
5668
Willy Tarreau33a7e692007-06-10 19:45:56 +02005669/* 7. Check on HTTP header's integer value. The integer value is returned.
5670 * FIXME: the type is 'int', it may not be appropriate for everything.
Willy Tarreauc11416f2007-06-17 16:58:38 +02005671 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
Willy Tarreau33a7e692007-06-10 19:45:56 +02005672 */
5673static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005674acl_fetch_hdr_val(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005675 struct acl_expr *expr, struct acl_test *test)
5676{
5677 struct http_txn *txn = l7;
5678 struct hdr_idx *idx = &txn->hdr_idx;
5679 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005680
Willy Tarreaub6866442008-07-14 23:54:42 +02005681 if (!txn)
5682 return 0;
5683
Willy Tarreau33a7e692007-06-10 19:45:56 +02005684 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5685 /* search for header from the beginning */
5686 ctx->idx = 0;
5687
Willy Tarreau33a7e692007-06-10 19:45:56 +02005688 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5689 test->flags |= ACL_TEST_F_FETCH_MORE;
5690 test->flags |= ACL_TEST_F_VOL_HDR;
5691 test->i = strl2ic((char *)ctx->line + ctx->val, ctx->vlen);
5692 return 1;
5693 }
5694
5695 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5696 test->flags |= ACL_TEST_F_VOL_HDR;
5697 return 0;
5698}
5699
Willy Tarreauc11416f2007-06-17 16:58:38 +02005700static int
5701acl_fetch_chdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5702 struct acl_expr *expr, struct acl_test *test)
5703{
5704 struct http_txn *txn = l7;
5705
Willy Tarreaub6866442008-07-14 23:54:42 +02005706 if (!txn)
5707 return 0;
5708
Willy Tarreauc11416f2007-06-17 16:58:38 +02005709 if (txn->req.msg_state != HTTP_MSG_BODY)
5710 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005711
Willy Tarreauc11416f2007-06-17 16:58:38 +02005712 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5713 /* ensure the indexes are not affected */
5714 return 0;
5715
5716 return acl_fetch_hdr_val(px, l4, txn, txn->req.sol, expr, test);
5717}
5718
5719static int
5720acl_fetch_shdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5721 struct acl_expr *expr, struct acl_test *test)
5722{
5723 struct http_txn *txn = l7;
5724
Willy Tarreaub6866442008-07-14 23:54:42 +02005725 if (!txn)
5726 return 0;
5727
Willy Tarreauc11416f2007-06-17 16:58:38 +02005728 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5729 return 0;
5730
5731 return acl_fetch_hdr_val(px, l4, txn, txn->rsp.sol, expr, test);
5732}
5733
Willy Tarreau737b0c12007-06-10 21:28:46 +02005734/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at
5735 * the first '/' after the possible hostname, and ends before the possible '?'.
5736 */
5737static int
5738acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
5739 struct acl_expr *expr, struct acl_test *test)
5740{
5741 struct http_txn *txn = l7;
5742 char *ptr, *end;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005743
Willy Tarreaub6866442008-07-14 23:54:42 +02005744 if (!txn)
5745 return 0;
5746
Willy Tarreauc11416f2007-06-17 16:58:38 +02005747 if (txn->req.msg_state != HTTP_MSG_BODY)
5748 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005749
Willy Tarreauc11416f2007-06-17 16:58:38 +02005750 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5751 /* ensure the indexes are not affected */
5752 return 0;
5753
Willy Tarreau21d2af32008-02-14 20:25:24 +01005754 end = txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
5755 ptr = http_get_path(txn);
5756 if (!ptr)
Willy Tarreau737b0c12007-06-10 21:28:46 +02005757 return 0;
5758
5759 /* OK, we got the '/' ! */
5760 test->ptr = ptr;
5761
5762 while (ptr < end && *ptr != '?')
5763 ptr++;
5764
5765 test->len = ptr - test->ptr;
5766
5767 /* we do not need to set READ_ONLY because the data is in a buffer */
5768 test->flags = ACL_TEST_F_VOL_1ST;
5769 return 1;
5770}
5771
5772
Willy Tarreau8797c062007-05-07 00:55:35 +02005773
5774/************************************************************************/
5775/* All supported keywords must be declared here. */
5776/************************************************************************/
5777
5778/* Note: must not be declared <const> as its list will be overwritten */
5779static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005780 { "method", acl_parse_meth, acl_fetch_meth, acl_match_meth, ACL_USE_L7REQ_PERMANENT },
5781 { "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5782 { "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str, ACL_USE_L7RTR_VOLATILE },
5783 { "status", acl_parse_int, acl_fetch_stcode, acl_match_int, ACL_USE_L7RTR_PERMANENT },
Willy Tarreau8797c062007-05-07 00:55:35 +02005784
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005785 { "url", acl_parse_str, acl_fetch_url, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5786 { "url_beg", acl_parse_str, acl_fetch_url, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5787 { "url_end", acl_parse_str, acl_fetch_url, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5788 { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5789 { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5790 { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
5791 { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5792 { "url_ip", acl_parse_ip, acl_fetch_url_ip, acl_match_ip, ACL_USE_L7REQ_VOLATILE },
5793 { "url_port", acl_parse_int, acl_fetch_url_port, acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau8797c062007-05-07 00:55:35 +02005794
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005795 /* note: we should set hdr* to use ACL_USE_HDR_VOLATILE, and chdr* to use L7REQ_VOLATILE */
5796 { "hdr", acl_parse_str, acl_fetch_chdr, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5797 { "hdr_reg", acl_parse_reg, acl_fetch_chdr, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5798 { "hdr_beg", acl_parse_str, acl_fetch_chdr, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5799 { "hdr_end", acl_parse_str, acl_fetch_chdr, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5800 { "hdr_sub", acl_parse_str, acl_fetch_chdr, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5801 { "hdr_dir", acl_parse_str, acl_fetch_chdr, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5802 { "hdr_dom", acl_parse_str, acl_fetch_chdr, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
5803 { "hdr_cnt", acl_parse_int, acl_fetch_chdr_cnt,acl_match_int, ACL_USE_L7REQ_VOLATILE },
5804 { "hdr_val", acl_parse_int, acl_fetch_chdr_val,acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreauc11416f2007-06-17 16:58:38 +02005805
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005806 { "shdr", acl_parse_str, acl_fetch_shdr, acl_match_str, ACL_USE_L7RTR_VOLATILE },
5807 { "shdr_reg", acl_parse_reg, acl_fetch_shdr, acl_match_reg, ACL_USE_L7RTR_VOLATILE },
5808 { "shdr_beg", acl_parse_str, acl_fetch_shdr, acl_match_beg, ACL_USE_L7RTR_VOLATILE },
5809 { "shdr_end", acl_parse_str, acl_fetch_shdr, acl_match_end, ACL_USE_L7RTR_VOLATILE },
5810 { "shdr_sub", acl_parse_str, acl_fetch_shdr, acl_match_sub, ACL_USE_L7RTR_VOLATILE },
5811 { "shdr_dir", acl_parse_str, acl_fetch_shdr, acl_match_dir, ACL_USE_L7RTR_VOLATILE },
5812 { "shdr_dom", acl_parse_str, acl_fetch_shdr, acl_match_dom, ACL_USE_L7RTR_VOLATILE },
5813 { "shdr_cnt", acl_parse_int, acl_fetch_shdr_cnt,acl_match_int, ACL_USE_L7RTR_VOLATILE },
5814 { "shdr_val", acl_parse_int, acl_fetch_shdr_val,acl_match_int, ACL_USE_L7RTR_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005815
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005816 { "path", acl_parse_str, acl_fetch_path, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5817 { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5818 { "path_beg", acl_parse_str, acl_fetch_path, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5819 { "path_end", acl_parse_str, acl_fetch_path, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5820 { "path_sub", acl_parse_str, acl_fetch_path, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5821 { "path_dir", acl_parse_str, acl_fetch_path, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5822 { "path_dom", acl_parse_str, acl_fetch_path, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005823
Willy Tarreauf3d25982007-05-08 22:45:09 +02005824 { NULL, NULL, NULL, NULL },
5825
5826#if 0
Willy Tarreau8797c062007-05-07 00:55:35 +02005827 { "line", acl_parse_str, acl_fetch_line, acl_match_str },
5828 { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg },
5829 { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg },
5830 { "line_end", acl_parse_str, acl_fetch_line, acl_match_end },
5831 { "line_sub", acl_parse_str, acl_fetch_line, acl_match_sub },
5832 { "line_dir", acl_parse_str, acl_fetch_line, acl_match_dir },
5833 { "line_dom", acl_parse_str, acl_fetch_line, acl_match_dom },
5834
Willy Tarreau8797c062007-05-07 00:55:35 +02005835 { "cook", acl_parse_str, acl_fetch_cook, acl_match_str },
5836 { "cook_reg", acl_parse_reg, acl_fetch_cook, acl_match_reg },
5837 { "cook_beg", acl_parse_str, acl_fetch_cook, acl_match_beg },
5838 { "cook_end", acl_parse_str, acl_fetch_cook, acl_match_end },
5839 { "cook_sub", acl_parse_str, acl_fetch_cook, acl_match_sub },
5840 { "cook_dir", acl_parse_str, acl_fetch_cook, acl_match_dir },
5841 { "cook_dom", acl_parse_str, acl_fetch_cook, acl_match_dom },
5842 { "cook_pst", acl_parse_none, acl_fetch_cook, acl_match_pst },
5843
5844 { "auth_user", acl_parse_str, acl_fetch_user, acl_match_str },
5845 { "auth_regex", acl_parse_reg, acl_fetch_user, acl_match_reg },
5846 { "auth_clear", acl_parse_str, acl_fetch_auth, acl_match_str },
5847 { "auth_md5", acl_parse_str, acl_fetch_auth, acl_match_md5 },
5848 { NULL, NULL, NULL, NULL },
5849#endif
5850}};
5851
5852
5853__attribute__((constructor))
5854static void __http_protocol_init(void)
5855{
5856 acl_register_keywords(&acl_kws);
5857}
5858
5859
Willy Tarreau58f10d72006-12-04 02:26:12 +01005860/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02005861 * Local variables:
5862 * c-indent-level: 8
5863 * c-basic-offset: 8
5864 * End:
5865 */