blob: 83406b61044e764ec5a0529a937863d086d17d52 [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 Tarreau67f0eea2008-08-10 22:55:22 +0200368static char *cli_stnames[4] = { "DAT", "SHR", "SHW", "CLS" };
369static char *srv_stnames[8] = { "IDL", "ANA", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
Willy Tarreaubaaee002006-06-26 02:48:02 +0200370#endif
371
Willy Tarreau42250582007-04-01 01:30:43 +0200372static void http_sess_log(struct session *s);
373
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100374/*
375 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
376 * CRLF. Text length is measured first, so it cannot be NULL.
377 * The header is also automatically added to the index <hdr_idx>, and the end
378 * of headers is automatically adjusted. The number of bytes added is returned
379 * on success, otherwise <0 is returned indicating an error.
380 */
381int http_header_add_tail(struct buffer *b, struct http_msg *msg,
382 struct hdr_idx *hdr_idx, const char *text)
383{
384 int bytes, len;
385
386 len = strlen(text);
387 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
388 if (!bytes)
389 return -1;
390 msg->eoh += bytes;
391 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
392}
393
394/*
395 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
396 * CRLF. <len> bytes are copied, not counting the CRLF. If <text> is NULL, then
397 * the buffer is only opened and the space reserved, but nothing is copied.
398 * The header is also automatically added to the index <hdr_idx>, and the end
399 * of headers is automatically adjusted. The number of bytes added is returned
400 * on success, otherwise <0 is returned indicating an error.
401 */
402int http_header_add_tail2(struct buffer *b, struct http_msg *msg,
403 struct hdr_idx *hdr_idx, const char *text, int len)
404{
405 int bytes;
406
407 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
408 if (!bytes)
409 return -1;
410 msg->eoh += bytes;
411 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
412}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200413
414/*
Willy Tarreauaa9dce32007-03-18 23:50:16 +0100415 * Checks if <hdr> is exactly <name> for <len> chars, and ends with a colon.
416 * If so, returns the position of the first non-space character relative to
417 * <hdr>, or <end>-<hdr> if not found before. If no value is found, it tries
418 * to return a pointer to the place after the first space. Returns 0 if the
419 * header name does not match. Checks are case-insensitive.
420 */
421int http_header_match2(const char *hdr, const char *end,
422 const char *name, int len)
423{
424 const char *val;
425
426 if (hdr + len >= end)
427 return 0;
428 if (hdr[len] != ':')
429 return 0;
430 if (strncasecmp(hdr, name, len) != 0)
431 return 0;
432 val = hdr + len + 1;
433 while (val < end && HTTP_IS_SPHT(*val))
434 val++;
435 if ((val >= end) && (len + 2 <= end - hdr))
436 return len + 2; /* we may replace starting from second space */
437 return val - hdr;
438}
439
Willy Tarreau33a7e692007-06-10 19:45:56 +0200440/* Find the end of the header value contained between <s> and <e>.
441 * See RFC2616, par 2.2 for more information. Note that it requires
442 * a valid header to return a valid result.
443 */
444const char *find_hdr_value_end(const char *s, const char *e)
445{
446 int quoted, qdpair;
447
448 quoted = qdpair = 0;
449 for (; s < e; s++) {
450 if (qdpair) qdpair = 0;
451 else if (quoted && *s == '\\') qdpair = 1;
452 else if (quoted && *s == '"') quoted = 0;
453 else if (*s == '"') quoted = 1;
454 else if (*s == ',') return s;
455 }
456 return s;
457}
458
459/* Find the first or next occurrence of header <name> in message buffer <sol>
460 * using headers index <idx>, and return it in the <ctx> structure. This
461 * structure holds everything necessary to use the header and find next
462 * occurrence. If its <idx> member is 0, the header is searched from the
463 * beginning. Otherwise, the next occurrence is returned. The function returns
464 * 1 when it finds a value, and 0 when there is no more.
465 */
466int http_find_header2(const char *name, int len,
467 const char *sol, struct hdr_idx *idx,
468 struct hdr_ctx *ctx)
469{
470 __label__ return_hdr, next_hdr;
471 const char *eol, *sov;
472 int cur_idx;
473
474 if (ctx->idx) {
475 /* We have previously returned a value, let's search
476 * another one on the same line.
477 */
478 cur_idx = ctx->idx;
479 sol = ctx->line;
480 sov = sol + ctx->val + ctx->vlen;
481 eol = sol + idx->v[cur_idx].len;
482
483 if (sov >= eol)
484 /* no more values in this header */
485 goto next_hdr;
486
487 /* values remaining for this header, skip the comma */
488 sov++;
489 while (sov < eol && http_is_lws[(unsigned char)*sov])
490 sov++;
491
492 goto return_hdr;
493 }
494
495 /* first request for this header */
496 sol += hdr_idx_first_pos(idx);
497 cur_idx = hdr_idx_first_idx(idx);
498
499 while (cur_idx) {
500 eol = sol + idx->v[cur_idx].len;
501
Willy Tarreau1ad7c6d2007-06-10 21:42:55 +0200502 if (len == 0) {
503 /* No argument was passed, we want any header.
504 * To achieve this, we simply build a fake request. */
505 while (sol + len < eol && sol[len] != ':')
506 len++;
507 name = sol;
508 }
509
Willy Tarreau33a7e692007-06-10 19:45:56 +0200510 if ((len < eol - sol) &&
511 (sol[len] == ':') &&
512 (strncasecmp(sol, name, len) == 0)) {
513
514 sov = sol + len + 1;
515 while (sov < eol && http_is_lws[(unsigned char)*sov])
516 sov++;
517 return_hdr:
518 ctx->line = sol;
519 ctx->idx = cur_idx;
520 ctx->val = sov - sol;
521
522 eol = find_hdr_value_end(sov, eol);
523 ctx->vlen = eol - sov;
524 return 1;
525 }
526 next_hdr:
527 sol = eol + idx->v[cur_idx].cr + 1;
528 cur_idx = idx->v[cur_idx].next;
529 }
530 return 0;
531}
532
533int http_find_header(const char *name,
534 const char *sol, struct hdr_idx *idx,
535 struct hdr_ctx *ctx)
536{
537 return http_find_header2(name, strlen(name), sol, idx, ctx);
538}
539
Willy Tarreaubaaee002006-06-26 02:48:02 +0200540/* This function turns the server state into the SV_STCLOSE, and sets
Willy Tarreau0f772532006-12-23 20:51:41 +0100541 * indicators accordingly. Note that if <status> is 0, or if the message
542 * pointer is NULL, then no message is returned.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200543 */
544void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreau0f772532006-12-23 20:51:41 +0100545 int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200546{
547 t->srv_state = SV_STCLOSE;
Willy Tarreau89edf5e2008-08-03 17:25:14 +0200548 buffer_shutw_done(t->req);
549 buffer_shutr_done(t->rep);
Willy Tarreau718f0ef2008-08-10 16:21:32 +0200550 t->rep->flags |= BF_MAY_FORWARD;
Willy Tarreau0f772532006-12-23 20:51:41 +0100551 if (status > 0 && msg) {
Willy Tarreau3bac9ff2007-03-18 17:31:28 +0100552 t->txn.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100553 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100554 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200555 }
556 if (!(t->flags & SN_ERR_MASK))
557 t->flags |= err;
558 if (!(t->flags & SN_FINST_MASK))
559 t->flags |= finst;
560}
561
Willy Tarreau80587432006-12-24 17:47:20 +0100562/* This function returns the appropriate error location for the given session
563 * and message.
564 */
565
566struct chunk *error_message(struct session *s, int msgnum)
567{
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200568 if (s->be->errmsg[msgnum].str)
569 return &s->be->errmsg[msgnum];
Willy Tarreau80587432006-12-24 17:47:20 +0100570 else if (s->fe->errmsg[msgnum].str)
571 return &s->fe->errmsg[msgnum];
572 else
573 return &http_err_chunks[msgnum];
574}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200575
Willy Tarreau53b6c742006-12-17 13:37:46 +0100576/*
577 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
578 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
579 */
580static http_meth_t find_http_meth(const char *str, const int len)
581{
582 unsigned char m;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100583 const struct http_method_desc *h;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100584
585 m = ((unsigned)*str - 'A');
586
587 if (m < 26) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100588 for (h = http_methods[m]; h->len > 0; h++) {
589 if (unlikely(h->len != len))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100590 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100591 if (likely(memcmp(str, h->text, h->len) == 0))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100592 return h->meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100593 };
594 return HTTP_METH_OTHER;
595 }
596 return HTTP_METH_NONE;
597
598}
599
Willy Tarreau21d2af32008-02-14 20:25:24 +0100600/* Parse the URI from the given transaction (which is assumed to be in request
601 * phase) and look for the "/" beginning the PATH. If not found, return NULL.
602 * It is returned otherwise.
603 */
604static char *
605http_get_path(struct http_txn *txn)
606{
607 char *ptr, *end;
608
609 ptr = txn->req.sol + txn->req.sl.rq.u;
610 end = ptr + txn->req.sl.rq.u_l;
611
612 if (ptr >= end)
613 return NULL;
614
615 /* RFC2616, par. 5.1.2 :
616 * Request-URI = "*" | absuri | abspath | authority
617 */
618
619 if (*ptr == '*')
620 return NULL;
621
622 if (isalpha((unsigned char)*ptr)) {
623 /* this is a scheme as described by RFC3986, par. 3.1 */
624 ptr++;
625 while (ptr < end &&
626 (isalnum((unsigned char)*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.'))
627 ptr++;
628 /* skip '://' */
629 if (ptr == end || *ptr++ != ':')
630 return NULL;
631 if (ptr == end || *ptr++ != '/')
632 return NULL;
633 if (ptr == end || *ptr++ != '/')
634 return NULL;
635 }
636 /* skip [user[:passwd]@]host[:[port]] */
637
638 while (ptr < end && *ptr != '/')
639 ptr++;
640
641 if (ptr == end)
642 return NULL;
643
644 /* OK, we got the '/' ! */
645 return ptr;
646}
647
Willy Tarreaubaaee002006-06-26 02:48:02 +0200648/* Processes the client and server jobs of a session task, then
649 * puts it back to the wait queue in a clean state, or
650 * cleans up its resources if it must be deleted. Returns
651 * the time the task accepts to wait, or TIME_ETERNITY for
652 * infinity.
653 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200654void process_session(struct task *t, int *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200655{
656 struct session *s = t->context;
657 int fsm_resync = 0;
658
659 do {
660 fsm_resync = 0;
661 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
662 fsm_resync |= process_cli(s);
663 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
664 fsm_resync |= process_srv(s);
665 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
666 } while (fsm_resync);
667
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200668 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100669
670 if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
671 session_process_counters(s);
672
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200673 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
674 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200675
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200676 t->expire = tick_first(tick_first(s->req->rex, s->req->wex),
677 tick_first(s->rep->rex, s->rep->wex));
678 t->expire = tick_first(t->expire, s->req->cex);
Willy Tarreau67f0eea2008-08-10 22:55:22 +0200679 if (s->analysis & AN_REQ_ANY) {
680 if (s->analysis & AN_REQ_INSPECT)
681 t->expire = tick_first(t->expire, s->inspect_exp);
682 else if (s->analysis & AN_REQ_HTTP_HDR)
683 t->expire = tick_first(t->expire, s->txn.exp);
684 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200685
686 /* restore t to its place in the task list */
687 task_queue(t);
688
Willy Tarreaud825eef2007-05-12 22:35:00 +0200689 *next = t->expire;
690 return; /* nothing more to do */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200691 }
692
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100693 s->fe->feconn--;
694 if (s->flags & SN_BE_ASSIGNED)
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200695 s->be->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200696 actconn--;
697
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200698 if (unlikely((global.mode & MODE_DEBUG) &&
699 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200700 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100701 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200702 s->uniq_id, s->be->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100703 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200704 write(1, trash, len);
705 }
706
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200707 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100708 session_process_counters(s);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200709
710 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200711 if (s->logs.logwait &&
712 !(s->flags & SN_MONITOR) &&
Willy Tarreau42250582007-04-01 01:30:43 +0200713 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total)) {
714 if (s->fe->to_log & LW_REQ)
715 http_sess_log(s);
716 else
717 tcp_sess_log(s);
718 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200719
720 /* the task MUST not be in the run queue anymore */
721 task_delete(t);
722 session_free(s);
723 task_free(t);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200724 *next = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200725}
726
727
Willy Tarreau42250582007-04-01 01:30:43 +0200728extern const char sess_term_cond[8];
729extern const char sess_fin_state[8];
730extern const char *monthname[12];
731const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
732const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
733 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
734 unknown, Set-cookie Rewritten */
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200735struct pool_head *pool2_requri;
Willy Tarreau086b3b42007-05-13 21:45:51 +0200736struct pool_head *pool2_capture;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100737
Willy Tarreau42250582007-04-01 01:30:43 +0200738/*
739 * send a log for the session when we have enough info about it.
740 * Will not log if the frontend has no log defined.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100741 */
Willy Tarreau42250582007-04-01 01:30:43 +0200742static void http_sess_log(struct session *s)
743{
744 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
745 struct proxy *fe = s->fe;
746 struct proxy *be = s->be;
747 struct proxy *prx_log;
748 struct http_txn *txn = &s->txn;
749 int tolog;
750 char *uri, *h;
751 char *svid;
Willy Tarreaufe944602007-10-25 10:34:16 +0200752 struct tm tm;
Willy Tarreau42250582007-04-01 01:30:43 +0200753 static char tmpline[MAX_SYSLOG_LEN];
Willy Tarreau70089872008-06-13 21:12:51 +0200754 int t_request;
Willy Tarreau42250582007-04-01 01:30:43 +0200755 int hdr;
756
757 if (fe->logfac1 < 0 && fe->logfac2 < 0)
758 return;
759 prx_log = fe;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100760
Willy Tarreau42250582007-04-01 01:30:43 +0200761 if (s->cli_addr.ss_family == AF_INET)
762 inet_ntop(AF_INET,
763 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
764 pn, sizeof(pn));
765 else
766 inet_ntop(AF_INET6,
767 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
768 pn, sizeof(pn));
769
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200770 get_localtime(s->logs.accept_date.tv_sec, &tm);
Willy Tarreau42250582007-04-01 01:30:43 +0200771
772 /* FIXME: let's limit ourselves to frontend logging for now. */
773 tolog = fe->to_log;
774
775 h = tmpline;
776 if (fe->to_log & LW_REQHDR &&
777 txn->req.cap &&
778 (h < tmpline + sizeof(tmpline) - 10)) {
779 *(h++) = ' ';
780 *(h++) = '{';
781 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
782 if (hdr)
783 *(h++) = '|';
784 if (txn->req.cap[hdr] != NULL)
785 h = encode_string(h, tmpline + sizeof(tmpline) - 7,
786 '#', hdr_encode_map, txn->req.cap[hdr]);
787 }
788 *(h++) = '}';
789 }
790
791 if (fe->to_log & LW_RSPHDR &&
792 txn->rsp.cap &&
793 (h < tmpline + sizeof(tmpline) - 7)) {
794 *(h++) = ' ';
795 *(h++) = '{';
796 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
797 if (hdr)
798 *(h++) = '|';
799 if (txn->rsp.cap[hdr] != NULL)
800 h = encode_string(h, tmpline + sizeof(tmpline) - 4,
801 '#', hdr_encode_map, txn->rsp.cap[hdr]);
802 }
803 *(h++) = '}';
804 }
805
806 if (h < tmpline + sizeof(tmpline) - 4) {
807 *(h++) = ' ';
808 *(h++) = '"';
809 uri = txn->uri ? txn->uri : "<BADREQ>";
810 h = encode_string(h, tmpline + sizeof(tmpline) - 1,
811 '#', url_encode_map, uri);
812 *(h++) = '"';
813 }
814 *h = '\0';
815
816 svid = (tolog & LW_SVID) ?
817 (s->data_source != DATA_SRC_STATS) ?
818 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
819
Willy Tarreau70089872008-06-13 21:12:51 +0200820 t_request = -1;
821 if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
822 t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
823
Willy Tarreau42250582007-04-01 01:30:43 +0200824 send_log(prx_log, LOG_INFO,
825 "%s:%d [%02d/%s/%04d:%02d:%02d:%02d.%03d]"
826 " %s %s/%s %d/%d/%d/%d/%s%d %d %s%lld"
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100827 " %s %s %c%c%c%c %d/%d/%d/%d/%s%u %d/%d%s\n",
Willy Tarreau42250582007-04-01 01:30:43 +0200828 pn,
829 (s->cli_addr.ss_family == AF_INET) ?
830 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
831 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
Willy Tarreaufe944602007-10-25 10:34:16 +0200832 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200833 tm.tm_hour, tm.tm_min, tm.tm_sec, s->logs.accept_date.tv_usec/1000,
Willy Tarreau42250582007-04-01 01:30:43 +0200834 fe->id, be->id, svid,
Willy Tarreau70089872008-06-13 21:12:51 +0200835 t_request,
836 (s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1,
Willy Tarreau42250582007-04-01 01:30:43 +0200837 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
838 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
839 (tolog & LW_BYTES) ? "" : "+", s->logs.t_close,
840 txn->status,
Willy Tarreau8b3977f2008-01-18 11:16:32 +0100841 (tolog & LW_BYTES) ? "" : "+", s->logs.bytes_out,
Willy Tarreau42250582007-04-01 01:30:43 +0200842 txn->cli_cookie ? txn->cli_cookie : "-",
843 txn->srv_cookie ? txn->srv_cookie : "-",
844 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
845 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
846 (be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-',
847 (be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-',
848 actconn, fe->feconn, be->beconn, s->srv ? s->srv->cur_sess : 0,
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100849 (s->flags & SN_REDISP)?"+":"",
850 (s->conn_retries>0)?(be->conn_retries - s->conn_retries):be->conn_retries,
Willy Tarreau42250582007-04-01 01:30:43 +0200851 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
852
853 s->logs.logwait = 0;
854}
855
Willy Tarreau117f59e2007-03-04 18:17:17 +0100856
857/*
858 * Capture headers from message starting at <som> according to header list
859 * <cap_hdr>, and fill the <idx> structure appropriately.
860 */
861void capture_headers(char *som, struct hdr_idx *idx,
862 char **cap, struct cap_hdr *cap_hdr)
863{
864 char *eol, *sol, *col, *sov;
865 int cur_idx;
866 struct cap_hdr *h;
867 int len;
868
869 sol = som + hdr_idx_first_pos(idx);
870 cur_idx = hdr_idx_first_idx(idx);
871
872 while (cur_idx) {
873 eol = sol + idx->v[cur_idx].len;
874
875 col = sol;
876 while (col < eol && *col != ':')
877 col++;
878
879 sov = col + 1;
880 while (sov < eol && http_is_lws[(unsigned char)*sov])
881 sov++;
882
883 for (h = cap_hdr; h; h = h->next) {
884 if ((h->namelen == col - sol) &&
885 (strncasecmp(sol, h->name, h->namelen) == 0)) {
886 if (cap[h->index] == NULL)
887 cap[h->index] =
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200888 pool_alloc2(h->pool);
Willy Tarreau117f59e2007-03-04 18:17:17 +0100889
890 if (cap[h->index] == NULL) {
891 Alert("HTTP capture : out of memory.\n");
892 continue;
893 }
894
895 len = eol - sov;
896 if (len > h->len)
897 len = h->len;
898
899 memcpy(cap[h->index], sov, len);
900 cap[h->index][len]=0;
901 }
902 }
903 sol = eol + idx->v[cur_idx].cr + 1;
904 cur_idx = idx->v[cur_idx].next;
905 }
906}
907
908
Willy Tarreau42250582007-04-01 01:30:43 +0200909/* either we find an LF at <ptr> or we jump to <bad>.
910 */
911#define EXPECT_LF_HERE(ptr, bad) do { if (unlikely(*(ptr) != '\n')) goto bad; } while (0)
912
913/* plays with variables <ptr>, <end> and <state>. Jumps to <good> if OK,
914 * otherwise to <http_msg_ood> with <state> set to <st>.
915 */
916#define EAT_AND_JUMP_OR_RETURN(good, st) do { \
917 ptr++; \
918 if (likely(ptr < end)) \
919 goto good; \
920 else { \
921 state = (st); \
922 goto http_msg_ood; \
923 } \
924 } while (0)
925
926
Willy Tarreaubaaee002006-06-26 02:48:02 +0200927/*
Willy Tarreaua15645d2007-03-18 16:22:39 +0100928 * This function parses a status line between <ptr> and <end>, starting with
Willy Tarreau8973c702007-01-21 23:58:29 +0100929 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
930 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
931 * will give undefined results.
932 * Note that it is upon the caller's responsibility to ensure that ptr < end,
933 * and that msg->sol points to the beginning of the response.
934 * If a complete line is found (which implies that at least one CR or LF is
935 * found before <end>, the updated <ptr> is returned, otherwise NULL is
936 * returned indicating an incomplete line (which does not mean that parts have
937 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
938 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
939 * upon next call.
940 *
Willy Tarreau9cdde232007-05-02 20:58:19 +0200941 * This function was intentionally designed to be called from
Willy Tarreau8973c702007-01-21 23:58:29 +0100942 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
943 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +0200944 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreau8973c702007-01-21 23:58:29 +0100945 */
Willy Tarreaue69eada2008-01-27 00:34:10 +0100946const char *http_parse_stsline(struct http_msg *msg, const char *msg_buf,
947 unsigned int state, const char *ptr, const char *end,
948 char **ret_ptr, unsigned int *ret_state)
Willy Tarreau8973c702007-01-21 23:58:29 +0100949{
950 __label__
951 http_msg_rpver,
952 http_msg_rpver_sp,
953 http_msg_rpcode,
954 http_msg_rpcode_sp,
955 http_msg_rpreason,
956 http_msg_rpline_eol,
957 http_msg_ood, /* out of data */
958 http_msg_invalid;
959
960 switch (state) {
961 http_msg_rpver:
962 case HTTP_MSG_RPVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100963 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8973c702007-01-21 23:58:29 +0100964 EAT_AND_JUMP_OR_RETURN(http_msg_rpver, HTTP_MSG_RPVER);
965
966 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +0100967 msg->sl.st.v_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +0100968 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
969 }
970 goto http_msg_invalid;
971
972 http_msg_rpver_sp:
973 case HTTP_MSG_RPVER_SP:
974 if (likely(!HTTP_IS_LWS(*ptr))) {
975 msg->sl.st.c = ptr - msg_buf;
976 goto http_msg_rpcode;
977 }
978 if (likely(HTTP_IS_SPHT(*ptr)))
979 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
980 /* so it's a CR/LF, this is invalid */
981 goto http_msg_invalid;
982
983 http_msg_rpcode:
984 case HTTP_MSG_RPCODE:
985 if (likely(!HTTP_IS_LWS(*ptr)))
986 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode, HTTP_MSG_RPCODE);
987
988 if (likely(HTTP_IS_SPHT(*ptr))) {
989 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
990 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
991 }
992
993 /* so it's a CR/LF, so there is no reason phrase */
994 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
995 http_msg_rsp_reason:
996 /* FIXME: should we support HTTP responses without any reason phrase ? */
997 msg->sl.st.r = ptr - msg_buf;
998 msg->sl.st.r_l = 0;
999 goto http_msg_rpline_eol;
1000
1001 http_msg_rpcode_sp:
1002 case HTTP_MSG_RPCODE_SP:
1003 if (likely(!HTTP_IS_LWS(*ptr))) {
1004 msg->sl.st.r = ptr - msg_buf;
1005 goto http_msg_rpreason;
1006 }
1007 if (likely(HTTP_IS_SPHT(*ptr)))
1008 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1009 /* so it's a CR/LF, so there is no reason phrase */
1010 goto http_msg_rsp_reason;
1011
1012 http_msg_rpreason:
1013 case HTTP_MSG_RPREASON:
1014 if (likely(!HTTP_IS_CRLF(*ptr)))
1015 EAT_AND_JUMP_OR_RETURN(http_msg_rpreason, HTTP_MSG_RPREASON);
1016 msg->sl.st.r_l = (ptr - msg_buf) - msg->sl.st.r;
1017 http_msg_rpline_eol:
1018 /* We have seen the end of line. Note that we do not
1019 * necessarily have the \n yet, but at least we know that we
1020 * have EITHER \r OR \n, otherwise the response would not be
1021 * complete. We can then record the response length and return
1022 * to the caller which will be able to register it.
1023 */
1024 msg->sl.st.l = ptr - msg->sol;
1025 return ptr;
1026
1027#ifdef DEBUG_FULL
1028 default:
1029 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1030 exit(1);
1031#endif
1032 }
1033
1034 http_msg_ood:
1035 /* out of data */
1036 if (ret_state)
1037 *ret_state = state;
1038 if (ret_ptr)
1039 *ret_ptr = (char *)ptr;
1040 return NULL;
1041
1042 http_msg_invalid:
1043 /* invalid message */
1044 if (ret_state)
1045 *ret_state = HTTP_MSG_ERROR;
1046 return NULL;
1047}
1048
1049
1050/*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001051 * This function parses a request line between <ptr> and <end>, starting with
1052 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
1053 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
1054 * will give undefined results.
1055 * Note that it is upon the caller's responsibility to ensure that ptr < end,
1056 * and that msg->sol points to the beginning of the request.
1057 * If a complete line is found (which implies that at least one CR or LF is
1058 * found before <end>, the updated <ptr> is returned, otherwise NULL is
1059 * returned indicating an incomplete line (which does not mean that parts have
1060 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
1061 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
1062 * upon next call.
1063 *
Willy Tarreau9cdde232007-05-02 20:58:19 +02001064 * This function was intentionally designed to be called from
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001065 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
1066 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +02001067 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001068 */
Willy Tarreaue69eada2008-01-27 00:34:10 +01001069const char *http_parse_reqline(struct http_msg *msg, const char *msg_buf,
1070 unsigned int state, const char *ptr, const char *end,
1071 char **ret_ptr, unsigned int *ret_state)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001072{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001073 __label__
1074 http_msg_rqmeth,
1075 http_msg_rqmeth_sp,
1076 http_msg_rquri,
1077 http_msg_rquri_sp,
1078 http_msg_rqver,
1079 http_msg_rqline_eol,
1080 http_msg_ood, /* out of data */
1081 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001082
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001083 switch (state) {
1084 http_msg_rqmeth:
1085 case HTTP_MSG_RQMETH:
1086 if (likely(HTTP_IS_TOKEN(*ptr)))
1087 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth, HTTP_MSG_RQMETH);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001088
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001089 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001090 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001091 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1092 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001093
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001094 if (likely(HTTP_IS_CRLF(*ptr))) {
1095 /* HTTP 0.9 request */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001096 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001097 http_msg_req09_uri:
1098 msg->sl.rq.u = ptr - msg_buf;
1099 http_msg_req09_uri_e:
1100 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1101 http_msg_req09_ver:
1102 msg->sl.rq.v = ptr - msg_buf;
1103 msg->sl.rq.v_l = 0;
1104 goto http_msg_rqline_eol;
1105 }
1106 goto http_msg_invalid;
1107
1108 http_msg_rqmeth_sp:
1109 case HTTP_MSG_RQMETH_SP:
1110 if (likely(!HTTP_IS_LWS(*ptr))) {
1111 msg->sl.rq.u = ptr - msg_buf;
1112 goto http_msg_rquri;
1113 }
1114 if (likely(HTTP_IS_SPHT(*ptr)))
1115 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1116 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1117 goto http_msg_req09_uri;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001118
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001119 http_msg_rquri:
1120 case HTTP_MSG_RQURI:
1121 if (likely(!HTTP_IS_LWS(*ptr)))
1122 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001123
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001124 if (likely(HTTP_IS_SPHT(*ptr))) {
1125 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1126 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1127 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001128
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001129 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1130 goto http_msg_req09_uri_e;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001131
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001132 http_msg_rquri_sp:
1133 case HTTP_MSG_RQURI_SP:
1134 if (likely(!HTTP_IS_LWS(*ptr))) {
1135 msg->sl.rq.v = ptr - msg_buf;
1136 goto http_msg_rqver;
1137 }
1138 if (likely(HTTP_IS_SPHT(*ptr)))
1139 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1140 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1141 goto http_msg_req09_ver;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001142
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001143 http_msg_rqver:
1144 case HTTP_MSG_RQVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001145 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001146 EAT_AND_JUMP_OR_RETURN(http_msg_rqver, HTTP_MSG_RQVER);
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001147
1148 if (likely(HTTP_IS_CRLF(*ptr))) {
1149 msg->sl.rq.v_l = (ptr - msg_buf) - msg->sl.rq.v;
1150 http_msg_rqline_eol:
1151 /* We have seen the end of line. Note that we do not
1152 * necessarily have the \n yet, but at least we know that we
1153 * have EITHER \r OR \n, otherwise the request would not be
1154 * complete. We can then record the request length and return
1155 * to the caller which will be able to register it.
1156 */
1157 msg->sl.rq.l = ptr - msg->sol;
1158 return ptr;
1159 }
1160
1161 /* neither an HTTP_VER token nor a CRLF */
1162 goto http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001163
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001164#ifdef DEBUG_FULL
1165 default:
1166 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1167 exit(1);
1168#endif
1169 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001170
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001171 http_msg_ood:
1172 /* out of data */
1173 if (ret_state)
1174 *ret_state = state;
1175 if (ret_ptr)
1176 *ret_ptr = (char *)ptr;
1177 return NULL;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001178
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001179 http_msg_invalid:
1180 /* invalid message */
1181 if (ret_state)
1182 *ret_state = HTTP_MSG_ERROR;
1183 return NULL;
1184}
Willy Tarreau58f10d72006-12-04 02:26:12 +01001185
1186
Willy Tarreau8973c702007-01-21 23:58:29 +01001187/*
1188 * This function parses an HTTP message, either a request or a response,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001189 * depending on the initial msg->msg_state. It can be preempted everywhere
Willy Tarreau8973c702007-01-21 23:58:29 +01001190 * when data are missing and recalled at the exact same location with no
1191 * information loss. The header index is re-initialized when switching from
Willy Tarreau9cdde232007-05-02 20:58:19 +02001192 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH. It modifies msg->sol among other
1193 * fields.
Willy Tarreau8973c702007-01-21 23:58:29 +01001194 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001195void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx *idx)
1196{
1197 __label__
1198 http_msg_rqbefore,
1199 http_msg_rqbefore_cr,
1200 http_msg_rqmeth,
1201 http_msg_rqline_end,
1202 http_msg_hdr_first,
1203 http_msg_hdr_name,
1204 http_msg_hdr_l1_sp,
1205 http_msg_hdr_l1_lf,
1206 http_msg_hdr_l1_lws,
1207 http_msg_hdr_val,
1208 http_msg_hdr_l2_lf,
1209 http_msg_hdr_l2_lws,
1210 http_msg_complete_header,
1211 http_msg_last_lf,
1212 http_msg_ood, /* out of data */
1213 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001214
Willy Tarreaue69eada2008-01-27 00:34:10 +01001215 unsigned int state; /* updated only when leaving the FSM */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001216 register char *ptr, *end; /* request pointers, to avoid dereferences */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001217
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001218 state = msg->msg_state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001219 ptr = buf->lr;
1220 end = buf->r;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001221
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001222 if (unlikely(ptr >= end))
1223 goto http_msg_ood;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001224
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001225 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +01001226 /*
1227 * First, states that are specific to the response only.
1228 * We check them first so that request and headers are
1229 * closer to each other (accessed more often).
1230 */
1231 http_msg_rpbefore:
1232 case HTTP_MSG_RPBEFORE:
1233 if (likely(HTTP_IS_TOKEN(*ptr))) {
1234 if (likely(ptr == buf->data)) {
1235 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001236 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001237 } else {
1238#if PARSE_PRESERVE_EMPTY_LINES
1239 /* only skip empty leading lines, don't remove them */
1240 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001241 msg->som = ptr - buf->data;
Willy Tarreau8973c702007-01-21 23:58:29 +01001242#else
1243 /* Remove empty leading lines, as recommended by
1244 * RFC2616. This takes a lot of time because we
1245 * must move all the buffer backwards, but this
1246 * is rarely needed. The method above will be
1247 * cleaner when we'll be able to start sending
1248 * the request from any place in the buffer.
1249 */
1250 buf->lr = ptr;
1251 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001252 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001253 msg->sol = buf->data;
1254 ptr = buf->data;
1255 end = buf->r;
1256#endif
1257 }
1258 hdr_idx_init(idx);
1259 state = HTTP_MSG_RPVER;
1260 goto http_msg_rpver;
1261 }
1262
1263 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1264 goto http_msg_invalid;
1265
1266 if (unlikely(*ptr == '\n'))
1267 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1268 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore_cr, HTTP_MSG_RPBEFORE_CR);
1269 /* stop here */
1270
1271 http_msg_rpbefore_cr:
1272 case HTTP_MSG_RPBEFORE_CR:
1273 EXPECT_LF_HERE(ptr, http_msg_invalid);
1274 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1275 /* stop here */
1276
1277 http_msg_rpver:
1278 case HTTP_MSG_RPVER:
1279 case HTTP_MSG_RPVER_SP:
1280 case HTTP_MSG_RPCODE:
1281 case HTTP_MSG_RPCODE_SP:
1282 case HTTP_MSG_RPREASON:
Willy Tarreaua15645d2007-03-18 16:22:39 +01001283 ptr = (char *)http_parse_stsline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001284 &buf->lr, &msg->msg_state);
Willy Tarreau8973c702007-01-21 23:58:29 +01001285 if (unlikely(!ptr))
1286 return;
1287
1288 /* we have a full response and we know that we have either a CR
1289 * or an LF at <ptr>.
1290 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001291 //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 +01001292 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
1293
1294 msg->sol = ptr;
1295 if (likely(*ptr == '\r'))
1296 EAT_AND_JUMP_OR_RETURN(http_msg_rpline_end, HTTP_MSG_RPLINE_END);
1297 goto http_msg_rpline_end;
1298
1299 http_msg_rpline_end:
1300 case HTTP_MSG_RPLINE_END:
1301 /* msg->sol must point to the first of CR or LF. */
1302 EXPECT_LF_HERE(ptr, http_msg_invalid);
1303 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
1304 /* stop here */
1305
1306 /*
1307 * Second, states that are specific to the request only
1308 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001309 http_msg_rqbefore:
1310 case HTTP_MSG_RQBEFORE:
1311 if (likely(HTTP_IS_TOKEN(*ptr))) {
1312 if (likely(ptr == buf->data)) {
1313 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001314 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001315 } else {
1316#if PARSE_PRESERVE_EMPTY_LINES
1317 /* only skip empty leading lines, don't remove them */
1318 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001319 msg->som = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001320#else
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001321 /* Remove empty leading lines, as recommended by
1322 * RFC2616. This takes a lot of time because we
1323 * must move all the buffer backwards, but this
1324 * is rarely needed. The method above will be
1325 * cleaner when we'll be able to start sending
1326 * the request from any place in the buffer.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001327 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001328 buf->lr = ptr;
1329 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001330 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001331 msg->sol = buf->data;
1332 ptr = buf->data;
1333 end = buf->r;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001334#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001335 }
Willy Tarreauf0d058e2007-01-25 12:03:42 +01001336 /* we will need this when keep-alive will be supported
1337 hdr_idx_init(idx);
1338 */
Willy Tarreau8973c702007-01-21 23:58:29 +01001339 state = HTTP_MSG_RQMETH;
1340 goto http_msg_rqmeth;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001341 }
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001342
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001343 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1344 goto http_msg_invalid;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001345
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001346 if (unlikely(*ptr == '\n'))
1347 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
1348 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore_cr, HTTP_MSG_RQBEFORE_CR);
Willy Tarreau8973c702007-01-21 23:58:29 +01001349 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001350
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001351 http_msg_rqbefore_cr:
1352 case HTTP_MSG_RQBEFORE_CR:
1353 EXPECT_LF_HERE(ptr, http_msg_invalid);
1354 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
Willy Tarreau8973c702007-01-21 23:58:29 +01001355 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001356
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001357 http_msg_rqmeth:
1358 case HTTP_MSG_RQMETH:
1359 case HTTP_MSG_RQMETH_SP:
1360 case HTTP_MSG_RQURI:
1361 case HTTP_MSG_RQURI_SP:
1362 case HTTP_MSG_RQVER:
1363 ptr = (char *)http_parse_reqline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001364 &buf->lr, &msg->msg_state);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001365 if (unlikely(!ptr))
1366 return;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001367
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001368 /* we have a full request and we know that we have either a CR
1369 * or an LF at <ptr>.
1370 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001371 //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 +01001372 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001373
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001374 msg->sol = ptr;
1375 if (likely(*ptr == '\r'))
1376 EAT_AND_JUMP_OR_RETURN(http_msg_rqline_end, HTTP_MSG_RQLINE_END);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001377 goto http_msg_rqline_end;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001378
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001379 http_msg_rqline_end:
1380 case HTTP_MSG_RQLINE_END:
1381 /* check for HTTP/0.9 request : no version information available.
1382 * msg->sol must point to the first of CR or LF.
1383 */
1384 if (unlikely(msg->sl.rq.v_l == 0))
1385 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001386
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001387 EXPECT_LF_HERE(ptr, http_msg_invalid);
1388 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
Willy Tarreau8973c702007-01-21 23:58:29 +01001389 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001390
Willy Tarreau8973c702007-01-21 23:58:29 +01001391 /*
1392 * Common states below
1393 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001394 http_msg_hdr_first:
1395 case HTTP_MSG_HDR_FIRST:
1396 msg->sol = ptr;
1397 if (likely(!HTTP_IS_CRLF(*ptr))) {
1398 goto http_msg_hdr_name;
1399 }
1400
1401 if (likely(*ptr == '\r'))
1402 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1403 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001404
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001405 http_msg_hdr_name:
1406 case HTTP_MSG_HDR_NAME:
1407 /* assumes msg->sol points to the first char */
1408 if (likely(HTTP_IS_TOKEN(*ptr)))
1409 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001410
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001411 if (likely(*ptr == ':')) {
1412 msg->col = ptr - buf->data;
1413 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
1414 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001415
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001416 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001417
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001418 http_msg_hdr_l1_sp:
1419 case HTTP_MSG_HDR_L1_SP:
1420 /* assumes msg->sol points to the first char and msg->col to the colon */
1421 if (likely(HTTP_IS_SPHT(*ptr)))
1422 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001423
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001424 /* header value can be basically anything except CR/LF */
1425 msg->sov = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001426
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001427 if (likely(!HTTP_IS_CRLF(*ptr))) {
1428 goto http_msg_hdr_val;
1429 }
1430
1431 if (likely(*ptr == '\r'))
1432 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lf, HTTP_MSG_HDR_L1_LF);
1433 goto http_msg_hdr_l1_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001434
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001435 http_msg_hdr_l1_lf:
1436 case HTTP_MSG_HDR_L1_LF:
1437 EXPECT_LF_HERE(ptr, http_msg_invalid);
1438 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lws, HTTP_MSG_HDR_L1_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001439
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001440 http_msg_hdr_l1_lws:
1441 case HTTP_MSG_HDR_L1_LWS:
1442 if (likely(HTTP_IS_SPHT(*ptr))) {
1443 /* replace HT,CR,LF with spaces */
1444 for (; buf->data+msg->sov < ptr; msg->sov++)
1445 buf->data[msg->sov] = ' ';
1446 goto http_msg_hdr_l1_sp;
1447 }
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001448 /* we had a header consisting only in spaces ! */
1449 msg->eol = buf->data + msg->sov;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001450 goto http_msg_complete_header;
1451
1452 http_msg_hdr_val:
1453 case HTTP_MSG_HDR_VAL:
1454 /* assumes msg->sol points to the first char, msg->col to the
1455 * colon, and msg->sov points to the first character of the
1456 * value.
1457 */
1458 if (likely(!HTTP_IS_CRLF(*ptr)))
1459 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001460
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001461 msg->eol = ptr;
1462 /* Note: we could also copy eol into ->eoh so that we have the
1463 * real header end in case it ends with lots of LWS, but is this
1464 * really needed ?
1465 */
1466 if (likely(*ptr == '\r'))
1467 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1468 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001469
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001470 http_msg_hdr_l2_lf:
1471 case HTTP_MSG_HDR_L2_LF:
1472 EXPECT_LF_HERE(ptr, http_msg_invalid);
1473 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001474
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001475 http_msg_hdr_l2_lws:
1476 case HTTP_MSG_HDR_L2_LWS:
1477 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1478 /* LWS: replace HT,CR,LF with spaces */
1479 for (; msg->eol < ptr; msg->eol++)
1480 *msg->eol = ' ';
1481 goto http_msg_hdr_val;
1482 }
1483 http_msg_complete_header:
1484 /*
1485 * It was a new header, so the last one is finished.
1486 * Assumes msg->sol points to the first char, msg->col to the
1487 * colon, msg->sov points to the first character of the value
1488 * and msg->eol to the first CR or LF so we know how the line
1489 * ends. We insert last header into the index.
1490 */
1491 /*
1492 fprintf(stderr,"registering %-2d bytes : ", msg->eol - msg->sol);
1493 write(2, msg->sol, msg->eol-msg->sol);
1494 fprintf(stderr,"\n");
1495 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001496
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001497 if (unlikely(hdr_idx_add(msg->eol - msg->sol, *msg->eol == '\r',
1498 idx, idx->tail) < 0))
1499 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001500
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001501 msg->sol = ptr;
1502 if (likely(!HTTP_IS_CRLF(*ptr))) {
1503 goto http_msg_hdr_name;
1504 }
1505
1506 if (likely(*ptr == '\r'))
1507 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1508 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001509
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001510 http_msg_last_lf:
1511 case HTTP_MSG_LAST_LF:
1512 /* Assumes msg->sol points to the first of either CR or LF */
1513 EXPECT_LF_HERE(ptr, http_msg_invalid);
1514 ptr++;
1515 buf->lr = ptr;
1516 msg->eoh = msg->sol - buf->data;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001517 msg->msg_state = HTTP_MSG_BODY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001518 return;
1519#ifdef DEBUG_FULL
1520 default:
1521 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1522 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001523#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001524 }
1525 http_msg_ood:
1526 /* out of data */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001527 msg->msg_state = state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001528 buf->lr = ptr;
1529 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001530
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001531 http_msg_invalid:
1532 /* invalid message */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001533 msg->msg_state = HTTP_MSG_ERROR;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001534 return;
1535}
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001536
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001537/*
1538 * manages the client FSM and its socket. BTW, it also tries to handle the
1539 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1540 * 0 else.
1541 */
1542int process_cli(struct session *t)
1543{
1544 int s = t->srv_state;
1545 int c = t->cli_state;
1546 struct buffer *req = t->req;
1547 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001548
Willy Tarreau6468d922008-08-03 19:15:35 +02001549 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 +01001550 cli_stnames[c], srv_stnames[s],
Willy Tarreauf161a342007-04-08 16:59:42 +02001551 EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
Willy Tarreau6468d922008-08-03 19:15:35 +02001552 req->rex, rep->wex);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001553
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001554 if (t->analysis & AN_REQ_INSPECT) {
Willy Tarreaub6866442008-07-14 23:54:42 +02001555 struct tcp_rule *rule;
1556 int partial;
1557
1558 /* We will abort if we encounter a read error. In theory,
1559 * we should not abort if we get a close, it might be
1560 * valid, also very unlikely. FIXME: we'll abort for now,
1561 * this will be easier to change later.
1562 */
1563 if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1564 t->inspect_exp = TICK_ETERNITY;
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001565 buffer_shutr_done(req);
1566 buffer_shutw_done(rep);
Willy Tarreaub6866442008-07-14 23:54:42 +02001567 fd_delete(t->cli_fd);
1568 t->cli_state = CL_STCLOSE;
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001569 t->analysis &= ~AN_REQ_ANY;
Willy Tarreaub6866442008-07-14 23:54:42 +02001570 t->fe->failed_req++;
1571 if (!(t->flags & SN_ERR_MASK))
1572 t->flags |= SN_ERR_CLICL;
1573 if (!(t->flags & SN_FINST_MASK))
1574 t->flags |= SN_FINST_R;
1575 return 1;
1576 }
1577
1578 /* Abort if client read timeout has expired */
1579 else if (unlikely(tick_is_expired(req->rex, now_ms))) {
1580 t->inspect_exp = TICK_ETERNITY;
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001581 buffer_shutr_done(req);
1582 buffer_shutw_done(rep);
Willy Tarreaub6866442008-07-14 23:54:42 +02001583 fd_delete(t->cli_fd);
1584 t->cli_state = CL_STCLOSE;
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001585 t->analysis &= ~AN_REQ_ANY;
Willy Tarreaub6866442008-07-14 23:54:42 +02001586 t->fe->failed_req++;
1587 if (!(t->flags & SN_ERR_MASK))
1588 t->flags |= SN_ERR_CLITO;
1589 if (!(t->flags & SN_FINST_MASK))
1590 t->flags |= SN_FINST_R;
1591 return 1;
1592 }
1593
1594 /* We don't know whether we have enough data, so must proceed
1595 * this way :
1596 * - iterate through all rules in their declaration order
1597 * - if one rule returns MISS, it means the inspect delay is
1598 * not over yet, then return immediately, otherwise consider
1599 * it as a non-match.
1600 * - if one rule returns OK, then return OK
1601 * - if one rule returns KO, then return KO
1602 */
1603
1604 if (tick_is_expired(t->inspect_exp, now_ms))
1605 partial = 0;
1606 else
1607 partial = ACL_PARTIAL;
1608
1609 list_for_each_entry(rule, &t->fe->tcp_req.inspect_rules, list) {
1610 int ret = ACL_PAT_PASS;
1611
1612 if (rule->cond) {
1613 ret = acl_exec_cond(rule->cond, t->fe, t, NULL, ACL_DIR_REQ | partial);
1614 if (ret == ACL_PAT_MISS) {
1615 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
1616 return 0;
1617 }
1618 ret = acl_pass(ret);
1619 if (rule->cond->pol == ACL_COND_UNLESS)
1620 ret = !ret;
1621 }
1622
1623 if (ret) {
1624 /* we have a matching rule. */
1625 if (rule->action == TCP_ACT_REJECT) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001626 buffer_shutr_done(req);
1627 buffer_shutw_done(rep);
Willy Tarreaub6866442008-07-14 23:54:42 +02001628 fd_delete(t->cli_fd);
1629 t->cli_state = CL_STCLOSE;
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001630 t->analysis &= ~AN_REQ_ANY;
Willy Tarreaub6866442008-07-14 23:54:42 +02001631 t->fe->failed_req++;
1632 if (!(t->flags & SN_ERR_MASK))
1633 t->flags |= SN_ERR_PRXCOND;
1634 if (!(t->flags & SN_FINST_MASK))
1635 t->flags |= SN_FINST_R;
1636 t->inspect_exp = TICK_ETERNITY;
1637 return 1;
1638 }
1639 /* otherwise accept */
1640 break;
1641 }
1642 }
1643
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001644 /* if we get there, it means we have no rule which matches, or
1645 * we have an explicit accept, so we apply the default accept.
Willy Tarreaub6866442008-07-14 23:54:42 +02001646 */
1647 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001648 t->analysis &= ~AN_REQ_INSPECT;
1649 if (t->analysis & AN_REQ_HTTP_HDR)
Willy Tarreaub6866442008-07-14 23:54:42 +02001650 t->txn.exp = tick_add_ifset(now_ms, t->fe->timeout.httpreq);
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001651 else
Willy Tarreau718f0ef2008-08-10 16:21:32 +02001652 req->flags |= BF_MAY_CONNECT | BF_MAY_FORWARD;
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001653
Willy Tarreaub6866442008-07-14 23:54:42 +02001654 t->inspect_exp = TICK_ETERNITY;
1655 return 1;
1656 }
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001657
1658 if (t->analysis & AN_REQ_HTTP_HDR) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001659 /*
1660 * Now parse the partial (or complete) lines.
1661 * We will check the request syntax, and also join multi-line
1662 * headers. An index of all the lines will be elaborated while
1663 * parsing.
1664 *
Willy Tarreau8973c702007-01-21 23:58:29 +01001665 * For the parsing, we use a 28 states FSM.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001666 *
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001667 * Here is the information we currently have :
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001668 * req->data + req->som = beginning of request
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001669 * req->data + req->eoh = end of processed headers / start of current one
1670 * req->data + req->eol = end of current header or line (LF or CRLF)
1671 * req->lr = first non-visited byte
1672 * req->r = end of data
1673 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001674
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001675 int cur_idx;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001676 struct http_txn *txn = &t->txn;
1677 struct http_msg *msg = &txn->req;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001678 struct proxy *cur_proxy;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001679
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001680 if (likely(req->lr < req->r))
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001681 http_msg_analyzer(req, msg, &txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001682
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001683 /* 1: we might have to print this header in debug mode */
1684 if (unlikely((global.mode & MODE_DEBUG) &&
1685 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001686 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001687 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001688
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001689 sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001690 eol = sol + msg->sl.rq.l;
1691 debug_hdr("clireq", t, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001692
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001693 sol += hdr_idx_first_pos(&txn->hdr_idx);
1694 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001695
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001696 while (cur_idx) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001697 eol = sol + txn->hdr_idx.v[cur_idx].len;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001698 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001699 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
1700 cur_idx = txn->hdr_idx.v[cur_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001701 }
1702 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001703
Willy Tarreau58f10d72006-12-04 02:26:12 +01001704
1705 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001706 * Now we quickly check if we have found a full valid request.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001707 * If not so, we check the FD and buffer states before leaving.
1708 * A full request is indicated by the fact that we have seen
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001709 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
1710 * requests are checked first.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001711 *
1712 */
1713
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001714 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001715 /*
1716 * First, let's catch bad requests.
1717 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001718 if (unlikely(msg->msg_state == HTTP_MSG_ERROR))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001719 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001720
1721 /* 1: Since we are in header mode, if there's no space
1722 * left for headers, we won't be able to free more
1723 * later, so the session will never terminate. We
1724 * must terminate it now.
1725 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001726 if (unlikely(req->l >= req->rlim - req->data)) {
1727 /* FIXME: check if URI is set and return Status
1728 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001729 */
Willy Tarreau06619262006-12-17 08:37:22 +01001730 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001731 }
1732
1733 /* 2: have we encountered a read error or a close ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001734 else if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1735 /* read error, or last read : give up. */
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001736 buffer_shutr_done(req);
1737 buffer_shutw_done(rep);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001738 fd_delete(t->cli_fd);
1739 t->cli_state = CL_STCLOSE;
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001740 t->analysis &= ~AN_REQ_ANY;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001741 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001742 if (!(t->flags & SN_ERR_MASK))
1743 t->flags |= SN_ERR_CLICL;
1744 if (!(t->flags & SN_FINST_MASK))
1745 t->flags |= SN_FINST_R;
1746 return 1;
1747 }
1748
1749 /* 3: has the read timeout expired ? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001750 else if (unlikely(tick_is_expired(req->rex, now_ms) ||
1751 tick_is_expired(txn->exp, now_ms))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001752 /* read timeout : give up with an error message. */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001753 txn->status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +01001754 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001755 t->analysis &= ~AN_REQ_ANY;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001756 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001757 if (!(t->flags & SN_ERR_MASK))
1758 t->flags |= SN_ERR_CLITO;
1759 if (!(t->flags & SN_FINST_MASK))
1760 t->flags |= SN_FINST_R;
1761 return 1;
1762 }
1763
1764 /* 4: do we need to re-enable the read socket ? */
Willy Tarreau66319382007-04-08 17:17:37 +02001765 else if (unlikely(EV_FD_COND_S(t->cli_fd, DIR_RD))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02001766 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreau58f10d72006-12-04 02:26:12 +01001767 * full. We cannot loop here since stream_sock_read will disable it only if
1768 * req->l == rlim-data
1769 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001770 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001771 }
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001772 /* we don't need to resync if the state has not changed */
1773 return !(t->analysis & AN_REQ_HTTP_HDR);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001774 }
1775
1776
1777 /****************************************************************
1778 * More interesting part now : we know that we have a complete *
1779 * request which at least looks like HTTP. We have an indicator *
1780 * of each header's length, so we can parse them quickly. *
1781 ****************************************************************/
1782
Willy Tarreau67f0eea2008-08-10 22:55:22 +02001783 t->analysis &= ~AN_REQ_HTTP_HDR;
1784
Willy Tarreau9cdde232007-05-02 20:58:19 +02001785 /* ensure we keep this pointer to the beginning of the message */
1786 msg->sol = req->data + msg->som;
1787
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001788 /*
1789 * 1: identify the method
1790 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001791 txn->meth = find_http_meth(&req->data[msg->som], msg->sl.rq.m_l);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001792
1793 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001794 * 2: check if the URI matches the monitor_uri.
Willy Tarreau06619262006-12-17 08:37:22 +01001795 * We have to do this for every request which gets in, because
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001796 * the monitor-uri is defined by the frontend.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001797 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001798 if (unlikely((t->fe->monitor_uri_len != 0) &&
1799 (t->fe->monitor_uri_len == msg->sl.rq.u_l) &&
1800 !memcmp(&req->data[msg->sl.rq.u],
1801 t->fe->monitor_uri,
1802 t->fe->monitor_uri_len))) {
1803 /*
1804 * We have found the monitor URI
1805 */
Willy Tarreaub80c2302007-11-30 20:51:32 +01001806 struct acl_cond *cond;
1807 cur_proxy = t->fe;
1808
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001809 t->flags |= SN_MONITOR;
Willy Tarreaub80c2302007-11-30 20:51:32 +01001810
1811 /* Check if we want to fail this monitor request or not */
1812 list_for_each_entry(cond, &cur_proxy->mon_fail_cond, list) {
1813 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001814
1815 ret = acl_pass(ret);
Willy Tarreaub80c2302007-11-30 20:51:32 +01001816 if (cond->pol == ACL_COND_UNLESS)
1817 ret = !ret;
1818
1819 if (ret) {
1820 /* we fail this request, let's return 503 service unavail */
1821 txn->status = 503;
1822 client_retnclose(t, error_message(t, HTTP_ERR_503));
1823 goto return_prx_cond;
1824 }
1825 }
1826
1827 /* nothing to fail, let's reply normaly */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001828 txn->status = 200;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001829 client_retnclose(t, &http_200_chunk);
1830 goto return_prx_cond;
1831 }
1832
1833 /*
1834 * 3: Maybe we have to copy the original REQURI for the logs ?
1835 * Note: we cannot log anymore if the request has been
1836 * classified as invalid.
1837 */
1838 if (unlikely(t->logs.logwait & LW_REQ)) {
1839 /* we have a complete HTTP request that we must log */
Willy Tarreau332f8bf2007-05-13 21:36:56 +02001840 if ((txn->uri = pool_alloc2(pool2_requri)) != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001841 int urilen = msg->sl.rq.l;
1842
1843 if (urilen >= REQURI_LEN)
1844 urilen = REQURI_LEN - 1;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001845 memcpy(txn->uri, &req->data[msg->som], urilen);
1846 txn->uri[urilen] = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001847
1848 if (!(t->logs.logwait &= ~LW_REQ))
Willy Tarreau42250582007-04-01 01:30:43 +02001849 http_sess_log(t);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001850 } else {
1851 Alert("HTTP logging : out of memory.\n");
1852 }
1853 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001854
Willy Tarreau06619262006-12-17 08:37:22 +01001855
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001856 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
1857 if (unlikely(msg->sl.rq.v_l == 0)) {
1858 int delta;
1859 char *cur_end;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001860 msg->sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001861 cur_end = msg->sol + msg->sl.rq.l;
1862 delta = 0;
Willy Tarreau06619262006-12-17 08:37:22 +01001863
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001864 if (msg->sl.rq.u_l == 0) {
1865 /* if no URI was set, add "/" */
1866 delta = buffer_replace2(req, cur_end, cur_end, " /", 2);
1867 cur_end += delta;
1868 msg->eoh += delta;
Willy Tarreau06619262006-12-17 08:37:22 +01001869 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001870 /* add HTTP version */
1871 delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
1872 msg->eoh += delta;
1873 cur_end += delta;
1874 cur_end = (char *)http_parse_reqline(msg, req->data,
1875 HTTP_MSG_RQMETH,
1876 msg->sol, cur_end + 1,
1877 NULL, NULL);
1878 if (unlikely(!cur_end))
1879 goto return_bad_req;
1880
1881 /* we have a full HTTP/1.0 request now and we know that
1882 * we have either a CR or an LF at <ptr>.
1883 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001884 hdr_idx_set_start(&txn->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
Willy Tarreau58f10d72006-12-04 02:26:12 +01001885 }
1886
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001887
1888 /* 5: we may need to capture headers */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001889 if (unlikely((t->logs.logwait & LW_REQHDR) && t->fe->req_cap))
Willy Tarreau117f59e2007-03-04 18:17:17 +01001890 capture_headers(req->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001891 txn->req.cap, t->fe->req_cap);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001892
1893 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001894 * 6: we will have to evaluate the filters.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001895 * As opposed to version 1.2, now they will be evaluated in the
1896 * filters order and not in the header order. This means that
1897 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001898 *
1899 * We can now check whether we want to switch to another
1900 * backend, in which case we will re-check the backend's
1901 * filters and various options. In order to support 3-level
1902 * switching, here's how we should proceed :
1903 *
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001904 * a) run be.
Willy Tarreau830ff452006-12-17 19:31:23 +01001905 * if (switch) then switch ->be to the new backend.
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001906 * b) run be if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001907 * There cannot be any switch from there, so ->be cannot be
1908 * changed anymore.
1909 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001910 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001911 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001912 * The response path will be able to apply either ->be, or
1913 * ->be then ->fe filters in order to match the reverse of
1914 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001915 */
1916
Willy Tarreau06619262006-12-17 08:37:22 +01001917 do {
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001918 struct acl_cond *cond;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001919 struct redirect_rule *rule;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001920 struct proxy *rule_set = t->be;
Willy Tarreau830ff452006-12-17 19:31:23 +01001921 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001922
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001923 /* first check whether we have some ACLs set to redirect this request */
1924 list_for_each_entry(rule, &cur_proxy->redirect_rules, list) {
1925 int ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001926
1927 ret = acl_pass(ret);
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001928 if (rule->cond->pol == ACL_COND_UNLESS)
1929 ret = !ret;
1930
1931 if (ret) {
1932 struct chunk rdr = { trash, 0 };
1933 const char *msg_fmt;
1934
1935 /* build redirect message */
1936 switch(rule->code) {
1937 case 303:
1938 rdr.len = strlen(HTTP_303);
1939 msg_fmt = HTTP_303;
1940 break;
1941 case 301:
1942 rdr.len = strlen(HTTP_301);
1943 msg_fmt = HTTP_301;
1944 break;
1945 case 302:
1946 default:
1947 rdr.len = strlen(HTTP_302);
1948 msg_fmt = HTTP_302;
1949 break;
1950 }
1951
1952 if (unlikely(rdr.len > sizeof(trash)))
1953 goto return_bad_req;
1954 memcpy(rdr.str, msg_fmt, rdr.len);
1955
1956 switch(rule->type) {
1957 case REDIRECT_TYPE_PREFIX: {
1958 const char *path;
1959 int pathlen;
1960
1961 path = http_get_path(txn);
1962 /* build message using path */
1963 if (path) {
1964 pathlen = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
1965 } else {
1966 path = "/";
1967 pathlen = 1;
1968 }
1969
1970 if (rdr.len + rule->rdr_len + pathlen > sizeof(trash) - 4)
1971 goto return_bad_req;
1972
1973 /* add prefix */
1974 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1975 rdr.len += rule->rdr_len;
1976
1977 /* add path */
1978 memcpy(rdr.str + rdr.len, path, pathlen);
1979 rdr.len += pathlen;
1980 break;
1981 }
1982 case REDIRECT_TYPE_LOCATION:
1983 default:
1984 if (rdr.len + rule->rdr_len > sizeof(trash) - 4)
1985 goto return_bad_req;
1986
1987 /* add location */
1988 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1989 rdr.len += rule->rdr_len;
1990 break;
1991 }
1992
1993 /* add end of headers */
1994 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
1995 rdr.len += 4;
1996
1997 txn->status = rule->code;
1998 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02001999 t->logs.tv_request = now;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02002000 client_retnclose(t, &rdr);
2001 goto return_prx_cond;
2002 }
2003 }
2004
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02002005 /* first check whether we have some ACLs set to block this request */
2006 list_for_each_entry(cond, &cur_proxy->block_cond, list) {
Willy Tarreaud41f8d82007-06-10 10:06:18 +02002007 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02002008
2009 ret = acl_pass(ret);
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02002010 if (cond->pol == ACL_COND_UNLESS)
2011 ret = !ret;
2012
2013 if (ret) {
2014 txn->status = 403;
2015 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02002016 t->logs.tv_request = now;
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02002017 client_retnclose(t, error_message(t, HTTP_ERR_403));
2018 goto return_prx_cond;
2019 }
2020 }
2021
Willy Tarreau06619262006-12-17 08:37:22 +01002022 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01002023 if (rule_set->req_exp != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002024 if (apply_filters_to_request(t, req, rule_set->req_exp) < 0)
2025 goto return_bad_req;
Willy Tarreau53b6c742006-12-17 13:37:46 +01002026 }
2027
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002028 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
2029 /* to ensure correct connection accounting on
2030 * the backend, we count the connection for the
2031 * one managing the queue.
2032 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002033 t->be->beconn++;
2034 if (t->be->beconn > t->be->beconn_max)
2035 t->be->beconn_max = t->be->beconn;
2036 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002037 t->flags |= SN_BE_ASSIGNED;
2038 }
2039
Willy Tarreau06619262006-12-17 08:37:22 +01002040 /* has the request been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01002041 if (txn->flags & TX_CLDENY) {
Willy Tarreau06619262006-12-17 08:37:22 +01002042 /* no need to go further */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002043 txn->status = 403;
Willy Tarreau06619262006-12-17 08:37:22 +01002044 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02002045 t->logs.tv_request = now;
Willy Tarreau80587432006-12-24 17:47:20 +01002046 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01002047 goto return_prx_cond;
2048 }
2049
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002050 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002051 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002052 !(t->flags & SN_CONN_CLOSED)) {
2053 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002054 int cur_idx, old_idx, delta, val;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002055 struct hdr_idx_elem *cur_hdr;
Willy Tarreau06619262006-12-17 08:37:22 +01002056
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002057 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002058 old_idx = 0;
2059
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002060 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
2061 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002062 cur_ptr = cur_next;
2063 cur_end = cur_ptr + cur_hdr->len;
2064 cur_next = cur_end + cur_hdr->cr + 1;
2065
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002066 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
2067 if (val) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002068 /* 3 possibilities :
2069 * - we have already set Connection: close,
2070 * so we remove this line.
2071 * - we have not yet set Connection: close,
2072 * but this line indicates close. We leave
2073 * it untouched and set the flag.
2074 * - we have not yet set Connection: close,
2075 * and this line indicates non-close. We
2076 * replace it.
2077 */
2078 if (t->flags & SN_CONN_CLOSED) {
2079 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002080 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002081 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002082 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
2083 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002084 cur_hdr->len = 0;
2085 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002086 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
2087 delta = buffer_replace2(req, cur_ptr + val, cur_end,
2088 "close", 5);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002089 cur_next += delta;
2090 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002091 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002092 }
2093 t->flags |= SN_CONN_CLOSED;
2094 }
2095 }
2096 old_idx = cur_idx;
2097 }
Willy Tarreauf2f0ee82007-03-30 12:02:43 +02002098 }
2099 /* add request headers from the rule sets in the same order */
2100 for (cur_idx = 0; cur_idx < rule_set->nb_reqadd; cur_idx++) {
2101 if (unlikely(http_header_add_tail(req,
2102 &txn->req,
2103 &txn->hdr_idx,
2104 rule_set->req_add[cur_idx])) < 0)
2105 goto return_bad_req;
Willy Tarreau06619262006-12-17 08:37:22 +01002106 }
Willy Tarreaub2513902006-12-17 14:52:38 +01002107
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002108 /* check if stats URI was requested, and if an auth is needed */
Willy Tarreau0214c3a2007-01-07 13:47:30 +01002109 if (rule_set->uri_auth != NULL &&
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002110 (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)) {
Willy Tarreaub2513902006-12-17 14:52:38 +01002111 /* we have to check the URI and auth for this request */
2112 if (stats_check_uri_auth(t, rule_set))
2113 return 1;
2114 }
2115
Willy Tarreau55ea7572007-06-17 19:56:27 +02002116 /* now check whether we have some switching rules for this request */
2117 if (!(t->flags & SN_BE_ASSIGNED)) {
2118 struct switching_rule *rule;
2119
2120 list_for_each_entry(rule, &cur_proxy->switching_rules, list) {
2121 int ret;
2122
2123 ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02002124
2125 ret = acl_pass(ret);
Willy Tarreaua8cfa342008-07-09 11:23:31 +02002126 if (rule->cond->pol == ACL_COND_UNLESS)
Willy Tarreau55ea7572007-06-17 19:56:27 +02002127 ret = !ret;
2128
2129 if (ret) {
2130 t->be = rule->be.backend;
2131 t->be->beconn++;
2132 if (t->be->beconn > t->be->beconn_max)
2133 t->be->beconn_max = t->be->beconn;
2134 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002135
2136 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002137 t->rep->rto = t->req->wto = t->be->timeout.server;
2138 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002139 t->conn_retries = t->be->conn_retries;
Willy Tarreau55ea7572007-06-17 19:56:27 +02002140 t->flags |= SN_BE_ASSIGNED;
2141 break;
2142 }
2143 }
2144 }
2145
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002146 if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
2147 /* No backend was set, but there was a default
2148 * backend set in the frontend, so we use it and
2149 * loop again.
2150 */
2151 t->be = cur_proxy->defbe.be;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002152 t->be->beconn++;
2153 if (t->be->beconn > t->be->beconn_max)
2154 t->be->beconn_max = t->be->beconn;
2155 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002156
2157 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002158 t->rep->rto = t->req->wto = t->be->timeout.server;
2159 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002160 t->conn_retries = t->be->conn_retries;
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002161 t->flags |= SN_BE_ASSIGNED;
2162 }
2163 } while (t->be != cur_proxy); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01002164
Willy Tarreau58f10d72006-12-04 02:26:12 +01002165
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002166 if (!(t->flags & SN_BE_ASSIGNED)) {
2167 /* To ensure correct connection accounting on
2168 * the backend, we count the connection for the
2169 * one managing the queue.
2170 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002171 t->be->beconn++;
2172 if (t->be->beconn > t->be->beconn_max)
2173 t->be->beconn_max = t->be->beconn;
2174 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002175 t->flags |= SN_BE_ASSIGNED;
2176 }
2177
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002178 /*
2179 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01002180 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002181 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01002182 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01002183 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01002184
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01002185 /*
2186 * If HTTP PROXY is set we simply get remote server address
2187 * parsing incoming request.
2188 */
2189 if ((t->be->options & PR_O_HTTP_PROXY) && !(t->flags & SN_ADDR_SET)) {
2190 url2sa(req->data + msg->sl.rq.u, msg->sl.rq.u_l, &t->srv_addr);
2191 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002192
Willy Tarreau2a324282006-12-05 00:05:46 +01002193 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002194 * 7: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01002195 * so let's do the same now.
2196 */
2197
2198 /* It needs to look into the URI */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002199 if (t->be->appsession_name) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01002200 get_srv_from_appsession(t, &req->data[msg->som], msg->sl.rq.l);
Willy Tarreau06619262006-12-17 08:37:22 +01002201 }
2202
2203
2204 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002205 * 8: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01002206 * Note that doing so might move headers in the request, but
2207 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01002208 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01002209 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01002210 if ((t->be->cookie_name || t->be->appsession_name || t->be->capture_name)
2211 && !(txn->flags & (TX_CLDENY|TX_CLTARPIT)))
Willy Tarreau2a324282006-12-05 00:05:46 +01002212 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01002213
Willy Tarreau58f10d72006-12-04 02:26:12 +01002214
Willy Tarreau2a324282006-12-05 00:05:46 +01002215 /*
Willy Tarreaubb046ac2007-03-03 19:17:03 +01002216 * 9: add X-Forwarded-For if either the frontend or the backend
2217 * asks for it.
Willy Tarreau2a324282006-12-05 00:05:46 +01002218 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002219 if ((t->fe->options | t->be->options) & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002220 if (t->cli_addr.ss_family == AF_INET) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002221 /* Add an X-Forwarded-For header unless the source IP is
2222 * in the 'except' network range.
2223 */
2224 if ((!t->fe->except_mask.s_addr ||
2225 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->fe->except_mask.s_addr)
2226 != t->fe->except_net.s_addr) &&
2227 (!t->be->except_mask.s_addr ||
2228 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->be->except_mask.s_addr)
2229 != t->be->except_net.s_addr)) {
2230 int len;
2231 unsigned char *pn;
2232 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
Willy Tarreau45e73e32006-12-17 00:05:15 +01002233
Ross Westaf72a1d2008-08-03 10:51:45 +02002234 /* Note: we rely on the backend to get the header name to be used for
2235 * x-forwarded-for, because the header is really meant for the backends.
2236 * However, if the backend did not specify any option, we have to rely
2237 * on the frontend's header name.
2238 */
2239 if (t->be->fwdfor_hdr_len) {
2240 len = t->be->fwdfor_hdr_len;
2241 memcpy(trash, t->be->fwdfor_hdr_name, len);
2242 } else {
2243 len = t->fe->fwdfor_hdr_len;
2244 memcpy(trash, t->fe->fwdfor_hdr_name, len);
2245 }
2246 len += sprintf(trash + len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002247
Ross Westaf72a1d2008-08-03 10:51:45 +02002248 if (unlikely(http_header_add_tail2(req, &txn->req,
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002249 &txn->hdr_idx, trash, len)) < 0)
2250 goto return_bad_req;
2251 }
Willy Tarreau2a324282006-12-05 00:05:46 +01002252 }
2253 else if (t->cli_addr.ss_family == AF_INET6) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002254 /* FIXME: for the sake of completeness, we should also support
2255 * 'except' here, although it is mostly useless in this case.
2256 */
Willy Tarreau2a324282006-12-05 00:05:46 +01002257 int len;
2258 char pn[INET6_ADDRSTRLEN];
2259 inet_ntop(AF_INET6,
2260 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2261 pn, sizeof(pn));
Ross Westaf72a1d2008-08-03 10:51:45 +02002262
2263 /* Note: we rely on the backend to get the header name to be used for
2264 * x-forwarded-for, because the header is really meant for the backends.
2265 * However, if the backend did not specify any option, we have to rely
2266 * on the frontend's header name.
2267 */
2268 if (t->be->fwdfor_hdr_len) {
2269 len = t->be->fwdfor_hdr_len;
2270 memcpy(trash, t->be->fwdfor_hdr_name, len);
2271 } else {
2272 len = t->fe->fwdfor_hdr_len;
2273 memcpy(trash, t->fe->fwdfor_hdr_name, len);
2274 }
2275 len += sprintf(trash + len, ": %s", pn);
2276
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002277 if (unlikely(http_header_add_tail2(req, &txn->req,
2278 &txn->hdr_idx, trash, len)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002279 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01002280 }
2281 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002282
Willy Tarreau2a324282006-12-05 00:05:46 +01002283 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002284 * 10: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02002285 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaub2513902006-12-17 14:52:38 +01002286 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02002287 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002288 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02002289 if ((unlikely(msg->sl.rq.v_l != 8) ||
2290 unlikely(req->data[msg->som + msg->sl.rq.v + 7] != '0')) &&
2291 unlikely(http_header_add_tail2(req, &txn->req, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002292 "Connection: close", 17)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002293 goto return_bad_req;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002294 t->flags |= SN_CONN_CLOSED;
Willy Tarreaue15d9132006-12-14 22:26:42 +01002295 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002296 /* Before we switch to data, was assignment set in manage_client_side_cookie?
2297 * If not assigned, perhaps we are balancing on url_param, but this is a
2298 * POST; and the parameters are in the body, maybe scan there to find our server.
2299 * (unless headers overflowed the buffer?)
2300 */
2301 if (!(t->flags & (SN_ASSIGNED|SN_DIRECT)) &&
2302 t->txn.meth == HTTP_METH_POST && t->be->url_param_name != NULL &&
Willy Tarreaufb0528b2008-08-11 00:21:56 +02002303 t->be->url_param_post_limit != 0 && req->l < BUFSIZE &&
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002304 memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) {
2305 /* are there enough bytes here? total == l || r || rlim ?
2306 * len is unsigned, but eoh is int,
2307 * how many bytes of body have we received?
2308 * eoh is the first empty line of the header
2309 */
2310 /* already established CRLF or LF at eoh, move to start of message, find message length in buffer */
Willy Tarreaufb0528b2008-08-11 00:21:56 +02002311 unsigned long len = req->l - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1);
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002312
2313 /* If we have HTTP/1.1 and Expect: 100-continue, then abort.
2314 * We can't assume responsibility for the server's decision,
2315 * on this URI and header set. See rfc2616: 14.20, 8.2.3,
2316 * We also can't change our mind later, about which server to choose, so round robin.
2317 */
2318 if ((likely(msg->sl.rq.v_l == 8) && req->data[msg->som + msg->sl.rq.v + 7] == '1')) {
2319 struct hdr_ctx ctx;
2320 ctx.idx = 0;
2321 /* Expect is allowed in 1.1, look for it */
2322 http_find_header2("Expect", 6, msg->sol, &txn->hdr_idx, &ctx);
2323 if (ctx.idx != 0 &&
2324 unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val,"100-continue",12)==0))
2325 /* We can't reliablly stall and wait for data, because of
2326 * .NET clients that don't conform to rfc2616; so, no need for
2327 * the next block to check length expectations.
2328 * We could send 100 status back to the client, but then we need to
2329 * re-write headers, and send the message. And this isn't the right
2330 * place for that action.
2331 * TODO: support Expect elsewhere and delete this block.
2332 */
2333 goto end_check_maybe_wait_for_body;
2334 }
2335 if ( likely(len > t->be->url_param_post_limit) ) {
2336 /* nothing to do, we got enough */
2337 } else {
2338 /* limit implies we are supposed to need this many bytes
2339 * to find the parameter. Let's see how many bytes we can wait for.
2340 */
2341 long long hint = len;
2342 struct hdr_ctx ctx;
2343 ctx.idx = 0;
2344 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
2345 if (unlikely(ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",7)==0)) {
2346 t->srv_state = SV_STANALYZE;
Willy Tarreau67f0eea2008-08-10 22:55:22 +02002347 t->analysis |= AN_REQ_HTTP_BODY;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002348 } else {
2349 ctx.idx = 0;
2350 http_find_header2("Content-Length", 14, msg->sol, &txn->hdr_idx, &ctx);
2351 /* now if we have a length, we'll take the hint */
2352 if ( ctx.idx ) {
2353 /* We have Content-Length */
2354 if ( strl2llrc(ctx.line+ctx.val,ctx.vlen, &hint) )
2355 hint = 0; /* parse failure, untrusted client */
2356 else {
2357 if ( hint > 0 )
2358 msg->hdr_content_len = hint;
2359 else
2360 hint = 0; /* bad client, sent negative length */
2361 }
2362 }
2363 /* but limited to what we care about, maybe we don't expect any entity data (hint == 0) */
2364 if ( t->be->url_param_post_limit < hint )
2365 hint = t->be->url_param_post_limit;
2366 /* now do we really need to buffer more data? */
Willy Tarreau67f0eea2008-08-10 22:55:22 +02002367 if ( len < hint ) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002368 t->srv_state = SV_STANALYZE;
Willy Tarreau67f0eea2008-08-10 22:55:22 +02002369 t->analysis |= AN_REQ_HTTP_BODY;
2370 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002371 /* else... There are no body bytes to wait for */
2372 }
2373 }
2374 }
2375 end_check_maybe_wait_for_body:
Willy Tarreaubaaee002006-06-26 02:48:02 +02002376
Willy Tarreau2a324282006-12-05 00:05:46 +01002377 /*************************************************************
2378 * OK, that's finished for the headers. We have done what we *
2379 * could. Let's switch to the DATA state. *
2380 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02002381
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002382 req->flags |= BF_MAY_CONNECT | BF_MAY_FORWARD;
Willy Tarreau2a324282006-12-05 00:05:46 +01002383 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002384
Willy Tarreau70089872008-06-13 21:12:51 +02002385 t->logs.tv_request = now;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002386
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002387 if (!t->fe->timeout.client ||
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002388 (!(rep->flags & BF_MAY_FORWARD) && t->be->timeout.server)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002389 /* If the client has no timeout, or if the server is not ready yet,
2390 * and we know for sure that it can expire, then it's cleaner to
2391 * disable the timeout on the client side so that too low values
2392 * cannot make the sessions abort too early.
2393 *
2394 * FIXME-20050705: the server needs a way to re-enable this time-out
2395 * when it switches its state, otherwise a client can stay connected
2396 * indefinitely. This now seems to be OK.
2397 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002398 req->rex = TICK_ETERNITY;
Willy Tarreau2a324282006-12-05 00:05:46 +01002399 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002400
Willy Tarreau1fa31262007-12-03 00:36:16 +01002401 /* When a connection is tarpitted, we use the tarpit timeout,
2402 * which may be the same as the connect timeout if unspecified.
2403 * If unset, then set it to zero because we really want it to
2404 * eventually expire.
Willy Tarreau2a324282006-12-05 00:05:46 +01002405 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002406 if (txn->flags & TX_CLTARPIT) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002407 t->req->l = 0;
2408 /* flush the request so that we can drop the connection early
2409 * if the client closes first.
2410 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002411 req->cex = tick_add_ifset(now_ms, t->be->timeout.tarpit);
2412 if (!req->cex)
2413 req->cex = now_ms;
Willy Tarreau2a324282006-12-05 00:05:46 +01002414 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002415
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002416 /* OK let's go on with the BODY now */
Willy Tarreau06619262006-12-17 08:37:22 +01002417 goto process_data;
2418
2419 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002420 txn->req.msg_state = HTTP_MSG_ERROR;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002421 txn->status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01002422 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002423 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01002424 return_prx_cond:
2425 if (!(t->flags & SN_ERR_MASK))
2426 t->flags |= SN_ERR_PRXCOND;
2427 if (!(t->flags & SN_FINST_MASK))
2428 t->flags |= SN_FINST_R;
2429 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002430 }
Willy Tarreau67f0eea2008-08-10 22:55:22 +02002431
2432 if (c == CL_STDATA) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002433 process_data:
2434 /* FIXME: this error handling is partly buggy because we always report
2435 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
2436 * or HEADER phase. BTW, it's not logical to expire the client while
2437 * we're waiting for the server to connect.
2438 */
2439 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002440 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002441 buffer_shutr_done(req);
2442 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002443 fd_delete(t->cli_fd);
2444 t->cli_state = CL_STCLOSE;
2445 if (!(t->flags & SN_ERR_MASK))
2446 t->flags |= SN_ERR_CLICL;
2447 if (!(t->flags & SN_FINST_MASK)) {
2448 if (t->pend_pos)
2449 t->flags |= SN_FINST_Q;
2450 else if (s == SV_STCONN)
2451 t->flags |= SN_FINST_C;
2452 else
2453 t->flags |= SN_FINST_D;
2454 }
2455 return 1;
2456 }
2457 /* last read, or end of server write */
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002458 else if (req->flags & (BF_READ_NULL | BF_SHUTW_STATUS)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002459 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002460 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002461 t->cli_state = CL_STSHUTR;
2462 return 1;
2463 }
2464 /* last server read and buffer empty */
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002465 else if (rep->flags & BF_SHUTR_STATUS && rep->l == 0) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002466 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002467 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002468 shutdown(t->cli_fd, SHUT_WR);
2469 /* We must ensure that the read part is still alive when switching
2470 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002471 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002472 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002473 t->cli_state = CL_STSHUTW;
2474 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2475 return 1;
2476 }
2477 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002478 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002479 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002480 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002481 t->cli_state = CL_STSHUTR;
2482 if (!(t->flags & SN_ERR_MASK))
2483 t->flags |= SN_ERR_CLITO;
2484 if (!(t->flags & SN_FINST_MASK)) {
2485 if (t->pend_pos)
2486 t->flags |= SN_FINST_Q;
2487 else if (s == SV_STCONN)
2488 t->flags |= SN_FINST_C;
2489 else
2490 t->flags |= SN_FINST_D;
2491 }
2492 return 1;
2493 }
2494 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002495 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002496 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002497 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002498 shutdown(t->cli_fd, SHUT_WR);
2499 /* We must ensure that the read part is still alive when switching
2500 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002501 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002502 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002503
2504 t->cli_state = CL_STSHUTW;
2505 if (!(t->flags & SN_ERR_MASK))
2506 t->flags |= SN_ERR_CLITO;
2507 if (!(t->flags & SN_FINST_MASK)) {
2508 if (t->pend_pos)
2509 t->flags |= SN_FINST_Q;
2510 else if (s == SV_STCONN)
2511 t->flags |= SN_FINST_C;
2512 else
2513 t->flags |= SN_FINST_D;
2514 }
2515 return 1;
2516 }
2517
2518 if (req->l >= req->rlim - req->data) {
2519 /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02002520 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002521 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002522 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002523 }
2524 } else {
2525 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002526 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002527 if (!t->fe->timeout.client ||
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002528 (!(rep->flags & BF_MAY_FORWARD) && t->be->timeout.server))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002529 /* If the client has no timeout, or if the server not ready yet, and we
2530 * know for sure that it can expire, then it's cleaner to disable the
2531 * timeout on the client side so that too low values cannot make the
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002532 * sessions abort too early. NB: we should only do this in HTTP states
2533 * before HEADERS.
Willy Tarreaubaaee002006-06-26 02:48:02 +02002534 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002535 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002536 else
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002537 req->rex = tick_add(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002538 }
2539 }
2540
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002541 /* we don't enable client write if the buffer is empty, nor if the server has to analyze it */
2542 if ((rep->l == 0) || !(rep->flags & BF_MAY_FORWARD)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002543 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2544 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002545 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002546 }
2547 } else {
2548 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002549 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2550 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002551 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
2552 if (rep->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002553 /* FIXME: to prevent the client from expiring read timeouts during writes,
2554 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002555 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002556 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002557 }
2558 }
2559 return 0; /* other cases change nothing */
2560 }
2561 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002562 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002563 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002564 fd_delete(t->cli_fd);
2565 t->cli_state = CL_STCLOSE;
2566 if (!(t->flags & SN_ERR_MASK))
2567 t->flags |= SN_ERR_CLICL;
2568 if (!(t->flags & SN_FINST_MASK)) {
2569 if (t->pend_pos)
2570 t->flags |= SN_FINST_Q;
2571 else if (s == SV_STCONN)
2572 t->flags |= SN_FINST_C;
2573 else
2574 t->flags |= SN_FINST_D;
2575 }
2576 return 1;
2577 }
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002578 else if ((rep->flags & BF_SHUTR_STATUS) && (rep->l == 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002579 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002580 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002581 fd_delete(t->cli_fd);
2582 t->cli_state = CL_STCLOSE;
2583 return 1;
2584 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002585 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002586 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002587 fd_delete(t->cli_fd);
2588 t->cli_state = CL_STCLOSE;
2589 if (!(t->flags & SN_ERR_MASK))
2590 t->flags |= SN_ERR_CLITO;
2591 if (!(t->flags & SN_FINST_MASK)) {
2592 if (t->pend_pos)
2593 t->flags |= SN_FINST_Q;
2594 else if (s == SV_STCONN)
2595 t->flags |= SN_FINST_C;
2596 else
2597 t->flags |= SN_FINST_D;
2598 }
2599 return 1;
2600 }
2601
2602 if (t->flags & SN_SELF_GEN) {
2603 produce_content(t);
2604 if (rep->l == 0) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002605 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002606 fd_delete(t->cli_fd);
2607 t->cli_state = CL_STCLOSE;
2608 return 1;
2609 }
2610 }
2611
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002612 if ((rep->l == 0) || !(rep->flags & BF_MAY_FORWARD)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002613 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2614 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002615 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002616 }
2617 } else {
2618 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002619 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2620 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002621 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002622 }
2623 }
2624 return 0;
2625 }
2626 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002627 if (req->flags & BF_READ_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002628 buffer_shutr_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002629 fd_delete(t->cli_fd);
2630 t->cli_state = CL_STCLOSE;
2631 if (!(t->flags & SN_ERR_MASK))
2632 t->flags |= SN_ERR_CLICL;
2633 if (!(t->flags & SN_FINST_MASK)) {
2634 if (t->pend_pos)
2635 t->flags |= SN_FINST_Q;
2636 else if (s == SV_STCONN)
2637 t->flags |= SN_FINST_C;
2638 else
2639 t->flags |= SN_FINST_D;
2640 }
2641 return 1;
2642 }
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002643 else if (req->flags & (BF_READ_NULL | BF_SHUTW_STATUS)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002644 buffer_shutr_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002645 fd_delete(t->cli_fd);
2646 t->cli_state = CL_STCLOSE;
2647 return 1;
2648 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002649 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002650 buffer_shutr_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002651 fd_delete(t->cli_fd);
2652 t->cli_state = CL_STCLOSE;
2653 if (!(t->flags & SN_ERR_MASK))
2654 t->flags |= SN_ERR_CLITO;
2655 if (!(t->flags & SN_FINST_MASK)) {
2656 if (t->pend_pos)
2657 t->flags |= SN_FINST_Q;
2658 else if (s == SV_STCONN)
2659 t->flags |= SN_FINST_C;
2660 else
2661 t->flags |= SN_FINST_D;
2662 }
2663 return 1;
2664 }
2665 else if (req->l >= req->rlim - req->data) {
2666 /* no room to read more data */
2667
2668 /* FIXME-20050705: is it possible for a client to maintain a session
2669 * after the timeout by sending more data after it receives a close ?
2670 */
2671
Willy Tarreau66319382007-04-08 17:17:37 +02002672 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002673 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002674 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002675 }
2676 } else {
2677 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002678 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002679 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002680 }
2681 }
2682 return 0;
2683 }
2684 else { /* CL_STCLOSE: nothing to do */
2685 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2686 int len;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002687 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 +02002688 write(1, trash, len);
2689 }
2690 return 0;
2691 }
2692 return 0;
2693}
2694
2695
2696/*
2697 * manages the server FSM and its socket. It returns 1 if a state has changed
2698 * (and a resync may be needed), 0 else.
2699 */
2700int process_srv(struct session *t)
2701{
2702 int s = t->srv_state;
Willy Tarreau3d300592007-03-18 18:34:41 +01002703 struct http_txn *txn = &t->txn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002704 struct buffer *req = t->req;
2705 struct buffer *rep = t->rep;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002706 int conn_err;
2707
Willy Tarreau6468d922008-08-03 19:15:35 +02002708 DPRINTF(stderr,"process_srv: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%u,%u\n",
Willy Tarreau9f1f24b2008-08-11 11:20:03 +02002709 cli_stnames[t->cli_state], srv_stnames[t->srv_state],
Willy Tarreau6468d922008-08-03 19:15:35 +02002710 EV_FD_ISSET(t->srv_fd, DIR_RD), EV_FD_ISSET(t->srv_fd, DIR_WR),
2711 rep->rex, req->wex);
Willy Tarreauee991362007-05-14 14:37:50 +02002712
Willy Tarreaubaaee002006-06-26 02:48:02 +02002713 if (s == SV_STIDLE) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002714 /* NOTE: The client processor may switch to SV_STANALYZE, which switches back SV_STIDLE.
2715 * This is logcially after CL_STHEADERS completed, CL_STDATA has started, but
2716 * we need to defer server selection until more data arrives, if possible.
2717 * This is rare, and only if balancing on parameter hash with values in the entity of a POST
2718 */
Willy Tarreaudc0a6a02008-08-03 20:38:13 +02002719 if ((rep->flags & BF_SHUTW_STATUS) ||
Willy Tarreau6468d922008-08-03 19:15:35 +02002720 ((req->flags & BF_SHUTR_STATUS) &&
2721 (req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002722 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002723 if (t->pend_pos)
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002724 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002725 /* note that this must not return any error because it would be able to
2726 * overwrite the client_retnclose() output.
2727 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002728 if (txn->flags & TX_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01002729 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02002730 else
Willy Tarreau0f772532006-12-23 20:51:41 +01002731 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 +02002732
2733 return 1;
2734 }
Willy Tarreaudc0a6a02008-08-03 20:38:13 +02002735 else if (req->flags & BF_MAY_CONNECT) {
2736 /* the client allows the server to connect */
Willy Tarreau3d300592007-03-18 18:34:41 +01002737 if (txn->flags & TX_CLTARPIT) {
Willy Tarreaub8750a82006-09-03 09:56:00 +02002738 /* This connection is being tarpitted. The CLIENT side has
2739 * already set the connect expiration date to the right
2740 * timeout. We just have to check that it has not expired.
2741 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002742 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreaub8750a82006-09-03 09:56:00 +02002743 return 0;
2744
2745 /* We will set the queue timer to the time spent, just for
2746 * logging purposes. We fake a 500 server error, so that the
2747 * attacker will not suspect his connection has been tarpitted.
2748 * It will not cause trouble to the logs because we can exclude
2749 * the tarpitted connections by filtering on the 'PT' status flags.
2750 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002751 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002752 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaub8750a82006-09-03 09:56:00 +02002753 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01002754 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02002755 return 1;
2756 }
2757
Willy Tarreaubaaee002006-06-26 02:48:02 +02002758 /* Right now, we will need to create a connection to the server.
2759 * We might already have tried, and got a connection pending, in
2760 * which case we will not do anything till it's pending. It's up
2761 * to any other session to release it and wake us up again.
2762 */
2763 if (t->pend_pos) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002764 if (!tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002765 return 0;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002766 } else {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002767 /* we've been waiting too long here */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002768 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002769 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002770 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01002771 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002772 if (t->srv)
2773 t->srv->failed_conns++;
Willy Tarreau50fd1e12007-12-10 15:25:35 +01002774 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002775 return 1;
2776 }
2777 }
2778
2779 do {
2780 /* first, get a connection */
Willy Tarreau21d2af32008-02-14 20:25:24 +01002781 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
2782 t->flags |= SN_REDIRECTABLE;
2783
Willy Tarreaubaaee002006-06-26 02:48:02 +02002784 if (srv_redispatch_connect(t))
2785 return t->srv_state != SV_STIDLE;
2786
Willy Tarreau21d2af32008-02-14 20:25:24 +01002787 if ((t->flags & SN_REDIRECTABLE) && t->srv && t->srv->rdr_len) {
2788 /* Server supporting redirection and it is possible.
2789 * Invalid requests are reported as such. It concerns all
2790 * the largest ones.
2791 */
2792 struct chunk rdr;
2793 char *path;
2794 int len;
2795
2796 /* 1: create the response header */
2797 rdr.len = strlen(HTTP_302);
2798 rdr.str = trash;
2799 memcpy(rdr.str, HTTP_302, rdr.len);
2800
2801 /* 2: add the server's prefix */
2802 if (rdr.len + t->srv->rdr_len > sizeof(trash))
2803 goto cancel_redir;
2804
2805 memcpy(rdr.str + rdr.len, t->srv->rdr_pfx, t->srv->rdr_len);
2806 rdr.len += t->srv->rdr_len;
2807
2808 /* 3: add the request URI */
2809 path = http_get_path(txn);
2810 if (!path)
2811 goto cancel_redir;
2812 len = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
2813 if (rdr.len + len > sizeof(trash) - 4) /* 4 for CRLF-CRLF */
2814 goto cancel_redir;
2815
2816 memcpy(rdr.str + rdr.len, path, len);
2817 rdr.len += len;
2818 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
2819 rdr.len += 4;
2820
2821 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C, 302, &rdr);
2822 /* FIXME: we should increase a counter of redirects per server and per backend. */
2823 if (t->srv)
2824 t->srv->cum_sess++;
2825 return 1;
2826 cancel_redir:
2827 txn->status = 400;
2828 t->fe->failed_req++;
2829 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C,
2830 400, error_message(t, HTTP_ERR_400));
2831 return 1;
2832 }
2833
Willy Tarreaubaaee002006-06-26 02:48:02 +02002834 /* try to (re-)connect to the server, and fail if we expire the
2835 * number of retries.
2836 */
2837 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002838 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002839 return t->srv_state != SV_STIDLE;
2840 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002841 } while (1);
2842 }
2843 }
2844 else if (s == SV_STCONN) { /* connection in progress */
Willy Tarreau6468d922008-08-03 19:15:35 +02002845 if ((rep->flags & BF_SHUTW_STATUS) ||
2846 ((req->flags & BF_SHUTR_STATUS) &&
2847 ((req->l == 0 && !(req->flags & BF_WRITE_STATUS)) ||
Willy Tarreauc9b654b2007-05-08 14:46:53 +02002848 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002849 req->cex = TICK_ETERNITY;
Willy Tarreauf899b942008-03-28 18:09:38 +01002850 if (!(t->flags & SN_CONN_TAR)) {
2851 /* if we are in turn-around, we have already closed the FD */
2852 fd_delete(t->srv_fd);
2853 if (t->srv) {
2854 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002855 sess_change_server(t, NULL);
Willy Tarreauf899b942008-03-28 18:09:38 +01002856 }
Willy Tarreau51406232008-03-10 22:04:20 +01002857 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002858
2859 /* note that this must not return any error because it would be able to
2860 * overwrite the client_retnclose() output.
2861 */
Willy Tarreau0f772532006-12-23 20:51:41 +01002862 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002863 return 1;
2864 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002865 if (!(req->flags & BF_WRITE_STATUS) && !tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002866 return 0; /* nothing changed */
2867 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002868 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002869 /* timeout, asynchronous connect error or first write error */
2870 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2871
Willy Tarreau541b5c22008-01-06 23:34:21 +01002872 if (t->flags & SN_CONN_TAR) {
2873 /* We are doing a turn-around waiting for a new connection attempt. */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002874 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreau541b5c22008-01-06 23:34:21 +01002875 return 0;
2876 t->flags &= ~SN_CONN_TAR;
2877 }
2878 else {
2879 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01002880 if (t->srv) {
Willy Tarreau541b5c22008-01-06 23:34:21 +01002881 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002882 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01002883 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002884
Willy Tarreau541b5c22008-01-06 23:34:21 +01002885 if (!(req->flags & BF_WRITE_STATUS))
2886 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
2887 else
2888 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
2889
2890 /* ensure that we have enough retries left */
2891 if (srv_count_retry_down(t, conn_err))
2892 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002893
Willy Tarreau541b5c22008-01-06 23:34:21 +01002894 if (req->flags & BF_WRITE_ERROR) {
2895 /* we encountered an immediate connection error, and we
2896 * will have to retry connecting to the same server, most
2897 * likely leading to the same result. To avoid this, we
2898 * fake a connection timeout to retry after a turn-around
2899 * time of 1 second. We will wait in the previous if block.
2900 */
2901 t->flags |= SN_CONN_TAR;
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002902 req->cex = tick_add(now_ms, MS_TO_TICKS(1000));
Willy Tarreau541b5c22008-01-06 23:34:21 +01002903 return 0;
2904 }
2905 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002906
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002907 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002908 /* We're on our last chance, and the REDISP option was specified.
2909 * We will ignore cookie and force to balance or use the dispatcher.
2910 */
2911 /* let's try to offer this slot to anybody */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002912 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02002913 process_srv_queue(t->srv);
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002914
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01002915 /* it's left to the dispatcher to choose a server */
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002916 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
Willy Tarreau7c669d72008-06-20 15:04:11 +02002917 t->prev_srv = t->srv;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002918
2919 /* first, get a connection */
2920 if (srv_redispatch_connect(t))
Willy Tarreau00559e72008-01-06 23:46:19 +01002921 return t->srv_state != SV_STCONN;
Krzysztof Piotr Oledzki626a19b2008-02-04 02:10:09 +01002922 } else {
2923 if (t->srv)
2924 t->srv->retries++;
2925 t->be->retries++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002926 }
2927
Willy Tarreaubaaee002006-06-26 02:48:02 +02002928 do {
2929 /* Now we will try to either reconnect to the same server or
2930 * connect to another server. If the connection gets queued
2931 * because all servers are saturated, then we will go back to
2932 * the SV_STIDLE state.
2933 */
2934 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002935 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002936 return t->srv_state != SV_STCONN;
2937 }
2938
2939 /* we need to redispatch the connection to another server */
2940 if (srv_redispatch_connect(t))
2941 return t->srv_state != SV_STCONN;
2942 } while (1);
2943 }
2944 else { /* no error or write 0 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002945 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002946
2947 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2948 if (req->l == 0) /* nothing to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002949 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002950 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002951 } else /* need the right to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002952 EV_FD_SET(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002953 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
2954 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002955 /* FIXME: to prevent the server from expiring read timeouts during writes,
2956 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002957 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002958 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002959 }
2960
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002961 if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreauf161a342007-04-08 16:59:42 +02002962 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002963 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002964 t->srv_state = SV_STDATA;
Willy Tarreau718f0ef2008-08-10 16:21:32 +02002965 rep->flags |= BF_MAY_FORWARD;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002966 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
2967
2968 /* if the user wants to log as soon as possible, without counting
2969 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002970 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002971 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
Willy Tarreau42250582007-04-01 01:30:43 +02002972 tcp_sess_log(t);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002973 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002974#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002975 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002976 /* TCP splicing supported by both FE and BE */
2977 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2978 }
2979#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002980 }
2981 else {
2982 t->srv_state = SV_STHEADERS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002983 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002984 t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
2985 /* reset hdr_idx which was already initialized by the request.
2986 * right now, the http parser does it.
2987 * hdr_idx_init(&t->txn.hdr_idx);
2988 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002989 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002990 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002991 return 1;
2992 }
2993 }
2994 else if (s == SV_STHEADERS) { /* receiving server headers */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002995 /*
2996 * Now parse the partial (or complete) lines.
2997 * We will check the response syntax, and also join multi-line
2998 * headers. An index of all the lines will be elaborated while
2999 * parsing.
3000 *
3001 * For the parsing, we use a 28 states FSM.
3002 *
3003 * Here is the information we currently have :
3004 * rep->data + req->som = beginning of response
3005 * rep->data + req->eoh = end of processed headers / start of current one
3006 * rep->data + req->eol = end of current header or line (LF or CRLF)
3007 * rep->lr = first non-visited byte
3008 * rep->r = end of data
3009 */
3010
3011 int cur_idx;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003012 struct http_msg *msg = &txn->rsp;
3013 struct proxy *cur_proxy;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003014
Willy Tarreaua15645d2007-03-18 16:22:39 +01003015 if (likely(rep->lr < rep->r))
3016 http_msg_analyzer(rep, msg, &txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003017
Willy Tarreaua15645d2007-03-18 16:22:39 +01003018 /* 1: we might have to print this header in debug mode */
3019 if (unlikely((global.mode & MODE_DEBUG) &&
3020 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
3021 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
3022 char *eol, *sol;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003023
Willy Tarreaua15645d2007-03-18 16:22:39 +01003024 sol = rep->data + msg->som;
3025 eol = sol + msg->sl.rq.l;
3026 debug_hdr("srvrep", t, sol, eol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003027
Willy Tarreaua15645d2007-03-18 16:22:39 +01003028 sol += hdr_idx_first_pos(&txn->hdr_idx);
3029 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003030
Willy Tarreaua15645d2007-03-18 16:22:39 +01003031 while (cur_idx) {
3032 eol = sol + txn->hdr_idx.v[cur_idx].len;
3033 debug_hdr("srvhdr", t, sol, eol);
3034 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
3035 cur_idx = txn->hdr_idx.v[cur_idx].next;
3036 }
3037 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003038
Willy Tarreaubaaee002006-06-26 02:48:02 +02003039
Willy Tarreau66319382007-04-08 17:17:37 +02003040 if ((rep->l < rep->rlim - rep->data) && EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003041 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreaua15645d2007-03-18 16:22:39 +01003042 * full. We cannot loop here since stream_sock_read will disable it only if
3043 * rep->l == rlim-data
3044 */
Willy Tarreauce09c522008-08-11 10:35:07 +02003045 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003046 }
3047
3048
3049 /*
3050 * Now we quickly check if we have found a full valid response.
3051 * If not so, we check the FD and buffer states before leaving.
3052 * A full response is indicated by the fact that we have seen
3053 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
3054 * responses are checked first.
3055 *
3056 * Depending on whether the client is still there or not, we
3057 * may send an error response back or not. Note that normally
3058 * we should only check for HTTP status there, and check I/O
3059 * errors somewhere else.
3060 */
3061
3062 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
3063
3064 /* Invalid response, or read error or write error */
3065 if (unlikely((msg->msg_state == HTTP_MSG_ERROR) ||
3066 (req->flags & BF_WRITE_ERROR) ||
3067 (rep->flags & BF_READ_ERROR))) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003068 buffer_shutr_done(rep);
3069 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003070 fd_delete(t->srv_fd);
3071 if (t->srv) {
3072 t->srv->cur_sess--;
3073 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003074 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003075 }
3076 t->be->failed_resp++;
3077 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003078 txn->status = 502;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003079 client_return(t, error_message(t, HTTP_ERR_502));
3080 if (!(t->flags & SN_ERR_MASK))
3081 t->flags |= SN_ERR_SRVCL;
3082 if (!(t->flags & SN_FINST_MASK))
3083 t->flags |= SN_FINST_H;
3084 /* We used to have a free connection slot. Since we'll never use it,
3085 * we have to inform the server that it may be used by another session.
3086 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003087 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003088 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003089
Willy Tarreaua15645d2007-03-18 16:22:39 +01003090 return 1;
3091 }
3092
3093 /* end of client write or end of server read.
3094 * since we are in header mode, if there's no space left for headers, we
3095 * won't be able to free more later, so the session will never terminate.
3096 */
Willy Tarreau6468d922008-08-03 19:15:35 +02003097 else if (unlikely(rep->flags & (BF_READ_NULL | BF_SHUTW_STATUS) ||
Willy Tarreaua15645d2007-03-18 16:22:39 +01003098 rep->l >= rep->rlim - rep->data)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003099 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003100 buffer_shutr_done(rep);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003101 t->srv_state = SV_STSHUTR;
3102 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3103 return 1;
3104 }
3105
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003106 /* read timeout : return a 504 to the client. */
Willy Tarreauf161a342007-04-08 16:59:42 +02003107 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_RD) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003108 tick_is_expired(rep->rex, now_ms))) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003109 buffer_shutr_done(rep);
3110 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003111 fd_delete(t->srv_fd);
3112 if (t->srv) {
3113 t->srv->cur_sess--;
3114 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003115 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003116 }
3117 t->be->failed_resp++;
3118 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003119 txn->status = 504;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003120 client_return(t, error_message(t, HTTP_ERR_504));
3121 if (!(t->flags & SN_ERR_MASK))
3122 t->flags |= SN_ERR_SRVTO;
3123 if (!(t->flags & SN_FINST_MASK))
3124 t->flags |= SN_FINST_H;
3125 /* We used to have a free connection slot. Since we'll never use it,
3126 * we have to inform the server that it may be used by another session.
3127 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003128 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003129 process_srv_queue(t->srv);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003130 return 1;
3131 }
3132
3133 /* last client read and buffer empty */
3134 /* FIXME!!! here, we don't want to switch to SHUTW if the
3135 * client shuts read too early, because we may still have
3136 * some work to do on the headers.
3137 * The side-effect is that if the client completely closes its
3138 * connection during SV_STHEADER, the connection to the server
3139 * is kept until a response comes back or the timeout is reached.
3140 */
Willy Tarreau6468d922008-08-03 19:15:35 +02003141 else if (0 && /* we don't want to switch to shutw for now */
3142 unlikely(req->flags & BF_SHUTR_STATUS && (req->l == 0))) {
3143
Willy Tarreauf161a342007-04-08 16:59:42 +02003144 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003145 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003146
3147 /* We must ensure that the read part is still
3148 * alive when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003149 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003150 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003151
3152 shutdown(t->srv_fd, SHUT_WR);
3153 t->srv_state = SV_STSHUTW;
3154 return 1;
3155 }
3156
3157 /* write timeout */
3158 /* FIXME!!! here, we don't want to switch to SHUTW if the
3159 * client shuts read too early, because we may still have
3160 * some work to do on the headers.
3161 */
Willy Tarreauf161a342007-04-08 16:59:42 +02003162 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_WR) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003163 tick_is_expired(req->wex, now_ms))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003164 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003165 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003166 shutdown(t->srv_fd, SHUT_WR);
3167 /* We must ensure that the read part is still alive
3168 * when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003169 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003170 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003171
3172 t->srv_state = SV_STSHUTW;
3173 if (!(t->flags & SN_ERR_MASK))
3174 t->flags |= SN_ERR_SRVTO;
3175 if (!(t->flags & SN_FINST_MASK))
3176 t->flags |= SN_FINST_H;
3177 return 1;
3178 }
3179
3180 /*
3181 * And now the non-error cases.
3182 */
3183
3184 /* Data remaining in the request buffer.
3185 * This happens during the first pass here, and during
3186 * long posts.
3187 */
3188 else if (likely(req->l)) {
Willy Tarreau66319382007-04-08 17:17:37 +02003189 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3190 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003191 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3192 if (req->wex) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003193 /* FIXME: to prevent the server from expiring read timeouts during writes,
3194 * we refresh it. */
3195 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003196 }
3197 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003198 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003199
Willy Tarreaua15645d2007-03-18 16:22:39 +01003200 /* nothing left in the request buffer */
3201 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003202 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3203 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003204 req->wex = TICK_ETERNITY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003205 }
3206 }
3207
3208 return t->srv_state != SV_STHEADERS;
3209 }
3210
3211
3212 /*****************************************************************
3213 * More interesting part now : we know that we have a complete *
3214 * response which at least looks like HTTP. We have an indicator *
3215 * of each header's length, so we can parse them quickly. *
3216 ****************************************************************/
3217
Willy Tarreau9cdde232007-05-02 20:58:19 +02003218 /* ensure we keep this pointer to the beginning of the message */
3219 msg->sol = rep->data + msg->som;
3220
Willy Tarreaua15645d2007-03-18 16:22:39 +01003221 /*
3222 * 1: get the status code and check for cacheability.
3223 */
3224
3225 t->logs.logwait &= ~LW_RESP;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003226 txn->status = strl2ui(rep->data + msg->sl.st.c, msg->sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003227
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003228 switch (txn->status) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003229 case 200:
3230 case 203:
3231 case 206:
3232 case 300:
3233 case 301:
3234 case 410:
3235 /* RFC2616 @13.4:
3236 * "A response received with a status code of
3237 * 200, 203, 206, 300, 301 or 410 MAY be stored
3238 * by a cache (...) unless a cache-control
3239 * directive prohibits caching."
3240 *
3241 * RFC2616 @9.5: POST method :
3242 * "Responses to this method are not cacheable,
3243 * unless the response includes appropriate
3244 * Cache-Control or Expires header fields."
3245 */
3246 if (likely(txn->meth != HTTP_METH_POST) &&
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003247 (t->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
Willy Tarreau3d300592007-03-18 18:34:41 +01003248 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003249 break;
3250 default:
3251 break;
3252 }
3253
3254 /*
3255 * 2: we may need to capture headers
3256 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003257 if (unlikely((t->logs.logwait & LW_RSPHDR) && t->fe->rsp_cap))
Willy Tarreaua15645d2007-03-18 16:22:39 +01003258 capture_headers(rep->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003259 txn->rsp.cap, t->fe->rsp_cap);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003260
3261 /*
3262 * 3: we will have to evaluate the filters.
3263 * As opposed to version 1.2, now they will be evaluated in the
3264 * filters order and not in the header order. This means that
3265 * each filter has to be validated among all headers.
3266 *
3267 * Filters are tried with ->be first, then with ->fe if it is
3268 * different from ->be.
3269 */
3270
3271 t->flags &= ~SN_CONN_CLOSED; /* prepare for inspection */
3272
3273 cur_proxy = t->be;
3274 while (1) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003275 struct proxy *rule_set = cur_proxy;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003276
3277 /* try headers filters */
3278 if (rule_set->rsp_exp != NULL) {
3279 if (apply_filters_to_response(t, rep, rule_set->rsp_exp) < 0) {
3280 return_bad_resp:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003281 if (t->srv) {
3282 t->srv->cur_sess--;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003283 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003284 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003285 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003286 cur_proxy->failed_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003287 return_srv_prx_502:
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003288 buffer_shutr_done(rep);
3289 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003290 fd_delete(t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003291 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003292 txn->status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01003293 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003294 if (!(t->flags & SN_ERR_MASK))
3295 t->flags |= SN_ERR_PRXCOND;
3296 if (!(t->flags & SN_FINST_MASK))
3297 t->flags |= SN_FINST_H;
3298 /* We used to have a free connection slot. Since we'll never use it,
3299 * we have to inform the server that it may be used by another session.
3300 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003301 if (t->srv && may_dequeue_tasks(t->srv, cur_proxy))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003302 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003303 return 1;
3304 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003305 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003306
Willy Tarreaua15645d2007-03-18 16:22:39 +01003307 /* has the response been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01003308 if (txn->flags & TX_SVDENY) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003309 if (t->srv) {
3310 t->srv->cur_sess--;
3311 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003312 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003313 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003314 cur_proxy->denied_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003315 goto return_srv_prx_502;
3316 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003317
Willy Tarreaua15645d2007-03-18 16:22:39 +01003318 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003319 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01003320 !(t->flags & SN_CONN_CLOSED)) {
3321 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003322 int cur_idx, old_idx, delta, val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003323 struct hdr_idx_elem *cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003324
Willy Tarreaua15645d2007-03-18 16:22:39 +01003325 cur_next = rep->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
3326 old_idx = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003327
Willy Tarreaua15645d2007-03-18 16:22:39 +01003328 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
3329 cur_hdr = &txn->hdr_idx.v[cur_idx];
3330 cur_ptr = cur_next;
3331 cur_end = cur_ptr + cur_hdr->len;
3332 cur_next = cur_end + cur_hdr->cr + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003333
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003334 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
3335 if (val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003336 /* 3 possibilities :
3337 * - we have already set Connection: close,
3338 * so we remove this line.
3339 * - we have not yet set Connection: close,
3340 * but this line indicates close. We leave
3341 * it untouched and set the flag.
3342 * - we have not yet set Connection: close,
3343 * and this line indicates non-close. We
3344 * replace it.
3345 */
3346 if (t->flags & SN_CONN_CLOSED) {
3347 delta = buffer_replace2(rep, cur_ptr, cur_next, NULL, 0);
3348 txn->rsp.eoh += delta;
3349 cur_next += delta;
3350 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3351 txn->hdr_idx.used--;
3352 cur_hdr->len = 0;
3353 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003354 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
3355 delta = buffer_replace2(rep, cur_ptr + val, cur_end,
3356 "close", 5);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003357 cur_next += delta;
3358 cur_hdr->len += delta;
3359 txn->rsp.eoh += delta;
3360 }
3361 t->flags |= SN_CONN_CLOSED;
3362 }
3363 }
3364 old_idx = cur_idx;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003365 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003366 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003367
Willy Tarreaua15645d2007-03-18 16:22:39 +01003368 /* add response headers from the rule sets in the same order */
3369 for (cur_idx = 0; cur_idx < rule_set->nb_rspadd; cur_idx++) {
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003370 if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx,
3371 rule_set->rsp_add[cur_idx])) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003372 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003373 }
3374
Willy Tarreaua15645d2007-03-18 16:22:39 +01003375 /* check whether we're already working on the frontend */
3376 if (cur_proxy == t->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003377 break;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003378 cur_proxy = t->fe;
3379 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003380
Willy Tarreaua15645d2007-03-18 16:22:39 +01003381 /*
3382 * 4: check for server cookie.
3383 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003384 if (t->be->cookie_name || t->be->appsession_name || t->be->capture_name
3385 || (t->be->options & PR_O_CHK_CACHE))
3386 manage_server_side_cookies(t, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003387
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003388
Willy Tarreaua15645d2007-03-18 16:22:39 +01003389 /*
Willy Tarreau396d2c62007-11-04 19:30:00 +01003390 * 5: check for cache-control or pragma headers if required.
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003391 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003392 if ((t->be->options & (PR_O_COOK_NOC | PR_O_CHK_CACHE)) != 0)
3393 check_response_for_cacheability(t, rep);
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003394
3395 /*
3396 * 6: add server cookie in the response if needed
Willy Tarreaua15645d2007-03-18 16:22:39 +01003397 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003398 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
3399 (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003400 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003401
Willy Tarreaua15645d2007-03-18 16:22:39 +01003402 /* the server is known, it's not the one the client requested, we have to
3403 * insert a set-cookie here, except if we want to insert only on POST
3404 * requests and this one isn't. Note that servers which don't have cookies
3405 * (eg: some backup servers) will return a full cookie removal request.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003406 */
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003407 len = sprintf(trash, "Set-Cookie: %s=%s; path=/",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003408 t->be->cookie_name,
Willy Tarreaua15645d2007-03-18 16:22:39 +01003409 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003410
Krzysztof Piotr Oledzki1acf2172008-05-29 23:03:34 +02003411 if (t->be->cookie_domain)
3412 len += sprintf(trash+len, "; domain=%s", t->be->cookie_domain);
Krzysztof Piotr Oledzkiefe3b6f2008-05-23 23:49:32 +02003413
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003414 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3415 trash, len)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003416 goto return_bad_resp;
Willy Tarreau3d300592007-03-18 18:34:41 +01003417 txn->flags |= TX_SCK_INSERTED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003418
Willy Tarreaua15645d2007-03-18 16:22:39 +01003419 /* Here, we will tell an eventual cache on the client side that we don't
3420 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3421 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3422 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3423 */
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003424 if ((t->be->options & PR_O_COOK_NOC) && (txn->flags & TX_CACHEABLE)) {
3425
3426 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
3427
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003428 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3429 "Cache-control: private", 22)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003430 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003431 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003432 }
3433
3434
3435 /*
Willy Tarreaua15645d2007-03-18 16:22:39 +01003436 * 7: check if result will be cacheable with a cookie.
3437 * We'll block the response if security checks have caught
3438 * nasty things such as a cacheable cookie.
3439 */
Willy Tarreau3d300592007-03-18 18:34:41 +01003440 if (((txn->flags & (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) ==
3441 (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003442 (t->be->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003443
Willy Tarreaua15645d2007-03-18 16:22:39 +01003444 /* we're in presence of a cacheable response containing
3445 * a set-cookie header. We'll block it as requested by
3446 * the 'checkcache' option, and send an alert.
3447 */
3448 if (t->srv) {
3449 t->srv->cur_sess--;
3450 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003451 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003452 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003453 t->be->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003454
Willy Tarreaua15645d2007-03-18 16:22:39 +01003455 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003456 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003457 send_log(t->be, LOG_ALERT,
3458 "Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003459 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003460 goto return_srv_prx_502;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003461 }
3462
Willy Tarreaua15645d2007-03-18 16:22:39 +01003463 /*
3464 * 8: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02003465 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003466 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02003467 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003468 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02003469 if ((unlikely(msg->sl.st.v_l != 8) ||
3470 unlikely(req->data[msg->som + 7] != '0')) &&
3471 unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003472 "Connection: close", 17)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003473 goto return_bad_resp;
3474 t->flags |= SN_CONN_CLOSED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003475 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003476
Willy Tarreaubaaee002006-06-26 02:48:02 +02003477
Willy Tarreaua15645d2007-03-18 16:22:39 +01003478 /*************************************************************
3479 * OK, that's finished for the headers. We have done what we *
3480 * could. Let's switch to the DATA state. *
3481 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02003482
Willy Tarreaua15645d2007-03-18 16:22:39 +01003483 t->srv_state = SV_STDATA;
Willy Tarreau718f0ef2008-08-10 16:21:32 +02003484 rep->flags |= BF_MAY_FORWARD;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003485 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02003486 t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003487
3488 /* client connection already closed or option 'forceclose' required :
3489 * we close the server's outgoing connection right now.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003490 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003491 if ((req->l == 0) &&
Willy Tarreau6468d922008-08-03 19:15:35 +02003492 (req->flags & BF_SHUTR_STATUS || t->be->options & PR_O_FORCE_CLO)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003493 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003494 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003495
3496 /* We must ensure that the read part is still alive when switching
3497 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003498 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003499 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003500
Willy Tarreaua15645d2007-03-18 16:22:39 +01003501 shutdown(t->srv_fd, SHUT_WR);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003502 t->srv_state = SV_STSHUTW;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003503 }
3504
Willy Tarreaua15645d2007-03-18 16:22:39 +01003505#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003506 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003507 /* TCP splicing supported by both FE and BE */
3508 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003509 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003510#endif
3511 /* if the user wants to log as soon as possible, without counting
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003512 * bytes from the server, then this is the right moment. We have
3513 * to temporarily assign bytes_out to log what we currently have.
3514 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003515 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
3516 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreau8b3977f2008-01-18 11:16:32 +01003517 t->logs.bytes_out = txn->rsp.eoh;
Willy Tarreau42250582007-04-01 01:30:43 +02003518 if (t->fe->to_log & LW_REQ)
3519 http_sess_log(t);
3520 else
3521 tcp_sess_log(t);
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003522 t->logs.bytes_out = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003523 }
3524
Willy Tarreaua15645d2007-03-18 16:22:39 +01003525 /* Note: we must not try to cheat by jumping directly to DATA,
3526 * otherwise we would not let the client side wake up.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003527 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003528
3529 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003530 }
3531 else if (s == SV_STDATA) {
3532 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003533 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003534 buffer_shutr_done(rep);
3535 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003536 fd_delete(t->srv_fd);
3537 if (t->srv) {
3538 t->srv->cur_sess--;
3539 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003540 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003541 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003542 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003543 t->srv_state = SV_STCLOSE;
3544 if (!(t->flags & SN_ERR_MASK))
3545 t->flags |= SN_ERR_SRVCL;
3546 if (!(t->flags & SN_FINST_MASK))
3547 t->flags |= SN_FINST_D;
3548 /* We used to have a free connection slot. Since we'll never use it,
3549 * we have to inform the server that it may be used by another session.
3550 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003551 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003552 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003553
3554 return 1;
3555 }
3556 /* last read, or end of client write */
Willy Tarreau6468d922008-08-03 19:15:35 +02003557 else if (rep->flags & (BF_READ_NULL | BF_SHUTW_STATUS)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003558 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003559 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003560 t->srv_state = SV_STSHUTR;
3561 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3562 return 1;
3563 }
3564 /* end of client read and no more data to send */
Willy Tarreau6468d922008-08-03 19:15:35 +02003565 else if (req->flags & BF_SHUTR_STATUS && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003566 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003567 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003568 shutdown(t->srv_fd, SHUT_WR);
3569 /* We must ensure that the read part is still alive when switching
3570 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003571 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003572 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003573
3574 t->srv_state = SV_STSHUTW;
3575 return 1;
3576 }
3577 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003578 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003579 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003580 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003581 t->srv_state = SV_STSHUTR;
3582 if (!(t->flags & SN_ERR_MASK))
3583 t->flags |= SN_ERR_SRVTO;
3584 if (!(t->flags & SN_FINST_MASK))
3585 t->flags |= SN_FINST_D;
3586 return 1;
3587 }
3588 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003589 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003590 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003591 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003592 shutdown(t->srv_fd, SHUT_WR);
3593 /* We must ensure that the read part is still alive when switching
3594 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003595 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003596 rep->cex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003597 t->srv_state = SV_STSHUTW;
3598 if (!(t->flags & SN_ERR_MASK))
3599 t->flags |= SN_ERR_SRVTO;
3600 if (!(t->flags & SN_FINST_MASK))
3601 t->flags |= SN_FINST_D;
3602 return 1;
3603 }
3604
3605 /* recompute request time-outs */
3606 if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003607 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3608 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003609 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003610 }
3611 }
3612 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau66319382007-04-08 17:17:37 +02003613 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3614 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003615 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3616 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003617 /* FIXME: to prevent the server from expiring read timeouts during writes,
3618 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02003619 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003620 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003621 }
3622 }
3623
3624 /* recompute response time-outs */
3625 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003626 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003627 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003628 }
3629 }
3630 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003631 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003632 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003633 }
3634 }
3635
3636 return 0; /* other cases change nothing */
3637 }
3638 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003639 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003640 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003641 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003642 fd_delete(t->srv_fd);
3643 if (t->srv) {
3644 t->srv->cur_sess--;
3645 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003646 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003647 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003648 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003649 //close(t->srv_fd);
3650 t->srv_state = SV_STCLOSE;
3651 if (!(t->flags & SN_ERR_MASK))
3652 t->flags |= SN_ERR_SRVCL;
3653 if (!(t->flags & SN_FINST_MASK))
3654 t->flags |= SN_FINST_D;
3655 /* We used to have a free connection slot. Since we'll never use it,
3656 * we have to inform the server that it may be used by another session.
3657 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003658 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003659 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003660
3661 return 1;
3662 }
Willy Tarreau6468d922008-08-03 19:15:35 +02003663 else if (req->flags & BF_SHUTR_STATUS && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003664 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003665 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003666 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003667 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003668 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003669 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003670 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003671 //close(t->srv_fd);
3672 t->srv_state = SV_STCLOSE;
3673 /* We used to have a free connection slot. Since we'll never use it,
3674 * we have to inform the server that it may be used by another session.
3675 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003676 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003677 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003678
3679 return 1;
3680 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003681 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003682 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003683 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003684 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003685 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003686 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003687 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003688 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003689 //close(t->srv_fd);
3690 t->srv_state = SV_STCLOSE;
3691 if (!(t->flags & SN_ERR_MASK))
3692 t->flags |= SN_ERR_SRVTO;
3693 if (!(t->flags & SN_FINST_MASK))
3694 t->flags |= SN_FINST_D;
3695 /* We used to have a free connection slot. Since we'll never use it,
3696 * we have to inform the server that it may be used by another session.
3697 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003698 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003699 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003700
3701 return 1;
3702 }
3703 else if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003704 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3705 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003706 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003707 }
3708 }
3709 else { /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02003710 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3711 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003712 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003713 }
3714 }
3715 return 0;
3716 }
3717 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003718 if (rep->flags & BF_READ_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003719 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003720 buffer_shutr_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003721 fd_delete(t->srv_fd);
3722 if (t->srv) {
3723 t->srv->cur_sess--;
3724 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003725 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003726 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003727 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003728 //close(t->srv_fd);
3729 t->srv_state = SV_STCLOSE;
3730 if (!(t->flags & SN_ERR_MASK))
3731 t->flags |= SN_ERR_SRVCL;
3732 if (!(t->flags & SN_FINST_MASK))
3733 t->flags |= SN_FINST_D;
3734 /* We used to have a free connection slot. Since we'll never use it,
3735 * we have to inform the server that it may be used by another session.
3736 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003737 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003738 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003739
3740 return 1;
3741 }
Willy Tarreau6468d922008-08-03 19:15:35 +02003742 else if (rep->flags & (BF_READ_NULL | BF_SHUTW_STATUS)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003743 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003744 buffer_shutr_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003745 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003746 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003747 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003748 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003749 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003750 //close(t->srv_fd);
3751 t->srv_state = SV_STCLOSE;
3752 /* We used to have a free connection slot. Since we'll never use it,
3753 * we have to inform the server that it may be used by another session.
3754 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003755 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003756 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003757
3758 return 1;
3759 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003760 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003761 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003762 buffer_shutr_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003763 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003764 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003765 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003766 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003767 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003768 //close(t->srv_fd);
3769 t->srv_state = SV_STCLOSE;
3770 if (!(t->flags & SN_ERR_MASK))
3771 t->flags |= SN_ERR_SRVTO;
3772 if (!(t->flags & SN_FINST_MASK))
3773 t->flags |= SN_FINST_D;
3774 /* We used to have a free connection slot. Since we'll never use it,
3775 * we have to inform the server that it may be used by another session.
3776 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003777 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003778 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003779
3780 return 1;
3781 }
3782 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003783 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003784 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003785 }
3786 }
3787 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003788 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003789 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003790 }
3791 }
3792 return 0;
3793 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003794 else if (s == SV_STANALYZE){
3795 /* this server state is set by the client to study the body for server assignment */
3796
3797 /* Have we been through this long enough to timeout? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003798 if (!tick_is_expired(req->rex, now_ms)) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003799 /* balance url_param check_post should have been the only to get into this.
3800 * just wait for data, check to compare how much
3801 */
3802 struct http_msg * msg = &t->txn.req;
3803 unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 :msg->eoh + 1;
Willy Tarreaufb0528b2008-08-11 00:21:56 +02003804 unsigned long len = req->l - body;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003805 long long limit = t->be->url_param_post_limit;
3806 struct hdr_ctx ctx;
3807 ctx.idx = 0;
3808 /* now if we have a length, we'll take the hint */
3809 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
3810 if ( ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",ctx.vlen)==0) {
3811 unsigned int chunk = 0;
Willy Tarreaufb0528b2008-08-11 00:21:56 +02003812 while ( body < req->l && !HTTP_IS_CRLF(msg->sol[body])) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003813 char c = msg->sol[body];
3814 if (ishex(c)) {
3815 unsigned int hex = toupper(c) - '0';
3816 if ( hex > 9 )
3817 hex -= 'A' - '9' - 1;
3818 chunk = (chunk << 4) | hex;
3819 }
3820 else break;
3821 body++;
3822 len--;
3823 }
Willy Tarreaufb0528b2008-08-11 00:21:56 +02003824 if ( body + 2 >= req->l )
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003825 return 0; /* end of buffer? data missing! */
3826
3827 if ( memcmp(msg->sol+body, "\r\n", 2) != 0 )
3828 return 0; /* chunked encoding len ends with CRLF, and we don't have it yet */
3829
3830 /* if we support more then one chunk here, we have to do it again when assigning server
3831 1. how much entity data do we have? new var
3832 2. should save entity_start, entity_cursor, elen & rlen in req; so we don't repeat scanning here
3833 3. test if elen > limit, or set new limit to elen if 0 (end of entity found)
3834 */
3835
3836 if ( chunk < limit )
3837 limit = chunk; /* only reading one chunk */
3838 } else {
3839 if ( msg->hdr_content_len < limit )
3840 limit = msg->hdr_content_len;
3841 }
3842 if ( len < limit )
3843 return 0;
3844 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003845 t->srv_state = SV_STIDLE;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003846 return 1;
3847 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003848 else { /* SV_STCLOSE : nothing to do */
3849 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
3850 int len;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003851 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003852 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003853 write(1, trash, len);
3854 }
3855 return 0;
3856 }
3857 return 0;
3858}
3859
3860
3861/*
3862 * Produces data for the session <s> depending on its source. Expects to be
3863 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3864 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3865 * session, which it uses to keep on being called when there is free space in
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003866 * the buffer, or simply by letting an empty buffer upon return. It returns 1
Willy Tarreaubaaee002006-06-26 02:48:02 +02003867 * if it changes the session state from CL_STSHUTR, otherwise 0.
3868 */
3869int produce_content(struct session *s)
3870{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003871 if (s->data_source == DATA_SRC_NONE) {
3872 s->flags &= ~SN_SELF_GEN;
3873 return 1;
3874 }
3875 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003876 /* dump server statistics */
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01003877 int ret = stats_dump_http(s, s->be->uri_auth);
Willy Tarreau91861262007-10-17 17:06:05 +02003878 if (ret >= 0)
3879 return ret;
3880 /* -1 indicates an error */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003881 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003882
Willy Tarreau91861262007-10-17 17:06:05 +02003883 /* unknown data source or internal error */
3884 s->txn.status = 500;
3885 client_retnclose(s, error_message(s, HTTP_ERR_500));
3886 if (!(s->flags & SN_ERR_MASK))
3887 s->flags |= SN_ERR_PRXCOND;
3888 if (!(s->flags & SN_FINST_MASK))
3889 s->flags |= SN_FINST_R;
3890 s->flags &= ~SN_SELF_GEN;
3891 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003892}
3893
3894
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003895/* Iterate the same filter through all request headers.
3896 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003897 * Since it can manage the switch to another backend, it updates the per-proxy
3898 * DENY stats.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003899 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003900int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003901{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003902 char term;
3903 char *cur_ptr, *cur_end, *cur_next;
3904 int cur_idx, old_idx, last_hdr;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003905 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003906 struct hdr_idx_elem *cur_hdr;
3907 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003908
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003909 last_hdr = 0;
3910
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003911 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003912 old_idx = 0;
3913
3914 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01003915 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003916 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003917 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003918 (exp->action == ACT_ALLOW ||
3919 exp->action == ACT_DENY ||
3920 exp->action == ACT_TARPIT))
3921 return 0;
3922
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003923 cur_idx = txn->hdr_idx.v[old_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003924 if (!cur_idx)
3925 break;
3926
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003927 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003928 cur_ptr = cur_next;
3929 cur_end = cur_ptr + cur_hdr->len;
3930 cur_next = cur_end + cur_hdr->cr + 1;
3931
3932 /* Now we have one header between cur_ptr and cur_end,
3933 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003934 */
3935
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003936 /* The annoying part is that pattern matching needs
3937 * that we modify the contents to null-terminate all
3938 * strings before testing them.
3939 */
3940
3941 term = *cur_end;
3942 *cur_end = '\0';
3943
3944 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3945 switch (exp->action) {
3946 case ACT_SETBE:
3947 /* It is not possible to jump a second time.
3948 * FIXME: should we return an HTTP/500 here so that
3949 * the admin knows there's a problem ?
3950 */
3951 if (t->be != t->fe)
3952 break;
3953
3954 /* Swithing Proxy */
3955 t->be = (struct proxy *) exp->replace;
3956
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003957 /* right now, the backend switch is not overly complicated
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003958 * because we have associated req_cap and rsp_cap to the
3959 * frontend, and the beconn will be updated later.
3960 */
3961
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003962 t->rep->rto = t->req->wto = t->be->timeout.server;
3963 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02003964 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003965 last_hdr = 1;
3966 break;
3967
3968 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003969 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003970 last_hdr = 1;
3971 break;
3972
3973 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003974 txn->flags |= TX_CLDENY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003975 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003976 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003977 break;
3978
3979 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003980 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003981 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003982 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003983 break;
3984
3985 case ACT_REPLACE:
3986 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3987 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3988 /* FIXME: if the user adds a newline in the replacement, the
3989 * index will not be recalculated for now, and the new line
3990 * will not be counted as a new header.
3991 */
3992
3993 cur_end += delta;
3994 cur_next += delta;
3995 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003996 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003997 break;
3998
3999 case ACT_REMOVE:
4000 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
4001 cur_next += delta;
4002
4003 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004004 txn->req.eoh += delta;
4005 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4006 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004007 cur_hdr->len = 0;
4008 cur_end = NULL; /* null-term has been rewritten */
4009 break;
4010
4011 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004012 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004013 if (cur_end)
4014 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004015
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004016 /* keep the link from this header to next one in case of later
4017 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004018 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004019 old_idx = cur_idx;
4020 }
4021 return 0;
4022}
4023
4024
4025/* Apply the filter to the request line.
4026 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4027 * or -1 if a replacement resulted in an invalid request line.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004028 * Since it can manage the switch to another backend, it updates the per-proxy
4029 * DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004030 */
4031int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
4032{
4033 char term;
4034 char *cur_ptr, *cur_end;
4035 int done;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004036 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004037 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004038
Willy Tarreau58f10d72006-12-04 02:26:12 +01004039
Willy Tarreau3d300592007-03-18 18:34:41 +01004040 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004041 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004042 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004043 (exp->action == ACT_ALLOW ||
4044 exp->action == ACT_DENY ||
4045 exp->action == ACT_TARPIT))
4046 return 0;
4047 else if (exp->action == ACT_REMOVE)
4048 return 0;
4049
4050 done = 0;
4051
Willy Tarreau9cdde232007-05-02 20:58:19 +02004052 cur_ptr = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004053 cur_end = cur_ptr + txn->req.sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004054
4055 /* Now we have the request line between cur_ptr and cur_end */
4056
4057 /* The annoying part is that pattern matching needs
4058 * that we modify the contents to null-terminate all
4059 * strings before testing them.
4060 */
4061
4062 term = *cur_end;
4063 *cur_end = '\0';
4064
4065 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4066 switch (exp->action) {
4067 case ACT_SETBE:
4068 /* It is not possible to jump a second time.
4069 * FIXME: should we return an HTTP/500 here so that
4070 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01004071 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004072 if (t->be != t->fe)
4073 break;
4074
4075 /* Swithing Proxy */
4076 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004077
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004078 /* right now, the backend switch is not too much complicated
4079 * because we have associated req_cap and rsp_cap to the
4080 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004081 */
4082
Willy Tarreaud7c30f92007-12-03 01:38:36 +01004083 t->rep->rto = t->req->wto = t->be->timeout.server;
4084 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02004085 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004086 done = 1;
4087 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004088
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004089 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004090 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004091 done = 1;
4092 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004093
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004094 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004095 txn->flags |= TX_CLDENY;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004096 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004097 done = 1;
4098 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004099
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004100 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01004101 txn->flags |= TX_CLTARPIT;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004102 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004103 done = 1;
4104 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004105
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004106 case ACT_REPLACE:
4107 *cur_end = term; /* restore the string terminator */
4108 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4109 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
4110 /* FIXME: if the user adds a newline in the replacement, the
4111 * index will not be recalculated for now, and the new line
4112 * will not be counted as a new header.
4113 */
Willy Tarreaua496b602006-12-17 23:15:24 +01004114
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004115 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004116 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01004117
Willy Tarreau9cdde232007-05-02 20:58:19 +02004118 txn->req.sol = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004119 cur_end = (char *)http_parse_reqline(&txn->req, req->data,
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004120 HTTP_MSG_RQMETH,
4121 cur_ptr, cur_end + 1,
4122 NULL, NULL);
4123 if (unlikely(!cur_end))
4124 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01004125
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004126 /* we have a full request and we know that we have either a CR
4127 * or an LF at <ptr>.
4128 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004129 txn->meth = find_http_meth(cur_ptr, txn->req.sl.rq.m_l);
4130 hdr_idx_set_start(&txn->hdr_idx, txn->req.sl.rq.l, *cur_end == '\r');
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004131 /* there is no point trying this regex on headers */
4132 return 1;
4133 }
4134 }
4135 *cur_end = term; /* restore the string terminator */
4136 return done;
4137}
Willy Tarreau97de6242006-12-27 17:18:38 +01004138
Willy Tarreau58f10d72006-12-04 02:26:12 +01004139
Willy Tarreau58f10d72006-12-04 02:26:12 +01004140
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004141/*
4142 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
4143 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
Willy Tarreaua15645d2007-03-18 16:22:39 +01004144 * unparsable request. Since it can manage the switch to another backend, it
4145 * updates the per-proxy DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004146 */
4147int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
4148{
Willy Tarreau3d300592007-03-18 18:34:41 +01004149 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004150 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004151 while (exp && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004152 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004153
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004154 /*
4155 * The interleaving of transformations and verdicts
4156 * makes it difficult to decide to continue or stop
4157 * the evaluation.
4158 */
4159
Willy Tarreau3d300592007-03-18 18:34:41 +01004160 if ((txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004161 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4162 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
4163 exp = exp->next;
4164 continue;
4165 }
4166
4167 /* Apply the filter to the request line. */
4168 ret = apply_filter_to_req_line(t, req, exp);
4169 if (unlikely(ret < 0))
4170 return -1;
4171
4172 if (likely(ret == 0)) {
4173 /* The filter did not match the request, it can be
4174 * iterated through all headers.
4175 */
4176 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004177 }
4178 exp = exp->next;
4179 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004180 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004181}
4182
4183
Willy Tarreaua15645d2007-03-18 16:22:39 +01004184
Willy Tarreau58f10d72006-12-04 02:26:12 +01004185/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004186 * Manage client-side cookie. It can impact performance by about 2% so it is
4187 * desirable to call it only when needed.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004188 */
4189void manage_client_side_cookies(struct session *t, struct buffer *req)
4190{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004191 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004192 char *p1, *p2, *p3, *p4;
4193 char *del_colon, *del_cookie, *colon;
4194 int app_cookies;
4195
4196 appsess *asession_temp = NULL;
4197 appsess local_asession;
4198
4199 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004200 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004201
Willy Tarreau2a324282006-12-05 00:05:46 +01004202 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004203 * we start with the start line.
4204 */
Willy Tarreau83969f42007-01-22 08:55:47 +01004205 old_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004206 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004207
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004208 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004209 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004210 int val;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004211
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004212 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01004213 cur_ptr = cur_next;
4214 cur_end = cur_ptr + cur_hdr->len;
4215 cur_next = cur_end + cur_hdr->cr + 1;
4216
4217 /* We have one full header between cur_ptr and cur_end, and the
4218 * next header starts at cur_next. We're only interested in
4219 * "Cookie:" headers.
4220 */
4221
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004222 val = http_header_match2(cur_ptr, cur_end, "Cookie", 6);
4223 if (!val) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004224 old_idx = cur_idx;
4225 continue;
4226 }
4227
4228 /* Now look for cookies. Conforming to RFC2109, we have to support
4229 * attributes whose name begin with a '$', and associate them with
4230 * the right cookie, if we want to delete this cookie.
4231 * So there are 3 cases for each cookie read :
4232 * 1) it's a special attribute, beginning with a '$' : ignore it.
4233 * 2) it's a server id cookie that we *MAY* want to delete : save
4234 * some pointers on it (last semi-colon, beginning of cookie...)
4235 * 3) it's an application cookie : we *MAY* have to delete a previous
4236 * "special" cookie.
4237 * At the end of loop, if a "special" cookie remains, we may have to
4238 * remove it. If no application cookie persists in the header, we
4239 * *MUST* delete it
4240 */
4241
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004242 colon = p1 = cur_ptr + val; /* first non-space char after 'Cookie:' */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004243
Willy Tarreau58f10d72006-12-04 02:26:12 +01004244 /* del_cookie == NULL => nothing to be deleted */
4245 del_colon = del_cookie = NULL;
4246 app_cookies = 0;
4247
4248 while (p1 < cur_end) {
4249 /* skip spaces and colons, but keep an eye on these ones */
4250 while (p1 < cur_end) {
4251 if (*p1 == ';' || *p1 == ',')
4252 colon = p1;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004253 else if (!isspace((unsigned char)*p1))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004254 break;
4255 p1++;
4256 }
4257
4258 if (p1 == cur_end)
4259 break;
4260
4261 /* p1 is at the beginning of the cookie name */
4262 p2 = p1;
4263 while (p2 < cur_end && *p2 != '=')
4264 p2++;
4265
4266 if (p2 == cur_end)
4267 break;
4268
4269 p3 = p2 + 1; /* skips the '=' sign */
4270 if (p3 == cur_end)
4271 break;
4272
4273 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004274 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';' && *p4 != ',')
Willy Tarreau58f10d72006-12-04 02:26:12 +01004275 p4++;
4276
4277 /* here, we have the cookie name between p1 and p2,
4278 * and its value between p3 and p4.
4279 * we can process it :
4280 *
4281 * Cookie: NAME=VALUE;
4282 * | || || |
4283 * | || || +--> p4
4284 * | || |+-------> p3
4285 * | || +--------> p2
4286 * | |+------------> p1
4287 * | +-------------> colon
4288 * +--------------------> cur_ptr
4289 */
4290
4291 if (*p1 == '$') {
4292 /* skip this one */
4293 }
4294 else {
4295 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004296 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004297 txn->cli_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004298 (p4 - p1 >= t->fe->capture_namelen) &&
4299 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004300 int log_len = p4 - p1;
4301
Willy Tarreau086b3b42007-05-13 21:45:51 +02004302 if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004303 Alert("HTTP logging : out of memory.\n");
4304 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004305 if (log_len > t->fe->capture_len)
4306 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004307 memcpy(txn->cli_cookie, p1, log_len);
4308 txn->cli_cookie[log_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004309 }
4310 }
4311
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004312 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4313 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004314 /* Cool... it's the right one */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004315 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004316 char *delim;
4317
4318 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4319 * have the server ID betweek p3 and delim, and the original cookie between
4320 * delim+1 and p4. Otherwise, delim==p4 :
4321 *
4322 * Cookie: NAME=SRV~VALUE;
4323 * | || || | |
4324 * | || || | +--> p4
4325 * | || || +--------> delim
4326 * | || |+-----------> p3
4327 * | || +------------> p2
4328 * | |+----------------> p1
4329 * | +-----------------> colon
4330 * +------------------------> cur_ptr
4331 */
4332
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004333 if (t->be->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004334 for (delim = p3; delim < p4; delim++)
4335 if (*delim == COOKIE_DELIM)
4336 break;
4337 }
4338 else
4339 delim = p4;
4340
4341
4342 /* Here, we'll look for the first running server which supports the cookie.
4343 * This allows to share a same cookie between several servers, for example
4344 * to dedicate backup servers to specific servers only.
4345 * However, to prevent clients from sticking to cookie-less backup server
4346 * when they have incidentely learned an empty cookie, we simply ignore
4347 * empty cookies and mark them as invalid.
4348 */
4349 if (delim == p3)
4350 srv = NULL;
4351
4352 while (srv) {
Willy Tarreau92f2ab12007-02-02 22:14:47 +01004353 if (srv->cookie && (srv->cklen == delim - p3) &&
4354 !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004355 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004356 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004357 txn->flags &= ~TX_CK_MASK;
4358 txn->flags |= TX_CK_VALID;
4359 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004360 t->srv = srv;
4361 break;
4362 } else {
4363 /* we found a server, but it's down */
Willy Tarreau3d300592007-03-18 18:34:41 +01004364 txn->flags &= ~TX_CK_MASK;
4365 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004366 }
4367 }
4368 srv = srv->next;
4369 }
4370
Willy Tarreau3d300592007-03-18 18:34:41 +01004371 if (!srv && !(txn->flags & TX_CK_DOWN)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004372 /* no server matched this cookie */
Willy Tarreau3d300592007-03-18 18:34:41 +01004373 txn->flags &= ~TX_CK_MASK;
4374 txn->flags |= TX_CK_INVALID;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004375 }
4376
4377 /* depending on the cookie mode, we may have to either :
4378 * - delete the complete cookie if we're in insert+indirect mode, so that
4379 * the server never sees it ;
4380 * - remove the server id from the cookie value, and tag the cookie as an
4381 * application cookie so that it does not get accidentely removed later,
4382 * if we're in cookie prefix mode
4383 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004384 if ((t->be->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004385 int delta; /* negative */
4386
4387 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
4388 p4 += delta;
4389 cur_end += delta;
4390 cur_next += delta;
4391 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004392 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004393
4394 del_cookie = del_colon = NULL;
4395 app_cookies++; /* protect the header from deletion */
4396 }
4397 else if (del_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004398 (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 +01004399 del_cookie = p1;
4400 del_colon = colon;
4401 }
4402 } else {
4403 /* now we know that we must keep this cookie since it's
4404 * not ours. But if we wanted to delete our cookie
4405 * earlier, we cannot remove the complete header, but we
4406 * can remove the previous block itself.
4407 */
4408 app_cookies++;
4409
4410 if (del_cookie != NULL) {
4411 int delta; /* negative */
4412
4413 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
4414 p4 += delta;
4415 cur_end += delta;
4416 cur_next += delta;
4417 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004418 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004419 del_cookie = del_colon = NULL;
4420 }
4421 }
4422
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004423 if ((t->be->appsession_name != NULL) &&
4424 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004425 /* first, let's see if the cookie is our appcookie*/
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004426
Willy Tarreau58f10d72006-12-04 02:26:12 +01004427 /* Cool... it's the right one */
4428
4429 asession_temp = &local_asession;
4430
Willy Tarreau63963c62007-05-13 21:29:55 +02004431 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004432 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4433 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4434 return;
4435 }
4436
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004437 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4438 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004439 asession_temp->serverid = NULL;
Willy Tarreau51041c72007-09-09 21:56:53 +02004440
Willy Tarreau58f10d72006-12-04 02:26:12 +01004441 /* only do insert, if lookup fails */
Willy Tarreau51041c72007-09-09 21:56:53 +02004442 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4443 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004444 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004445 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004446 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004447 Alert("Not enough memory process_cli():asession:calloc().\n");
4448 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4449 return;
4450 }
4451
4452 asession_temp->sessid = local_asession.sessid;
4453 asession_temp->serverid = local_asession.serverid;
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004454 asession_temp->request_count = 0;
Willy Tarreau51041c72007-09-09 21:56:53 +02004455 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004456 } else {
4457 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004458 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004459 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004460 if (asession_temp->serverid == NULL) {
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004461 /* TODO redispatch request */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004462 Alert("Found Application Session without matching server.\n");
4463 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004464 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004465 while (srv) {
4466 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004467 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004468 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004469 txn->flags &= ~TX_CK_MASK;
4470 txn->flags |= TX_CK_VALID;
4471 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004472 t->srv = srv;
4473 break;
4474 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01004475 txn->flags &= ~TX_CK_MASK;
4476 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004477 }
4478 }
4479 srv = srv->next;
4480 }/* end while(srv) */
4481 }/* end else if server == NULL */
4482
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004483 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004484 asession_temp->request_count++;
4485#if defined(DEBUG_HASH)
4486 Alert("manage_client_side_cookies\n");
4487 appsession_hash_dump(&(t->be->htbl_proxy));
4488#endif
Willy Tarreau58f10d72006-12-04 02:26:12 +01004489 }/* end if ((t->proxy->appsession_name != NULL) ... */
4490 }
4491
4492 /* we'll have to look for another cookie ... */
4493 p1 = p4;
4494 } /* while (p1 < cur_end) */
4495
4496 /* There's no more cookie on this line.
4497 * We may have marked the last one(s) for deletion.
4498 * We must do this now in two ways :
4499 * - if there is no app cookie, we simply delete the header ;
4500 * - if there are app cookies, we must delete the end of the
4501 * string properly, including the colon/semi-colon before
4502 * the cookie name.
4503 */
4504 if (del_cookie != NULL) {
4505 int delta;
4506 if (app_cookies) {
4507 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
4508 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004509 cur_hdr->len += delta;
4510 } else {
4511 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004512
4513 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004514 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4515 txn->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004516 cur_hdr->len = 0;
4517 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01004518 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004519 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004520 }
4521
4522 /* keep the link from this header to next one */
4523 old_idx = cur_idx;
4524 } /* end of cookie processing on this header */
4525}
4526
4527
Willy Tarreaua15645d2007-03-18 16:22:39 +01004528/* Iterate the same filter through all response headers contained in <rtr>.
4529 * Returns 1 if this filter can be stopped upon return, otherwise 0.
4530 */
4531int apply_filter_to_resp_headers(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4532{
4533 char term;
4534 char *cur_ptr, *cur_end, *cur_next;
4535 int cur_idx, old_idx, last_hdr;
4536 struct http_txn *txn = &t->txn;
4537 struct hdr_idx_elem *cur_hdr;
4538 int len, delta;
4539
4540 last_hdr = 0;
4541
4542 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4543 old_idx = 0;
4544
4545 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004546 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004547 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004548 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004549 (exp->action == ACT_ALLOW ||
4550 exp->action == ACT_DENY))
4551 return 0;
4552
4553 cur_idx = txn->hdr_idx.v[old_idx].next;
4554 if (!cur_idx)
4555 break;
4556
4557 cur_hdr = &txn->hdr_idx.v[cur_idx];
4558 cur_ptr = cur_next;
4559 cur_end = cur_ptr + cur_hdr->len;
4560 cur_next = cur_end + cur_hdr->cr + 1;
4561
4562 /* Now we have one header between cur_ptr and cur_end,
4563 * and the next header starts at cur_next.
4564 */
4565
4566 /* The annoying part is that pattern matching needs
4567 * that we modify the contents to null-terminate all
4568 * strings before testing them.
4569 */
4570
4571 term = *cur_end;
4572 *cur_end = '\0';
4573
4574 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4575 switch (exp->action) {
4576 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004577 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004578 last_hdr = 1;
4579 break;
4580
4581 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004582 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004583 last_hdr = 1;
4584 break;
4585
4586 case ACT_REPLACE:
4587 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4588 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4589 /* FIXME: if the user adds a newline in the replacement, the
4590 * index will not be recalculated for now, and the new line
4591 * will not be counted as a new header.
4592 */
4593
4594 cur_end += delta;
4595 cur_next += delta;
4596 cur_hdr->len += delta;
4597 txn->rsp.eoh += delta;
4598 break;
4599
4600 case ACT_REMOVE:
4601 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4602 cur_next += delta;
4603
4604 /* FIXME: this should be a separate function */
4605 txn->rsp.eoh += delta;
4606 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4607 txn->hdr_idx.used--;
4608 cur_hdr->len = 0;
4609 cur_end = NULL; /* null-term has been rewritten */
4610 break;
4611
4612 }
4613 }
4614 if (cur_end)
4615 *cur_end = term; /* restore the string terminator */
4616
4617 /* keep the link from this header to next one in case of later
4618 * removal of next header.
4619 */
4620 old_idx = cur_idx;
4621 }
4622 return 0;
4623}
4624
4625
4626/* Apply the filter to the status line in the response buffer <rtr>.
4627 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4628 * or -1 if a replacement resulted in an invalid status line.
4629 */
4630int apply_filter_to_sts_line(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4631{
4632 char term;
4633 char *cur_ptr, *cur_end;
4634 int done;
4635 struct http_txn *txn = &t->txn;
4636 int len, delta;
4637
4638
Willy Tarreau3d300592007-03-18 18:34:41 +01004639 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004640 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004641 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004642 (exp->action == ACT_ALLOW ||
4643 exp->action == ACT_DENY))
4644 return 0;
4645 else if (exp->action == ACT_REMOVE)
4646 return 0;
4647
4648 done = 0;
4649
Willy Tarreau9cdde232007-05-02 20:58:19 +02004650 cur_ptr = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004651 cur_end = cur_ptr + txn->rsp.sl.rq.l;
4652
4653 /* Now we have the status line between cur_ptr and cur_end */
4654
4655 /* The annoying part is that pattern matching needs
4656 * that we modify the contents to null-terminate all
4657 * strings before testing them.
4658 */
4659
4660 term = *cur_end;
4661 *cur_end = '\0';
4662
4663 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4664 switch (exp->action) {
4665 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004666 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004667 done = 1;
4668 break;
4669
4670 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004671 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004672 done = 1;
4673 break;
4674
4675 case ACT_REPLACE:
4676 *cur_end = term; /* restore the string terminator */
4677 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4678 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4679 /* FIXME: if the user adds a newline in the replacement, the
4680 * index will not be recalculated for now, and the new line
4681 * will not be counted as a new header.
4682 */
4683
4684 txn->rsp.eoh += delta;
4685 cur_end += delta;
4686
Willy Tarreau9cdde232007-05-02 20:58:19 +02004687 txn->rsp.sol = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004688 cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data,
Willy Tarreau02785762007-04-03 14:45:44 +02004689 HTTP_MSG_RPVER,
Willy Tarreaua15645d2007-03-18 16:22:39 +01004690 cur_ptr, cur_end + 1,
4691 NULL, NULL);
4692 if (unlikely(!cur_end))
4693 return -1;
4694
4695 /* we have a full respnse and we know that we have either a CR
4696 * or an LF at <ptr>.
4697 */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004698 txn->status = strl2ui(rtr->data + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004699 hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.rq.l, *cur_end == '\r');
4700 /* there is no point trying this regex on headers */
4701 return 1;
4702 }
4703 }
4704 *cur_end = term; /* restore the string terminator */
4705 return done;
4706}
4707
4708
4709
4710/*
4711 * Apply all the resp filters <exp> to all headers in buffer <rtr> of session <t>.
4712 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
4713 * unparsable response.
4714 */
4715int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4716{
Willy Tarreau3d300592007-03-18 18:34:41 +01004717 struct http_txn *txn = &t->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004718 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004719 while (exp && !(txn->flags & TX_SVDENY)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004720 int ret;
4721
4722 /*
4723 * The interleaving of transformations and verdicts
4724 * makes it difficult to decide to continue or stop
4725 * the evaluation.
4726 */
4727
Willy Tarreau3d300592007-03-18 18:34:41 +01004728 if ((txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004729 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4730 exp->action == ACT_PASS)) {
4731 exp = exp->next;
4732 continue;
4733 }
4734
4735 /* Apply the filter to the status line. */
4736 ret = apply_filter_to_sts_line(t, rtr, exp);
4737 if (unlikely(ret < 0))
4738 return -1;
4739
4740 if (likely(ret == 0)) {
4741 /* The filter did not match the response, it can be
4742 * iterated through all headers.
4743 */
4744 apply_filter_to_resp_headers(t, rtr, exp);
4745 }
4746 exp = exp->next;
4747 }
4748 return 0;
4749}
4750
4751
4752
4753/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004754 * Manage server-side cookies. It can impact performance by about 2% so it is
4755 * desirable to call it only when needed.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004756 */
4757void manage_server_side_cookies(struct session *t, struct buffer *rtr)
4758{
4759 struct http_txn *txn = &t->txn;
4760 char *p1, *p2, *p3, *p4;
4761
4762 appsess *asession_temp = NULL;
4763 appsess local_asession;
4764
4765 char *cur_ptr, *cur_end, *cur_next;
4766 int cur_idx, old_idx, delta;
4767
Willy Tarreaua15645d2007-03-18 16:22:39 +01004768 /* Iterate through the headers.
4769 * we start with the start line.
4770 */
4771 old_idx = 0;
4772 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4773
4774 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
4775 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004776 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004777
4778 cur_hdr = &txn->hdr_idx.v[cur_idx];
4779 cur_ptr = cur_next;
4780 cur_end = cur_ptr + cur_hdr->len;
4781 cur_next = cur_end + cur_hdr->cr + 1;
4782
4783 /* We have one full header between cur_ptr and cur_end, and the
4784 * next header starts at cur_next. We're only interested in
4785 * "Cookie:" headers.
4786 */
4787
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004788 val = http_header_match2(cur_ptr, cur_end, "Set-Cookie", 10);
4789 if (!val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004790 old_idx = cur_idx;
4791 continue;
4792 }
4793
4794 /* OK, right now we know we have a set-cookie at cur_ptr */
Willy Tarreau3d300592007-03-18 18:34:41 +01004795 txn->flags |= TX_SCK_ANY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004796
4797
4798 /* maybe we only wanted to see if there was a set-cookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004799 if (t->be->cookie_name == NULL &&
4800 t->be->appsession_name == NULL &&
4801 t->be->capture_name == NULL)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004802 return;
4803
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004804 p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004805
4806 while (p1 < cur_end) { /* in fact, we'll break after the first cookie */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004807 if (p1 == cur_end || *p1 == ';') /* end of cookie */
4808 break;
4809
4810 /* p1 is at the beginning of the cookie name */
4811 p2 = p1;
4812
4813 while (p2 < cur_end && *p2 != '=' && *p2 != ';')
4814 p2++;
4815
4816 if (p2 == cur_end || *p2 == ';') /* next cookie */
4817 break;
4818
4819 p3 = p2 + 1; /* skip the '=' sign */
4820 if (p3 == cur_end)
4821 break;
4822
4823 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004824 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';')
Willy Tarreaua15645d2007-03-18 16:22:39 +01004825 p4++;
4826
4827 /* here, we have the cookie name between p1 and p2,
4828 * and its value between p3 and p4.
4829 * we can process it.
4830 */
4831
4832 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004833 if (t->be->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004834 txn->srv_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004835 (p4 - p1 >= t->be->capture_namelen) &&
4836 memcmp(p1, t->be->capture_name, t->be->capture_namelen) == 0) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004837 int log_len = p4 - p1;
4838
Willy Tarreau086b3b42007-05-13 21:45:51 +02004839 if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004840 Alert("HTTP logging : out of memory.\n");
4841 }
4842
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004843 if (log_len > t->be->capture_len)
4844 log_len = t->be->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004845 memcpy(txn->srv_cookie, p1, log_len);
4846 txn->srv_cookie[log_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004847 }
4848
4849 /* now check if we need to process it for persistence */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004850 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4851 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004852 /* Cool... it's the right one */
Willy Tarreau3d300592007-03-18 18:34:41 +01004853 txn->flags |= TX_SCK_SEEN;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004854
4855 /* If the cookie is in insert mode on a known server, we'll delete
4856 * this occurrence because we'll insert another one later.
4857 * We'll delete it too if the "indirect" option is set and we're in
4858 * a direct access. */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004859 if (((t->srv) && (t->be->options & PR_O_COOK_INS)) ||
4860 ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004861 /* this header must be deleted */
4862 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4863 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4864 txn->hdr_idx.used--;
4865 cur_hdr->len = 0;
4866 cur_next += delta;
4867 txn->rsp.eoh += delta;
4868
Willy Tarreau3d300592007-03-18 18:34:41 +01004869 txn->flags |= TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004870 }
4871 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004872 (t->be->options & PR_O_COOK_RW)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004873 /* replace bytes p3->p4 with the cookie name associated
4874 * with this server since we know it.
4875 */
4876 delta = buffer_replace2(rtr, p3, p4, t->srv->cookie, t->srv->cklen);
4877 cur_hdr->len += delta;
4878 cur_next += delta;
4879 txn->rsp.eoh += delta;
4880
Willy Tarreau3d300592007-03-18 18:34:41 +01004881 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004882 }
4883 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004884 (t->be->options & PR_O_COOK_PFX)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004885 /* insert the cookie name associated with this server
4886 * before existing cookie, and insert a delimitor between them..
4887 */
4888 delta = buffer_replace2(rtr, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4889 cur_hdr->len += delta;
4890 cur_next += delta;
4891 txn->rsp.eoh += delta;
4892
4893 p3[t->srv->cklen] = COOKIE_DELIM;
Willy Tarreau3d300592007-03-18 18:34:41 +01004894 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004895 }
4896 }
4897 /* next, let's see if the cookie is our appcookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004898 else if ((t->be->appsession_name != NULL) &&
4899 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004900
4901 /* Cool... it's the right one */
4902
4903 size_t server_id_len = strlen(t->srv->id) + 1;
4904 asession_temp = &local_asession;
4905
Willy Tarreau63963c62007-05-13 21:29:55 +02004906 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004907 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4908 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4909 return;
4910 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004911 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4912 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004913 asession_temp->serverid = NULL;
4914
4915 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01004916 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4917 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004918 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004919 Alert("Not enough Memory process_srv():asession:calloc().\n");
4920 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
4921 return;
4922 }
4923 asession_temp->sessid = local_asession.sessid;
4924 asession_temp->serverid = local_asession.serverid;
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004925 asession_temp->request_count = 0;
Willy Tarreau51041c72007-09-09 21:56:53 +02004926 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
4927 } else {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004928 /* free wasted memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004929 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau51041c72007-09-09 21:56:53 +02004930 }
4931
Willy Tarreaua15645d2007-03-18 16:22:39 +01004932 if (asession_temp->serverid == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004933 if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004934 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4935 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4936 return;
4937 }
4938 asession_temp->serverid[0] = '\0';
4939 }
4940
4941 if (asession_temp->serverid[0] == '\0')
4942 memcpy(asession_temp->serverid, t->srv->id, server_id_len);
4943
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004944 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004945 asession_temp->request_count++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004946#if defined(DEBUG_HASH)
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02004947 Alert("manage_server_side_cookies\n");
Willy Tarreau51041c72007-09-09 21:56:53 +02004948 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreaua15645d2007-03-18 16:22:39 +01004949#endif
4950 }/* end if ((t->proxy->appsession_name != NULL) ... */
4951 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4952 } /* we're now at the end of the cookie value */
4953
4954 /* keep the link from this header to next one */
4955 old_idx = cur_idx;
4956 } /* end of cookie processing on this header */
4957}
4958
4959
4960
4961/*
4962 * Check if response is cacheable or not. Updates t->flags.
4963 */
4964void check_response_for_cacheability(struct session *t, struct buffer *rtr)
4965{
4966 struct http_txn *txn = &t->txn;
4967 char *p1, *p2;
4968
4969 char *cur_ptr, *cur_end, *cur_next;
4970 int cur_idx;
4971
Willy Tarreau5df51872007-11-25 16:20:08 +01004972 if (!(txn->flags & TX_CACHEABLE))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004973 return;
4974
4975 /* Iterate through the headers.
4976 * we start with the start line.
4977 */
4978 cur_idx = 0;
4979 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4980
4981 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
4982 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004983 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004984
4985 cur_hdr = &txn->hdr_idx.v[cur_idx];
4986 cur_ptr = cur_next;
4987 cur_end = cur_ptr + cur_hdr->len;
4988 cur_next = cur_end + cur_hdr->cr + 1;
4989
4990 /* We have one full header between cur_ptr and cur_end, and the
4991 * next header starts at cur_next. We're only interested in
4992 * "Cookie:" headers.
4993 */
4994
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004995 val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
4996 if (val) {
4997 if ((cur_end - (cur_ptr + val) >= 8) &&
4998 strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
4999 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
5000 return;
5001 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01005002 }
5003
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005004 val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
5005 if (!val)
Willy Tarreaua15645d2007-03-18 16:22:39 +01005006 continue;
5007
5008 /* OK, right now we know we have a cache-control header at cur_ptr */
5009
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005010 p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01005011
5012 if (p1 >= cur_end) /* no more info */
5013 continue;
5014
5015 /* p1 is at the beginning of the value */
5016 p2 = p1;
5017
Willy Tarreau8f8e6452007-06-17 21:51:38 +02005018 while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((unsigned char)*p2))
Willy Tarreaua15645d2007-03-18 16:22:39 +01005019 p2++;
5020
5021 /* we have a complete value between p1 and p2 */
5022 if (p2 < cur_end && *p2 == '=') {
5023 /* we have something of the form no-cache="set-cookie" */
5024 if ((cur_end - p1 >= 21) &&
5025 strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0
5026 && (p1[20] == '"' || p1[20] == ','))
Willy Tarreau3d300592007-03-18 18:34:41 +01005027 txn->flags &= ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005028 continue;
5029 }
5030
5031 /* OK, so we know that either p2 points to the end of string or to a comma */
5032 if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) ||
5033 ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) ||
5034 ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) ||
5035 ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005036 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005037 return;
5038 }
5039
5040 if ((p2 - p1 == 6) && strncasecmp(p1, "public", 6) == 0) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005041 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005042 continue;
5043 }
5044 }
5045}
5046
5047
Willy Tarreau58f10d72006-12-04 02:26:12 +01005048/*
5049 * Try to retrieve a known appsession in the URI, then the associated server.
5050 * If the server is found, it's assigned to the session.
5051 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005052void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01005053{
Willy Tarreau3d300592007-03-18 18:34:41 +01005054 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005055 appsess *asession_temp = NULL;
5056 appsess local_asession;
5057 char *request_line;
5058
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005059 if (t->be->appsession_name == NULL ||
Willy Tarreaub326fcc2007-03-03 13:54:32 +01005060 (t->txn.meth != HTTP_METH_GET && t->txn.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005061 (request_line = memchr(begin, ';', len)) == NULL ||
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005062 ((1 + t->be->appsession_name_len + 1 + t->be->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01005063 return;
5064
5065 /* skip ';' */
5066 request_line++;
5067
5068 /* look if we have a jsessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005069 if (strncasecmp(request_line, t->be->appsession_name, t->be->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01005070 return;
5071
5072 /* skip jsessionid= */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005073 request_line += t->be->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005074
5075 /* First try if we already have an appsession */
5076 asession_temp = &local_asession;
5077
Willy Tarreau63963c62007-05-13 21:29:55 +02005078 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005079 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
5080 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
5081 return;
5082 }
5083
5084 /* Copy the sessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005085 memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
5086 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005087 asession_temp->serverid = NULL;
5088
5089 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01005090 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
5091 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02005092 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005093 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005094 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005095 Alert("Not enough memory process_cli():asession:calloc().\n");
5096 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
5097 return;
5098 }
5099 asession_temp->sessid = local_asession.sessid;
5100 asession_temp->serverid = local_asession.serverid;
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02005101 asession_temp->request_count=0;
Willy Tarreau51041c72007-09-09 21:56:53 +02005102 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005103 }
5104 else {
5105 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005106 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005107 }
Willy Tarreau51041c72007-09-09 21:56:53 +02005108
Willy Tarreau0c303ee2008-07-07 00:09:58 +02005109 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005110 asession_temp->request_count++;
Willy Tarreau51041c72007-09-09 21:56:53 +02005111
Willy Tarreau58f10d72006-12-04 02:26:12 +01005112#if defined(DEBUG_HASH)
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02005113 Alert("get_srv_from_appsession\n");
Willy Tarreau51041c72007-09-09 21:56:53 +02005114 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreau58f10d72006-12-04 02:26:12 +01005115#endif
5116 if (asession_temp->serverid == NULL) {
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02005117 /* TODO redispatch request */
Willy Tarreau58f10d72006-12-04 02:26:12 +01005118 Alert("Found Application Session without matching server.\n");
5119 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005120 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005121 while (srv) {
5122 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005123 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005124 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01005125 txn->flags &= ~TX_CK_MASK;
5126 txn->flags |= TX_CK_VALID;
5127 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005128 t->srv = srv;
5129 break;
5130 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01005131 txn->flags &= ~TX_CK_MASK;
5132 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005133 }
5134 }
5135 srv = srv->next;
5136 }
5137 }
5138}
5139
5140
Willy Tarreaub2513902006-12-17 14:52:38 +01005141/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005142 * In a GET or HEAD request, check if the requested URI matches the stats uri
5143 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01005144 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005145 * It is assumed that the request is either a HEAD or GET and that the
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005146 * t->be->uri_auth field is valid. An HTTP/401 response may be sent, or
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005147 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01005148 *
5149 * Returns 1 if the session's state changes, otherwise 0.
5150 */
5151int stats_check_uri_auth(struct session *t, struct proxy *backend)
5152{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005153 struct http_txn *txn = &t->txn;
Willy Tarreaub2513902006-12-17 14:52:38 +01005154 struct uri_auth *uri_auth = backend->uri_auth;
5155 struct user_auth *user;
5156 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005157 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01005158
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005159 memset(&t->data_ctx.stats, 0, sizeof(t->data_ctx.stats));
5160
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005161 /* check URI size */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005162 if (uri_auth->uri_len > txn->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01005163 return 0;
5164
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005165 h = t->req->data + txn->req.sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005166
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005167 /* the URI is in h */
5168 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01005169 return 0;
5170
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005171 h += uri_auth->uri_len;
5172 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 3) {
5173 if (memcmp(h, ";up", 3) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005174 t->data_ctx.stats.flags |= STAT_HIDE_DOWN;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005175 break;
5176 }
5177 h++;
5178 }
5179
5180 if (uri_auth->refresh) {
5181 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5182 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 10) {
5183 if (memcmp(h, ";norefresh", 10) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005184 t->data_ctx.stats.flags |= STAT_NO_REFRESH;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005185 break;
5186 }
5187 h++;
5188 }
5189 }
5190
Willy Tarreau55bb8452007-10-17 18:44:57 +02005191 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5192 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 4) {
5193 if (memcmp(h, ";csv", 4) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005194 t->data_ctx.stats.flags |= STAT_FMT_CSV;
Willy Tarreau55bb8452007-10-17 18:44:57 +02005195 break;
5196 }
5197 h++;
5198 }
5199
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005200 t->data_ctx.stats.flags |= STAT_SHOW_STAT | STAT_SHOW_INFO;
5201
Willy Tarreaub2513902006-12-17 14:52:38 +01005202 /* we are in front of a interceptable URI. Let's check
5203 * if there's an authentication and if it's valid.
5204 */
5205 user = uri_auth->users;
5206 if (!user) {
5207 /* no user auth required, it's OK */
5208 authenticated = 1;
5209 } else {
5210 authenticated = 0;
5211
5212 /* a user list is defined, we have to check.
5213 * skip 21 chars for "Authorization: Basic ".
5214 */
5215
5216 /* FIXME: this should move to an earlier place */
5217 cur_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005218 h = t->req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
5219 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
5220 int len = txn->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005221 if (len > 14 &&
5222 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005223 txn->auth_hdr.str = h;
5224 txn->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005225 break;
5226 }
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005227 h += len + txn->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01005228 }
5229
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005230 if (txn->auth_hdr.len < 21 ||
5231 memcmp(txn->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01005232 user = NULL;
5233
5234 while (user) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005235 if ((txn->auth_hdr.len == user->user_len + 14 + 7)
5236 && !memcmp(txn->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01005237 user->user_pwd, user->user_len)) {
5238 authenticated = 1;
5239 break;
5240 }
5241 user = user->next;
5242 }
5243 }
5244
5245 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01005246 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01005247
5248 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01005249 msg.str = trash;
5250 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005251 txn->status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01005252 client_retnclose(t, &msg);
Willy Tarreau67f0eea2008-08-10 22:55:22 +02005253 t->analysis &= ~AN_REQ_ANY;
Willy Tarreaub2513902006-12-17 14:52:38 +01005254 if (!(t->flags & SN_ERR_MASK))
5255 t->flags |= SN_ERR_PRXCOND;
5256 if (!(t->flags & SN_FINST_MASK))
5257 t->flags |= SN_FINST_R;
5258 return 1;
5259 }
5260
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005261 /* The request is valid, the user is authenticated. Let's start sending
Willy Tarreaub2513902006-12-17 14:52:38 +01005262 * data.
5263 */
Willy Tarreau284c7b32008-06-29 16:38:43 +02005264 EV_FD_CLR(t->cli_fd, DIR_RD);
5265 buffer_shutr(t->req);
5266 buffer_shutr(t->rep);
Willy Tarreaub2513902006-12-17 14:52:38 +01005267 t->cli_state = CL_STSHUTR;
5268 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau70089872008-06-13 21:12:51 +02005269 t->logs.tv_request = now;
Willy Tarreaub2513902006-12-17 14:52:38 +01005270 t->data_source = DATA_SRC_STATS;
5271 t->data_state = DATA_ST_INIT;
Willy Tarreau91e99932008-06-30 07:51:00 +02005272 t->task->nice = -32; /* small boost for HTTP statistics */
Willy Tarreaub2513902006-12-17 14:52:38 +01005273 produce_content(t);
5274 return 1;
5275}
5276
5277
Willy Tarreaubaaee002006-06-26 02:48:02 +02005278/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01005279 * Print a debug line with a header
5280 */
5281void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
5282{
5283 int len, max;
5284 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
5285 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
5286 max = end - start;
5287 UBOUND(max, sizeof(trash) - len - 1);
5288 len += strlcpy2(trash + len, start, max + 1);
5289 trash[len++] = '\n';
5290 write(1, trash, len);
5291}
5292
5293
Willy Tarreau8797c062007-05-07 00:55:35 +02005294/************************************************************************/
5295/* The code below is dedicated to ACL parsing and matching */
5296/************************************************************************/
5297
5298
5299
5300
5301/* 1. Check on METHOD
5302 * We use the pre-parsed method if it is known, and store its number as an
5303 * integer. If it is unknown, we use the pointer and the length.
5304 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005305static int acl_parse_meth(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005306{
5307 int len, meth;
5308
Willy Tarreauae8b7962007-06-09 23:10:04 +02005309 len = strlen(*text);
5310 meth = find_http_meth(*text, len);
Willy Tarreau8797c062007-05-07 00:55:35 +02005311
5312 pattern->val.i = meth;
5313 if (meth == HTTP_METH_OTHER) {
Willy Tarreauae8b7962007-06-09 23:10:04 +02005314 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005315 if (!pattern->ptr.str)
5316 return 0;
5317 pattern->len = len;
5318 }
5319 return 1;
5320}
5321
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005322static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005323acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
5324 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005325{
5326 int meth;
5327 struct http_txn *txn = l7;
5328
Willy Tarreaub6866442008-07-14 23:54:42 +02005329 if (!txn)
5330 return 0;
5331
Willy Tarreauc11416f2007-06-17 16:58:38 +02005332 if (txn->req.msg_state != HTTP_MSG_BODY)
5333 return 0;
5334
Willy Tarreau8797c062007-05-07 00:55:35 +02005335 meth = txn->meth;
5336 test->i = meth;
5337 if (meth == HTTP_METH_OTHER) {
Willy Tarreauc11416f2007-06-17 16:58:38 +02005338 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5339 /* ensure the indexes are not affected */
5340 return 0;
Willy Tarreau8797c062007-05-07 00:55:35 +02005341 test->len = txn->req.sl.rq.m_l;
5342 test->ptr = txn->req.sol;
5343 }
5344 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5345 return 1;
5346}
5347
5348static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
5349{
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005350 int icase;
5351
Willy Tarreau8797c062007-05-07 00:55:35 +02005352 if (test->i != pattern->val.i)
Willy Tarreau11382812008-07-09 16:18:21 +02005353 return ACL_PAT_FAIL;
Willy Tarreau8797c062007-05-07 00:55:35 +02005354
5355 if (test->i != HTTP_METH_OTHER)
Willy Tarreau11382812008-07-09 16:18:21 +02005356 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005357
5358 /* Other method, we must compare the strings */
5359 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +02005360 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005361
5362 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
5363 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) != 0) ||
5364 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +02005365 return ACL_PAT_FAIL;
5366 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005367}
5368
5369/* 2. Check on Request/Status Version
5370 * We simply compare strings here.
5371 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005372static int acl_parse_ver(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005373{
Willy Tarreauae8b7962007-06-09 23:10:04 +02005374 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005375 if (!pattern->ptr.str)
5376 return 0;
Willy Tarreauae8b7962007-06-09 23:10:04 +02005377 pattern->len = strlen(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005378 return 1;
5379}
5380
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005381static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005382acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
5383 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005384{
5385 struct http_txn *txn = l7;
5386 char *ptr;
5387 int len;
5388
Willy Tarreaub6866442008-07-14 23:54:42 +02005389 if (!txn)
5390 return 0;
5391
Willy Tarreauc11416f2007-06-17 16:58:38 +02005392 if (txn->req.msg_state != HTTP_MSG_BODY)
5393 return 0;
5394
Willy Tarreau8797c062007-05-07 00:55:35 +02005395 len = txn->req.sl.rq.v_l;
5396 ptr = txn->req.sol + txn->req.sl.rq.v - txn->req.som;
5397
5398 while ((len-- > 0) && (*ptr++ != '/'));
5399 if (len <= 0)
5400 return 0;
5401
5402 test->ptr = ptr;
5403 test->len = len;
5404
5405 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5406 return 1;
5407}
5408
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005409static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005410acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
5411 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005412{
5413 struct http_txn *txn = l7;
5414 char *ptr;
5415 int len;
5416
Willy Tarreaub6866442008-07-14 23:54:42 +02005417 if (!txn)
5418 return 0;
5419
Willy Tarreauc11416f2007-06-17 16:58:38 +02005420 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5421 return 0;
5422
Willy Tarreau8797c062007-05-07 00:55:35 +02005423 len = txn->rsp.sl.st.v_l;
5424 ptr = txn->rsp.sol;
5425
5426 while ((len-- > 0) && (*ptr++ != '/'));
5427 if (len <= 0)
5428 return 0;
5429
5430 test->ptr = ptr;
5431 test->len = len;
5432
5433 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5434 return 1;
5435}
5436
5437/* 3. Check on Status Code. We manipulate integers here. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005438static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005439acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, int dir,
5440 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005441{
5442 struct http_txn *txn = l7;
5443 char *ptr;
5444 int len;
5445
Willy Tarreaub6866442008-07-14 23:54:42 +02005446 if (!txn)
5447 return 0;
5448
Willy Tarreauc11416f2007-06-17 16:58:38 +02005449 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5450 return 0;
5451
Willy Tarreau8797c062007-05-07 00:55:35 +02005452 len = txn->rsp.sl.st.c_l;
5453 ptr = txn->rsp.sol + txn->rsp.sl.st.c - txn->rsp.som;
5454
5455 test->i = __strl2ui(ptr, len);
5456 test->flags = ACL_TEST_F_VOL_1ST;
5457 return 1;
5458}
5459
5460/* 4. Check on URL/URI. A pointer to the URI is stored. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005461static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005462acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
5463 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005464{
5465 struct http_txn *txn = l7;
5466
Willy Tarreaub6866442008-07-14 23:54:42 +02005467 if (!txn)
5468 return 0;
5469
Willy Tarreauc11416f2007-06-17 16:58:38 +02005470 if (txn->req.msg_state != HTTP_MSG_BODY)
5471 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005472
Willy Tarreauc11416f2007-06-17 16:58:38 +02005473 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5474 /* ensure the indexes are not affected */
5475 return 0;
5476
Willy Tarreau8797c062007-05-07 00:55:35 +02005477 test->len = txn->req.sl.rq.u_l;
5478 test->ptr = txn->req.sol + txn->req.sl.rq.u;
5479
Willy Tarreauf3d25982007-05-08 22:45:09 +02005480 /* we do not need to set READ_ONLY because the data is in a buffer */
5481 test->flags = ACL_TEST_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +02005482 return 1;
5483}
5484
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005485static int
5486acl_fetch_url_ip(struct proxy *px, struct session *l4, void *l7, int dir,
5487 struct acl_expr *expr, struct acl_test *test)
5488{
5489 struct http_txn *txn = l7;
5490
Willy Tarreaub6866442008-07-14 23:54:42 +02005491 if (!txn)
5492 return 0;
5493
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005494 if (txn->req.msg_state != HTTP_MSG_BODY)
5495 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005496
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005497 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5498 /* ensure the indexes are not affected */
5499 return 0;
5500
5501 /* Parse HTTP request */
5502 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5503 test->ptr = (void *)&((struct sockaddr_in *)&l4->srv_addr)->sin_addr;
5504 test->i = AF_INET;
5505
5506 /*
5507 * If we are parsing url in frontend space, we prepare backend stage
5508 * to not parse again the same url ! optimization lazyness...
5509 */
5510 if (px->options & PR_O_HTTP_PROXY)
5511 l4->flags |= SN_ADDR_SET;
5512
5513 test->flags = ACL_TEST_F_READ_ONLY;
5514 return 1;
5515}
5516
5517static int
5518acl_fetch_url_port(struct proxy *px, struct session *l4, void *l7, int dir,
5519 struct acl_expr *expr, struct acl_test *test)
5520{
5521 struct http_txn *txn = l7;
5522
Willy Tarreaub6866442008-07-14 23:54:42 +02005523 if (!txn)
5524 return 0;
5525
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005526 if (txn->req.msg_state != HTTP_MSG_BODY)
5527 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005528
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005529 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5530 /* ensure the indexes are not affected */
5531 return 0;
5532
5533 /* Same optimization as url_ip */
5534 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5535 test->i = ntohs(((struct sockaddr_in *)&l4->srv_addr)->sin_port);
5536
5537 if (px->options & PR_O_HTTP_PROXY)
5538 l4->flags |= SN_ADDR_SET;
5539
5540 test->flags = ACL_TEST_F_READ_ONLY;
5541 return 1;
5542}
5543
Willy Tarreauc11416f2007-06-17 16:58:38 +02005544/* 5. Check on HTTP header. A pointer to the beginning of the value is returned.
5545 * This generic function is used by both acl_fetch_chdr() and acl_fetch_shdr().
5546 */
Willy Tarreau33a7e692007-06-10 19:45:56 +02005547static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005548acl_fetch_hdr(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005549 struct acl_expr *expr, struct acl_test *test)
5550{
5551 struct http_txn *txn = l7;
5552 struct hdr_idx *idx = &txn->hdr_idx;
5553 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005554
Willy Tarreaub6866442008-07-14 23:54:42 +02005555 if (!txn)
5556 return 0;
5557
Willy Tarreau33a7e692007-06-10 19:45:56 +02005558 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5559 /* search for header from the beginning */
5560 ctx->idx = 0;
5561
Willy Tarreau33a7e692007-06-10 19:45:56 +02005562 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5563 test->flags |= ACL_TEST_F_FETCH_MORE;
5564 test->flags |= ACL_TEST_F_VOL_HDR;
5565 test->len = ctx->vlen;
5566 test->ptr = (char *)ctx->line + ctx->val;
5567 return 1;
5568 }
5569
5570 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5571 test->flags |= ACL_TEST_F_VOL_HDR;
5572 return 0;
5573}
5574
Willy Tarreau33a7e692007-06-10 19:45:56 +02005575static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005576acl_fetch_chdr(struct proxy *px, struct session *l4, void *l7, int dir,
5577 struct acl_expr *expr, struct acl_test *test)
5578{
5579 struct http_txn *txn = l7;
5580
Willy Tarreaub6866442008-07-14 23:54:42 +02005581 if (!txn)
5582 return 0;
5583
Willy Tarreauc11416f2007-06-17 16:58:38 +02005584 if (txn->req.msg_state != HTTP_MSG_BODY)
5585 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005586
Willy Tarreauc11416f2007-06-17 16:58:38 +02005587 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5588 /* ensure the indexes are not affected */
5589 return 0;
5590
5591 return acl_fetch_hdr(px, l4, txn, txn->req.sol, expr, test);
5592}
5593
5594static int
5595acl_fetch_shdr(struct proxy *px, struct session *l4, void *l7, int dir,
5596 struct acl_expr *expr, struct acl_test *test)
5597{
5598 struct http_txn *txn = l7;
5599
Willy Tarreaub6866442008-07-14 23:54:42 +02005600 if (!txn)
5601 return 0;
5602
Willy Tarreauc11416f2007-06-17 16:58:38 +02005603 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5604 return 0;
5605
5606 return acl_fetch_hdr(px, l4, txn, txn->rsp.sol, expr, test);
5607}
5608
5609/* 6. Check on HTTP header count. The number of occurrences is returned.
5610 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
5611 */
5612static int
5613acl_fetch_hdr_cnt(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005614 struct acl_expr *expr, struct acl_test *test)
5615{
5616 struct http_txn *txn = l7;
5617 struct hdr_idx *idx = &txn->hdr_idx;
5618 struct hdr_ctx ctx;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005619 int cnt;
Willy Tarreau8797c062007-05-07 00:55:35 +02005620
Willy Tarreaub6866442008-07-14 23:54:42 +02005621 if (!txn)
5622 return 0;
5623
Willy Tarreau33a7e692007-06-10 19:45:56 +02005624 ctx.idx = 0;
5625 cnt = 0;
5626 while (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, &ctx))
5627 cnt++;
5628
5629 test->i = cnt;
5630 test->flags = ACL_TEST_F_VOL_HDR;
5631 return 1;
5632}
5633
Willy Tarreauc11416f2007-06-17 16:58:38 +02005634static int
5635acl_fetch_chdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5636 struct acl_expr *expr, struct acl_test *test)
5637{
5638 struct http_txn *txn = l7;
5639
Willy Tarreaub6866442008-07-14 23:54:42 +02005640 if (!txn)
5641 return 0;
5642
Willy Tarreauc11416f2007-06-17 16:58:38 +02005643 if (txn->req.msg_state != HTTP_MSG_BODY)
5644 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005645
Willy Tarreauc11416f2007-06-17 16:58:38 +02005646 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5647 /* ensure the indexes are not affected */
5648 return 0;
5649
5650 return acl_fetch_hdr_cnt(px, l4, txn, txn->req.sol, expr, test);
5651}
5652
5653static int
5654acl_fetch_shdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5655 struct acl_expr *expr, struct acl_test *test)
5656{
5657 struct http_txn *txn = l7;
5658
Willy Tarreaub6866442008-07-14 23:54:42 +02005659 if (!txn)
5660 return 0;
5661
Willy Tarreauc11416f2007-06-17 16:58:38 +02005662 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5663 return 0;
5664
5665 return acl_fetch_hdr_cnt(px, l4, txn, txn->rsp.sol, expr, test);
5666}
5667
Willy Tarreau33a7e692007-06-10 19:45:56 +02005668/* 7. Check on HTTP header's integer value. The integer value is returned.
5669 * FIXME: the type is 'int', it may not be appropriate for everything.
Willy Tarreauc11416f2007-06-17 16:58:38 +02005670 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
Willy Tarreau33a7e692007-06-10 19:45:56 +02005671 */
5672static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005673acl_fetch_hdr_val(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005674 struct acl_expr *expr, struct acl_test *test)
5675{
5676 struct http_txn *txn = l7;
5677 struct hdr_idx *idx = &txn->hdr_idx;
5678 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005679
Willy Tarreaub6866442008-07-14 23:54:42 +02005680 if (!txn)
5681 return 0;
5682
Willy Tarreau33a7e692007-06-10 19:45:56 +02005683 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5684 /* search for header from the beginning */
5685 ctx->idx = 0;
5686
Willy Tarreau33a7e692007-06-10 19:45:56 +02005687 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5688 test->flags |= ACL_TEST_F_FETCH_MORE;
5689 test->flags |= ACL_TEST_F_VOL_HDR;
5690 test->i = strl2ic((char *)ctx->line + ctx->val, ctx->vlen);
5691 return 1;
5692 }
5693
5694 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5695 test->flags |= ACL_TEST_F_VOL_HDR;
5696 return 0;
5697}
5698
Willy Tarreauc11416f2007-06-17 16:58:38 +02005699static int
5700acl_fetch_chdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5701 struct acl_expr *expr, struct acl_test *test)
5702{
5703 struct http_txn *txn = l7;
5704
Willy Tarreaub6866442008-07-14 23:54:42 +02005705 if (!txn)
5706 return 0;
5707
Willy Tarreauc11416f2007-06-17 16:58:38 +02005708 if (txn->req.msg_state != HTTP_MSG_BODY)
5709 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005710
Willy Tarreauc11416f2007-06-17 16:58:38 +02005711 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5712 /* ensure the indexes are not affected */
5713 return 0;
5714
5715 return acl_fetch_hdr_val(px, l4, txn, txn->req.sol, expr, test);
5716}
5717
5718static int
5719acl_fetch_shdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5720 struct acl_expr *expr, struct acl_test *test)
5721{
5722 struct http_txn *txn = l7;
5723
Willy Tarreaub6866442008-07-14 23:54:42 +02005724 if (!txn)
5725 return 0;
5726
Willy Tarreauc11416f2007-06-17 16:58:38 +02005727 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5728 return 0;
5729
5730 return acl_fetch_hdr_val(px, l4, txn, txn->rsp.sol, expr, test);
5731}
5732
Willy Tarreau737b0c12007-06-10 21:28:46 +02005733/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at
5734 * the first '/' after the possible hostname, and ends before the possible '?'.
5735 */
5736static int
5737acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
5738 struct acl_expr *expr, struct acl_test *test)
5739{
5740 struct http_txn *txn = l7;
5741 char *ptr, *end;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005742
Willy Tarreaub6866442008-07-14 23:54:42 +02005743 if (!txn)
5744 return 0;
5745
Willy Tarreauc11416f2007-06-17 16:58:38 +02005746 if (txn->req.msg_state != HTTP_MSG_BODY)
5747 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005748
Willy Tarreauc11416f2007-06-17 16:58:38 +02005749 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5750 /* ensure the indexes are not affected */
5751 return 0;
5752
Willy Tarreau21d2af32008-02-14 20:25:24 +01005753 end = txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
5754 ptr = http_get_path(txn);
5755 if (!ptr)
Willy Tarreau737b0c12007-06-10 21:28:46 +02005756 return 0;
5757
5758 /* OK, we got the '/' ! */
5759 test->ptr = ptr;
5760
5761 while (ptr < end && *ptr != '?')
5762 ptr++;
5763
5764 test->len = ptr - test->ptr;
5765
5766 /* we do not need to set READ_ONLY because the data is in a buffer */
5767 test->flags = ACL_TEST_F_VOL_1ST;
5768 return 1;
5769}
5770
5771
Willy Tarreau8797c062007-05-07 00:55:35 +02005772
5773/************************************************************************/
5774/* All supported keywords must be declared here. */
5775/************************************************************************/
5776
5777/* Note: must not be declared <const> as its list will be overwritten */
5778static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005779 { "method", acl_parse_meth, acl_fetch_meth, acl_match_meth, ACL_USE_L7REQ_PERMANENT },
5780 { "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5781 { "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str, ACL_USE_L7RTR_VOLATILE },
5782 { "status", acl_parse_int, acl_fetch_stcode, acl_match_int, ACL_USE_L7RTR_PERMANENT },
Willy Tarreau8797c062007-05-07 00:55:35 +02005783
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005784 { "url", acl_parse_str, acl_fetch_url, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5785 { "url_beg", acl_parse_str, acl_fetch_url, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5786 { "url_end", acl_parse_str, acl_fetch_url, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5787 { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5788 { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5789 { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
5790 { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5791 { "url_ip", acl_parse_ip, acl_fetch_url_ip, acl_match_ip, ACL_USE_L7REQ_VOLATILE },
5792 { "url_port", acl_parse_int, acl_fetch_url_port, acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau8797c062007-05-07 00:55:35 +02005793
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005794 /* note: we should set hdr* to use ACL_USE_HDR_VOLATILE, and chdr* to use L7REQ_VOLATILE */
5795 { "hdr", acl_parse_str, acl_fetch_chdr, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5796 { "hdr_reg", acl_parse_reg, acl_fetch_chdr, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5797 { "hdr_beg", acl_parse_str, acl_fetch_chdr, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5798 { "hdr_end", acl_parse_str, acl_fetch_chdr, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5799 { "hdr_sub", acl_parse_str, acl_fetch_chdr, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5800 { "hdr_dir", acl_parse_str, acl_fetch_chdr, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5801 { "hdr_dom", acl_parse_str, acl_fetch_chdr, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
5802 { "hdr_cnt", acl_parse_int, acl_fetch_chdr_cnt,acl_match_int, ACL_USE_L7REQ_VOLATILE },
5803 { "hdr_val", acl_parse_int, acl_fetch_chdr_val,acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreauc11416f2007-06-17 16:58:38 +02005804
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005805 { "shdr", acl_parse_str, acl_fetch_shdr, acl_match_str, ACL_USE_L7RTR_VOLATILE },
5806 { "shdr_reg", acl_parse_reg, acl_fetch_shdr, acl_match_reg, ACL_USE_L7RTR_VOLATILE },
5807 { "shdr_beg", acl_parse_str, acl_fetch_shdr, acl_match_beg, ACL_USE_L7RTR_VOLATILE },
5808 { "shdr_end", acl_parse_str, acl_fetch_shdr, acl_match_end, ACL_USE_L7RTR_VOLATILE },
5809 { "shdr_sub", acl_parse_str, acl_fetch_shdr, acl_match_sub, ACL_USE_L7RTR_VOLATILE },
5810 { "shdr_dir", acl_parse_str, acl_fetch_shdr, acl_match_dir, ACL_USE_L7RTR_VOLATILE },
5811 { "shdr_dom", acl_parse_str, acl_fetch_shdr, acl_match_dom, ACL_USE_L7RTR_VOLATILE },
5812 { "shdr_cnt", acl_parse_int, acl_fetch_shdr_cnt,acl_match_int, ACL_USE_L7RTR_VOLATILE },
5813 { "shdr_val", acl_parse_int, acl_fetch_shdr_val,acl_match_int, ACL_USE_L7RTR_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005814
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005815 { "path", acl_parse_str, acl_fetch_path, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5816 { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5817 { "path_beg", acl_parse_str, acl_fetch_path, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5818 { "path_end", acl_parse_str, acl_fetch_path, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5819 { "path_sub", acl_parse_str, acl_fetch_path, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5820 { "path_dir", acl_parse_str, acl_fetch_path, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5821 { "path_dom", acl_parse_str, acl_fetch_path, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005822
Willy Tarreauf3d25982007-05-08 22:45:09 +02005823 { NULL, NULL, NULL, NULL },
5824
5825#if 0
Willy Tarreau8797c062007-05-07 00:55:35 +02005826 { "line", acl_parse_str, acl_fetch_line, acl_match_str },
5827 { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg },
5828 { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg },
5829 { "line_end", acl_parse_str, acl_fetch_line, acl_match_end },
5830 { "line_sub", acl_parse_str, acl_fetch_line, acl_match_sub },
5831 { "line_dir", acl_parse_str, acl_fetch_line, acl_match_dir },
5832 { "line_dom", acl_parse_str, acl_fetch_line, acl_match_dom },
5833
Willy Tarreau8797c062007-05-07 00:55:35 +02005834 { "cook", acl_parse_str, acl_fetch_cook, acl_match_str },
5835 { "cook_reg", acl_parse_reg, acl_fetch_cook, acl_match_reg },
5836 { "cook_beg", acl_parse_str, acl_fetch_cook, acl_match_beg },
5837 { "cook_end", acl_parse_str, acl_fetch_cook, acl_match_end },
5838 { "cook_sub", acl_parse_str, acl_fetch_cook, acl_match_sub },
5839 { "cook_dir", acl_parse_str, acl_fetch_cook, acl_match_dir },
5840 { "cook_dom", acl_parse_str, acl_fetch_cook, acl_match_dom },
5841 { "cook_pst", acl_parse_none, acl_fetch_cook, acl_match_pst },
5842
5843 { "auth_user", acl_parse_str, acl_fetch_user, acl_match_str },
5844 { "auth_regex", acl_parse_reg, acl_fetch_user, acl_match_reg },
5845 { "auth_clear", acl_parse_str, acl_fetch_auth, acl_match_str },
5846 { "auth_md5", acl_parse_str, acl_fetch_auth, acl_match_md5 },
5847 { NULL, NULL, NULL, NULL },
5848#endif
5849}};
5850
5851
5852__attribute__((constructor))
5853static void __http_protocol_init(void)
5854{
5855 acl_register_keywords(&acl_kws);
5856}
5857
5858
Willy Tarreau58f10d72006-12-04 02:26:12 +01005859/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02005860 * Local variables:
5861 * c-indent-level: 8
5862 * c-basic-offset: 8
5863 * End:
5864 */