blob: e366ee5638e2c1b91098902ddc682ed3aea0ba83 [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>
33#include <common/time.h>
34#include <common/uri_auth.h>
35#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020036
Willy Tarreau8797c062007-05-07 00:55:35 +020037#include <types/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020038#include <types/capture.h>
39#include <types/client.h>
40#include <types/global.h>
41#include <types/httperr.h>
42#include <types/polling.h>
43#include <types/proxy.h>
44#include <types/server.h>
45
Willy Tarreau8797c062007-05-07 00:55:35 +020046#include <proto/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020047#include <proto/backend.h>
48#include <proto/buffers.h>
Willy Tarreau91861262007-10-17 17:06:05 +020049#include <proto/dumpstats.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020050#include <proto/fd.h>
51#include <proto/log.h>
Willy Tarreau58f10d72006-12-04 02:26:12 +010052#include <proto/hdr_idx.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020053#include <proto/proto_http.h>
54#include <proto/queue.h>
Willy Tarreau91861262007-10-17 17:06:05 +020055#include <proto/senddata.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020056#include <proto/session.h>
57#include <proto/task.h>
58
Willy Tarreau6d1a9882007-01-07 02:03:04 +010059#ifdef CONFIG_HAP_TCPSPLICE
60#include <libtcpsplice.h>
61#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020062
Willy Tarreau58f10d72006-12-04 02:26:12 +010063#define DEBUG_PARSE_NO_SPEEDUP
64#undef DEBUG_PARSE_NO_SPEEDUP
65
Willy Tarreau976f1ee2006-12-17 10:06:03 +010066/* This is used to perform a quick jump as an alternative to a break/continue
67 * instruction. The first argument is the label for normal operation, and the
68 * second one is the break/continue instruction in the no_speedup mode.
69 */
70
71#ifdef DEBUG_PARSE_NO_SPEEDUP
72#define QUICK_JUMP(x,y) y
73#else
74#define QUICK_JUMP(x,y) goto x
75#endif
76
Willy Tarreau1c47f852006-07-09 08:22:27 +020077/* This is used by remote monitoring */
Willy Tarreau0f772532006-12-23 20:51:41 +010078const char HTTP_200[] =
Willy Tarreau1c47f852006-07-09 08:22:27 +020079 "HTTP/1.0 200 OK\r\n"
80 "Cache-Control: no-cache\r\n"
81 "Connection: close\r\n"
82 "Content-Type: text/html\r\n"
83 "\r\n"
84 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
85
Willy Tarreau0f772532006-12-23 20:51:41 +010086const struct chunk http_200_chunk = {
87 .str = (char *)&HTTP_200,
88 .len = sizeof(HTTP_200)-1
89};
90
Willy Tarreaub463dfb2008-06-07 23:08:56 +020091const char *HTTP_301 =
92 "HTTP/1.0 301 Moved Permantenly\r\n"
93 "Cache-Control: no-cache\r\n"
94 "Connection: close\r\n"
95 "Location: "; /* not terminated since it will be concatenated with the URL */
96
Willy Tarreau0f772532006-12-23 20:51:41 +010097const char *HTTP_302 =
98 "HTTP/1.0 302 Found\r\n"
99 "Cache-Control: no-cache\r\n"
100 "Connection: close\r\n"
101 "Location: "; /* not terminated since it will be concatenated with the URL */
102
103/* same as 302 except that the browser MUST retry with the GET method */
104const char *HTTP_303 =
105 "HTTP/1.0 303 See Other\r\n"
106 "Cache-Control: no-cache\r\n"
107 "Connection: close\r\n"
108 "Location: "; /* not terminated since it will be concatenated with the URL */
109
Willy Tarreaubaaee002006-06-26 02:48:02 +0200110/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
111const char *HTTP_401_fmt =
112 "HTTP/1.0 401 Unauthorized\r\n"
113 "Cache-Control: no-cache\r\n"
114 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +0200115 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200116 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
117 "\r\n"
118 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
119
Willy Tarreau0f772532006-12-23 20:51:41 +0100120
121const int http_err_codes[HTTP_ERR_SIZE] = {
122 [HTTP_ERR_400] = 400,
123 [HTTP_ERR_403] = 403,
124 [HTTP_ERR_408] = 408,
125 [HTTP_ERR_500] = 500,
126 [HTTP_ERR_502] = 502,
127 [HTTP_ERR_503] = 503,
128 [HTTP_ERR_504] = 504,
129};
130
Willy Tarreau80587432006-12-24 17:47:20 +0100131static const char *http_err_msgs[HTTP_ERR_SIZE] = {
Willy Tarreau0f772532006-12-23 20:51:41 +0100132 [HTTP_ERR_400] =
Willy Tarreau80587432006-12-24 17:47:20 +0100133 "HTTP/1.0 400 Bad request\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +0100134 "Cache-Control: no-cache\r\n"
135 "Connection: close\r\n"
136 "Content-Type: text/html\r\n"
137 "\r\n"
138 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
139
140 [HTTP_ERR_403] =
141 "HTTP/1.0 403 Forbidden\r\n"
142 "Cache-Control: no-cache\r\n"
143 "Connection: close\r\n"
144 "Content-Type: text/html\r\n"
145 "\r\n"
146 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
147
148 [HTTP_ERR_408] =
149 "HTTP/1.0 408 Request Time-out\r\n"
150 "Cache-Control: no-cache\r\n"
151 "Connection: close\r\n"
152 "Content-Type: text/html\r\n"
153 "\r\n"
154 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
155
156 [HTTP_ERR_500] =
157 "HTTP/1.0 500 Server Error\r\n"
158 "Cache-Control: no-cache\r\n"
159 "Connection: close\r\n"
160 "Content-Type: text/html\r\n"
161 "\r\n"
162 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n",
163
164 [HTTP_ERR_502] =
165 "HTTP/1.0 502 Bad Gateway\r\n"
166 "Cache-Control: no-cache\r\n"
167 "Connection: close\r\n"
168 "Content-Type: text/html\r\n"
169 "\r\n"
170 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n",
171
172 [HTTP_ERR_503] =
173 "HTTP/1.0 503 Service Unavailable\r\n"
174 "Cache-Control: no-cache\r\n"
175 "Connection: close\r\n"
176 "Content-Type: text/html\r\n"
177 "\r\n"
178 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n",
179
180 [HTTP_ERR_504] =
181 "HTTP/1.0 504 Gateway Time-out\r\n"
182 "Cache-Control: no-cache\r\n"
183 "Connection: close\r\n"
184 "Content-Type: text/html\r\n"
185 "\r\n"
186 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n",
187
188};
189
Willy Tarreau80587432006-12-24 17:47:20 +0100190/* We must put the messages here since GCC cannot initialize consts depending
191 * on strlen().
192 */
193struct chunk http_err_chunks[HTTP_ERR_SIZE];
194
Willy Tarreau42250582007-04-01 01:30:43 +0200195#define FD_SETS_ARE_BITFIELDS
196#ifdef FD_SETS_ARE_BITFIELDS
197/*
198 * This map is used with all the FD_* macros to check whether a particular bit
199 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
200 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
201 * byte should be encoded. Be careful to always pass bytes from 0 to 255
202 * exclusively to the macros.
203 */
204fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
205fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
206
207#else
208#error "Check if your OS uses bitfields for fd_sets"
209#endif
210
Willy Tarreau80587432006-12-24 17:47:20 +0100211void init_proto_http()
212{
Willy Tarreau42250582007-04-01 01:30:43 +0200213 int i;
214 char *tmp;
Willy Tarreau80587432006-12-24 17:47:20 +0100215 int msg;
Willy Tarreau42250582007-04-01 01:30:43 +0200216
Willy Tarreau80587432006-12-24 17:47:20 +0100217 for (msg = 0; msg < HTTP_ERR_SIZE; msg++) {
218 if (!http_err_msgs[msg]) {
219 Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n", msg);
220 abort();
221 }
222
223 http_err_chunks[msg].str = (char *)http_err_msgs[msg];
224 http_err_chunks[msg].len = strlen(http_err_msgs[msg]);
225 }
Willy Tarreau42250582007-04-01 01:30:43 +0200226
227 /* initialize the log header encoding map : '{|}"#' should be encoded with
228 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
229 * URL encoding only requires '"', '#' to be encoded as well as non-
230 * printable characters above.
231 */
232 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
233 memset(url_encode_map, 0, sizeof(url_encode_map));
234 for (i = 0; i < 32; i++) {
235 FD_SET(i, hdr_encode_map);
236 FD_SET(i, url_encode_map);
237 }
238 for (i = 127; i < 256; i++) {
239 FD_SET(i, hdr_encode_map);
240 FD_SET(i, url_encode_map);
241 }
242
243 tmp = "\"#{|}";
244 while (*tmp) {
245 FD_SET(*tmp, hdr_encode_map);
246 tmp++;
247 }
248
249 tmp = "\"#";
250 while (*tmp) {
251 FD_SET(*tmp, url_encode_map);
252 tmp++;
253 }
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200254
255 /* memory allocations */
256 pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED);
Willy Tarreau086b3b42007-05-13 21:45:51 +0200257 pool2_capture = create_pool("capture", CAPTURE_LEN, MEM_F_SHARED);
Willy Tarreau80587432006-12-24 17:47:20 +0100258}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200259
Willy Tarreau53b6c742006-12-17 13:37:46 +0100260/*
261 * We have 26 list of methods (1 per first letter), each of which can have
262 * up to 3 entries (2 valid, 1 null).
263 */
264struct http_method_desc {
265 http_meth_t meth;
266 int len;
267 const char text[8];
268};
269
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100270const struct http_method_desc http_methods[26][3] = {
Willy Tarreau53b6c742006-12-17 13:37:46 +0100271 ['C' - 'A'] = {
272 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
273 },
274 ['D' - 'A'] = {
275 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
276 },
277 ['G' - 'A'] = {
278 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
279 },
280 ['H' - 'A'] = {
281 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
282 },
283 ['P' - 'A'] = {
284 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
285 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
286 },
287 ['T' - 'A'] = {
288 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
289 },
290 /* rest is empty like this :
291 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
292 */
293};
294
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100295/* It is about twice as fast on recent architectures to lookup a byte in a
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +0200296 * table than to perform a boolean AND or OR between two tests. Refer to
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100297 * RFC2616 for those chars.
298 */
299
300const char http_is_spht[256] = {
301 [' '] = 1, ['\t'] = 1,
302};
303
304const char http_is_crlf[256] = {
305 ['\r'] = 1, ['\n'] = 1,
306};
307
308const char http_is_lws[256] = {
309 [' '] = 1, ['\t'] = 1,
310 ['\r'] = 1, ['\n'] = 1,
311};
312
313const char http_is_sep[256] = {
314 ['('] = 1, [')'] = 1, ['<'] = 1, ['>'] = 1,
315 ['@'] = 1, [','] = 1, [';'] = 1, [':'] = 1,
316 ['"'] = 1, ['/'] = 1, ['['] = 1, [']'] = 1,
317 ['{'] = 1, ['}'] = 1, ['?'] = 1, ['='] = 1,
318 [' '] = 1, ['\t'] = 1, ['\\'] = 1,
319};
320
321const char http_is_ctl[256] = {
322 [0 ... 31] = 1,
323 [127] = 1,
324};
325
326/*
327 * A token is any ASCII char that is neither a separator nor a CTL char.
328 * Do not overwrite values in assignment since gcc-2.95 will not handle
329 * them correctly. Instead, define every non-CTL char's status.
330 */
331const char http_is_token[256] = {
332 [' '] = 0, ['!'] = 1, ['"'] = 0, ['#'] = 1,
333 ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1,
334 ['('] = 0, [')'] = 0, ['*'] = 1, ['+'] = 1,
335 [','] = 0, ['-'] = 1, ['.'] = 1, ['/'] = 0,
336 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1,
337 ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1,
338 ['8'] = 1, ['9'] = 1, [':'] = 0, [';'] = 0,
339 ['<'] = 0, ['='] = 0, ['>'] = 0, ['?'] = 0,
340 ['@'] = 0, ['A'] = 1, ['B'] = 1, ['C'] = 1,
341 ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1,
342 ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1,
343 ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1,
344 ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1,
345 ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1,
346 ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 0,
347 ['\\'] = 0, [']'] = 0, ['^'] = 1, ['_'] = 1,
348 ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1,
349 ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1,
350 ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1,
351 ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1,
352 ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1,
353 ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1,
354 ['x'] = 1, ['y'] = 1, ['z'] = 1, ['{'] = 0,
355 ['|'] = 1, ['}'] = 0, ['~'] = 1,
356};
357
358
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100359/*
360 * An http ver_token is any ASCII which can be found in an HTTP version,
361 * which includes 'H', 'T', 'P', '/', '.' and any digit.
362 */
363const char http_is_ver_token[256] = {
364 ['.'] = 1, ['/'] = 1,
365 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1,
366 ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1,
367 ['H'] = 1, ['P'] = 1, ['T'] = 1,
368};
369
370
Willy Tarreaubaaee002006-06-26 02:48:02 +0200371#ifdef DEBUG_FULL
372static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
373static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
374#endif
375
Willy Tarreau42250582007-04-01 01:30:43 +0200376static void http_sess_log(struct session *s);
377
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100378/*
379 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
380 * CRLF. Text length is measured first, so it cannot be NULL.
381 * The header is also automatically added to the index <hdr_idx>, and the end
382 * of headers is automatically adjusted. The number of bytes added is returned
383 * on success, otherwise <0 is returned indicating an error.
384 */
385int http_header_add_tail(struct buffer *b, struct http_msg *msg,
386 struct hdr_idx *hdr_idx, const char *text)
387{
388 int bytes, len;
389
390 len = strlen(text);
391 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
392 if (!bytes)
393 return -1;
394 msg->eoh += bytes;
395 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
396}
397
398/*
399 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
400 * CRLF. <len> bytes are copied, not counting the CRLF. If <text> is NULL, then
401 * the buffer is only opened and the space reserved, but nothing is copied.
402 * The header is also automatically added to the index <hdr_idx>, and the end
403 * of headers is automatically adjusted. The number of bytes added is returned
404 * on success, otherwise <0 is returned indicating an error.
405 */
406int http_header_add_tail2(struct buffer *b, struct http_msg *msg,
407 struct hdr_idx *hdr_idx, const char *text, int len)
408{
409 int bytes;
410
411 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
412 if (!bytes)
413 return -1;
414 msg->eoh += bytes;
415 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
416}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200417
418/*
Willy Tarreauaa9dce32007-03-18 23:50:16 +0100419 * Checks if <hdr> is exactly <name> for <len> chars, and ends with a colon.
420 * If so, returns the position of the first non-space character relative to
421 * <hdr>, or <end>-<hdr> if not found before. If no value is found, it tries
422 * to return a pointer to the place after the first space. Returns 0 if the
423 * header name does not match. Checks are case-insensitive.
424 */
425int http_header_match2(const char *hdr, const char *end,
426 const char *name, int len)
427{
428 const char *val;
429
430 if (hdr + len >= end)
431 return 0;
432 if (hdr[len] != ':')
433 return 0;
434 if (strncasecmp(hdr, name, len) != 0)
435 return 0;
436 val = hdr + len + 1;
437 while (val < end && HTTP_IS_SPHT(*val))
438 val++;
439 if ((val >= end) && (len + 2 <= end - hdr))
440 return len + 2; /* we may replace starting from second space */
441 return val - hdr;
442}
443
Willy Tarreau33a7e692007-06-10 19:45:56 +0200444/* Find the end of the header value contained between <s> and <e>.
445 * See RFC2616, par 2.2 for more information. Note that it requires
446 * a valid header to return a valid result.
447 */
448const char *find_hdr_value_end(const char *s, const char *e)
449{
450 int quoted, qdpair;
451
452 quoted = qdpair = 0;
453 for (; s < e; s++) {
454 if (qdpair) qdpair = 0;
455 else if (quoted && *s == '\\') qdpair = 1;
456 else if (quoted && *s == '"') quoted = 0;
457 else if (*s == '"') quoted = 1;
458 else if (*s == ',') return s;
459 }
460 return s;
461}
462
463/* Find the first or next occurrence of header <name> in message buffer <sol>
464 * using headers index <idx>, and return it in the <ctx> structure. This
465 * structure holds everything necessary to use the header and find next
466 * occurrence. If its <idx> member is 0, the header is searched from the
467 * beginning. Otherwise, the next occurrence is returned. The function returns
468 * 1 when it finds a value, and 0 when there is no more.
469 */
470int http_find_header2(const char *name, int len,
471 const char *sol, struct hdr_idx *idx,
472 struct hdr_ctx *ctx)
473{
474 __label__ return_hdr, next_hdr;
475 const char *eol, *sov;
476 int cur_idx;
477
478 if (ctx->idx) {
479 /* We have previously returned a value, let's search
480 * another one on the same line.
481 */
482 cur_idx = ctx->idx;
483 sol = ctx->line;
484 sov = sol + ctx->val + ctx->vlen;
485 eol = sol + idx->v[cur_idx].len;
486
487 if (sov >= eol)
488 /* no more values in this header */
489 goto next_hdr;
490
491 /* values remaining for this header, skip the comma */
492 sov++;
493 while (sov < eol && http_is_lws[(unsigned char)*sov])
494 sov++;
495
496 goto return_hdr;
497 }
498
499 /* first request for this header */
500 sol += hdr_idx_first_pos(idx);
501 cur_idx = hdr_idx_first_idx(idx);
502
503 while (cur_idx) {
504 eol = sol + idx->v[cur_idx].len;
505
Willy Tarreau1ad7c6d2007-06-10 21:42:55 +0200506 if (len == 0) {
507 /* No argument was passed, we want any header.
508 * To achieve this, we simply build a fake request. */
509 while (sol + len < eol && sol[len] != ':')
510 len++;
511 name = sol;
512 }
513
Willy Tarreau33a7e692007-06-10 19:45:56 +0200514 if ((len < eol - sol) &&
515 (sol[len] == ':') &&
516 (strncasecmp(sol, name, len) == 0)) {
517
518 sov = sol + len + 1;
519 while (sov < eol && http_is_lws[(unsigned char)*sov])
520 sov++;
521 return_hdr:
522 ctx->line = sol;
523 ctx->idx = cur_idx;
524 ctx->val = sov - sol;
525
526 eol = find_hdr_value_end(sov, eol);
527 ctx->vlen = eol - sov;
528 return 1;
529 }
530 next_hdr:
531 sol = eol + idx->v[cur_idx].cr + 1;
532 cur_idx = idx->v[cur_idx].next;
533 }
534 return 0;
535}
536
537int http_find_header(const char *name,
538 const char *sol, struct hdr_idx *idx,
539 struct hdr_ctx *ctx)
540{
541 return http_find_header2(name, strlen(name), sol, idx, ctx);
542}
543
Willy Tarreaubaaee002006-06-26 02:48:02 +0200544/* This function turns the server state into the SV_STCLOSE, and sets
Willy Tarreau0f772532006-12-23 20:51:41 +0100545 * indicators accordingly. Note that if <status> is 0, or if the message
546 * pointer is NULL, then no message is returned.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200547 */
548void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreau0f772532006-12-23 20:51:41 +0100549 int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200550{
551 t->srv_state = SV_STCLOSE;
Willy Tarreau0f772532006-12-23 20:51:41 +0100552 if (status > 0 && msg) {
Willy Tarreau3bac9ff2007-03-18 17:31:28 +0100553 t->txn.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100554 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100555 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200556 }
557 if (!(t->flags & SN_ERR_MASK))
558 t->flags |= err;
559 if (!(t->flags & SN_FINST_MASK))
560 t->flags |= finst;
561}
562
Willy Tarreau80587432006-12-24 17:47:20 +0100563/* This function returns the appropriate error location for the given session
564 * and message.
565 */
566
567struct chunk *error_message(struct session *s, int msgnum)
568{
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200569 if (s->be->errmsg[msgnum].str)
570 return &s->be->errmsg[msgnum];
Willy Tarreau80587432006-12-24 17:47:20 +0100571 else if (s->fe->errmsg[msgnum].str)
572 return &s->fe->errmsg[msgnum];
573 else
574 return &http_err_chunks[msgnum];
575}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200576
Willy Tarreau53b6c742006-12-17 13:37:46 +0100577/*
578 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
579 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
580 */
581static http_meth_t find_http_meth(const char *str, const int len)
582{
583 unsigned char m;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100584 const struct http_method_desc *h;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100585
586 m = ((unsigned)*str - 'A');
587
588 if (m < 26) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100589 for (h = http_methods[m]; h->len > 0; h++) {
590 if (unlikely(h->len != len))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100591 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100592 if (likely(memcmp(str, h->text, h->len) == 0))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100593 return h->meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100594 };
595 return HTTP_METH_OTHER;
596 }
597 return HTTP_METH_NONE;
598
599}
600
Willy Tarreau21d2af32008-02-14 20:25:24 +0100601/* Parse the URI from the given transaction (which is assumed to be in request
602 * phase) and look for the "/" beginning the PATH. If not found, return NULL.
603 * It is returned otherwise.
604 */
605static char *
606http_get_path(struct http_txn *txn)
607{
608 char *ptr, *end;
609
610 ptr = txn->req.sol + txn->req.sl.rq.u;
611 end = ptr + txn->req.sl.rq.u_l;
612
613 if (ptr >= end)
614 return NULL;
615
616 /* RFC2616, par. 5.1.2 :
617 * Request-URI = "*" | absuri | abspath | authority
618 */
619
620 if (*ptr == '*')
621 return NULL;
622
623 if (isalpha((unsigned char)*ptr)) {
624 /* this is a scheme as described by RFC3986, par. 3.1 */
625 ptr++;
626 while (ptr < end &&
627 (isalnum((unsigned char)*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.'))
628 ptr++;
629 /* skip '://' */
630 if (ptr == end || *ptr++ != ':')
631 return NULL;
632 if (ptr == end || *ptr++ != '/')
633 return NULL;
634 if (ptr == end || *ptr++ != '/')
635 return NULL;
636 }
637 /* skip [user[:passwd]@]host[:[port]] */
638
639 while (ptr < end && *ptr != '/')
640 ptr++;
641
642 if (ptr == end)
643 return NULL;
644
645 /* OK, we got the '/' ! */
646 return ptr;
647}
648
Willy Tarreaubaaee002006-06-26 02:48:02 +0200649/* Processes the client and server jobs of a session task, then
650 * puts it back to the wait queue in a clean state, or
651 * cleans up its resources if it must be deleted. Returns
652 * the time the task accepts to wait, or TIME_ETERNITY for
653 * infinity.
654 */
Willy Tarreaud825eef2007-05-12 22:35:00 +0200655void process_session(struct task *t, struct timeval *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200656{
657 struct session *s = t->context;
658 int fsm_resync = 0;
659
660 do {
661 fsm_resync = 0;
662 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
663 fsm_resync |= process_cli(s);
664 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
665 fsm_resync |= process_srv(s);
666 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
667 } while (fsm_resync);
668
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200669 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100670
671 if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
672 session_process_counters(s);
673
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200674 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
675 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200676
Willy Tarreaua6a6a932007-04-28 22:40:08 +0200677 tv_min(&t->expire, &s->req->rex, &s->req->wex);
678 tv_bound(&t->expire, &s->req->cex);
679 tv_bound(&t->expire, &s->rep->rex);
680 tv_bound(&t->expire, &s->rep->wex);
Willy Tarreau036fae02008-01-06 13:24:40 +0100681 if (s->cli_state == CL_STHEADERS)
682 tv_bound(&t->expire, &s->txn.exp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200683
684 /* restore t to its place in the task list */
685 task_queue(t);
686
687#ifdef DEBUG_FULL
688 /* DEBUG code : this should never ever happen, otherwise it indicates
689 * that a task still has something to do and will provoke a quick loop.
690 */
Willy Tarreaub8816082008-01-18 12:18:15 +0100691 if (tv_ms_remain2(&now, &t->expire) <= 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200692 exit(100);
693#endif
Willy Tarreaud825eef2007-05-12 22:35:00 +0200694 *next = t->expire;
695 return; /* nothing more to do */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200696 }
697
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100698 s->fe->feconn--;
699 if (s->flags & SN_BE_ASSIGNED)
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200700 s->be->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200701 actconn--;
702
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200703 if (unlikely((global.mode & MODE_DEBUG) &&
704 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200705 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100706 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200707 s->uniq_id, s->be->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100708 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200709 write(1, trash, len);
710 }
711
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200712 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100713 session_process_counters(s);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200714
715 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200716 if (s->logs.logwait &&
717 !(s->flags & SN_MONITOR) &&
Willy Tarreau42250582007-04-01 01:30:43 +0200718 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total)) {
719 if (s->fe->to_log & LW_REQ)
720 http_sess_log(s);
721 else
722 tcp_sess_log(s);
723 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200724
725 /* the task MUST not be in the run queue anymore */
726 task_delete(t);
727 session_free(s);
728 task_free(t);
Willy Tarreaud825eef2007-05-12 22:35:00 +0200729 tv_eternity(next);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200730}
731
732
Willy Tarreau42250582007-04-01 01:30:43 +0200733extern const char sess_term_cond[8];
734extern const char sess_fin_state[8];
735extern const char *monthname[12];
736const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
737const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
738 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
739 unknown, Set-cookie Rewritten */
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200740struct pool_head *pool2_requri;
Willy Tarreau086b3b42007-05-13 21:45:51 +0200741struct pool_head *pool2_capture;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100742
Willy Tarreau42250582007-04-01 01:30:43 +0200743/*
744 * send a log for the session when we have enough info about it.
745 * Will not log if the frontend has no log defined.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100746 */
Willy Tarreau42250582007-04-01 01:30:43 +0200747static void http_sess_log(struct session *s)
748{
749 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
750 struct proxy *fe = s->fe;
751 struct proxy *be = s->be;
752 struct proxy *prx_log;
753 struct http_txn *txn = &s->txn;
754 int tolog;
755 char *uri, *h;
756 char *svid;
Willy Tarreaufe944602007-10-25 10:34:16 +0200757 struct tm tm;
Willy Tarreau42250582007-04-01 01:30:43 +0200758 static char tmpline[MAX_SYSLOG_LEN];
Willy Tarreau70089872008-06-13 21:12:51 +0200759 int t_request;
Willy Tarreau42250582007-04-01 01:30:43 +0200760 int hdr;
761
762 if (fe->logfac1 < 0 && fe->logfac2 < 0)
763 return;
764 prx_log = fe;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100765
Willy Tarreau42250582007-04-01 01:30:43 +0200766 if (s->cli_addr.ss_family == AF_INET)
767 inet_ntop(AF_INET,
768 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
769 pn, sizeof(pn));
770 else
771 inet_ntop(AF_INET6,
772 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
773 pn, sizeof(pn));
774
Willy Tarreaufe944602007-10-25 10:34:16 +0200775 get_localtime(s->logs.tv_accept.tv_sec, &tm);
Willy Tarreau42250582007-04-01 01:30:43 +0200776
777 /* FIXME: let's limit ourselves to frontend logging for now. */
778 tolog = fe->to_log;
779
780 h = tmpline;
781 if (fe->to_log & LW_REQHDR &&
782 txn->req.cap &&
783 (h < tmpline + sizeof(tmpline) - 10)) {
784 *(h++) = ' ';
785 *(h++) = '{';
786 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
787 if (hdr)
788 *(h++) = '|';
789 if (txn->req.cap[hdr] != NULL)
790 h = encode_string(h, tmpline + sizeof(tmpline) - 7,
791 '#', hdr_encode_map, txn->req.cap[hdr]);
792 }
793 *(h++) = '}';
794 }
795
796 if (fe->to_log & LW_RSPHDR &&
797 txn->rsp.cap &&
798 (h < tmpline + sizeof(tmpline) - 7)) {
799 *(h++) = ' ';
800 *(h++) = '{';
801 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
802 if (hdr)
803 *(h++) = '|';
804 if (txn->rsp.cap[hdr] != NULL)
805 h = encode_string(h, tmpline + sizeof(tmpline) - 4,
806 '#', hdr_encode_map, txn->rsp.cap[hdr]);
807 }
808 *(h++) = '}';
809 }
810
811 if (h < tmpline + sizeof(tmpline) - 4) {
812 *(h++) = ' ';
813 *(h++) = '"';
814 uri = txn->uri ? txn->uri : "<BADREQ>";
815 h = encode_string(h, tmpline + sizeof(tmpline) - 1,
816 '#', url_encode_map, uri);
817 *(h++) = '"';
818 }
819 *h = '\0';
820
821 svid = (tolog & LW_SVID) ?
822 (s->data_source != DATA_SRC_STATS) ?
823 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
824
Willy Tarreau70089872008-06-13 21:12:51 +0200825 t_request = -1;
826 if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
827 t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
828
Willy Tarreau42250582007-04-01 01:30:43 +0200829 send_log(prx_log, LOG_INFO,
830 "%s:%d [%02d/%s/%04d:%02d:%02d:%02d.%03d]"
831 " %s %s/%s %d/%d/%d/%d/%s%d %d %s%lld"
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100832 " %s %s %c%c%c%c %d/%d/%d/%d/%s%u %d/%d%s\n",
Willy Tarreau42250582007-04-01 01:30:43 +0200833 pn,
834 (s->cli_addr.ss_family == AF_INET) ?
835 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
836 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
Willy Tarreaufe944602007-10-25 10:34:16 +0200837 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
838 tm.tm_hour, tm.tm_min, tm.tm_sec, s->logs.tv_accept.tv_usec/1000,
Willy Tarreau42250582007-04-01 01:30:43 +0200839 fe->id, be->id, svid,
Willy Tarreau70089872008-06-13 21:12:51 +0200840 t_request,
841 (s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1,
Willy Tarreau42250582007-04-01 01:30:43 +0200842 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
843 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
844 (tolog & LW_BYTES) ? "" : "+", s->logs.t_close,
845 txn->status,
Willy Tarreau8b3977f2008-01-18 11:16:32 +0100846 (tolog & LW_BYTES) ? "" : "+", s->logs.bytes_out,
Willy Tarreau42250582007-04-01 01:30:43 +0200847 txn->cli_cookie ? txn->cli_cookie : "-",
848 txn->srv_cookie ? txn->srv_cookie : "-",
849 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
850 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
851 (be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-',
852 (be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-',
853 actconn, fe->feconn, be->beconn, s->srv ? s->srv->cur_sess : 0,
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100854 (s->flags & SN_REDISP)?"+":"",
855 (s->conn_retries>0)?(be->conn_retries - s->conn_retries):be->conn_retries,
Willy Tarreau42250582007-04-01 01:30:43 +0200856 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
857
858 s->logs.logwait = 0;
859}
860
Willy Tarreau117f59e2007-03-04 18:17:17 +0100861
862/*
863 * Capture headers from message starting at <som> according to header list
864 * <cap_hdr>, and fill the <idx> structure appropriately.
865 */
866void capture_headers(char *som, struct hdr_idx *idx,
867 char **cap, struct cap_hdr *cap_hdr)
868{
869 char *eol, *sol, *col, *sov;
870 int cur_idx;
871 struct cap_hdr *h;
872 int len;
873
874 sol = som + hdr_idx_first_pos(idx);
875 cur_idx = hdr_idx_first_idx(idx);
876
877 while (cur_idx) {
878 eol = sol + idx->v[cur_idx].len;
879
880 col = sol;
881 while (col < eol && *col != ':')
882 col++;
883
884 sov = col + 1;
885 while (sov < eol && http_is_lws[(unsigned char)*sov])
886 sov++;
887
888 for (h = cap_hdr; h; h = h->next) {
889 if ((h->namelen == col - sol) &&
890 (strncasecmp(sol, h->name, h->namelen) == 0)) {
891 if (cap[h->index] == NULL)
892 cap[h->index] =
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200893 pool_alloc2(h->pool);
Willy Tarreau117f59e2007-03-04 18:17:17 +0100894
895 if (cap[h->index] == NULL) {
896 Alert("HTTP capture : out of memory.\n");
897 continue;
898 }
899
900 len = eol - sov;
901 if (len > h->len)
902 len = h->len;
903
904 memcpy(cap[h->index], sov, len);
905 cap[h->index][len]=0;
906 }
907 }
908 sol = eol + idx->v[cur_idx].cr + 1;
909 cur_idx = idx->v[cur_idx].next;
910 }
911}
912
913
Willy Tarreau42250582007-04-01 01:30:43 +0200914/* either we find an LF at <ptr> or we jump to <bad>.
915 */
916#define EXPECT_LF_HERE(ptr, bad) do { if (unlikely(*(ptr) != '\n')) goto bad; } while (0)
917
918/* plays with variables <ptr>, <end> and <state>. Jumps to <good> if OK,
919 * otherwise to <http_msg_ood> with <state> set to <st>.
920 */
921#define EAT_AND_JUMP_OR_RETURN(good, st) do { \
922 ptr++; \
923 if (likely(ptr < end)) \
924 goto good; \
925 else { \
926 state = (st); \
927 goto http_msg_ood; \
928 } \
929 } while (0)
930
931
Willy Tarreaubaaee002006-06-26 02:48:02 +0200932/*
Willy Tarreaua15645d2007-03-18 16:22:39 +0100933 * This function parses a status line between <ptr> and <end>, starting with
Willy Tarreau8973c702007-01-21 23:58:29 +0100934 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
935 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
936 * will give undefined results.
937 * Note that it is upon the caller's responsibility to ensure that ptr < end,
938 * and that msg->sol points to the beginning of the response.
939 * If a complete line is found (which implies that at least one CR or LF is
940 * found before <end>, the updated <ptr> is returned, otherwise NULL is
941 * returned indicating an incomplete line (which does not mean that parts have
942 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
943 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
944 * upon next call.
945 *
Willy Tarreau9cdde232007-05-02 20:58:19 +0200946 * This function was intentionally designed to be called from
Willy Tarreau8973c702007-01-21 23:58:29 +0100947 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
948 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +0200949 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreau8973c702007-01-21 23:58:29 +0100950 */
Willy Tarreaue69eada2008-01-27 00:34:10 +0100951const char *http_parse_stsline(struct http_msg *msg, const char *msg_buf,
952 unsigned int state, const char *ptr, const char *end,
953 char **ret_ptr, unsigned int *ret_state)
Willy Tarreau8973c702007-01-21 23:58:29 +0100954{
955 __label__
956 http_msg_rpver,
957 http_msg_rpver_sp,
958 http_msg_rpcode,
959 http_msg_rpcode_sp,
960 http_msg_rpreason,
961 http_msg_rpline_eol,
962 http_msg_ood, /* out of data */
963 http_msg_invalid;
964
965 switch (state) {
966 http_msg_rpver:
967 case HTTP_MSG_RPVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100968 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8973c702007-01-21 23:58:29 +0100969 EAT_AND_JUMP_OR_RETURN(http_msg_rpver, HTTP_MSG_RPVER);
970
971 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +0100972 msg->sl.st.v_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +0100973 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
974 }
975 goto http_msg_invalid;
976
977 http_msg_rpver_sp:
978 case HTTP_MSG_RPVER_SP:
979 if (likely(!HTTP_IS_LWS(*ptr))) {
980 msg->sl.st.c = ptr - msg_buf;
981 goto http_msg_rpcode;
982 }
983 if (likely(HTTP_IS_SPHT(*ptr)))
984 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
985 /* so it's a CR/LF, this is invalid */
986 goto http_msg_invalid;
987
988 http_msg_rpcode:
989 case HTTP_MSG_RPCODE:
990 if (likely(!HTTP_IS_LWS(*ptr)))
991 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode, HTTP_MSG_RPCODE);
992
993 if (likely(HTTP_IS_SPHT(*ptr))) {
994 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
995 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
996 }
997
998 /* so it's a CR/LF, so there is no reason phrase */
999 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
1000 http_msg_rsp_reason:
1001 /* FIXME: should we support HTTP responses without any reason phrase ? */
1002 msg->sl.st.r = ptr - msg_buf;
1003 msg->sl.st.r_l = 0;
1004 goto http_msg_rpline_eol;
1005
1006 http_msg_rpcode_sp:
1007 case HTTP_MSG_RPCODE_SP:
1008 if (likely(!HTTP_IS_LWS(*ptr))) {
1009 msg->sl.st.r = ptr - msg_buf;
1010 goto http_msg_rpreason;
1011 }
1012 if (likely(HTTP_IS_SPHT(*ptr)))
1013 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1014 /* so it's a CR/LF, so there is no reason phrase */
1015 goto http_msg_rsp_reason;
1016
1017 http_msg_rpreason:
1018 case HTTP_MSG_RPREASON:
1019 if (likely(!HTTP_IS_CRLF(*ptr)))
1020 EAT_AND_JUMP_OR_RETURN(http_msg_rpreason, HTTP_MSG_RPREASON);
1021 msg->sl.st.r_l = (ptr - msg_buf) - msg->sl.st.r;
1022 http_msg_rpline_eol:
1023 /* We have seen the end of line. Note that we do not
1024 * necessarily have the \n yet, but at least we know that we
1025 * have EITHER \r OR \n, otherwise the response would not be
1026 * complete. We can then record the response length and return
1027 * to the caller which will be able to register it.
1028 */
1029 msg->sl.st.l = ptr - msg->sol;
1030 return ptr;
1031
1032#ifdef DEBUG_FULL
1033 default:
1034 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1035 exit(1);
1036#endif
1037 }
1038
1039 http_msg_ood:
1040 /* out of data */
1041 if (ret_state)
1042 *ret_state = state;
1043 if (ret_ptr)
1044 *ret_ptr = (char *)ptr;
1045 return NULL;
1046
1047 http_msg_invalid:
1048 /* invalid message */
1049 if (ret_state)
1050 *ret_state = HTTP_MSG_ERROR;
1051 return NULL;
1052}
1053
1054
1055/*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001056 * This function parses a request line between <ptr> and <end>, starting with
1057 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
1058 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
1059 * will give undefined results.
1060 * Note that it is upon the caller's responsibility to ensure that ptr < end,
1061 * and that msg->sol points to the beginning of the request.
1062 * If a complete line is found (which implies that at least one CR or LF is
1063 * found before <end>, the updated <ptr> is returned, otherwise NULL is
1064 * returned indicating an incomplete line (which does not mean that parts have
1065 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
1066 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
1067 * upon next call.
1068 *
Willy Tarreau9cdde232007-05-02 20:58:19 +02001069 * This function was intentionally designed to be called from
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001070 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
1071 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +02001072 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001073 */
Willy Tarreaue69eada2008-01-27 00:34:10 +01001074const char *http_parse_reqline(struct http_msg *msg, const char *msg_buf,
1075 unsigned int state, const char *ptr, const char *end,
1076 char **ret_ptr, unsigned int *ret_state)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001077{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001078 __label__
1079 http_msg_rqmeth,
1080 http_msg_rqmeth_sp,
1081 http_msg_rquri,
1082 http_msg_rquri_sp,
1083 http_msg_rqver,
1084 http_msg_rqline_eol,
1085 http_msg_ood, /* out of data */
1086 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001087
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001088 switch (state) {
1089 http_msg_rqmeth:
1090 case HTTP_MSG_RQMETH:
1091 if (likely(HTTP_IS_TOKEN(*ptr)))
1092 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth, HTTP_MSG_RQMETH);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001093
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001094 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001095 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001096 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1097 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001098
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001099 if (likely(HTTP_IS_CRLF(*ptr))) {
1100 /* HTTP 0.9 request */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001101 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001102 http_msg_req09_uri:
1103 msg->sl.rq.u = ptr - msg_buf;
1104 http_msg_req09_uri_e:
1105 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1106 http_msg_req09_ver:
1107 msg->sl.rq.v = ptr - msg_buf;
1108 msg->sl.rq.v_l = 0;
1109 goto http_msg_rqline_eol;
1110 }
1111 goto http_msg_invalid;
1112
1113 http_msg_rqmeth_sp:
1114 case HTTP_MSG_RQMETH_SP:
1115 if (likely(!HTTP_IS_LWS(*ptr))) {
1116 msg->sl.rq.u = ptr - msg_buf;
1117 goto http_msg_rquri;
1118 }
1119 if (likely(HTTP_IS_SPHT(*ptr)))
1120 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1121 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1122 goto http_msg_req09_uri;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001123
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001124 http_msg_rquri:
1125 case HTTP_MSG_RQURI:
1126 if (likely(!HTTP_IS_LWS(*ptr)))
1127 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001128
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001129 if (likely(HTTP_IS_SPHT(*ptr))) {
1130 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1131 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1132 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001133
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001134 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1135 goto http_msg_req09_uri_e;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001136
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001137 http_msg_rquri_sp:
1138 case HTTP_MSG_RQURI_SP:
1139 if (likely(!HTTP_IS_LWS(*ptr))) {
1140 msg->sl.rq.v = ptr - msg_buf;
1141 goto http_msg_rqver;
1142 }
1143 if (likely(HTTP_IS_SPHT(*ptr)))
1144 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1145 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1146 goto http_msg_req09_ver;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001147
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001148 http_msg_rqver:
1149 case HTTP_MSG_RQVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001150 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001151 EAT_AND_JUMP_OR_RETURN(http_msg_rqver, HTTP_MSG_RQVER);
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001152
1153 if (likely(HTTP_IS_CRLF(*ptr))) {
1154 msg->sl.rq.v_l = (ptr - msg_buf) - msg->sl.rq.v;
1155 http_msg_rqline_eol:
1156 /* We have seen the end of line. Note that we do not
1157 * necessarily have the \n yet, but at least we know that we
1158 * have EITHER \r OR \n, otherwise the request would not be
1159 * complete. We can then record the request length and return
1160 * to the caller which will be able to register it.
1161 */
1162 msg->sl.rq.l = ptr - msg->sol;
1163 return ptr;
1164 }
1165
1166 /* neither an HTTP_VER token nor a CRLF */
1167 goto http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001168
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001169#ifdef DEBUG_FULL
1170 default:
1171 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1172 exit(1);
1173#endif
1174 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001175
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001176 http_msg_ood:
1177 /* out of data */
1178 if (ret_state)
1179 *ret_state = state;
1180 if (ret_ptr)
1181 *ret_ptr = (char *)ptr;
1182 return NULL;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001183
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001184 http_msg_invalid:
1185 /* invalid message */
1186 if (ret_state)
1187 *ret_state = HTTP_MSG_ERROR;
1188 return NULL;
1189}
Willy Tarreau58f10d72006-12-04 02:26:12 +01001190
1191
Willy Tarreau8973c702007-01-21 23:58:29 +01001192/*
1193 * This function parses an HTTP message, either a request or a response,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001194 * depending on the initial msg->msg_state. It can be preempted everywhere
Willy Tarreau8973c702007-01-21 23:58:29 +01001195 * when data are missing and recalled at the exact same location with no
1196 * information loss. The header index is re-initialized when switching from
Willy Tarreau9cdde232007-05-02 20:58:19 +02001197 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH. It modifies msg->sol among other
1198 * fields.
Willy Tarreau8973c702007-01-21 23:58:29 +01001199 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001200void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx *idx)
1201{
1202 __label__
1203 http_msg_rqbefore,
1204 http_msg_rqbefore_cr,
1205 http_msg_rqmeth,
1206 http_msg_rqline_end,
1207 http_msg_hdr_first,
1208 http_msg_hdr_name,
1209 http_msg_hdr_l1_sp,
1210 http_msg_hdr_l1_lf,
1211 http_msg_hdr_l1_lws,
1212 http_msg_hdr_val,
1213 http_msg_hdr_l2_lf,
1214 http_msg_hdr_l2_lws,
1215 http_msg_complete_header,
1216 http_msg_last_lf,
1217 http_msg_ood, /* out of data */
1218 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001219
Willy Tarreaue69eada2008-01-27 00:34:10 +01001220 unsigned int state; /* updated only when leaving the FSM */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001221 register char *ptr, *end; /* request pointers, to avoid dereferences */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001222
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001223 state = msg->msg_state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001224 ptr = buf->lr;
1225 end = buf->r;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001226
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001227 if (unlikely(ptr >= end))
1228 goto http_msg_ood;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001229
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001230 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +01001231 /*
1232 * First, states that are specific to the response only.
1233 * We check them first so that request and headers are
1234 * closer to each other (accessed more often).
1235 */
1236 http_msg_rpbefore:
1237 case HTTP_MSG_RPBEFORE:
1238 if (likely(HTTP_IS_TOKEN(*ptr))) {
1239 if (likely(ptr == buf->data)) {
1240 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001241 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001242 } else {
1243#if PARSE_PRESERVE_EMPTY_LINES
1244 /* only skip empty leading lines, don't remove them */
1245 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001246 msg->som = ptr - buf->data;
Willy Tarreau8973c702007-01-21 23:58:29 +01001247#else
1248 /* Remove empty leading lines, as recommended by
1249 * RFC2616. This takes a lot of time because we
1250 * must move all the buffer backwards, but this
1251 * is rarely needed. The method above will be
1252 * cleaner when we'll be able to start sending
1253 * the request from any place in the buffer.
1254 */
1255 buf->lr = ptr;
1256 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001257 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001258 msg->sol = buf->data;
1259 ptr = buf->data;
1260 end = buf->r;
1261#endif
1262 }
1263 hdr_idx_init(idx);
1264 state = HTTP_MSG_RPVER;
1265 goto http_msg_rpver;
1266 }
1267
1268 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1269 goto http_msg_invalid;
1270
1271 if (unlikely(*ptr == '\n'))
1272 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1273 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore_cr, HTTP_MSG_RPBEFORE_CR);
1274 /* stop here */
1275
1276 http_msg_rpbefore_cr:
1277 case HTTP_MSG_RPBEFORE_CR:
1278 EXPECT_LF_HERE(ptr, http_msg_invalid);
1279 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1280 /* stop here */
1281
1282 http_msg_rpver:
1283 case HTTP_MSG_RPVER:
1284 case HTTP_MSG_RPVER_SP:
1285 case HTTP_MSG_RPCODE:
1286 case HTTP_MSG_RPCODE_SP:
1287 case HTTP_MSG_RPREASON:
Willy Tarreaua15645d2007-03-18 16:22:39 +01001288 ptr = (char *)http_parse_stsline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001289 &buf->lr, &msg->msg_state);
Willy Tarreau8973c702007-01-21 23:58:29 +01001290 if (unlikely(!ptr))
1291 return;
1292
1293 /* we have a full response and we know that we have either a CR
1294 * or an LF at <ptr>.
1295 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001296 //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 +01001297 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
1298
1299 msg->sol = ptr;
1300 if (likely(*ptr == '\r'))
1301 EAT_AND_JUMP_OR_RETURN(http_msg_rpline_end, HTTP_MSG_RPLINE_END);
1302 goto http_msg_rpline_end;
1303
1304 http_msg_rpline_end:
1305 case HTTP_MSG_RPLINE_END:
1306 /* msg->sol must point to the first of CR or LF. */
1307 EXPECT_LF_HERE(ptr, http_msg_invalid);
1308 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
1309 /* stop here */
1310
1311 /*
1312 * Second, states that are specific to the request only
1313 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001314 http_msg_rqbefore:
1315 case HTTP_MSG_RQBEFORE:
1316 if (likely(HTTP_IS_TOKEN(*ptr))) {
1317 if (likely(ptr == buf->data)) {
1318 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001319 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001320 } else {
1321#if PARSE_PRESERVE_EMPTY_LINES
1322 /* only skip empty leading lines, don't remove them */
1323 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001324 msg->som = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001325#else
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001326 /* Remove empty leading lines, as recommended by
1327 * RFC2616. This takes a lot of time because we
1328 * must move all the buffer backwards, but this
1329 * is rarely needed. The method above will be
1330 * cleaner when we'll be able to start sending
1331 * the request from any place in the buffer.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001332 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001333 buf->lr = ptr;
1334 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001335 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001336 msg->sol = buf->data;
1337 ptr = buf->data;
1338 end = buf->r;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001339#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001340 }
Willy Tarreauf0d058e2007-01-25 12:03:42 +01001341 /* we will need this when keep-alive will be supported
1342 hdr_idx_init(idx);
1343 */
Willy Tarreau8973c702007-01-21 23:58:29 +01001344 state = HTTP_MSG_RQMETH;
1345 goto http_msg_rqmeth;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001346 }
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001347
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001348 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1349 goto http_msg_invalid;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001350
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001351 if (unlikely(*ptr == '\n'))
1352 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
1353 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore_cr, HTTP_MSG_RQBEFORE_CR);
Willy Tarreau8973c702007-01-21 23:58:29 +01001354 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001355
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001356 http_msg_rqbefore_cr:
1357 case HTTP_MSG_RQBEFORE_CR:
1358 EXPECT_LF_HERE(ptr, http_msg_invalid);
1359 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
Willy Tarreau8973c702007-01-21 23:58:29 +01001360 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001361
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001362 http_msg_rqmeth:
1363 case HTTP_MSG_RQMETH:
1364 case HTTP_MSG_RQMETH_SP:
1365 case HTTP_MSG_RQURI:
1366 case HTTP_MSG_RQURI_SP:
1367 case HTTP_MSG_RQVER:
1368 ptr = (char *)http_parse_reqline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001369 &buf->lr, &msg->msg_state);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001370 if (unlikely(!ptr))
1371 return;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001372
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001373 /* we have a full request and we know that we have either a CR
1374 * or an LF at <ptr>.
1375 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001376 //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 +01001377 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001378
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001379 msg->sol = ptr;
1380 if (likely(*ptr == '\r'))
1381 EAT_AND_JUMP_OR_RETURN(http_msg_rqline_end, HTTP_MSG_RQLINE_END);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001382 goto http_msg_rqline_end;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001383
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001384 http_msg_rqline_end:
1385 case HTTP_MSG_RQLINE_END:
1386 /* check for HTTP/0.9 request : no version information available.
1387 * msg->sol must point to the first of CR or LF.
1388 */
1389 if (unlikely(msg->sl.rq.v_l == 0))
1390 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001391
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001392 EXPECT_LF_HERE(ptr, http_msg_invalid);
1393 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
Willy Tarreau8973c702007-01-21 23:58:29 +01001394 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001395
Willy Tarreau8973c702007-01-21 23:58:29 +01001396 /*
1397 * Common states below
1398 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001399 http_msg_hdr_first:
1400 case HTTP_MSG_HDR_FIRST:
1401 msg->sol = ptr;
1402 if (likely(!HTTP_IS_CRLF(*ptr))) {
1403 goto http_msg_hdr_name;
1404 }
1405
1406 if (likely(*ptr == '\r'))
1407 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1408 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001409
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001410 http_msg_hdr_name:
1411 case HTTP_MSG_HDR_NAME:
1412 /* assumes msg->sol points to the first char */
1413 if (likely(HTTP_IS_TOKEN(*ptr)))
1414 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001415
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001416 if (likely(*ptr == ':')) {
1417 msg->col = ptr - buf->data;
1418 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
1419 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001420
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001421 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001422
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001423 http_msg_hdr_l1_sp:
1424 case HTTP_MSG_HDR_L1_SP:
1425 /* assumes msg->sol points to the first char and msg->col to the colon */
1426 if (likely(HTTP_IS_SPHT(*ptr)))
1427 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001428
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001429 /* header value can be basically anything except CR/LF */
1430 msg->sov = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001431
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001432 if (likely(!HTTP_IS_CRLF(*ptr))) {
1433 goto http_msg_hdr_val;
1434 }
1435
1436 if (likely(*ptr == '\r'))
1437 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lf, HTTP_MSG_HDR_L1_LF);
1438 goto http_msg_hdr_l1_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001439
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001440 http_msg_hdr_l1_lf:
1441 case HTTP_MSG_HDR_L1_LF:
1442 EXPECT_LF_HERE(ptr, http_msg_invalid);
1443 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lws, HTTP_MSG_HDR_L1_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001444
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001445 http_msg_hdr_l1_lws:
1446 case HTTP_MSG_HDR_L1_LWS:
1447 if (likely(HTTP_IS_SPHT(*ptr))) {
1448 /* replace HT,CR,LF with spaces */
1449 for (; buf->data+msg->sov < ptr; msg->sov++)
1450 buf->data[msg->sov] = ' ';
1451 goto http_msg_hdr_l1_sp;
1452 }
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001453 /* we had a header consisting only in spaces ! */
1454 msg->eol = buf->data + msg->sov;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001455 goto http_msg_complete_header;
1456
1457 http_msg_hdr_val:
1458 case HTTP_MSG_HDR_VAL:
1459 /* assumes msg->sol points to the first char, msg->col to the
1460 * colon, and msg->sov points to the first character of the
1461 * value.
1462 */
1463 if (likely(!HTTP_IS_CRLF(*ptr)))
1464 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001465
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001466 msg->eol = ptr;
1467 /* Note: we could also copy eol into ->eoh so that we have the
1468 * real header end in case it ends with lots of LWS, but is this
1469 * really needed ?
1470 */
1471 if (likely(*ptr == '\r'))
1472 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1473 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001474
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001475 http_msg_hdr_l2_lf:
1476 case HTTP_MSG_HDR_L2_LF:
1477 EXPECT_LF_HERE(ptr, http_msg_invalid);
1478 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001479
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001480 http_msg_hdr_l2_lws:
1481 case HTTP_MSG_HDR_L2_LWS:
1482 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1483 /* LWS: replace HT,CR,LF with spaces */
1484 for (; msg->eol < ptr; msg->eol++)
1485 *msg->eol = ' ';
1486 goto http_msg_hdr_val;
1487 }
1488 http_msg_complete_header:
1489 /*
1490 * It was a new header, so the last one is finished.
1491 * Assumes msg->sol points to the first char, msg->col to the
1492 * colon, msg->sov points to the first character of the value
1493 * and msg->eol to the first CR or LF so we know how the line
1494 * ends. We insert last header into the index.
1495 */
1496 /*
1497 fprintf(stderr,"registering %-2d bytes : ", msg->eol - msg->sol);
1498 write(2, msg->sol, msg->eol-msg->sol);
1499 fprintf(stderr,"\n");
1500 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001501
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001502 if (unlikely(hdr_idx_add(msg->eol - msg->sol, *msg->eol == '\r',
1503 idx, idx->tail) < 0))
1504 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001505
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001506 msg->sol = ptr;
1507 if (likely(!HTTP_IS_CRLF(*ptr))) {
1508 goto http_msg_hdr_name;
1509 }
1510
1511 if (likely(*ptr == '\r'))
1512 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1513 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001514
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001515 http_msg_last_lf:
1516 case HTTP_MSG_LAST_LF:
1517 /* Assumes msg->sol points to the first of either CR or LF */
1518 EXPECT_LF_HERE(ptr, http_msg_invalid);
1519 ptr++;
1520 buf->lr = ptr;
1521 msg->eoh = msg->sol - buf->data;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001522 msg->msg_state = HTTP_MSG_BODY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001523 return;
1524#ifdef DEBUG_FULL
1525 default:
1526 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1527 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001528#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001529 }
1530 http_msg_ood:
1531 /* out of data */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001532 msg->msg_state = state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001533 buf->lr = ptr;
1534 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001535
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001536 http_msg_invalid:
1537 /* invalid message */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001538 msg->msg_state = HTTP_MSG_ERROR;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001539 return;
1540}
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001541
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001542/*
1543 * manages the client FSM and its socket. BTW, it also tries to handle the
1544 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1545 * 0 else.
1546 */
1547int process_cli(struct session *t)
1548{
1549 int s = t->srv_state;
1550 int c = t->cli_state;
1551 struct buffer *req = t->req;
1552 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001553
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001554 DPRINTF(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
1555 cli_stnames[c], srv_stnames[s],
Willy Tarreauf161a342007-04-08 16:59:42 +02001556 EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001557 req->rex.tv_sec, req->rex.tv_usec,
1558 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001559
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001560 if (c == CL_STHEADERS) {
1561 /*
1562 * Now parse the partial (or complete) lines.
1563 * We will check the request syntax, and also join multi-line
1564 * headers. An index of all the lines will be elaborated while
1565 * parsing.
1566 *
Willy Tarreau8973c702007-01-21 23:58:29 +01001567 * For the parsing, we use a 28 states FSM.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001568 *
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001569 * Here is the information we currently have :
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001570 * req->data + req->som = beginning of request
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001571 * req->data + req->eoh = end of processed headers / start of current one
1572 * req->data + req->eol = end of current header or line (LF or CRLF)
1573 * req->lr = first non-visited byte
1574 * req->r = end of data
1575 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001576
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001577 int cur_idx;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001578 struct http_txn *txn = &t->txn;
1579 struct http_msg *msg = &txn->req;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001580 struct proxy *cur_proxy;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001581
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001582 if (likely(req->lr < req->r))
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001583 http_msg_analyzer(req, msg, &txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001584
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001585 /* 1: we might have to print this header in debug mode */
1586 if (unlikely((global.mode & MODE_DEBUG) &&
1587 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001588 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001589 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001590
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001591 sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001592 eol = sol + msg->sl.rq.l;
1593 debug_hdr("clireq", t, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001594
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001595 sol += hdr_idx_first_pos(&txn->hdr_idx);
1596 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001597
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001598 while (cur_idx) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001599 eol = sol + txn->hdr_idx.v[cur_idx].len;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001600 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001601 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
1602 cur_idx = txn->hdr_idx.v[cur_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001603 }
1604 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001605
Willy Tarreau58f10d72006-12-04 02:26:12 +01001606
1607 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001608 * Now we quickly check if we have found a full valid request.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001609 * If not so, we check the FD and buffer states before leaving.
1610 * A full request is indicated by the fact that we have seen
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001611 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
1612 * requests are checked first.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001613 *
1614 */
1615
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001616 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001617 /*
1618 * First, let's catch bad requests.
1619 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001620 if (unlikely(msg->msg_state == HTTP_MSG_ERROR))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001621 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001622
1623 /* 1: Since we are in header mode, if there's no space
1624 * left for headers, we won't be able to free more
1625 * later, so the session will never terminate. We
1626 * must terminate it now.
1627 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001628 if (unlikely(req->l >= req->rlim - req->data)) {
1629 /* FIXME: check if URI is set and return Status
1630 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001631 */
Willy Tarreau06619262006-12-17 08:37:22 +01001632 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001633 }
1634
1635 /* 2: have we encountered a read error or a close ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001636 else if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1637 /* read error, or last read : give up. */
Willy Tarreaufa645582007-06-03 15:59:52 +02001638 buffer_shutr(req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001639 fd_delete(t->cli_fd);
1640 t->cli_state = CL_STCLOSE;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001641 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001642 if (!(t->flags & SN_ERR_MASK))
1643 t->flags |= SN_ERR_CLICL;
1644 if (!(t->flags & SN_FINST_MASK))
1645 t->flags |= SN_FINST_R;
1646 return 1;
1647 }
1648
1649 /* 3: has the read timeout expired ? */
Willy Tarreau036fae02008-01-06 13:24:40 +01001650 else if (unlikely(tv_isle(&req->rex, &now) ||
1651 tv_isle(&txn->exp, &now))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001652 /* read timeout : give up with an error message. */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001653 txn->status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +01001654 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001655 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001656 if (!(t->flags & SN_ERR_MASK))
1657 t->flags |= SN_ERR_CLITO;
1658 if (!(t->flags & SN_FINST_MASK))
1659 t->flags |= SN_FINST_R;
1660 return 1;
1661 }
1662
1663 /* 4: do we need to re-enable the read socket ? */
Willy Tarreau66319382007-04-08 17:17:37 +02001664 else if (unlikely(EV_FD_COND_S(t->cli_fd, DIR_RD))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02001665 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreau58f10d72006-12-04 02:26:12 +01001666 * full. We cannot loop here since stream_sock_read will disable it only if
1667 * req->l == rlim-data
1668 */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01001669 if (!tv_add_ifset(&req->rex, &now, &t->fe->timeout.client))
Willy Tarreau58f10d72006-12-04 02:26:12 +01001670 tv_eternity(&req->rex);
1671 }
1672 return t->cli_state != CL_STHEADERS;
1673 }
1674
1675
1676 /****************************************************************
1677 * More interesting part now : we know that we have a complete *
1678 * request which at least looks like HTTP. We have an indicator *
1679 * of each header's length, so we can parse them quickly. *
1680 ****************************************************************/
1681
Willy Tarreau9cdde232007-05-02 20:58:19 +02001682 /* ensure we keep this pointer to the beginning of the message */
1683 msg->sol = req->data + msg->som;
1684
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001685 /*
1686 * 1: identify the method
1687 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001688 txn->meth = find_http_meth(&req->data[msg->som], msg->sl.rq.m_l);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001689
1690 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001691 * 2: check if the URI matches the monitor_uri.
Willy Tarreau06619262006-12-17 08:37:22 +01001692 * We have to do this for every request which gets in, because
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001693 * the monitor-uri is defined by the frontend.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001694 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001695 if (unlikely((t->fe->monitor_uri_len != 0) &&
1696 (t->fe->monitor_uri_len == msg->sl.rq.u_l) &&
1697 !memcmp(&req->data[msg->sl.rq.u],
1698 t->fe->monitor_uri,
1699 t->fe->monitor_uri_len))) {
1700 /*
1701 * We have found the monitor URI
1702 */
Willy Tarreaub80c2302007-11-30 20:51:32 +01001703 struct acl_cond *cond;
1704 cur_proxy = t->fe;
1705
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001706 t->flags |= SN_MONITOR;
Willy Tarreaub80c2302007-11-30 20:51:32 +01001707
1708 /* Check if we want to fail this monitor request or not */
1709 list_for_each_entry(cond, &cur_proxy->mon_fail_cond, list) {
1710 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
1711 if (cond->pol == ACL_COND_UNLESS)
1712 ret = !ret;
1713
1714 if (ret) {
1715 /* we fail this request, let's return 503 service unavail */
1716 txn->status = 503;
1717 client_retnclose(t, error_message(t, HTTP_ERR_503));
1718 goto return_prx_cond;
1719 }
1720 }
1721
1722 /* nothing to fail, let's reply normaly */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001723 txn->status = 200;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001724 client_retnclose(t, &http_200_chunk);
1725 goto return_prx_cond;
1726 }
1727
1728 /*
1729 * 3: Maybe we have to copy the original REQURI for the logs ?
1730 * Note: we cannot log anymore if the request has been
1731 * classified as invalid.
1732 */
1733 if (unlikely(t->logs.logwait & LW_REQ)) {
1734 /* we have a complete HTTP request that we must log */
Willy Tarreau332f8bf2007-05-13 21:36:56 +02001735 if ((txn->uri = pool_alloc2(pool2_requri)) != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001736 int urilen = msg->sl.rq.l;
1737
1738 if (urilen >= REQURI_LEN)
1739 urilen = REQURI_LEN - 1;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001740 memcpy(txn->uri, &req->data[msg->som], urilen);
1741 txn->uri[urilen] = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001742
1743 if (!(t->logs.logwait &= ~LW_REQ))
Willy Tarreau42250582007-04-01 01:30:43 +02001744 http_sess_log(t);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001745 } else {
1746 Alert("HTTP logging : out of memory.\n");
1747 }
1748 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001749
Willy Tarreau06619262006-12-17 08:37:22 +01001750
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001751 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
1752 if (unlikely(msg->sl.rq.v_l == 0)) {
1753 int delta;
1754 char *cur_end;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001755 msg->sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001756 cur_end = msg->sol + msg->sl.rq.l;
1757 delta = 0;
Willy Tarreau06619262006-12-17 08:37:22 +01001758
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001759 if (msg->sl.rq.u_l == 0) {
1760 /* if no URI was set, add "/" */
1761 delta = buffer_replace2(req, cur_end, cur_end, " /", 2);
1762 cur_end += delta;
1763 msg->eoh += delta;
Willy Tarreau06619262006-12-17 08:37:22 +01001764 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001765 /* add HTTP version */
1766 delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
1767 msg->eoh += delta;
1768 cur_end += delta;
1769 cur_end = (char *)http_parse_reqline(msg, req->data,
1770 HTTP_MSG_RQMETH,
1771 msg->sol, cur_end + 1,
1772 NULL, NULL);
1773 if (unlikely(!cur_end))
1774 goto return_bad_req;
1775
1776 /* we have a full HTTP/1.0 request now and we know that
1777 * we have either a CR or an LF at <ptr>.
1778 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001779 hdr_idx_set_start(&txn->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
Willy Tarreau58f10d72006-12-04 02:26:12 +01001780 }
1781
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001782
1783 /* 5: we may need to capture headers */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001784 if (unlikely((t->logs.logwait & LW_REQHDR) && t->fe->req_cap))
Willy Tarreau117f59e2007-03-04 18:17:17 +01001785 capture_headers(req->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001786 txn->req.cap, t->fe->req_cap);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001787
1788 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001789 * 6: we will have to evaluate the filters.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001790 * As opposed to version 1.2, now they will be evaluated in the
1791 * filters order and not in the header order. This means that
1792 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001793 *
1794 * We can now check whether we want to switch to another
1795 * backend, in which case we will re-check the backend's
1796 * filters and various options. In order to support 3-level
1797 * switching, here's how we should proceed :
1798 *
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001799 * a) run be.
Willy Tarreau830ff452006-12-17 19:31:23 +01001800 * if (switch) then switch ->be to the new backend.
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001801 * b) run be if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001802 * There cannot be any switch from there, so ->be cannot be
1803 * changed anymore.
1804 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001805 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001806 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001807 * The response path will be able to apply either ->be, or
1808 * ->be then ->fe filters in order to match the reverse of
1809 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001810 */
1811
Willy Tarreau06619262006-12-17 08:37:22 +01001812 do {
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001813 struct acl_cond *cond;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001814 struct redirect_rule *rule;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001815 struct proxy *rule_set = t->be;
Willy Tarreau830ff452006-12-17 19:31:23 +01001816 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001817
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001818 /* first check whether we have some ACLs set to redirect this request */
1819 list_for_each_entry(rule, &cur_proxy->redirect_rules, list) {
1820 int ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
1821 if (rule->cond->pol == ACL_COND_UNLESS)
1822 ret = !ret;
1823
1824 if (ret) {
1825 struct chunk rdr = { trash, 0 };
1826 const char *msg_fmt;
1827
1828 /* build redirect message */
1829 switch(rule->code) {
1830 case 303:
1831 rdr.len = strlen(HTTP_303);
1832 msg_fmt = HTTP_303;
1833 break;
1834 case 301:
1835 rdr.len = strlen(HTTP_301);
1836 msg_fmt = HTTP_301;
1837 break;
1838 case 302:
1839 default:
1840 rdr.len = strlen(HTTP_302);
1841 msg_fmt = HTTP_302;
1842 break;
1843 }
1844
1845 if (unlikely(rdr.len > sizeof(trash)))
1846 goto return_bad_req;
1847 memcpy(rdr.str, msg_fmt, rdr.len);
1848
1849 switch(rule->type) {
1850 case REDIRECT_TYPE_PREFIX: {
1851 const char *path;
1852 int pathlen;
1853
1854 path = http_get_path(txn);
1855 /* build message using path */
1856 if (path) {
1857 pathlen = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
1858 } else {
1859 path = "/";
1860 pathlen = 1;
1861 }
1862
1863 if (rdr.len + rule->rdr_len + pathlen > sizeof(trash) - 4)
1864 goto return_bad_req;
1865
1866 /* add prefix */
1867 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1868 rdr.len += rule->rdr_len;
1869
1870 /* add path */
1871 memcpy(rdr.str + rdr.len, path, pathlen);
1872 rdr.len += pathlen;
1873 break;
1874 }
1875 case REDIRECT_TYPE_LOCATION:
1876 default:
1877 if (rdr.len + rule->rdr_len > sizeof(trash) - 4)
1878 goto return_bad_req;
1879
1880 /* add location */
1881 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1882 rdr.len += rule->rdr_len;
1883 break;
1884 }
1885
1886 /* add end of headers */
1887 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
1888 rdr.len += 4;
1889
1890 txn->status = rule->code;
1891 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02001892 t->logs.tv_request = now;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001893 client_retnclose(t, &rdr);
1894 goto return_prx_cond;
1895 }
1896 }
1897
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001898 /* first check whether we have some ACLs set to block this request */
1899 list_for_each_entry(cond, &cur_proxy->block_cond, list) {
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001900 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001901 if (cond->pol == ACL_COND_UNLESS)
1902 ret = !ret;
1903
1904 if (ret) {
1905 txn->status = 403;
1906 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02001907 t->logs.tv_request = now;
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001908 client_retnclose(t, error_message(t, HTTP_ERR_403));
1909 goto return_prx_cond;
1910 }
1911 }
1912
Willy Tarreau06619262006-12-17 08:37:22 +01001913 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01001914 if (rule_set->req_exp != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001915 if (apply_filters_to_request(t, req, rule_set->req_exp) < 0)
1916 goto return_bad_req;
Willy Tarreau53b6c742006-12-17 13:37:46 +01001917 }
1918
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001919 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
1920 /* to ensure correct connection accounting on
1921 * the backend, we count the connection for the
1922 * one managing the queue.
1923 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001924 t->be->beconn++;
1925 if (t->be->beconn > t->be->beconn_max)
1926 t->be->beconn_max = t->be->beconn;
1927 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001928 t->flags |= SN_BE_ASSIGNED;
1929 }
1930
Willy Tarreau06619262006-12-17 08:37:22 +01001931 /* has the request been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01001932 if (txn->flags & TX_CLDENY) {
Willy Tarreau06619262006-12-17 08:37:22 +01001933 /* no need to go further */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001934 txn->status = 403;
Willy Tarreau06619262006-12-17 08:37:22 +01001935 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02001936 t->logs.tv_request = now;
Willy Tarreau80587432006-12-24 17:47:20 +01001937 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01001938 goto return_prx_cond;
1939 }
1940
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001941 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01001942 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001943 !(t->flags & SN_CONN_CLOSED)) {
1944 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001945 int cur_idx, old_idx, delta, val;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001946 struct hdr_idx_elem *cur_hdr;
Willy Tarreau06619262006-12-17 08:37:22 +01001947
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001948 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001949 old_idx = 0;
1950
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001951 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
1952 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001953 cur_ptr = cur_next;
1954 cur_end = cur_ptr + cur_hdr->len;
1955 cur_next = cur_end + cur_hdr->cr + 1;
1956
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001957 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
1958 if (val) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001959 /* 3 possibilities :
1960 * - we have already set Connection: close,
1961 * so we remove this line.
1962 * - we have not yet set Connection: close,
1963 * but this line indicates close. We leave
1964 * it untouched and set the flag.
1965 * - we have not yet set Connection: close,
1966 * and this line indicates non-close. We
1967 * replace it.
1968 */
1969 if (t->flags & SN_CONN_CLOSED) {
1970 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001971 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001972 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001973 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
1974 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001975 cur_hdr->len = 0;
1976 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001977 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
1978 delta = buffer_replace2(req, cur_ptr + val, cur_end,
1979 "close", 5);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001980 cur_next += delta;
1981 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001982 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001983 }
1984 t->flags |= SN_CONN_CLOSED;
1985 }
1986 }
1987 old_idx = cur_idx;
1988 }
Willy Tarreauf2f0ee82007-03-30 12:02:43 +02001989 }
1990 /* add request headers from the rule sets in the same order */
1991 for (cur_idx = 0; cur_idx < rule_set->nb_reqadd; cur_idx++) {
1992 if (unlikely(http_header_add_tail(req,
1993 &txn->req,
1994 &txn->hdr_idx,
1995 rule_set->req_add[cur_idx])) < 0)
1996 goto return_bad_req;
Willy Tarreau06619262006-12-17 08:37:22 +01001997 }
Willy Tarreaub2513902006-12-17 14:52:38 +01001998
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001999 /* check if stats URI was requested, and if an auth is needed */
Willy Tarreau0214c3a2007-01-07 13:47:30 +01002000 if (rule_set->uri_auth != NULL &&
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002001 (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)) {
Willy Tarreaub2513902006-12-17 14:52:38 +01002002 /* we have to check the URI and auth for this request */
2003 if (stats_check_uri_auth(t, rule_set))
2004 return 1;
2005 }
2006
Willy Tarreau55ea7572007-06-17 19:56:27 +02002007 /* now check whether we have some switching rules for this request */
2008 if (!(t->flags & SN_BE_ASSIGNED)) {
2009 struct switching_rule *rule;
2010
2011 list_for_each_entry(rule, &cur_proxy->switching_rules, list) {
2012 int ret;
2013
2014 ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
2015 if (cond->pol == ACL_COND_UNLESS)
2016 ret = !ret;
2017
2018 if (ret) {
2019 t->be = rule->be.backend;
2020 t->be->beconn++;
2021 if (t->be->beconn > t->be->beconn_max)
2022 t->be->beconn_max = t->be->beconn;
2023 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002024
2025 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002026 t->rep->rto = t->req->wto = t->be->timeout.server;
2027 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002028 t->conn_retries = t->be->conn_retries;
Willy Tarreau55ea7572007-06-17 19:56:27 +02002029 t->flags |= SN_BE_ASSIGNED;
2030 break;
2031 }
2032 }
2033 }
2034
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002035 if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
2036 /* No backend was set, but there was a default
2037 * backend set in the frontend, so we use it and
2038 * loop again.
2039 */
2040 t->be = cur_proxy->defbe.be;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002041 t->be->beconn++;
2042 if (t->be->beconn > t->be->beconn_max)
2043 t->be->beconn_max = t->be->beconn;
2044 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002045
2046 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002047 t->rep->rto = t->req->wto = t->be->timeout.server;
2048 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002049 t->conn_retries = t->be->conn_retries;
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002050 t->flags |= SN_BE_ASSIGNED;
2051 }
2052 } while (t->be != cur_proxy); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01002053
Willy Tarreau58f10d72006-12-04 02:26:12 +01002054
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002055 if (!(t->flags & SN_BE_ASSIGNED)) {
2056 /* To ensure correct connection accounting on
2057 * the backend, we count the connection for the
2058 * one managing the queue.
2059 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002060 t->be->beconn++;
2061 if (t->be->beconn > t->be->beconn_max)
2062 t->be->beconn_max = t->be->beconn;
2063 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002064 t->flags |= SN_BE_ASSIGNED;
2065 }
2066
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002067 /*
2068 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01002069 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002070 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01002071 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01002072 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01002073
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01002074 /*
2075 * If HTTP PROXY is set we simply get remote server address
2076 * parsing incoming request.
2077 */
2078 if ((t->be->options & PR_O_HTTP_PROXY) && !(t->flags & SN_ADDR_SET)) {
2079 url2sa(req->data + msg->sl.rq.u, msg->sl.rq.u_l, &t->srv_addr);
2080 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002081
Willy Tarreau2a324282006-12-05 00:05:46 +01002082 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002083 * 7: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01002084 * so let's do the same now.
2085 */
2086
2087 /* It needs to look into the URI */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002088 if (t->be->appsession_name) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01002089 get_srv_from_appsession(t, &req->data[msg->som], msg->sl.rq.l);
Willy Tarreau06619262006-12-17 08:37:22 +01002090 }
2091
2092
2093 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002094 * 8: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01002095 * Note that doing so might move headers in the request, but
2096 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01002097 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01002098 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01002099 if ((t->be->cookie_name || t->be->appsession_name || t->be->capture_name)
2100 && !(txn->flags & (TX_CLDENY|TX_CLTARPIT)))
Willy Tarreau2a324282006-12-05 00:05:46 +01002101 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01002102
Willy Tarreau58f10d72006-12-04 02:26:12 +01002103
Willy Tarreau2a324282006-12-05 00:05:46 +01002104 /*
Willy Tarreaubb046ac2007-03-03 19:17:03 +01002105 * 9: add X-Forwarded-For if either the frontend or the backend
2106 * asks for it.
Willy Tarreau2a324282006-12-05 00:05:46 +01002107 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002108 if ((t->fe->options | t->be->options) & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002109 if (t->cli_addr.ss_family == AF_INET) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002110 /* Add an X-Forwarded-For header unless the source IP is
2111 * in the 'except' network range.
2112 */
2113 if ((!t->fe->except_mask.s_addr ||
2114 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->fe->except_mask.s_addr)
2115 != t->fe->except_net.s_addr) &&
2116 (!t->be->except_mask.s_addr ||
2117 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->be->except_mask.s_addr)
2118 != t->be->except_net.s_addr)) {
2119 int len;
2120 unsigned char *pn;
2121 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
Willy Tarreau45e73e32006-12-17 00:05:15 +01002122
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002123 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d",
2124 pn[0], pn[1], pn[2], pn[3]);
2125
2126 if (unlikely(http_header_add_tail2(req, &txn->req,
2127 &txn->hdr_idx, trash, len)) < 0)
2128 goto return_bad_req;
2129 }
Willy Tarreau2a324282006-12-05 00:05:46 +01002130 }
2131 else if (t->cli_addr.ss_family == AF_INET6) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002132 /* FIXME: for the sake of completeness, we should also support
2133 * 'except' here, although it is mostly useless in this case.
2134 */
Willy Tarreau2a324282006-12-05 00:05:46 +01002135 int len;
2136 char pn[INET6_ADDRSTRLEN];
2137 inet_ntop(AF_INET6,
2138 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2139 pn, sizeof(pn));
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002140 len = sprintf(trash, "X-Forwarded-For: %s", pn);
2141 if (unlikely(http_header_add_tail2(req, &txn->req,
2142 &txn->hdr_idx, trash, len)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002143 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01002144 }
2145 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002146
Willy Tarreau2a324282006-12-05 00:05:46 +01002147 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002148 * 10: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02002149 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaub2513902006-12-17 14:52:38 +01002150 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02002151 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002152 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02002153 if ((unlikely(msg->sl.rq.v_l != 8) ||
2154 unlikely(req->data[msg->som + msg->sl.rq.v + 7] != '0')) &&
2155 unlikely(http_header_add_tail2(req, &txn->req, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002156 "Connection: close", 17)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002157 goto return_bad_req;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002158 t->flags |= SN_CONN_CLOSED;
Willy Tarreaue15d9132006-12-14 22:26:42 +01002159 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002160 /* Before we switch to data, was assignment set in manage_client_side_cookie?
2161 * If not assigned, perhaps we are balancing on url_param, but this is a
2162 * POST; and the parameters are in the body, maybe scan there to find our server.
2163 * (unless headers overflowed the buffer?)
2164 */
2165 if (!(t->flags & (SN_ASSIGNED|SN_DIRECT)) &&
2166 t->txn.meth == HTTP_METH_POST && t->be->url_param_name != NULL &&
2167 t->be->url_param_post_limit != 0 && req->total < BUFSIZE &&
2168 memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) {
2169 /* are there enough bytes here? total == l || r || rlim ?
2170 * len is unsigned, but eoh is int,
2171 * how many bytes of body have we received?
2172 * eoh is the first empty line of the header
2173 */
2174 /* already established CRLF or LF at eoh, move to start of message, find message length in buffer */
2175 unsigned long len = req->total - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1);
2176
2177 /* If we have HTTP/1.1 and Expect: 100-continue, then abort.
2178 * We can't assume responsibility for the server's decision,
2179 * on this URI and header set. See rfc2616: 14.20, 8.2.3,
2180 * We also can't change our mind later, about which server to choose, so round robin.
2181 */
2182 if ((likely(msg->sl.rq.v_l == 8) && req->data[msg->som + msg->sl.rq.v + 7] == '1')) {
2183 struct hdr_ctx ctx;
2184 ctx.idx = 0;
2185 /* Expect is allowed in 1.1, look for it */
2186 http_find_header2("Expect", 6, msg->sol, &txn->hdr_idx, &ctx);
2187 if (ctx.idx != 0 &&
2188 unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val,"100-continue",12)==0))
2189 /* We can't reliablly stall and wait for data, because of
2190 * .NET clients that don't conform to rfc2616; so, no need for
2191 * the next block to check length expectations.
2192 * We could send 100 status back to the client, but then we need to
2193 * re-write headers, and send the message. And this isn't the right
2194 * place for that action.
2195 * TODO: support Expect elsewhere and delete this block.
2196 */
2197 goto end_check_maybe_wait_for_body;
2198 }
2199 if ( likely(len > t->be->url_param_post_limit) ) {
2200 /* nothing to do, we got enough */
2201 } else {
2202 /* limit implies we are supposed to need this many bytes
2203 * to find the parameter. Let's see how many bytes we can wait for.
2204 */
2205 long long hint = len;
2206 struct hdr_ctx ctx;
2207 ctx.idx = 0;
2208 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
2209 if (unlikely(ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",7)==0)) {
2210 t->srv_state = SV_STANALYZE;
2211 } else {
2212 ctx.idx = 0;
2213 http_find_header2("Content-Length", 14, msg->sol, &txn->hdr_idx, &ctx);
2214 /* now if we have a length, we'll take the hint */
2215 if ( ctx.idx ) {
2216 /* We have Content-Length */
2217 if ( strl2llrc(ctx.line+ctx.val,ctx.vlen, &hint) )
2218 hint = 0; /* parse failure, untrusted client */
2219 else {
2220 if ( hint > 0 )
2221 msg->hdr_content_len = hint;
2222 else
2223 hint = 0; /* bad client, sent negative length */
2224 }
2225 }
2226 /* but limited to what we care about, maybe we don't expect any entity data (hint == 0) */
2227 if ( t->be->url_param_post_limit < hint )
2228 hint = t->be->url_param_post_limit;
2229 /* now do we really need to buffer more data? */
2230 if ( len < hint )
2231 t->srv_state = SV_STANALYZE;
2232 /* else... There are no body bytes to wait for */
2233 }
2234 }
2235 }
2236 end_check_maybe_wait_for_body:
Willy Tarreaubaaee002006-06-26 02:48:02 +02002237
Willy Tarreau2a324282006-12-05 00:05:46 +01002238 /*************************************************************
2239 * OK, that's finished for the headers. We have done what we *
2240 * could. Let's switch to the DATA state. *
2241 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02002242
Willy Tarreau2a324282006-12-05 00:05:46 +01002243 t->cli_state = CL_STDATA;
2244 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002245
Willy Tarreau70089872008-06-13 21:12:51 +02002246 t->logs.tv_request = now;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002247
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002248 if (!tv_isset(&t->fe->timeout.client) ||
2249 (t->srv_state < SV_STDATA && tv_isset(&t->be->timeout.server))) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002250 /* If the client has no timeout, or if the server is not ready yet,
2251 * and we know for sure that it can expire, then it's cleaner to
2252 * disable the timeout on the client side so that too low values
2253 * cannot make the sessions abort too early.
2254 *
2255 * FIXME-20050705: the server needs a way to re-enable this time-out
2256 * when it switches its state, otherwise a client can stay connected
2257 * indefinitely. This now seems to be OK.
2258 */
2259 tv_eternity(&req->rex);
2260 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002261
Willy Tarreau1fa31262007-12-03 00:36:16 +01002262 /* When a connection is tarpitted, we use the tarpit timeout,
2263 * which may be the same as the connect timeout if unspecified.
2264 * If unset, then set it to zero because we really want it to
2265 * eventually expire.
Willy Tarreau2a324282006-12-05 00:05:46 +01002266 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002267 if (txn->flags & TX_CLTARPIT) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002268 t->req->l = 0;
2269 /* flush the request so that we can drop the connection early
2270 * if the client closes first.
2271 */
Willy Tarreau1fa31262007-12-03 00:36:16 +01002272 if (!tv_add_ifset(&req->cex, &now, &t->be->timeout.tarpit))
Willy Tarreaud825eef2007-05-12 22:35:00 +02002273 req->cex = now;
Willy Tarreau2a324282006-12-05 00:05:46 +01002274 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002275
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002276 /* OK let's go on with the BODY now */
Willy Tarreau06619262006-12-17 08:37:22 +01002277 goto process_data;
2278
2279 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002280 txn->req.msg_state = HTTP_MSG_ERROR;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002281 txn->status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01002282 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002283 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01002284 return_prx_cond:
2285 if (!(t->flags & SN_ERR_MASK))
2286 t->flags |= SN_ERR_PRXCOND;
2287 if (!(t->flags & SN_FINST_MASK))
2288 t->flags |= SN_FINST_R;
2289 return 1;
2290
Willy Tarreaubaaee002006-06-26 02:48:02 +02002291 }
2292 else if (c == CL_STDATA) {
2293 process_data:
2294 /* FIXME: this error handling is partly buggy because we always report
2295 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
2296 * or HEADER phase. BTW, it's not logical to expire the client while
2297 * we're waiting for the server to connect.
2298 */
2299 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002300 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002301 buffer_shutr(req);
2302 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002303 fd_delete(t->cli_fd);
2304 t->cli_state = CL_STCLOSE;
2305 if (!(t->flags & SN_ERR_MASK))
2306 t->flags |= SN_ERR_CLICL;
2307 if (!(t->flags & SN_FINST_MASK)) {
2308 if (t->pend_pos)
2309 t->flags |= SN_FINST_Q;
2310 else if (s == SV_STCONN)
2311 t->flags |= SN_FINST_C;
2312 else
2313 t->flags |= SN_FINST_D;
2314 }
2315 return 1;
2316 }
2317 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002318 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002319 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002320 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002321 t->cli_state = CL_STSHUTR;
2322 return 1;
2323 }
2324 /* last server read and buffer empty */
2325 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002326 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02002327 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002328 shutdown(t->cli_fd, SHUT_WR);
2329 /* We must ensure that the read part is still alive when switching
2330 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002331 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002332 tv_add_ifset(&req->rex, &now, &t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002333 t->cli_state = CL_STSHUTW;
2334 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2335 return 1;
2336 }
2337 /* read timeout */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002338 else if (tv_isle(&req->rex, &now)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002339 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002340 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002341 t->cli_state = CL_STSHUTR;
2342 if (!(t->flags & SN_ERR_MASK))
2343 t->flags |= SN_ERR_CLITO;
2344 if (!(t->flags & SN_FINST_MASK)) {
2345 if (t->pend_pos)
2346 t->flags |= SN_FINST_Q;
2347 else if (s == SV_STCONN)
2348 t->flags |= SN_FINST_C;
2349 else
2350 t->flags |= SN_FINST_D;
2351 }
2352 return 1;
2353 }
2354 /* write timeout */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002355 else if (tv_isle(&rep->wex, &now)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002356 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02002357 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002358 shutdown(t->cli_fd, SHUT_WR);
2359 /* We must ensure that the read part is still alive when switching
2360 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002361 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002362 tv_add_ifset(&req->rex, &now, &t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002363
2364 t->cli_state = CL_STSHUTW;
2365 if (!(t->flags & SN_ERR_MASK))
2366 t->flags |= SN_ERR_CLITO;
2367 if (!(t->flags & SN_FINST_MASK)) {
2368 if (t->pend_pos)
2369 t->flags |= SN_FINST_Q;
2370 else if (s == SV_STCONN)
2371 t->flags |= SN_FINST_C;
2372 else
2373 t->flags |= SN_FINST_D;
2374 }
2375 return 1;
2376 }
2377
2378 if (req->l >= req->rlim - req->data) {
2379 /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02002380 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002381 /* stop reading until we get some space */
Willy Tarreaud7971282006-07-29 18:36:34 +02002382 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002383 }
2384 } else {
2385 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002386 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002387 if (!tv_isset(&t->fe->timeout.client) ||
2388 (t->srv_state < SV_STDATA && tv_isset(&t->be->timeout.server)))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002389 /* If the client has no timeout, or if the server not ready yet, and we
2390 * know for sure that it can expire, then it's cleaner to disable the
2391 * timeout on the client side so that too low values cannot make the
2392 * sessions abort too early.
2393 */
Willy Tarreaud7971282006-07-29 18:36:34 +02002394 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002395 else
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002396 tv_add(&req->rex, &now, &t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002397 }
2398 }
2399
2400 if ((rep->l == 0) ||
2401 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002402 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2403 /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002404 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002405 }
2406 } else {
2407 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002408 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2409 /* restart writing */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002410 if (tv_add_ifset(&rep->wex, &now, &t->fe->timeout.client)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002411 /* FIXME: to prevent the client from expiring read timeouts during writes,
2412 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002413 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002414 }
2415 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002416 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002417 }
2418 }
2419 return 0; /* other cases change nothing */
2420 }
2421 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002422 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002423 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002424 fd_delete(t->cli_fd);
2425 t->cli_state = CL_STCLOSE;
2426 if (!(t->flags & SN_ERR_MASK))
2427 t->flags |= SN_ERR_CLICL;
2428 if (!(t->flags & SN_FINST_MASK)) {
2429 if (t->pend_pos)
2430 t->flags |= SN_FINST_Q;
2431 else if (s == SV_STCONN)
2432 t->flags |= SN_FINST_C;
2433 else
2434 t->flags |= SN_FINST_D;
2435 }
2436 return 1;
2437 }
2438 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
2439 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002440 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002441 fd_delete(t->cli_fd);
2442 t->cli_state = CL_STCLOSE;
2443 return 1;
2444 }
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002445 else if (tv_isle(&rep->wex, &now)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002446 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002447 fd_delete(t->cli_fd);
2448 t->cli_state = CL_STCLOSE;
2449 if (!(t->flags & SN_ERR_MASK))
2450 t->flags |= SN_ERR_CLITO;
2451 if (!(t->flags & SN_FINST_MASK)) {
2452 if (t->pend_pos)
2453 t->flags |= SN_FINST_Q;
2454 else if (s == SV_STCONN)
2455 t->flags |= SN_FINST_C;
2456 else
2457 t->flags |= SN_FINST_D;
2458 }
2459 return 1;
2460 }
2461
2462 if (t->flags & SN_SELF_GEN) {
2463 produce_content(t);
2464 if (rep->l == 0) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002465 buffer_shutw(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002466 fd_delete(t->cli_fd);
2467 t->cli_state = CL_STCLOSE;
2468 return 1;
2469 }
2470 }
2471
2472 if ((rep->l == 0)
2473 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002474 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2475 /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002476 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002477 }
2478 } else {
2479 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002480 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2481 /* restart writing */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002482 if (!tv_add_ifset(&rep->wex, &now, &t->fe->timeout.client))
Willy Tarreaud7971282006-07-29 18:36:34 +02002483 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002484 }
2485 }
2486 return 0;
2487 }
2488 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002489 if (req->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002490 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002491 fd_delete(t->cli_fd);
2492 t->cli_state = CL_STCLOSE;
2493 if (!(t->flags & SN_ERR_MASK))
2494 t->flags |= SN_ERR_CLICL;
2495 if (!(t->flags & SN_FINST_MASK)) {
2496 if (t->pend_pos)
2497 t->flags |= SN_FINST_Q;
2498 else if (s == SV_STCONN)
2499 t->flags |= SN_FINST_C;
2500 else
2501 t->flags |= SN_FINST_D;
2502 }
2503 return 1;
2504 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002505 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002506 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002507 fd_delete(t->cli_fd);
2508 t->cli_state = CL_STCLOSE;
2509 return 1;
2510 }
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002511 else if (tv_isle(&req->rex, &now)) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002512 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002513 fd_delete(t->cli_fd);
2514 t->cli_state = CL_STCLOSE;
2515 if (!(t->flags & SN_ERR_MASK))
2516 t->flags |= SN_ERR_CLITO;
2517 if (!(t->flags & SN_FINST_MASK)) {
2518 if (t->pend_pos)
2519 t->flags |= SN_FINST_Q;
2520 else if (s == SV_STCONN)
2521 t->flags |= SN_FINST_C;
2522 else
2523 t->flags |= SN_FINST_D;
2524 }
2525 return 1;
2526 }
2527 else if (req->l >= req->rlim - req->data) {
2528 /* no room to read more data */
2529
2530 /* FIXME-20050705: is it possible for a client to maintain a session
2531 * after the timeout by sending more data after it receives a close ?
2532 */
2533
Willy Tarreau66319382007-04-08 17:17:37 +02002534 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002535 /* stop reading until we get some space */
Willy Tarreaud7971282006-07-29 18:36:34 +02002536 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002537 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2538 }
2539 } else {
2540 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002541 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002542 if (!tv_add_ifset(&req->rex, &now, &t->fe->timeout.client))
Willy Tarreaud7971282006-07-29 18:36:34 +02002543 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002544 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2545 }
2546 }
2547 return 0;
2548 }
2549 else { /* CL_STCLOSE: nothing to do */
2550 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2551 int len;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002552 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 +02002553 write(1, trash, len);
2554 }
2555 return 0;
2556 }
2557 return 0;
2558}
2559
2560
2561/*
2562 * manages the server FSM and its socket. It returns 1 if a state has changed
2563 * (and a resync may be needed), 0 else.
2564 */
2565int process_srv(struct session *t)
2566{
2567 int s = t->srv_state;
2568 int c = t->cli_state;
Willy Tarreau3d300592007-03-18 18:34:41 +01002569 struct http_txn *txn = &t->txn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002570 struct buffer *req = t->req;
2571 struct buffer *rep = t->rep;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002572 int conn_err;
2573
2574#ifdef DEBUG_FULL
2575 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2576#endif
Willy Tarreauee991362007-05-14 14:37:50 +02002577
2578#if 0
2579 fprintf(stderr,"%s:%d fe->clito=%d.%d, fe->conto=%d.%d, fe->srvto=%d.%d\n",
2580 __FUNCTION__, __LINE__,
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002581 t->fe->timeout.client.tv_sec, t->fe->timeout.client.tv_usec,
2582 t->fe->timeout.connect.tv_sec, t->fe->timeout.connect.tv_usec,
2583 t->fe->timeout.server.tv_sec, t->fe->timeout.server.tv_usec);
Willy Tarreauee991362007-05-14 14:37:50 +02002584 fprintf(stderr,"%s:%d be->clito=%d.%d, be->conto=%d.%d, be->srvto=%d.%d\n",
2585 __FUNCTION__, __LINE__,
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002586 t->be->timeout.client.tv_sec, t->be->timeout.client.tv_usec,
2587 t->be->timeout.connect.tv_sec, t->be->timeout.connect.tv_usec,
2588 t->be->timeout.server.tv_sec, t->be->timeout.server.tv_usec);
Willy Tarreauee991362007-05-14 14:37:50 +02002589
2590 fprintf(stderr,"%s:%d req->cto=%d.%d, req->rto=%d.%d, req->wto=%d.%d\n",
2591 __FUNCTION__, __LINE__,
2592 req->cto.tv_sec, req->cto.tv_usec,
2593 req->rto.tv_sec, req->rto.tv_usec,
2594 req->wto.tv_sec, req->wto.tv_usec);
2595
2596 fprintf(stderr,"%s:%d rep->cto=%d.%d, rep->rto=%d.%d, rep->wto=%d.%d\n",
2597 __FUNCTION__, __LINE__,
2598 rep->cto.tv_sec, rep->cto.tv_usec,
2599 rep->rto.tv_sec, rep->rto.tv_usec,
2600 rep->wto.tv_sec, rep->wto.tv_usec);
2601#endif
2602
Willy Tarreaubaaee002006-06-26 02:48:02 +02002603 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
Willy Tarreauf161a342007-04-08 16:59:42 +02002604 //EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
2605 //EV_FD_ISSET(t->srv_fd, DIR_RD), EV_FD_ISSET(t->srv_fd, DIR_WR)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002606 //);
2607 if (s == SV_STIDLE) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002608 /* NOTE: The client processor may switch to SV_STANALYZE, which switches back SV_STIDLE.
2609 * This is logcially after CL_STHEADERS completed, CL_STDATA has started, but
2610 * we need to defer server selection until more data arrives, if possible.
2611 * This is rare, and only if balancing on parameter hash with values in the entity of a POST
2612 */
2613 if (c == CL_STHEADERS )
Willy Tarreaubaaee002006-06-26 02:48:02 +02002614 return 0; /* stay in idle, waiting for data to reach the client side */
2615 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
2616 (c == CL_STSHUTR &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002617 (t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02002618 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002619 if (t->pend_pos)
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002620 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002621 /* note that this must not return any error because it would be able to
2622 * overwrite the client_retnclose() output.
2623 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002624 if (txn->flags & TX_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01002625 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02002626 else
Willy Tarreau0f772532006-12-23 20:51:41 +01002627 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 +02002628
2629 return 1;
2630 }
2631 else {
Willy Tarreau3d300592007-03-18 18:34:41 +01002632 if (txn->flags & TX_CLTARPIT) {
Willy Tarreaub8750a82006-09-03 09:56:00 +02002633 /* This connection is being tarpitted. The CLIENT side has
2634 * already set the connect expiration date to the right
2635 * timeout. We just have to check that it has not expired.
2636 */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002637 if (!tv_isle(&req->cex, &now))
Willy Tarreaub8750a82006-09-03 09:56:00 +02002638 return 0;
2639
2640 /* We will set the queue timer to the time spent, just for
2641 * logging purposes. We fake a 500 server error, so that the
2642 * attacker will not suspect his connection has been tarpitted.
2643 * It will not cause trouble to the logs because we can exclude
2644 * the tarpitted connections by filtering on the 'PT' status flags.
2645 */
2646 tv_eternity(&req->cex);
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002647 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaub8750a82006-09-03 09:56:00 +02002648 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01002649 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02002650 return 1;
2651 }
2652
Willy Tarreaubaaee002006-06-26 02:48:02 +02002653 /* Right now, we will need to create a connection to the server.
2654 * We might already have tried, and got a connection pending, in
2655 * which case we will not do anything till it's pending. It's up
2656 * to any other session to release it and wake us up again.
2657 */
2658 if (t->pend_pos) {
Willy Tarreau7c669d72008-06-20 15:04:11 +02002659 if (!tv_isle(&req->cex, &now)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002660 return 0;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002661 } else {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002662 /* we've been waiting too long here */
Willy Tarreaud7971282006-07-29 18:36:34 +02002663 tv_eternity(&req->cex);
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002664 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002665 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01002666 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002667 if (t->srv)
2668 t->srv->failed_conns++;
Willy Tarreau50fd1e12007-12-10 15:25:35 +01002669 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002670 return 1;
2671 }
2672 }
2673
2674 do {
2675 /* first, get a connection */
Willy Tarreau21d2af32008-02-14 20:25:24 +01002676 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
2677 t->flags |= SN_REDIRECTABLE;
2678
Willy Tarreaubaaee002006-06-26 02:48:02 +02002679 if (srv_redispatch_connect(t))
2680 return t->srv_state != SV_STIDLE;
2681
Willy Tarreau21d2af32008-02-14 20:25:24 +01002682 if ((t->flags & SN_REDIRECTABLE) && t->srv && t->srv->rdr_len) {
2683 /* Server supporting redirection and it is possible.
2684 * Invalid requests are reported as such. It concerns all
2685 * the largest ones.
2686 */
2687 struct chunk rdr;
2688 char *path;
2689 int len;
2690
2691 /* 1: create the response header */
2692 rdr.len = strlen(HTTP_302);
2693 rdr.str = trash;
2694 memcpy(rdr.str, HTTP_302, rdr.len);
2695
2696 /* 2: add the server's prefix */
2697 if (rdr.len + t->srv->rdr_len > sizeof(trash))
2698 goto cancel_redir;
2699
2700 memcpy(rdr.str + rdr.len, t->srv->rdr_pfx, t->srv->rdr_len);
2701 rdr.len += t->srv->rdr_len;
2702
2703 /* 3: add the request URI */
2704 path = http_get_path(txn);
2705 if (!path)
2706 goto cancel_redir;
2707 len = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
2708 if (rdr.len + len > sizeof(trash) - 4) /* 4 for CRLF-CRLF */
2709 goto cancel_redir;
2710
2711 memcpy(rdr.str + rdr.len, path, len);
2712 rdr.len += len;
2713 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
2714 rdr.len += 4;
2715
2716 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C, 302, &rdr);
2717 /* FIXME: we should increase a counter of redirects per server and per backend. */
2718 if (t->srv)
2719 t->srv->cum_sess++;
2720 return 1;
2721 cancel_redir:
2722 txn->status = 400;
2723 t->fe->failed_req++;
2724 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C,
2725 400, error_message(t, HTTP_ERR_400));
2726 return 1;
2727 }
2728
Willy Tarreaubaaee002006-06-26 02:48:02 +02002729 /* try to (re-)connect to the server, and fail if we expire the
2730 * number of retries.
2731 */
2732 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002733 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002734 return t->srv_state != SV_STIDLE;
2735 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002736 } while (1);
2737 }
2738 }
2739 else if (s == SV_STCONN) { /* connection in progress */
2740 if (c == CL_STCLOSE || c == CL_STSHUTW ||
2741 (c == CL_STSHUTR &&
Willy Tarreauc9b654b2007-05-08 14:46:53 +02002742 ((t->req->l == 0 && !(req->flags & BF_WRITE_STATUS)) ||
2743 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02002744 tv_eternity(&req->cex);
Willy Tarreauf899b942008-03-28 18:09:38 +01002745 if (!(t->flags & SN_CONN_TAR)) {
2746 /* if we are in turn-around, we have already closed the FD */
2747 fd_delete(t->srv_fd);
2748 if (t->srv) {
2749 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002750 sess_change_server(t, NULL);
Willy Tarreauf899b942008-03-28 18:09:38 +01002751 }
Willy Tarreau51406232008-03-10 22:04:20 +01002752 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002753
2754 /* note that this must not return any error because it would be able to
2755 * overwrite the client_retnclose() output.
2756 */
Willy Tarreau0f772532006-12-23 20:51:41 +01002757 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002758 return 1;
2759 }
Willy Tarreaua8b55e32007-05-13 16:08:19 +02002760 if (!(req->flags & BF_WRITE_STATUS) && !tv_isle(&req->cex, &now)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002761 //fprintf(stderr,"1: c=%d, s=%d, now=%d.%06d, exp=%d.%06d\n", c, s, now.tv_sec, now.tv_usec, req->cex.tv_sec, req->cex.tv_usec);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002762 return 0; /* nothing changed */
2763 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002764 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002765 /* timeout, asynchronous connect error or first write error */
2766 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2767
Willy Tarreau541b5c22008-01-06 23:34:21 +01002768 if (t->flags & SN_CONN_TAR) {
2769 /* We are doing a turn-around waiting for a new connection attempt. */
2770 if (!tv_isle(&req->cex, &now))
2771 return 0;
2772 t->flags &= ~SN_CONN_TAR;
2773 }
2774 else {
2775 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01002776 if (t->srv) {
Willy Tarreau541b5c22008-01-06 23:34:21 +01002777 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002778 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01002779 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002780
Willy Tarreau541b5c22008-01-06 23:34:21 +01002781 if (!(req->flags & BF_WRITE_STATUS))
2782 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
2783 else
2784 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
2785
2786 /* ensure that we have enough retries left */
2787 if (srv_count_retry_down(t, conn_err))
2788 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002789
Willy Tarreau541b5c22008-01-06 23:34:21 +01002790 if (req->flags & BF_WRITE_ERROR) {
2791 /* we encountered an immediate connection error, and we
2792 * will have to retry connecting to the same server, most
2793 * likely leading to the same result. To avoid this, we
2794 * fake a connection timeout to retry after a turn-around
2795 * time of 1 second. We will wait in the previous if block.
2796 */
2797 t->flags |= SN_CONN_TAR;
2798 tv_ms_add(&req->cex, &now, 1000);
2799 return 0;
2800 }
2801 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002802
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002803 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002804 /* We're on our last chance, and the REDISP option was specified.
2805 * We will ignore cookie and force to balance or use the dispatcher.
2806 */
2807 /* let's try to offer this slot to anybody */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002808 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02002809 process_srv_queue(t->srv);
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002810
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01002811 /* it's left to the dispatcher to choose a server */
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002812 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
Willy Tarreau7c669d72008-06-20 15:04:11 +02002813 t->prev_srv = t->srv;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002814
2815 /* first, get a connection */
2816 if (srv_redispatch_connect(t))
Willy Tarreau00559e72008-01-06 23:46:19 +01002817 return t->srv_state != SV_STCONN;
Krzysztof Piotr Oledzki626a19b2008-02-04 02:10:09 +01002818 } else {
2819 if (t->srv)
2820 t->srv->retries++;
2821 t->be->retries++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002822 }
2823
Willy Tarreaubaaee002006-06-26 02:48:02 +02002824 do {
2825 /* Now we will try to either reconnect to the same server or
2826 * connect to another server. If the connection gets queued
2827 * because all servers are saturated, then we will go back to
2828 * the SV_STIDLE state.
2829 */
2830 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002831 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002832 return t->srv_state != SV_STCONN;
2833 }
2834
2835 /* we need to redispatch the connection to another server */
2836 if (srv_redispatch_connect(t))
2837 return t->srv_state != SV_STCONN;
2838 } while (1);
2839 }
2840 else { /* no error or write 0 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002841 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002842
2843 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2844 if (req->l == 0) /* nothing to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002845 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaud7971282006-07-29 18:36:34 +02002846 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002847 } else /* need the right to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002848 EV_FD_SET(t->srv_fd, DIR_WR);
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002849 if (tv_add_ifset(&req->wex, &now, &t->be->timeout.server)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002850 /* FIXME: to prevent the server from expiring read timeouts during writes,
2851 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002852 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002853 }
2854 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002855 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002856 }
2857
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002858 if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreauf161a342007-04-08 16:59:42 +02002859 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002860 if (!tv_add_ifset(&rep->rex, &now, &t->be->timeout.server))
Willy Tarreaud7971282006-07-29 18:36:34 +02002861 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002862
2863 t->srv_state = SV_STDATA;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002864 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
2865
2866 /* if the user wants to log as soon as possible, without counting
2867 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002868 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002869 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
Willy Tarreau42250582007-04-01 01:30:43 +02002870 tcp_sess_log(t);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002871 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002872#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002873 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002874 /* TCP splicing supported by both FE and BE */
2875 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2876 }
2877#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002878 }
2879 else {
2880 t->srv_state = SV_STHEADERS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002881 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002882 t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
2883 /* reset hdr_idx which was already initialized by the request.
2884 * right now, the http parser does it.
2885 * hdr_idx_init(&t->txn.hdr_idx);
2886 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002887 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002888 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002889 return 1;
2890 }
2891 }
2892 else if (s == SV_STHEADERS) { /* receiving server headers */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002893 /*
2894 * Now parse the partial (or complete) lines.
2895 * We will check the response syntax, and also join multi-line
2896 * headers. An index of all the lines will be elaborated while
2897 * parsing.
2898 *
2899 * For the parsing, we use a 28 states FSM.
2900 *
2901 * Here is the information we currently have :
2902 * rep->data + req->som = beginning of response
2903 * rep->data + req->eoh = end of processed headers / start of current one
2904 * rep->data + req->eol = end of current header or line (LF or CRLF)
2905 * rep->lr = first non-visited byte
2906 * rep->r = end of data
2907 */
2908
2909 int cur_idx;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002910 struct http_msg *msg = &txn->rsp;
2911 struct proxy *cur_proxy;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002912
Willy Tarreaua15645d2007-03-18 16:22:39 +01002913 if (likely(rep->lr < rep->r))
2914 http_msg_analyzer(rep, msg, &txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002915
Willy Tarreaua15645d2007-03-18 16:22:39 +01002916 /* 1: we might have to print this header in debug mode */
2917 if (unlikely((global.mode & MODE_DEBUG) &&
2918 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
2919 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
2920 char *eol, *sol;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002921
Willy Tarreaua15645d2007-03-18 16:22:39 +01002922 sol = rep->data + msg->som;
2923 eol = sol + msg->sl.rq.l;
2924 debug_hdr("srvrep", t, sol, eol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002925
Willy Tarreaua15645d2007-03-18 16:22:39 +01002926 sol += hdr_idx_first_pos(&txn->hdr_idx);
2927 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002928
Willy Tarreaua15645d2007-03-18 16:22:39 +01002929 while (cur_idx) {
2930 eol = sol + txn->hdr_idx.v[cur_idx].len;
2931 debug_hdr("srvhdr", t, sol, eol);
2932 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
2933 cur_idx = txn->hdr_idx.v[cur_idx].next;
2934 }
2935 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002936
Willy Tarreaubaaee002006-06-26 02:48:02 +02002937
Willy Tarreau66319382007-04-08 17:17:37 +02002938 if ((rep->l < rep->rlim - rep->data) && EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002939 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreaua15645d2007-03-18 16:22:39 +01002940 * full. We cannot loop here since stream_sock_read will disable it only if
2941 * rep->l == rlim-data
2942 */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002943 if (!tv_add_ifset(&rep->rex, &now, &t->be->timeout.server))
Willy Tarreaua15645d2007-03-18 16:22:39 +01002944 tv_eternity(&rep->rex);
2945 }
2946
2947
2948 /*
2949 * Now we quickly check if we have found a full valid response.
2950 * If not so, we check the FD and buffer states before leaving.
2951 * A full response is indicated by the fact that we have seen
2952 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
2953 * responses are checked first.
2954 *
2955 * Depending on whether the client is still there or not, we
2956 * may send an error response back or not. Note that normally
2957 * we should only check for HTTP status there, and check I/O
2958 * errors somewhere else.
2959 */
2960
2961 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
2962
2963 /* Invalid response, or read error or write error */
2964 if (unlikely((msg->msg_state == HTTP_MSG_ERROR) ||
2965 (req->flags & BF_WRITE_ERROR) ||
2966 (rep->flags & BF_READ_ERROR))) {
Willy Tarreaufa645582007-06-03 15:59:52 +02002967 buffer_shutr(rep);
2968 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002969 fd_delete(t->srv_fd);
2970 if (t->srv) {
2971 t->srv->cur_sess--;
2972 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002973 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01002974 }
2975 t->be->failed_resp++;
2976 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002977 txn->status = 502;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002978 client_return(t, error_message(t, HTTP_ERR_502));
2979 if (!(t->flags & SN_ERR_MASK))
2980 t->flags |= SN_ERR_SRVCL;
2981 if (!(t->flags & SN_FINST_MASK))
2982 t->flags |= SN_FINST_H;
2983 /* We used to have a free connection slot. Since we'll never use it,
2984 * we have to inform the server that it may be used by another session.
2985 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002986 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02002987 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002988
Willy Tarreaua15645d2007-03-18 16:22:39 +01002989 return 1;
2990 }
2991
2992 /* end of client write or end of server read.
2993 * since we are in header mode, if there's no space left for headers, we
2994 * won't be able to free more later, so the session will never terminate.
2995 */
2996 else if (unlikely(rep->flags & BF_READ_NULL ||
2997 c == CL_STSHUTW || c == CL_STCLOSE ||
2998 rep->l >= rep->rlim - rep->data)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002999 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003000 buffer_shutr(rep);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003001 t->srv_state = SV_STSHUTR;
3002 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3003 return 1;
3004 }
3005
3006 /* read timeout : return a 504 to the client.
3007 */
Willy Tarreauf161a342007-04-08 16:59:42 +02003008 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_RD) &&
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003009 tv_isle(&rep->rex, &now))) {
Willy Tarreaufa645582007-06-03 15:59:52 +02003010 buffer_shutr(rep);
3011 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003012 fd_delete(t->srv_fd);
3013 if (t->srv) {
3014 t->srv->cur_sess--;
3015 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003016 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003017 }
3018 t->be->failed_resp++;
3019 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003020 txn->status = 504;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003021 client_return(t, error_message(t, HTTP_ERR_504));
3022 if (!(t->flags & SN_ERR_MASK))
3023 t->flags |= SN_ERR_SRVTO;
3024 if (!(t->flags & SN_FINST_MASK))
3025 t->flags |= SN_FINST_H;
3026 /* We used to have a free connection slot. Since we'll never use it,
3027 * we have to inform the server that it may be used by another session.
3028 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003029 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003030 process_srv_queue(t->srv);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003031 return 1;
3032 }
3033
3034 /* last client read and buffer empty */
3035 /* FIXME!!! here, we don't want to switch to SHUTW if the
3036 * client shuts read too early, because we may still have
3037 * some work to do on the headers.
3038 * The side-effect is that if the client completely closes its
3039 * connection during SV_STHEADER, the connection to the server
3040 * is kept until a response comes back or the timeout is reached.
3041 */
3042 else if (unlikely((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) &&
3043 (req->l == 0))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003044 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003045 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003046
3047 /* We must ensure that the read part is still
3048 * alive when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003049 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003050 tv_add_ifset(&rep->rex, &now, &t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003051
3052 shutdown(t->srv_fd, SHUT_WR);
3053 t->srv_state = SV_STSHUTW;
3054 return 1;
3055 }
3056
3057 /* write timeout */
3058 /* FIXME!!! here, we don't want to switch to SHUTW if the
3059 * client shuts read too early, because we may still have
3060 * some work to do on the headers.
3061 */
Willy Tarreauf161a342007-04-08 16:59:42 +02003062 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_WR) &&
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003063 tv_isle(&req->wex, &now))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003064 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003065 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003066 shutdown(t->srv_fd, SHUT_WR);
3067 /* We must ensure that the read part is still alive
3068 * when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003069 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003070 tv_add_ifset(&rep->rex, &now, &t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003071
3072 t->srv_state = SV_STSHUTW;
3073 if (!(t->flags & SN_ERR_MASK))
3074 t->flags |= SN_ERR_SRVTO;
3075 if (!(t->flags & SN_FINST_MASK))
3076 t->flags |= SN_FINST_H;
3077 return 1;
3078 }
3079
3080 /*
3081 * And now the non-error cases.
3082 */
3083
3084 /* Data remaining in the request buffer.
3085 * This happens during the first pass here, and during
3086 * long posts.
3087 */
3088 else if (likely(req->l)) {
Willy Tarreau66319382007-04-08 17:17:37 +02003089 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3090 /* restart writing */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003091 if (tv_add_ifset(&req->wex, &now, &t->be->timeout.server)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003092 /* FIXME: to prevent the server from expiring read timeouts during writes,
3093 * we refresh it. */
3094 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003095 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003096 else
3097 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003098 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003099 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003100
Willy Tarreaua15645d2007-03-18 16:22:39 +01003101 /* nothing left in the request buffer */
3102 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003103 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3104 /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02003105 tv_eternity(&req->wex);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003106 }
3107 }
3108
3109 return t->srv_state != SV_STHEADERS;
3110 }
3111
3112
3113 /*****************************************************************
3114 * More interesting part now : we know that we have a complete *
3115 * response which at least looks like HTTP. We have an indicator *
3116 * of each header's length, so we can parse them quickly. *
3117 ****************************************************************/
3118
Willy Tarreau9cdde232007-05-02 20:58:19 +02003119 /* ensure we keep this pointer to the beginning of the message */
3120 msg->sol = rep->data + msg->som;
3121
Willy Tarreaua15645d2007-03-18 16:22:39 +01003122 /*
3123 * 1: get the status code and check for cacheability.
3124 */
3125
3126 t->logs.logwait &= ~LW_RESP;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003127 txn->status = strl2ui(rep->data + msg->sl.st.c, msg->sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003128
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003129 switch (txn->status) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003130 case 200:
3131 case 203:
3132 case 206:
3133 case 300:
3134 case 301:
3135 case 410:
3136 /* RFC2616 @13.4:
3137 * "A response received with a status code of
3138 * 200, 203, 206, 300, 301 or 410 MAY be stored
3139 * by a cache (...) unless a cache-control
3140 * directive prohibits caching."
3141 *
3142 * RFC2616 @9.5: POST method :
3143 * "Responses to this method are not cacheable,
3144 * unless the response includes appropriate
3145 * Cache-Control or Expires header fields."
3146 */
3147 if (likely(txn->meth != HTTP_METH_POST) &&
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003148 (t->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
Willy Tarreau3d300592007-03-18 18:34:41 +01003149 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003150 break;
3151 default:
3152 break;
3153 }
3154
3155 /*
3156 * 2: we may need to capture headers
3157 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003158 if (unlikely((t->logs.logwait & LW_RSPHDR) && t->fe->rsp_cap))
Willy Tarreaua15645d2007-03-18 16:22:39 +01003159 capture_headers(rep->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003160 txn->rsp.cap, t->fe->rsp_cap);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003161
3162 /*
3163 * 3: we will have to evaluate the filters.
3164 * As opposed to version 1.2, now they will be evaluated in the
3165 * filters order and not in the header order. This means that
3166 * each filter has to be validated among all headers.
3167 *
3168 * Filters are tried with ->be first, then with ->fe if it is
3169 * different from ->be.
3170 */
3171
3172 t->flags &= ~SN_CONN_CLOSED; /* prepare for inspection */
3173
3174 cur_proxy = t->be;
3175 while (1) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003176 struct proxy *rule_set = cur_proxy;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003177
3178 /* try headers filters */
3179 if (rule_set->rsp_exp != NULL) {
3180 if (apply_filters_to_response(t, rep, rule_set->rsp_exp) < 0) {
3181 return_bad_resp:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003182 if (t->srv) {
3183 t->srv->cur_sess--;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003184 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003185 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003186 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003187 cur_proxy->failed_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003188 return_srv_prx_502:
Willy Tarreaufa645582007-06-03 15:59:52 +02003189 buffer_shutr(rep);
3190 buffer_shutw(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003191 fd_delete(t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003192 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003193 txn->status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01003194 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003195 if (!(t->flags & SN_ERR_MASK))
3196 t->flags |= SN_ERR_PRXCOND;
3197 if (!(t->flags & SN_FINST_MASK))
3198 t->flags |= SN_FINST_H;
3199 /* We used to have a free connection slot. Since we'll never use it,
3200 * we have to inform the server that it may be used by another session.
3201 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003202 if (t->srv && may_dequeue_tasks(t->srv, cur_proxy))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003203 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003204 return 1;
3205 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003206 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003207
Willy Tarreaua15645d2007-03-18 16:22:39 +01003208 /* has the response been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01003209 if (txn->flags & TX_SVDENY) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003210 if (t->srv) {
3211 t->srv->cur_sess--;
3212 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003213 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003214 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003215 cur_proxy->denied_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003216 goto return_srv_prx_502;
3217 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003218
Willy Tarreaua15645d2007-03-18 16:22:39 +01003219 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003220 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01003221 !(t->flags & SN_CONN_CLOSED)) {
3222 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003223 int cur_idx, old_idx, delta, val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003224 struct hdr_idx_elem *cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003225
Willy Tarreaua15645d2007-03-18 16:22:39 +01003226 cur_next = rep->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
3227 old_idx = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003228
Willy Tarreaua15645d2007-03-18 16:22:39 +01003229 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
3230 cur_hdr = &txn->hdr_idx.v[cur_idx];
3231 cur_ptr = cur_next;
3232 cur_end = cur_ptr + cur_hdr->len;
3233 cur_next = cur_end + cur_hdr->cr + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003234
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003235 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
3236 if (val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003237 /* 3 possibilities :
3238 * - we have already set Connection: close,
3239 * so we remove this line.
3240 * - we have not yet set Connection: close,
3241 * but this line indicates close. We leave
3242 * it untouched and set the flag.
3243 * - we have not yet set Connection: close,
3244 * and this line indicates non-close. We
3245 * replace it.
3246 */
3247 if (t->flags & SN_CONN_CLOSED) {
3248 delta = buffer_replace2(rep, cur_ptr, cur_next, NULL, 0);
3249 txn->rsp.eoh += delta;
3250 cur_next += delta;
3251 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3252 txn->hdr_idx.used--;
3253 cur_hdr->len = 0;
3254 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003255 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
3256 delta = buffer_replace2(rep, cur_ptr + val, cur_end,
3257 "close", 5);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003258 cur_next += delta;
3259 cur_hdr->len += delta;
3260 txn->rsp.eoh += delta;
3261 }
3262 t->flags |= SN_CONN_CLOSED;
3263 }
3264 }
3265 old_idx = cur_idx;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003266 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003267 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003268
Willy Tarreaua15645d2007-03-18 16:22:39 +01003269 /* add response headers from the rule sets in the same order */
3270 for (cur_idx = 0; cur_idx < rule_set->nb_rspadd; cur_idx++) {
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003271 if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx,
3272 rule_set->rsp_add[cur_idx])) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003273 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003274 }
3275
Willy Tarreaua15645d2007-03-18 16:22:39 +01003276 /* check whether we're already working on the frontend */
3277 if (cur_proxy == t->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003278 break;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003279 cur_proxy = t->fe;
3280 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003281
Willy Tarreaua15645d2007-03-18 16:22:39 +01003282 /*
3283 * 4: check for server cookie.
3284 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003285 if (t->be->cookie_name || t->be->appsession_name || t->be->capture_name
3286 || (t->be->options & PR_O_CHK_CACHE))
3287 manage_server_side_cookies(t, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003288
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003289
Willy Tarreaua15645d2007-03-18 16:22:39 +01003290 /*
Willy Tarreau396d2c62007-11-04 19:30:00 +01003291 * 5: check for cache-control or pragma headers if required.
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003292 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003293 if ((t->be->options & (PR_O_COOK_NOC | PR_O_CHK_CACHE)) != 0)
3294 check_response_for_cacheability(t, rep);
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003295
3296 /*
3297 * 6: add server cookie in the response if needed
Willy Tarreaua15645d2007-03-18 16:22:39 +01003298 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003299 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
3300 (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003301 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003302
Willy Tarreaua15645d2007-03-18 16:22:39 +01003303 /* the server is known, it's not the one the client requested, we have to
3304 * insert a set-cookie here, except if we want to insert only on POST
3305 * requests and this one isn't. Note that servers which don't have cookies
3306 * (eg: some backup servers) will return a full cookie removal request.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003307 */
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003308 len = sprintf(trash, "Set-Cookie: %s=%s; path=/",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003309 t->be->cookie_name,
Willy Tarreaua15645d2007-03-18 16:22:39 +01003310 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003311
Krzysztof Piotr Oledzki1acf2172008-05-29 23:03:34 +02003312 if (t->be->cookie_domain)
3313 len += sprintf(trash+len, "; domain=%s", t->be->cookie_domain);
Krzysztof Piotr Oledzkiefe3b6f2008-05-23 23:49:32 +02003314
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003315 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3316 trash, len)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003317 goto return_bad_resp;
Willy Tarreau3d300592007-03-18 18:34:41 +01003318 txn->flags |= TX_SCK_INSERTED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003319
Willy Tarreaua15645d2007-03-18 16:22:39 +01003320 /* Here, we will tell an eventual cache on the client side that we don't
3321 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3322 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3323 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3324 */
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003325 if ((t->be->options & PR_O_COOK_NOC) && (txn->flags & TX_CACHEABLE)) {
3326
3327 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
3328
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003329 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3330 "Cache-control: private", 22)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003331 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003332 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003333 }
3334
3335
3336 /*
Willy Tarreaua15645d2007-03-18 16:22:39 +01003337 * 7: check if result will be cacheable with a cookie.
3338 * We'll block the response if security checks have caught
3339 * nasty things such as a cacheable cookie.
3340 */
Willy Tarreau3d300592007-03-18 18:34:41 +01003341 if (((txn->flags & (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) ==
3342 (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003343 (t->be->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003344
Willy Tarreaua15645d2007-03-18 16:22:39 +01003345 /* we're in presence of a cacheable response containing
3346 * a set-cookie header. We'll block it as requested by
3347 * the 'checkcache' option, and send an alert.
3348 */
3349 if (t->srv) {
3350 t->srv->cur_sess--;
3351 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003352 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003353 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003354 t->be->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003355
Willy Tarreaua15645d2007-03-18 16:22:39 +01003356 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003357 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003358 send_log(t->be, LOG_ALERT,
3359 "Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003360 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003361 goto return_srv_prx_502;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003362 }
3363
Willy Tarreaua15645d2007-03-18 16:22:39 +01003364 /*
3365 * 8: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02003366 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003367 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02003368 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003369 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02003370 if ((unlikely(msg->sl.st.v_l != 8) ||
3371 unlikely(req->data[msg->som + 7] != '0')) &&
3372 unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003373 "Connection: close", 17)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003374 goto return_bad_resp;
3375 t->flags |= SN_CONN_CLOSED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003376 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003377
Willy Tarreaubaaee002006-06-26 02:48:02 +02003378
Willy Tarreaua15645d2007-03-18 16:22:39 +01003379 /*************************************************************
3380 * OK, that's finished for the headers. We have done what we *
3381 * could. Let's switch to the DATA state. *
3382 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02003383
Willy Tarreaua15645d2007-03-18 16:22:39 +01003384 t->srv_state = SV_STDATA;
3385 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02003386 t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003387
3388 /* client connection already closed or option 'forceclose' required :
3389 * we close the server's outgoing connection right now.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003390 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003391 if ((req->l == 0) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003392 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->options & PR_O_FORCE_CLO)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003393 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003394 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003395
3396 /* We must ensure that the read part is still alive when switching
3397 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003398 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003399 tv_add_ifset(&rep->rex, &now, &t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003400
Willy Tarreaua15645d2007-03-18 16:22:39 +01003401 shutdown(t->srv_fd, SHUT_WR);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003402 t->srv_state = SV_STSHUTW;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003403 }
3404
Willy Tarreaua15645d2007-03-18 16:22:39 +01003405#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003406 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003407 /* TCP splicing supported by both FE and BE */
3408 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003409 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003410#endif
3411 /* if the user wants to log as soon as possible, without counting
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003412 * bytes from the server, then this is the right moment. We have
3413 * to temporarily assign bytes_out to log what we currently have.
3414 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003415 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
3416 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreau8b3977f2008-01-18 11:16:32 +01003417 t->logs.bytes_out = txn->rsp.eoh;
Willy Tarreau42250582007-04-01 01:30:43 +02003418 if (t->fe->to_log & LW_REQ)
3419 http_sess_log(t);
3420 else
3421 tcp_sess_log(t);
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003422 t->logs.bytes_out = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003423 }
3424
Willy Tarreaua15645d2007-03-18 16:22:39 +01003425 /* Note: we must not try to cheat by jumping directly to DATA,
3426 * otherwise we would not let the client side wake up.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003427 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003428
3429 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003430 }
3431 else if (s == SV_STDATA) {
3432 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003433 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaufa645582007-06-03 15:59:52 +02003434 buffer_shutr(rep);
3435 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003436 fd_delete(t->srv_fd);
3437 if (t->srv) {
3438 t->srv->cur_sess--;
3439 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003440 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003441 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003442 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003443 t->srv_state = SV_STCLOSE;
3444 if (!(t->flags & SN_ERR_MASK))
3445 t->flags |= SN_ERR_SRVCL;
3446 if (!(t->flags & SN_FINST_MASK))
3447 t->flags |= SN_FINST_D;
3448 /* We used to have a free connection slot. Since we'll never use it,
3449 * we have to inform the server that it may be used by another session.
3450 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003451 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003452 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003453
3454 return 1;
3455 }
3456 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003457 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003458 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003459 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003460 t->srv_state = SV_STSHUTR;
3461 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3462 return 1;
3463 }
3464 /* end of client read and no more data to send */
3465 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003466 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003467 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003468 shutdown(t->srv_fd, SHUT_WR);
3469 /* We must ensure that the read part is still alive when switching
3470 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003471 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003472 tv_add_ifset(&rep->rex, &now, &t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003473
3474 t->srv_state = SV_STSHUTW;
3475 return 1;
3476 }
3477 /* read timeout */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003478 else if (tv_isle(&rep->rex, &now)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003479 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003480 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003481 t->srv_state = SV_STSHUTR;
3482 if (!(t->flags & SN_ERR_MASK))
3483 t->flags |= SN_ERR_SRVTO;
3484 if (!(t->flags & SN_FINST_MASK))
3485 t->flags |= SN_FINST_D;
3486 return 1;
3487 }
3488 /* write timeout */
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003489 else if (tv_isle(&req->wex, &now)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003490 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003491 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003492 shutdown(t->srv_fd, SHUT_WR);
3493 /* We must ensure that the read part is still alive when switching
3494 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003495 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003496 tv_add_ifset(&rep->rex, &now, &t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003497 t->srv_state = SV_STSHUTW;
3498 if (!(t->flags & SN_ERR_MASK))
3499 t->flags |= SN_ERR_SRVTO;
3500 if (!(t->flags & SN_FINST_MASK))
3501 t->flags |= SN_FINST_D;
3502 return 1;
3503 }
3504
3505 /* recompute request time-outs */
3506 if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003507 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3508 /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02003509 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003510 }
3511 }
3512 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau66319382007-04-08 17:17:37 +02003513 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3514 /* restart writing */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003515 if (tv_add_ifset(&req->wex, &now, &t->be->timeout.server)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003516 /* FIXME: to prevent the server from expiring read timeouts during writes,
3517 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02003518 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003519 }
3520 else
Willy Tarreaud7971282006-07-29 18:36:34 +02003521 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003522 }
3523 }
3524
3525 /* recompute response time-outs */
3526 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003527 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02003528 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003529 }
3530 }
3531 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003532 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003533 if (!tv_add_ifset(&rep->rex, &now, &t->be->timeout.server))
Willy Tarreaud7971282006-07-29 18:36:34 +02003534 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003535 }
3536 }
3537
3538 return 0; /* other cases change nothing */
3539 }
3540 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003541 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003542 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003543 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003544 fd_delete(t->srv_fd);
3545 if (t->srv) {
3546 t->srv->cur_sess--;
3547 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003548 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003549 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003550 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003551 //close(t->srv_fd);
3552 t->srv_state = SV_STCLOSE;
3553 if (!(t->flags & SN_ERR_MASK))
3554 t->flags |= SN_ERR_SRVCL;
3555 if (!(t->flags & SN_FINST_MASK))
3556 t->flags |= SN_FINST_D;
3557 /* We used to have a free connection slot. Since we'll never use it,
3558 * we have to inform the server that it may be used by another session.
3559 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003560 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003561 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003562
3563 return 1;
3564 }
3565 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003566 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003567 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003568 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003569 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003570 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003571 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003572 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003573 //close(t->srv_fd);
3574 t->srv_state = SV_STCLOSE;
3575 /* We used to have a free connection slot. Since we'll never use it,
3576 * we have to inform the server that it may be used by another session.
3577 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003578 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003579 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003580
3581 return 1;
3582 }
Willy Tarreaua8b55e32007-05-13 16:08:19 +02003583 else if (tv_isle(&req->wex, &now)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003584 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreaufa645582007-06-03 15:59:52 +02003585 buffer_shutw(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003586 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003587 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003588 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003589 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003590 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003591 //close(t->srv_fd);
3592 t->srv_state = SV_STCLOSE;
3593 if (!(t->flags & SN_ERR_MASK))
3594 t->flags |= SN_ERR_SRVTO;
3595 if (!(t->flags & SN_FINST_MASK))
3596 t->flags |= SN_FINST_D;
3597 /* We used to have a free connection slot. Since we'll never use it,
3598 * we have to inform the server that it may be used by another session.
3599 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003600 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003601 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003602
3603 return 1;
3604 }
3605 else if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003606 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3607 /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02003608 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003609 }
3610 }
3611 else { /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02003612 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3613 /* restart writing */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003614 if (!tv_add_ifset(&req->wex, &now, &t->be->timeout.server))
Willy Tarreaud7971282006-07-29 18:36:34 +02003615 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003616 }
3617 }
3618 return 0;
3619 }
3620 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003621 if (rep->flags & BF_READ_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003622 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003623 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003624 fd_delete(t->srv_fd);
3625 if (t->srv) {
3626 t->srv->cur_sess--;
3627 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003628 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003629 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003630 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003631 //close(t->srv_fd);
3632 t->srv_state = SV_STCLOSE;
3633 if (!(t->flags & SN_ERR_MASK))
3634 t->flags |= SN_ERR_SRVCL;
3635 if (!(t->flags & SN_FINST_MASK))
3636 t->flags |= SN_FINST_D;
3637 /* We used to have a free connection slot. Since we'll never use it,
3638 * we have to inform the server that it may be used by another session.
3639 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003640 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003641 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003642
3643 return 1;
3644 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003645 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003646 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003647 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003648 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003649 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003650 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003651 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003652 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003653 //close(t->srv_fd);
3654 t->srv_state = SV_STCLOSE;
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 Tarreaua8b55e32007-05-13 16:08:19 +02003663 else if (tv_isle(&rep->rex, &now)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003664 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003665 buffer_shutr(rep);
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 if (!(t->flags & SN_ERR_MASK))
3674 t->flags |= SN_ERR_SRVTO;
3675 if (!(t->flags & SN_FINST_MASK))
3676 t->flags |= SN_FINST_D;
3677 /* We used to have a free connection slot. Since we'll never use it,
3678 * we have to inform the server that it may be used by another session.
3679 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003680 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003681 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003682
3683 return 1;
3684 }
3685 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003686 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02003687 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003688 }
3689 }
3690 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003691 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003692 if (!tv_add_ifset(&rep->rex, &now, &t->be->timeout.server))
Willy Tarreaud7971282006-07-29 18:36:34 +02003693 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003694 }
3695 }
3696 return 0;
3697 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003698 else if (s == SV_STANALYZE){
3699 /* this server state is set by the client to study the body for server assignment */
3700
3701 /* Have we been through this long enough to timeout? */
3702 if (!tv_isle(&req->rex, &now)) {
3703 /* balance url_param check_post should have been the only to get into this.
3704 * just wait for data, check to compare how much
3705 */
3706 struct http_msg * msg = &t->txn.req;
3707 unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 :msg->eoh + 1;
3708 unsigned long len = req->total - body;
3709 long long limit = t->be->url_param_post_limit;
3710 struct hdr_ctx ctx;
3711 ctx.idx = 0;
3712 /* now if we have a length, we'll take the hint */
3713 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
3714 if ( ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",ctx.vlen)==0) {
3715 unsigned int chunk = 0;
3716 while ( body < req->total && !HTTP_IS_CRLF(msg->sol[body])) {
3717 char c = msg->sol[body];
3718 if (ishex(c)) {
3719 unsigned int hex = toupper(c) - '0';
3720 if ( hex > 9 )
3721 hex -= 'A' - '9' - 1;
3722 chunk = (chunk << 4) | hex;
3723 }
3724 else break;
3725 body++;
3726 len--;
3727 }
3728 if ( body == req->total )
3729 return 0; /* end of buffer? data missing! */
3730
3731 if ( memcmp(msg->sol+body, "\r\n", 2) != 0 )
3732 return 0; /* chunked encoding len ends with CRLF, and we don't have it yet */
3733
3734 /* if we support more then one chunk here, we have to do it again when assigning server
3735 1. how much entity data do we have? new var
3736 2. should save entity_start, entity_cursor, elen & rlen in req; so we don't repeat scanning here
3737 3. test if elen > limit, or set new limit to elen if 0 (end of entity found)
3738 */
3739
3740 if ( chunk < limit )
3741 limit = chunk; /* only reading one chunk */
3742 } else {
3743 if ( msg->hdr_content_len < limit )
3744 limit = msg->hdr_content_len;
3745 }
3746 if ( len < limit )
3747 return 0;
3748 }
3749 t->srv_state=SV_STIDLE;
3750 return 1;
3751 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003752 else { /* SV_STCLOSE : nothing to do */
3753 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
3754 int len;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003755 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003756 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003757 write(1, trash, len);
3758 }
3759 return 0;
3760 }
3761 return 0;
3762}
3763
3764
3765/*
3766 * Produces data for the session <s> depending on its source. Expects to be
3767 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3768 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3769 * session, which it uses to keep on being called when there is free space in
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003770 * the buffer, or simply by letting an empty buffer upon return. It returns 1
Willy Tarreaubaaee002006-06-26 02:48:02 +02003771 * if it changes the session state from CL_STSHUTR, otherwise 0.
3772 */
3773int produce_content(struct session *s)
3774{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003775 if (s->data_source == DATA_SRC_NONE) {
3776 s->flags &= ~SN_SELF_GEN;
3777 return 1;
3778 }
3779 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003780 /* dump server statistics */
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01003781 int ret = stats_dump_http(s, s->be->uri_auth);
Willy Tarreau91861262007-10-17 17:06:05 +02003782 if (ret >= 0)
3783 return ret;
3784 /* -1 indicates an error */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003785 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003786
Willy Tarreau91861262007-10-17 17:06:05 +02003787 /* unknown data source or internal error */
3788 s->txn.status = 500;
3789 client_retnclose(s, error_message(s, HTTP_ERR_500));
3790 if (!(s->flags & SN_ERR_MASK))
3791 s->flags |= SN_ERR_PRXCOND;
3792 if (!(s->flags & SN_FINST_MASK))
3793 s->flags |= SN_FINST_R;
3794 s->flags &= ~SN_SELF_GEN;
3795 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003796}
3797
3798
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003799/* Iterate the same filter through all request headers.
3800 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003801 * Since it can manage the switch to another backend, it updates the per-proxy
3802 * DENY stats.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003803 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003804int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003805{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003806 char term;
3807 char *cur_ptr, *cur_end, *cur_next;
3808 int cur_idx, old_idx, last_hdr;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003809 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003810 struct hdr_idx_elem *cur_hdr;
3811 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003812
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003813 last_hdr = 0;
3814
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003815 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003816 old_idx = 0;
3817
3818 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01003819 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003820 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003821 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003822 (exp->action == ACT_ALLOW ||
3823 exp->action == ACT_DENY ||
3824 exp->action == ACT_TARPIT))
3825 return 0;
3826
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003827 cur_idx = txn->hdr_idx.v[old_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003828 if (!cur_idx)
3829 break;
3830
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003831 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003832 cur_ptr = cur_next;
3833 cur_end = cur_ptr + cur_hdr->len;
3834 cur_next = cur_end + cur_hdr->cr + 1;
3835
3836 /* Now we have one header between cur_ptr and cur_end,
3837 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003838 */
3839
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003840 /* The annoying part is that pattern matching needs
3841 * that we modify the contents to null-terminate all
3842 * strings before testing them.
3843 */
3844
3845 term = *cur_end;
3846 *cur_end = '\0';
3847
3848 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3849 switch (exp->action) {
3850 case ACT_SETBE:
3851 /* It is not possible to jump a second time.
3852 * FIXME: should we return an HTTP/500 here so that
3853 * the admin knows there's a problem ?
3854 */
3855 if (t->be != t->fe)
3856 break;
3857
3858 /* Swithing Proxy */
3859 t->be = (struct proxy *) exp->replace;
3860
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003861 /* right now, the backend switch is not overly complicated
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003862 * because we have associated req_cap and rsp_cap to the
3863 * frontend, and the beconn will be updated later.
3864 */
3865
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003866 t->rep->rto = t->req->wto = t->be->timeout.server;
3867 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02003868 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003869 last_hdr = 1;
3870 break;
3871
3872 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003873 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003874 last_hdr = 1;
3875 break;
3876
3877 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003878 txn->flags |= TX_CLDENY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003879 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003880 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003881 break;
3882
3883 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003884 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003885 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003886 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003887 break;
3888
3889 case ACT_REPLACE:
3890 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3891 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3892 /* FIXME: if the user adds a newline in the replacement, the
3893 * index will not be recalculated for now, and the new line
3894 * will not be counted as a new header.
3895 */
3896
3897 cur_end += delta;
3898 cur_next += delta;
3899 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003900 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003901 break;
3902
3903 case ACT_REMOVE:
3904 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3905 cur_next += delta;
3906
3907 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003908 txn->req.eoh += delta;
3909 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3910 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003911 cur_hdr->len = 0;
3912 cur_end = NULL; /* null-term has been rewritten */
3913 break;
3914
3915 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01003916 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003917 if (cur_end)
3918 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003919
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003920 /* keep the link from this header to next one in case of later
3921 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003922 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003923 old_idx = cur_idx;
3924 }
3925 return 0;
3926}
3927
3928
3929/* Apply the filter to the request line.
3930 * Returns 0 if nothing has been done, 1 if the filter has been applied,
3931 * or -1 if a replacement resulted in an invalid request line.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003932 * Since it can manage the switch to another backend, it updates the per-proxy
3933 * DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003934 */
3935int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
3936{
3937 char term;
3938 char *cur_ptr, *cur_end;
3939 int done;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003940 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003941 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003942
Willy Tarreau58f10d72006-12-04 02:26:12 +01003943
Willy Tarreau3d300592007-03-18 18:34:41 +01003944 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003945 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003946 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003947 (exp->action == ACT_ALLOW ||
3948 exp->action == ACT_DENY ||
3949 exp->action == ACT_TARPIT))
3950 return 0;
3951 else if (exp->action == ACT_REMOVE)
3952 return 0;
3953
3954 done = 0;
3955
Willy Tarreau9cdde232007-05-02 20:58:19 +02003956 cur_ptr = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003957 cur_end = cur_ptr + txn->req.sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003958
3959 /* Now we have the request line between cur_ptr and cur_end */
3960
3961 /* The annoying part is that pattern matching needs
3962 * that we modify the contents to null-terminate all
3963 * strings before testing them.
3964 */
3965
3966 term = *cur_end;
3967 *cur_end = '\0';
3968
3969 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3970 switch (exp->action) {
3971 case ACT_SETBE:
3972 /* It is not possible to jump a second time.
3973 * FIXME: should we return an HTTP/500 here so that
3974 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01003975 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003976 if (t->be != t->fe)
3977 break;
3978
3979 /* Swithing Proxy */
3980 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003981
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003982 /* right now, the backend switch is not too much complicated
3983 * because we have associated req_cap and rsp_cap to the
3984 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003985 */
3986
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003987 t->rep->rto = t->req->wto = t->be->timeout.server;
3988 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02003989 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003990 done = 1;
3991 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003992
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003993 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003994 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003995 done = 1;
3996 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003997
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003998 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003999 txn->flags |= TX_CLDENY;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004000 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004001 done = 1;
4002 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004003
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004004 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01004005 txn->flags |= TX_CLTARPIT;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004006 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004007 done = 1;
4008 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004009
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004010 case ACT_REPLACE:
4011 *cur_end = term; /* restore the string terminator */
4012 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4013 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
4014 /* FIXME: if the user adds a newline in the replacement, the
4015 * index will not be recalculated for now, and the new line
4016 * will not be counted as a new header.
4017 */
Willy Tarreaua496b602006-12-17 23:15:24 +01004018
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004019 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004020 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01004021
Willy Tarreau9cdde232007-05-02 20:58:19 +02004022 txn->req.sol = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004023 cur_end = (char *)http_parse_reqline(&txn->req, req->data,
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004024 HTTP_MSG_RQMETH,
4025 cur_ptr, cur_end + 1,
4026 NULL, NULL);
4027 if (unlikely(!cur_end))
4028 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01004029
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004030 /* we have a full request and we know that we have either a CR
4031 * or an LF at <ptr>.
4032 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004033 txn->meth = find_http_meth(cur_ptr, txn->req.sl.rq.m_l);
4034 hdr_idx_set_start(&txn->hdr_idx, txn->req.sl.rq.l, *cur_end == '\r');
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004035 /* there is no point trying this regex on headers */
4036 return 1;
4037 }
4038 }
4039 *cur_end = term; /* restore the string terminator */
4040 return done;
4041}
Willy Tarreau97de6242006-12-27 17:18:38 +01004042
Willy Tarreau58f10d72006-12-04 02:26:12 +01004043
Willy Tarreau58f10d72006-12-04 02:26:12 +01004044
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004045/*
4046 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
4047 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
Willy Tarreaua15645d2007-03-18 16:22:39 +01004048 * unparsable request. Since it can manage the switch to another backend, it
4049 * updates the per-proxy DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004050 */
4051int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
4052{
Willy Tarreau3d300592007-03-18 18:34:41 +01004053 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004054 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004055 while (exp && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004056 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004057
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004058 /*
4059 * The interleaving of transformations and verdicts
4060 * makes it difficult to decide to continue or stop
4061 * the evaluation.
4062 */
4063
Willy Tarreau3d300592007-03-18 18:34:41 +01004064 if ((txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004065 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4066 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
4067 exp = exp->next;
4068 continue;
4069 }
4070
4071 /* Apply the filter to the request line. */
4072 ret = apply_filter_to_req_line(t, req, exp);
4073 if (unlikely(ret < 0))
4074 return -1;
4075
4076 if (likely(ret == 0)) {
4077 /* The filter did not match the request, it can be
4078 * iterated through all headers.
4079 */
4080 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004081 }
4082 exp = exp->next;
4083 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004084 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004085}
4086
4087
Willy Tarreaua15645d2007-03-18 16:22:39 +01004088
Willy Tarreau58f10d72006-12-04 02:26:12 +01004089/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004090 * Manage client-side cookie. It can impact performance by about 2% so it is
4091 * desirable to call it only when needed.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004092 */
4093void manage_client_side_cookies(struct session *t, struct buffer *req)
4094{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004095 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004096 char *p1, *p2, *p3, *p4;
4097 char *del_colon, *del_cookie, *colon;
4098 int app_cookies;
4099
4100 appsess *asession_temp = NULL;
4101 appsess local_asession;
4102
4103 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004104 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004105
Willy Tarreau2a324282006-12-05 00:05:46 +01004106 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004107 * we start with the start line.
4108 */
Willy Tarreau83969f42007-01-22 08:55:47 +01004109 old_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004110 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004111
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004112 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004113 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004114 int val;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004115
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004116 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01004117 cur_ptr = cur_next;
4118 cur_end = cur_ptr + cur_hdr->len;
4119 cur_next = cur_end + cur_hdr->cr + 1;
4120
4121 /* We have one full header between cur_ptr and cur_end, and the
4122 * next header starts at cur_next. We're only interested in
4123 * "Cookie:" headers.
4124 */
4125
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004126 val = http_header_match2(cur_ptr, cur_end, "Cookie", 6);
4127 if (!val) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004128 old_idx = cur_idx;
4129 continue;
4130 }
4131
4132 /* Now look for cookies. Conforming to RFC2109, we have to support
4133 * attributes whose name begin with a '$', and associate them with
4134 * the right cookie, if we want to delete this cookie.
4135 * So there are 3 cases for each cookie read :
4136 * 1) it's a special attribute, beginning with a '$' : ignore it.
4137 * 2) it's a server id cookie that we *MAY* want to delete : save
4138 * some pointers on it (last semi-colon, beginning of cookie...)
4139 * 3) it's an application cookie : we *MAY* have to delete a previous
4140 * "special" cookie.
4141 * At the end of loop, if a "special" cookie remains, we may have to
4142 * remove it. If no application cookie persists in the header, we
4143 * *MUST* delete it
4144 */
4145
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004146 colon = p1 = cur_ptr + val; /* first non-space char after 'Cookie:' */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004147
Willy Tarreau58f10d72006-12-04 02:26:12 +01004148 /* del_cookie == NULL => nothing to be deleted */
4149 del_colon = del_cookie = NULL;
4150 app_cookies = 0;
4151
4152 while (p1 < cur_end) {
4153 /* skip spaces and colons, but keep an eye on these ones */
4154 while (p1 < cur_end) {
4155 if (*p1 == ';' || *p1 == ',')
4156 colon = p1;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004157 else if (!isspace((unsigned char)*p1))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004158 break;
4159 p1++;
4160 }
4161
4162 if (p1 == cur_end)
4163 break;
4164
4165 /* p1 is at the beginning of the cookie name */
4166 p2 = p1;
4167 while (p2 < cur_end && *p2 != '=')
4168 p2++;
4169
4170 if (p2 == cur_end)
4171 break;
4172
4173 p3 = p2 + 1; /* skips the '=' sign */
4174 if (p3 == cur_end)
4175 break;
4176
4177 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004178 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';' && *p4 != ',')
Willy Tarreau58f10d72006-12-04 02:26:12 +01004179 p4++;
4180
4181 /* here, we have the cookie name between p1 and p2,
4182 * and its value between p3 and p4.
4183 * we can process it :
4184 *
4185 * Cookie: NAME=VALUE;
4186 * | || || |
4187 * | || || +--> p4
4188 * | || |+-------> p3
4189 * | || +--------> p2
4190 * | |+------------> p1
4191 * | +-------------> colon
4192 * +--------------------> cur_ptr
4193 */
4194
4195 if (*p1 == '$') {
4196 /* skip this one */
4197 }
4198 else {
4199 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004200 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004201 txn->cli_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004202 (p4 - p1 >= t->fe->capture_namelen) &&
4203 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004204 int log_len = p4 - p1;
4205
Willy Tarreau086b3b42007-05-13 21:45:51 +02004206 if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004207 Alert("HTTP logging : out of memory.\n");
4208 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004209 if (log_len > t->fe->capture_len)
4210 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004211 memcpy(txn->cli_cookie, p1, log_len);
4212 txn->cli_cookie[log_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004213 }
4214 }
4215
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004216 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4217 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004218 /* Cool... it's the right one */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004219 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004220 char *delim;
4221
4222 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4223 * have the server ID betweek p3 and delim, and the original cookie between
4224 * delim+1 and p4. Otherwise, delim==p4 :
4225 *
4226 * Cookie: NAME=SRV~VALUE;
4227 * | || || | |
4228 * | || || | +--> p4
4229 * | || || +--------> delim
4230 * | || |+-----------> p3
4231 * | || +------------> p2
4232 * | |+----------------> p1
4233 * | +-----------------> colon
4234 * +------------------------> cur_ptr
4235 */
4236
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004237 if (t->be->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004238 for (delim = p3; delim < p4; delim++)
4239 if (*delim == COOKIE_DELIM)
4240 break;
4241 }
4242 else
4243 delim = p4;
4244
4245
4246 /* Here, we'll look for the first running server which supports the cookie.
4247 * This allows to share a same cookie between several servers, for example
4248 * to dedicate backup servers to specific servers only.
4249 * However, to prevent clients from sticking to cookie-less backup server
4250 * when they have incidentely learned an empty cookie, we simply ignore
4251 * empty cookies and mark them as invalid.
4252 */
4253 if (delim == p3)
4254 srv = NULL;
4255
4256 while (srv) {
Willy Tarreau92f2ab12007-02-02 22:14:47 +01004257 if (srv->cookie && (srv->cklen == delim - p3) &&
4258 !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004259 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004260 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004261 txn->flags &= ~TX_CK_MASK;
4262 txn->flags |= TX_CK_VALID;
4263 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004264 t->srv = srv;
4265 break;
4266 } else {
4267 /* we found a server, but it's down */
Willy Tarreau3d300592007-03-18 18:34:41 +01004268 txn->flags &= ~TX_CK_MASK;
4269 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004270 }
4271 }
4272 srv = srv->next;
4273 }
4274
Willy Tarreau3d300592007-03-18 18:34:41 +01004275 if (!srv && !(txn->flags & TX_CK_DOWN)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004276 /* no server matched this cookie */
Willy Tarreau3d300592007-03-18 18:34:41 +01004277 txn->flags &= ~TX_CK_MASK;
4278 txn->flags |= TX_CK_INVALID;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004279 }
4280
4281 /* depending on the cookie mode, we may have to either :
4282 * - delete the complete cookie if we're in insert+indirect mode, so that
4283 * the server never sees it ;
4284 * - remove the server id from the cookie value, and tag the cookie as an
4285 * application cookie so that it does not get accidentely removed later,
4286 * if we're in cookie prefix mode
4287 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004288 if ((t->be->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004289 int delta; /* negative */
4290
4291 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
4292 p4 += delta;
4293 cur_end += delta;
4294 cur_next += delta;
4295 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004296 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004297
4298 del_cookie = del_colon = NULL;
4299 app_cookies++; /* protect the header from deletion */
4300 }
4301 else if (del_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004302 (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 +01004303 del_cookie = p1;
4304 del_colon = colon;
4305 }
4306 } else {
4307 /* now we know that we must keep this cookie since it's
4308 * not ours. But if we wanted to delete our cookie
4309 * earlier, we cannot remove the complete header, but we
4310 * can remove the previous block itself.
4311 */
4312 app_cookies++;
4313
4314 if (del_cookie != NULL) {
4315 int delta; /* negative */
4316
4317 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
4318 p4 += delta;
4319 cur_end += delta;
4320 cur_next += delta;
4321 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004322 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004323 del_cookie = del_colon = NULL;
4324 }
4325 }
4326
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004327 if ((t->be->appsession_name != NULL) &&
4328 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004329 /* first, let's see if the cookie is our appcookie*/
4330
4331 /* Cool... it's the right one */
4332
4333 asession_temp = &local_asession;
4334
Willy Tarreau63963c62007-05-13 21:29:55 +02004335 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004336 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4337 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4338 return;
4339 }
4340
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004341 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4342 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004343 asession_temp->serverid = NULL;
Willy Tarreau51041c72007-09-09 21:56:53 +02004344
Willy Tarreau58f10d72006-12-04 02:26:12 +01004345 /* only do insert, if lookup fails */
Willy Tarreau51041c72007-09-09 21:56:53 +02004346 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4347 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004348 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004349 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004350 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004351 Alert("Not enough memory process_cli():asession:calloc().\n");
4352 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4353 return;
4354 }
4355
4356 asession_temp->sessid = local_asession.sessid;
4357 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004358 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004359 } else {
4360 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004361 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004362 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004363 if (asession_temp->serverid == NULL) {
4364 Alert("Found Application Session without matching server.\n");
4365 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004366 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004367 while (srv) {
4368 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004369 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004370 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004371 txn->flags &= ~TX_CK_MASK;
4372 txn->flags |= TX_CK_VALID;
4373 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004374 t->srv = srv;
4375 break;
4376 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01004377 txn->flags &= ~TX_CK_MASK;
4378 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004379 }
4380 }
4381 srv = srv->next;
4382 }/* end while(srv) */
4383 }/* end else if server == NULL */
4384
Willy Tarreaud7c30f92007-12-03 01:38:36 +01004385 tv_add(&asession_temp->expire, &now, &t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004386 }/* end if ((t->proxy->appsession_name != NULL) ... */
4387 }
4388
4389 /* we'll have to look for another cookie ... */
4390 p1 = p4;
4391 } /* while (p1 < cur_end) */
4392
4393 /* There's no more cookie on this line.
4394 * We may have marked the last one(s) for deletion.
4395 * We must do this now in two ways :
4396 * - if there is no app cookie, we simply delete the header ;
4397 * - if there are app cookies, we must delete the end of the
4398 * string properly, including the colon/semi-colon before
4399 * the cookie name.
4400 */
4401 if (del_cookie != NULL) {
4402 int delta;
4403 if (app_cookies) {
4404 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
4405 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004406 cur_hdr->len += delta;
4407 } else {
4408 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004409
4410 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004411 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4412 txn->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004413 cur_hdr->len = 0;
4414 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01004415 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004416 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004417 }
4418
4419 /* keep the link from this header to next one */
4420 old_idx = cur_idx;
4421 } /* end of cookie processing on this header */
4422}
4423
4424
Willy Tarreaua15645d2007-03-18 16:22:39 +01004425/* Iterate the same filter through all response headers contained in <rtr>.
4426 * Returns 1 if this filter can be stopped upon return, otherwise 0.
4427 */
4428int apply_filter_to_resp_headers(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4429{
4430 char term;
4431 char *cur_ptr, *cur_end, *cur_next;
4432 int cur_idx, old_idx, last_hdr;
4433 struct http_txn *txn = &t->txn;
4434 struct hdr_idx_elem *cur_hdr;
4435 int len, delta;
4436
4437 last_hdr = 0;
4438
4439 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4440 old_idx = 0;
4441
4442 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004443 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004444 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004445 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004446 (exp->action == ACT_ALLOW ||
4447 exp->action == ACT_DENY))
4448 return 0;
4449
4450 cur_idx = txn->hdr_idx.v[old_idx].next;
4451 if (!cur_idx)
4452 break;
4453
4454 cur_hdr = &txn->hdr_idx.v[cur_idx];
4455 cur_ptr = cur_next;
4456 cur_end = cur_ptr + cur_hdr->len;
4457 cur_next = cur_end + cur_hdr->cr + 1;
4458
4459 /* Now we have one header between cur_ptr and cur_end,
4460 * and the next header starts at cur_next.
4461 */
4462
4463 /* The annoying part is that pattern matching needs
4464 * that we modify the contents to null-terminate all
4465 * strings before testing them.
4466 */
4467
4468 term = *cur_end;
4469 *cur_end = '\0';
4470
4471 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4472 switch (exp->action) {
4473 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004474 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004475 last_hdr = 1;
4476 break;
4477
4478 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004479 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004480 last_hdr = 1;
4481 break;
4482
4483 case ACT_REPLACE:
4484 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4485 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4486 /* FIXME: if the user adds a newline in the replacement, the
4487 * index will not be recalculated for now, and the new line
4488 * will not be counted as a new header.
4489 */
4490
4491 cur_end += delta;
4492 cur_next += delta;
4493 cur_hdr->len += delta;
4494 txn->rsp.eoh += delta;
4495 break;
4496
4497 case ACT_REMOVE:
4498 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4499 cur_next += delta;
4500
4501 /* FIXME: this should be a separate function */
4502 txn->rsp.eoh += delta;
4503 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4504 txn->hdr_idx.used--;
4505 cur_hdr->len = 0;
4506 cur_end = NULL; /* null-term has been rewritten */
4507 break;
4508
4509 }
4510 }
4511 if (cur_end)
4512 *cur_end = term; /* restore the string terminator */
4513
4514 /* keep the link from this header to next one in case of later
4515 * removal of next header.
4516 */
4517 old_idx = cur_idx;
4518 }
4519 return 0;
4520}
4521
4522
4523/* Apply the filter to the status line in the response buffer <rtr>.
4524 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4525 * or -1 if a replacement resulted in an invalid status line.
4526 */
4527int apply_filter_to_sts_line(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4528{
4529 char term;
4530 char *cur_ptr, *cur_end;
4531 int done;
4532 struct http_txn *txn = &t->txn;
4533 int len, delta;
4534
4535
Willy Tarreau3d300592007-03-18 18:34:41 +01004536 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004537 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004538 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004539 (exp->action == ACT_ALLOW ||
4540 exp->action == ACT_DENY))
4541 return 0;
4542 else if (exp->action == ACT_REMOVE)
4543 return 0;
4544
4545 done = 0;
4546
Willy Tarreau9cdde232007-05-02 20:58:19 +02004547 cur_ptr = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004548 cur_end = cur_ptr + txn->rsp.sl.rq.l;
4549
4550 /* Now we have the status line between cur_ptr and cur_end */
4551
4552 /* The annoying part is that pattern matching needs
4553 * that we modify the contents to null-terminate all
4554 * strings before testing them.
4555 */
4556
4557 term = *cur_end;
4558 *cur_end = '\0';
4559
4560 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4561 switch (exp->action) {
4562 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004563 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004564 done = 1;
4565 break;
4566
4567 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004568 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004569 done = 1;
4570 break;
4571
4572 case ACT_REPLACE:
4573 *cur_end = term; /* restore the string terminator */
4574 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4575 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4576 /* FIXME: if the user adds a newline in the replacement, the
4577 * index will not be recalculated for now, and the new line
4578 * will not be counted as a new header.
4579 */
4580
4581 txn->rsp.eoh += delta;
4582 cur_end += delta;
4583
Willy Tarreau9cdde232007-05-02 20:58:19 +02004584 txn->rsp.sol = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004585 cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data,
Willy Tarreau02785762007-04-03 14:45:44 +02004586 HTTP_MSG_RPVER,
Willy Tarreaua15645d2007-03-18 16:22:39 +01004587 cur_ptr, cur_end + 1,
4588 NULL, NULL);
4589 if (unlikely(!cur_end))
4590 return -1;
4591
4592 /* we have a full respnse and we know that we have either a CR
4593 * or an LF at <ptr>.
4594 */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004595 txn->status = strl2ui(rtr->data + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004596 hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.rq.l, *cur_end == '\r');
4597 /* there is no point trying this regex on headers */
4598 return 1;
4599 }
4600 }
4601 *cur_end = term; /* restore the string terminator */
4602 return done;
4603}
4604
4605
4606
4607/*
4608 * Apply all the resp filters <exp> to all headers in buffer <rtr> of session <t>.
4609 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
4610 * unparsable response.
4611 */
4612int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4613{
Willy Tarreau3d300592007-03-18 18:34:41 +01004614 struct http_txn *txn = &t->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004615 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004616 while (exp && !(txn->flags & TX_SVDENY)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004617 int ret;
4618
4619 /*
4620 * The interleaving of transformations and verdicts
4621 * makes it difficult to decide to continue or stop
4622 * the evaluation.
4623 */
4624
Willy Tarreau3d300592007-03-18 18:34:41 +01004625 if ((txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004626 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4627 exp->action == ACT_PASS)) {
4628 exp = exp->next;
4629 continue;
4630 }
4631
4632 /* Apply the filter to the status line. */
4633 ret = apply_filter_to_sts_line(t, rtr, exp);
4634 if (unlikely(ret < 0))
4635 return -1;
4636
4637 if (likely(ret == 0)) {
4638 /* The filter did not match the response, it can be
4639 * iterated through all headers.
4640 */
4641 apply_filter_to_resp_headers(t, rtr, exp);
4642 }
4643 exp = exp->next;
4644 }
4645 return 0;
4646}
4647
4648
4649
4650/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004651 * Manage server-side cookies. It can impact performance by about 2% so it is
4652 * desirable to call it only when needed.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004653 */
4654void manage_server_side_cookies(struct session *t, struct buffer *rtr)
4655{
4656 struct http_txn *txn = &t->txn;
4657 char *p1, *p2, *p3, *p4;
4658
4659 appsess *asession_temp = NULL;
4660 appsess local_asession;
4661
4662 char *cur_ptr, *cur_end, *cur_next;
4663 int cur_idx, old_idx, delta;
4664
Willy Tarreaua15645d2007-03-18 16:22:39 +01004665 /* Iterate through the headers.
4666 * we start with the start line.
4667 */
4668 old_idx = 0;
4669 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4670
4671 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
4672 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004673 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004674
4675 cur_hdr = &txn->hdr_idx.v[cur_idx];
4676 cur_ptr = cur_next;
4677 cur_end = cur_ptr + cur_hdr->len;
4678 cur_next = cur_end + cur_hdr->cr + 1;
4679
4680 /* We have one full header between cur_ptr and cur_end, and the
4681 * next header starts at cur_next. We're only interested in
4682 * "Cookie:" headers.
4683 */
4684
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004685 val = http_header_match2(cur_ptr, cur_end, "Set-Cookie", 10);
4686 if (!val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004687 old_idx = cur_idx;
4688 continue;
4689 }
4690
4691 /* OK, right now we know we have a set-cookie at cur_ptr */
Willy Tarreau3d300592007-03-18 18:34:41 +01004692 txn->flags |= TX_SCK_ANY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004693
4694
4695 /* maybe we only wanted to see if there was a set-cookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004696 if (t->be->cookie_name == NULL &&
4697 t->be->appsession_name == NULL &&
4698 t->be->capture_name == NULL)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004699 return;
4700
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004701 p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004702
4703 while (p1 < cur_end) { /* in fact, we'll break after the first cookie */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004704 if (p1 == cur_end || *p1 == ';') /* end of cookie */
4705 break;
4706
4707 /* p1 is at the beginning of the cookie name */
4708 p2 = p1;
4709
4710 while (p2 < cur_end && *p2 != '=' && *p2 != ';')
4711 p2++;
4712
4713 if (p2 == cur_end || *p2 == ';') /* next cookie */
4714 break;
4715
4716 p3 = p2 + 1; /* skip the '=' sign */
4717 if (p3 == cur_end)
4718 break;
4719
4720 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004721 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';')
Willy Tarreaua15645d2007-03-18 16:22:39 +01004722 p4++;
4723
4724 /* here, we have the cookie name between p1 and p2,
4725 * and its value between p3 and p4.
4726 * we can process it.
4727 */
4728
4729 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004730 if (t->be->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004731 txn->srv_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004732 (p4 - p1 >= t->be->capture_namelen) &&
4733 memcmp(p1, t->be->capture_name, t->be->capture_namelen) == 0) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004734 int log_len = p4 - p1;
4735
Willy Tarreau086b3b42007-05-13 21:45:51 +02004736 if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004737 Alert("HTTP logging : out of memory.\n");
4738 }
4739
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004740 if (log_len > t->be->capture_len)
4741 log_len = t->be->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004742 memcpy(txn->srv_cookie, p1, log_len);
4743 txn->srv_cookie[log_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004744 }
4745
4746 /* now check if we need to process it for persistence */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004747 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4748 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004749 /* Cool... it's the right one */
Willy Tarreau3d300592007-03-18 18:34:41 +01004750 txn->flags |= TX_SCK_SEEN;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004751
4752 /* If the cookie is in insert mode on a known server, we'll delete
4753 * this occurrence because we'll insert another one later.
4754 * We'll delete it too if the "indirect" option is set and we're in
4755 * a direct access. */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004756 if (((t->srv) && (t->be->options & PR_O_COOK_INS)) ||
4757 ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004758 /* this header must be deleted */
4759 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4760 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4761 txn->hdr_idx.used--;
4762 cur_hdr->len = 0;
4763 cur_next += delta;
4764 txn->rsp.eoh += delta;
4765
Willy Tarreau3d300592007-03-18 18:34:41 +01004766 txn->flags |= TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004767 }
4768 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004769 (t->be->options & PR_O_COOK_RW)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004770 /* replace bytes p3->p4 with the cookie name associated
4771 * with this server since we know it.
4772 */
4773 delta = buffer_replace2(rtr, p3, p4, t->srv->cookie, t->srv->cklen);
4774 cur_hdr->len += delta;
4775 cur_next += delta;
4776 txn->rsp.eoh += delta;
4777
Willy Tarreau3d300592007-03-18 18:34:41 +01004778 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004779 }
4780 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004781 (t->be->options & PR_O_COOK_PFX)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004782 /* insert the cookie name associated with this server
4783 * before existing cookie, and insert a delimitor between them..
4784 */
4785 delta = buffer_replace2(rtr, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4786 cur_hdr->len += delta;
4787 cur_next += delta;
4788 txn->rsp.eoh += delta;
4789
4790 p3[t->srv->cklen] = COOKIE_DELIM;
Willy Tarreau3d300592007-03-18 18:34:41 +01004791 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004792 }
4793 }
4794 /* next, let's see if the cookie is our appcookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004795 else if ((t->be->appsession_name != NULL) &&
4796 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004797
4798 /* Cool... it's the right one */
4799
4800 size_t server_id_len = strlen(t->srv->id) + 1;
4801 asession_temp = &local_asession;
4802
Willy Tarreau63963c62007-05-13 21:29:55 +02004803 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004804 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4805 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4806 return;
4807 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004808 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4809 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004810 asession_temp->serverid = NULL;
4811
4812 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01004813 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4814 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004815 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004816 Alert("Not enough Memory process_srv():asession:calloc().\n");
4817 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
4818 return;
4819 }
4820 asession_temp->sessid = local_asession.sessid;
4821 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004822 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
4823 } else {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004824 /* free wasted memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004825 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau51041c72007-09-09 21:56:53 +02004826 }
4827
Willy Tarreaua15645d2007-03-18 16:22:39 +01004828 if (asession_temp->serverid == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004829 if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004830 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4831 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4832 return;
4833 }
4834 asession_temp->serverid[0] = '\0';
4835 }
4836
4837 if (asession_temp->serverid[0] == '\0')
4838 memcpy(asession_temp->serverid, t->srv->id, server_id_len);
4839
Willy Tarreaud7c30f92007-12-03 01:38:36 +01004840 tv_add(&asession_temp->expire, &now, &t->be->timeout.appsession);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004841
4842#if defined(DEBUG_HASH)
Willy Tarreau51041c72007-09-09 21:56:53 +02004843 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreaua15645d2007-03-18 16:22:39 +01004844#endif
4845 }/* end if ((t->proxy->appsession_name != NULL) ... */
4846 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4847 } /* we're now at the end of the cookie value */
4848
4849 /* keep the link from this header to next one */
4850 old_idx = cur_idx;
4851 } /* end of cookie processing on this header */
4852}
4853
4854
4855
4856/*
4857 * Check if response is cacheable or not. Updates t->flags.
4858 */
4859void check_response_for_cacheability(struct session *t, struct buffer *rtr)
4860{
4861 struct http_txn *txn = &t->txn;
4862 char *p1, *p2;
4863
4864 char *cur_ptr, *cur_end, *cur_next;
4865 int cur_idx;
4866
Willy Tarreau5df51872007-11-25 16:20:08 +01004867 if (!(txn->flags & TX_CACHEABLE))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004868 return;
4869
4870 /* Iterate through the headers.
4871 * we start with the start line.
4872 */
4873 cur_idx = 0;
4874 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4875
4876 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
4877 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004878 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004879
4880 cur_hdr = &txn->hdr_idx.v[cur_idx];
4881 cur_ptr = cur_next;
4882 cur_end = cur_ptr + cur_hdr->len;
4883 cur_next = cur_end + cur_hdr->cr + 1;
4884
4885 /* We have one full header between cur_ptr and cur_end, and the
4886 * next header starts at cur_next. We're only interested in
4887 * "Cookie:" headers.
4888 */
4889
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004890 val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
4891 if (val) {
4892 if ((cur_end - (cur_ptr + val) >= 8) &&
4893 strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
4894 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
4895 return;
4896 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01004897 }
4898
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004899 val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
4900 if (!val)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004901 continue;
4902
4903 /* OK, right now we know we have a cache-control header at cur_ptr */
4904
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004905 p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004906
4907 if (p1 >= cur_end) /* no more info */
4908 continue;
4909
4910 /* p1 is at the beginning of the value */
4911 p2 = p1;
4912
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004913 while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((unsigned char)*p2))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004914 p2++;
4915
4916 /* we have a complete value between p1 and p2 */
4917 if (p2 < cur_end && *p2 == '=') {
4918 /* we have something of the form no-cache="set-cookie" */
4919 if ((cur_end - p1 >= 21) &&
4920 strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0
4921 && (p1[20] == '"' || p1[20] == ','))
Willy Tarreau3d300592007-03-18 18:34:41 +01004922 txn->flags &= ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004923 continue;
4924 }
4925
4926 /* OK, so we know that either p2 points to the end of string or to a comma */
4927 if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) ||
4928 ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) ||
4929 ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) ||
4930 ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004931 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004932 return;
4933 }
4934
4935 if ((p2 - p1 == 6) && strncasecmp(p1, "public", 6) == 0) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004936 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004937 continue;
4938 }
4939 }
4940}
4941
4942
Willy Tarreau58f10d72006-12-04 02:26:12 +01004943/*
4944 * Try to retrieve a known appsession in the URI, then the associated server.
4945 * If the server is found, it's assigned to the session.
4946 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004947void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004948{
Willy Tarreau3d300592007-03-18 18:34:41 +01004949 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004950 appsess *asession_temp = NULL;
4951 appsess local_asession;
4952 char *request_line;
4953
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004954 if (t->be->appsession_name == NULL ||
Willy Tarreaub326fcc2007-03-03 13:54:32 +01004955 (t->txn.meth != HTTP_METH_GET && t->txn.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004956 (request_line = memchr(begin, ';', len)) == NULL ||
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004957 ((1 + t->be->appsession_name_len + 1 + t->be->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004958 return;
4959
4960 /* skip ';' */
4961 request_line++;
4962
4963 /* look if we have a jsessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004964 if (strncasecmp(request_line, t->be->appsession_name, t->be->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004965 return;
4966
4967 /* skip jsessionid= */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004968 request_line += t->be->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004969
4970 /* First try if we already have an appsession */
4971 asession_temp = &local_asession;
4972
Willy Tarreau63963c62007-05-13 21:29:55 +02004973 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004974 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4975 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4976 return;
4977 }
4978
4979 /* Copy the sessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004980 memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
4981 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004982 asession_temp->serverid = NULL;
4983
4984 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01004985 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4986 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004987 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004988 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004989 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004990 Alert("Not enough memory process_cli():asession:calloc().\n");
4991 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4992 return;
4993 }
4994 asession_temp->sessid = local_asession.sessid;
4995 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004996 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004997 }
4998 else {
4999 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005000 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005001 }
Willy Tarreau51041c72007-09-09 21:56:53 +02005002
Willy Tarreaud7c30f92007-12-03 01:38:36 +01005003 tv_add(&asession_temp->expire, &now, &t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005004 asession_temp->request_count++;
Willy Tarreau51041c72007-09-09 21:56:53 +02005005
Willy Tarreau58f10d72006-12-04 02:26:12 +01005006#if defined(DEBUG_HASH)
Willy Tarreau51041c72007-09-09 21:56:53 +02005007 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreau58f10d72006-12-04 02:26:12 +01005008#endif
5009 if (asession_temp->serverid == NULL) {
5010 Alert("Found Application Session without matching server.\n");
5011 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005012 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005013 while (srv) {
5014 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005015 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005016 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01005017 txn->flags &= ~TX_CK_MASK;
5018 txn->flags |= TX_CK_VALID;
5019 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005020 t->srv = srv;
5021 break;
5022 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01005023 txn->flags &= ~TX_CK_MASK;
5024 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005025 }
5026 }
5027 srv = srv->next;
5028 }
5029 }
5030}
5031
5032
Willy Tarreaub2513902006-12-17 14:52:38 +01005033/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005034 * In a GET or HEAD request, check if the requested URI matches the stats uri
5035 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01005036 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005037 * It is assumed that the request is either a HEAD or GET and that the
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005038 * t->be->uri_auth field is valid. An HTTP/401 response may be sent, or
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005039 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01005040 *
5041 * Returns 1 if the session's state changes, otherwise 0.
5042 */
5043int stats_check_uri_auth(struct session *t, struct proxy *backend)
5044{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005045 struct http_txn *txn = &t->txn;
Willy Tarreaub2513902006-12-17 14:52:38 +01005046 struct uri_auth *uri_auth = backend->uri_auth;
5047 struct user_auth *user;
5048 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005049 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01005050
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005051 memset(&t->data_ctx.stats, 0, sizeof(t->data_ctx.stats));
5052
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005053 /* check URI size */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005054 if (uri_auth->uri_len > txn->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01005055 return 0;
5056
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005057 h = t->req->data + txn->req.sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005058
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005059 /* the URI is in h */
5060 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01005061 return 0;
5062
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005063 h += uri_auth->uri_len;
5064 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 3) {
5065 if (memcmp(h, ";up", 3) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005066 t->data_ctx.stats.flags |= STAT_HIDE_DOWN;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005067 break;
5068 }
5069 h++;
5070 }
5071
5072 if (uri_auth->refresh) {
5073 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5074 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 10) {
5075 if (memcmp(h, ";norefresh", 10) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005076 t->data_ctx.stats.flags |= STAT_NO_REFRESH;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005077 break;
5078 }
5079 h++;
5080 }
5081 }
5082
Willy Tarreau55bb8452007-10-17 18:44:57 +02005083 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5084 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 4) {
5085 if (memcmp(h, ";csv", 4) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005086 t->data_ctx.stats.flags |= STAT_FMT_CSV;
Willy Tarreau55bb8452007-10-17 18:44:57 +02005087 break;
5088 }
5089 h++;
5090 }
5091
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005092 t->data_ctx.stats.flags |= STAT_SHOW_STAT | STAT_SHOW_INFO;
5093
Willy Tarreaub2513902006-12-17 14:52:38 +01005094 /* we are in front of a interceptable URI. Let's check
5095 * if there's an authentication and if it's valid.
5096 */
5097 user = uri_auth->users;
5098 if (!user) {
5099 /* no user auth required, it's OK */
5100 authenticated = 1;
5101 } else {
5102 authenticated = 0;
5103
5104 /* a user list is defined, we have to check.
5105 * skip 21 chars for "Authorization: Basic ".
5106 */
5107
5108 /* FIXME: this should move to an earlier place */
5109 cur_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005110 h = t->req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
5111 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
5112 int len = txn->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005113 if (len > 14 &&
5114 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005115 txn->auth_hdr.str = h;
5116 txn->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005117 break;
5118 }
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005119 h += len + txn->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01005120 }
5121
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005122 if (txn->auth_hdr.len < 21 ||
5123 memcmp(txn->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01005124 user = NULL;
5125
5126 while (user) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005127 if ((txn->auth_hdr.len == user->user_len + 14 + 7)
5128 && !memcmp(txn->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01005129 user->user_pwd, user->user_len)) {
5130 authenticated = 1;
5131 break;
5132 }
5133 user = user->next;
5134 }
5135 }
5136
5137 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01005138 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01005139
5140 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01005141 msg.str = trash;
5142 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005143 txn->status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01005144 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01005145 if (!(t->flags & SN_ERR_MASK))
5146 t->flags |= SN_ERR_PRXCOND;
5147 if (!(t->flags & SN_FINST_MASK))
5148 t->flags |= SN_FINST_R;
5149 return 1;
5150 }
5151
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005152 /* The request is valid, the user is authenticated. Let's start sending
Willy Tarreaub2513902006-12-17 14:52:38 +01005153 * data.
5154 */
5155 t->cli_state = CL_STSHUTR;
5156 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau70089872008-06-13 21:12:51 +02005157 t->logs.tv_request = now;
Willy Tarreaub2513902006-12-17 14:52:38 +01005158 t->data_source = DATA_SRC_STATS;
5159 t->data_state = DATA_ST_INIT;
5160 produce_content(t);
5161 return 1;
5162}
5163
5164
Willy Tarreaubaaee002006-06-26 02:48:02 +02005165/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01005166 * Print a debug line with a header
5167 */
5168void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
5169{
5170 int len, max;
5171 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
5172 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
5173 max = end - start;
5174 UBOUND(max, sizeof(trash) - len - 1);
5175 len += strlcpy2(trash + len, start, max + 1);
5176 trash[len++] = '\n';
5177 write(1, trash, len);
5178}
5179
5180
Willy Tarreau8797c062007-05-07 00:55:35 +02005181/************************************************************************/
5182/* The code below is dedicated to ACL parsing and matching */
5183/************************************************************************/
5184
5185
5186
5187
5188/* 1. Check on METHOD
5189 * We use the pre-parsed method if it is known, and store its number as an
5190 * integer. If it is unknown, we use the pointer and the length.
5191 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005192static int acl_parse_meth(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005193{
5194 int len, meth;
5195
Willy Tarreauae8b7962007-06-09 23:10:04 +02005196 len = strlen(*text);
5197 meth = find_http_meth(*text, len);
Willy Tarreau8797c062007-05-07 00:55:35 +02005198
5199 pattern->val.i = meth;
5200 if (meth == HTTP_METH_OTHER) {
Willy Tarreauae8b7962007-06-09 23:10:04 +02005201 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005202 if (!pattern->ptr.str)
5203 return 0;
5204 pattern->len = len;
5205 }
5206 return 1;
5207}
5208
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005209static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005210acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
5211 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005212{
5213 int meth;
5214 struct http_txn *txn = l7;
5215
Willy Tarreauc11416f2007-06-17 16:58:38 +02005216 if (txn->req.msg_state != HTTP_MSG_BODY)
5217 return 0;
5218
Willy Tarreau8797c062007-05-07 00:55:35 +02005219 meth = txn->meth;
5220 test->i = meth;
5221 if (meth == HTTP_METH_OTHER) {
Willy Tarreauc11416f2007-06-17 16:58:38 +02005222 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5223 /* ensure the indexes are not affected */
5224 return 0;
Willy Tarreau8797c062007-05-07 00:55:35 +02005225 test->len = txn->req.sl.rq.m_l;
5226 test->ptr = txn->req.sol;
5227 }
5228 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5229 return 1;
5230}
5231
5232static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
5233{
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005234 int icase;
5235
Willy Tarreau8797c062007-05-07 00:55:35 +02005236 if (test->i != pattern->val.i)
5237 return 0;
5238
5239 if (test->i != HTTP_METH_OTHER)
5240 return 1;
5241
5242 /* Other method, we must compare the strings */
5243 if (pattern->len != test->len)
5244 return 0;
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005245
5246 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
5247 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) != 0) ||
5248 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) != 0))
Willy Tarreau8797c062007-05-07 00:55:35 +02005249 return 0;
5250 return 1;
5251}
5252
5253/* 2. Check on Request/Status Version
5254 * We simply compare strings here.
5255 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005256static int acl_parse_ver(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005257{
Willy Tarreauae8b7962007-06-09 23:10:04 +02005258 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005259 if (!pattern->ptr.str)
5260 return 0;
Willy Tarreauae8b7962007-06-09 23:10:04 +02005261 pattern->len = strlen(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005262 return 1;
5263}
5264
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005265static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005266acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
5267 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005268{
5269 struct http_txn *txn = l7;
5270 char *ptr;
5271 int len;
5272
Willy Tarreauc11416f2007-06-17 16:58:38 +02005273 if (txn->req.msg_state != HTTP_MSG_BODY)
5274 return 0;
5275
Willy Tarreau8797c062007-05-07 00:55:35 +02005276 len = txn->req.sl.rq.v_l;
5277 ptr = txn->req.sol + txn->req.sl.rq.v - txn->req.som;
5278
5279 while ((len-- > 0) && (*ptr++ != '/'));
5280 if (len <= 0)
5281 return 0;
5282
5283 test->ptr = ptr;
5284 test->len = len;
5285
5286 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5287 return 1;
5288}
5289
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005290static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005291acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
5292 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005293{
5294 struct http_txn *txn = l7;
5295 char *ptr;
5296 int len;
5297
Willy Tarreauc11416f2007-06-17 16:58:38 +02005298 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5299 return 0;
5300
Willy Tarreau8797c062007-05-07 00:55:35 +02005301 len = txn->rsp.sl.st.v_l;
5302 ptr = txn->rsp.sol;
5303
5304 while ((len-- > 0) && (*ptr++ != '/'));
5305 if (len <= 0)
5306 return 0;
5307
5308 test->ptr = ptr;
5309 test->len = len;
5310
5311 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5312 return 1;
5313}
5314
5315/* 3. Check on Status Code. We manipulate integers here. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005316static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005317acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, int dir,
5318 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005319{
5320 struct http_txn *txn = l7;
5321 char *ptr;
5322 int len;
5323
Willy Tarreauc11416f2007-06-17 16:58:38 +02005324 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5325 return 0;
5326
Willy Tarreau8797c062007-05-07 00:55:35 +02005327 len = txn->rsp.sl.st.c_l;
5328 ptr = txn->rsp.sol + txn->rsp.sl.st.c - txn->rsp.som;
5329
5330 test->i = __strl2ui(ptr, len);
5331 test->flags = ACL_TEST_F_VOL_1ST;
5332 return 1;
5333}
5334
5335/* 4. Check on URL/URI. A pointer to the URI is stored. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005336static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005337acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
5338 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005339{
5340 struct http_txn *txn = l7;
5341
Willy Tarreauc11416f2007-06-17 16:58:38 +02005342 if (txn->req.msg_state != HTTP_MSG_BODY)
5343 return 0;
5344 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5345 /* ensure the indexes are not affected */
5346 return 0;
5347
Willy Tarreau8797c062007-05-07 00:55:35 +02005348 test->len = txn->req.sl.rq.u_l;
5349 test->ptr = txn->req.sol + txn->req.sl.rq.u;
5350
Willy Tarreauf3d25982007-05-08 22:45:09 +02005351 /* we do not need to set READ_ONLY because the data is in a buffer */
5352 test->flags = ACL_TEST_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +02005353 return 1;
5354}
5355
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005356static int
5357acl_fetch_url_ip(struct proxy *px, struct session *l4, void *l7, int dir,
5358 struct acl_expr *expr, struct acl_test *test)
5359{
5360 struct http_txn *txn = l7;
5361
5362 if (txn->req.msg_state != HTTP_MSG_BODY)
5363 return 0;
5364 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5365 /* ensure the indexes are not affected */
5366 return 0;
5367
5368 /* Parse HTTP request */
5369 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5370 test->ptr = (void *)&((struct sockaddr_in *)&l4->srv_addr)->sin_addr;
5371 test->i = AF_INET;
5372
5373 /*
5374 * If we are parsing url in frontend space, we prepare backend stage
5375 * to not parse again the same url ! optimization lazyness...
5376 */
5377 if (px->options & PR_O_HTTP_PROXY)
5378 l4->flags |= SN_ADDR_SET;
5379
5380 test->flags = ACL_TEST_F_READ_ONLY;
5381 return 1;
5382}
5383
5384static int
5385acl_fetch_url_port(struct proxy *px, struct session *l4, void *l7, int dir,
5386 struct acl_expr *expr, struct acl_test *test)
5387{
5388 struct http_txn *txn = l7;
5389
5390 if (txn->req.msg_state != HTTP_MSG_BODY)
5391 return 0;
5392 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5393 /* ensure the indexes are not affected */
5394 return 0;
5395
5396 /* Same optimization as url_ip */
5397 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5398 test->i = ntohs(((struct sockaddr_in *)&l4->srv_addr)->sin_port);
5399
5400 if (px->options & PR_O_HTTP_PROXY)
5401 l4->flags |= SN_ADDR_SET;
5402
5403 test->flags = ACL_TEST_F_READ_ONLY;
5404 return 1;
5405}
5406
Willy Tarreauc11416f2007-06-17 16:58:38 +02005407/* 5. Check on HTTP header. A pointer to the beginning of the value is returned.
5408 * This generic function is used by both acl_fetch_chdr() and acl_fetch_shdr().
5409 */
Willy Tarreau33a7e692007-06-10 19:45:56 +02005410static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005411acl_fetch_hdr(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005412 struct acl_expr *expr, struct acl_test *test)
5413{
5414 struct http_txn *txn = l7;
5415 struct hdr_idx *idx = &txn->hdr_idx;
5416 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005417
5418 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5419 /* search for header from the beginning */
5420 ctx->idx = 0;
5421
Willy Tarreau33a7e692007-06-10 19:45:56 +02005422 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5423 test->flags |= ACL_TEST_F_FETCH_MORE;
5424 test->flags |= ACL_TEST_F_VOL_HDR;
5425 test->len = ctx->vlen;
5426 test->ptr = (char *)ctx->line + ctx->val;
5427 return 1;
5428 }
5429
5430 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5431 test->flags |= ACL_TEST_F_VOL_HDR;
5432 return 0;
5433}
5434
Willy Tarreau33a7e692007-06-10 19:45:56 +02005435static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005436acl_fetch_chdr(struct proxy *px, struct session *l4, void *l7, int dir,
5437 struct acl_expr *expr, struct acl_test *test)
5438{
5439 struct http_txn *txn = l7;
5440
5441 if (txn->req.msg_state != HTTP_MSG_BODY)
5442 return 0;
5443 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5444 /* ensure the indexes are not affected */
5445 return 0;
5446
5447 return acl_fetch_hdr(px, l4, txn, txn->req.sol, expr, test);
5448}
5449
5450static int
5451acl_fetch_shdr(struct proxy *px, struct session *l4, void *l7, int dir,
5452 struct acl_expr *expr, struct acl_test *test)
5453{
5454 struct http_txn *txn = l7;
5455
5456 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5457 return 0;
5458
5459 return acl_fetch_hdr(px, l4, txn, txn->rsp.sol, expr, test);
5460}
5461
5462/* 6. Check on HTTP header count. The number of occurrences is returned.
5463 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
5464 */
5465static int
5466acl_fetch_hdr_cnt(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005467 struct acl_expr *expr, struct acl_test *test)
5468{
5469 struct http_txn *txn = l7;
5470 struct hdr_idx *idx = &txn->hdr_idx;
5471 struct hdr_ctx ctx;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005472 int cnt;
Willy Tarreau8797c062007-05-07 00:55:35 +02005473
Willy Tarreau33a7e692007-06-10 19:45:56 +02005474 ctx.idx = 0;
5475 cnt = 0;
5476 while (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, &ctx))
5477 cnt++;
5478
5479 test->i = cnt;
5480 test->flags = ACL_TEST_F_VOL_HDR;
5481 return 1;
5482}
5483
Willy Tarreauc11416f2007-06-17 16:58:38 +02005484static int
5485acl_fetch_chdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5486 struct acl_expr *expr, struct acl_test *test)
5487{
5488 struct http_txn *txn = l7;
5489
5490 if (txn->req.msg_state != HTTP_MSG_BODY)
5491 return 0;
5492 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5493 /* ensure the indexes are not affected */
5494 return 0;
5495
5496 return acl_fetch_hdr_cnt(px, l4, txn, txn->req.sol, expr, test);
5497}
5498
5499static int
5500acl_fetch_shdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5501 struct acl_expr *expr, struct acl_test *test)
5502{
5503 struct http_txn *txn = l7;
5504
5505 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5506 return 0;
5507
5508 return acl_fetch_hdr_cnt(px, l4, txn, txn->rsp.sol, expr, test);
5509}
5510
Willy Tarreau33a7e692007-06-10 19:45:56 +02005511/* 7. Check on HTTP header's integer value. The integer value is returned.
5512 * FIXME: the type is 'int', it may not be appropriate for everything.
Willy Tarreauc11416f2007-06-17 16:58:38 +02005513 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
Willy Tarreau33a7e692007-06-10 19:45:56 +02005514 */
5515static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005516acl_fetch_hdr_val(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005517 struct acl_expr *expr, struct acl_test *test)
5518{
5519 struct http_txn *txn = l7;
5520 struct hdr_idx *idx = &txn->hdr_idx;
5521 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005522
5523 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5524 /* search for header from the beginning */
5525 ctx->idx = 0;
5526
Willy Tarreau33a7e692007-06-10 19:45:56 +02005527 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5528 test->flags |= ACL_TEST_F_FETCH_MORE;
5529 test->flags |= ACL_TEST_F_VOL_HDR;
5530 test->i = strl2ic((char *)ctx->line + ctx->val, ctx->vlen);
5531 return 1;
5532 }
5533
5534 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5535 test->flags |= ACL_TEST_F_VOL_HDR;
5536 return 0;
5537}
5538
Willy Tarreauc11416f2007-06-17 16:58:38 +02005539static int
5540acl_fetch_chdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5541 struct acl_expr *expr, struct acl_test *test)
5542{
5543 struct http_txn *txn = l7;
5544
5545 if (txn->req.msg_state != HTTP_MSG_BODY)
5546 return 0;
5547 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5548 /* ensure the indexes are not affected */
5549 return 0;
5550
5551 return acl_fetch_hdr_val(px, l4, txn, txn->req.sol, expr, test);
5552}
5553
5554static int
5555acl_fetch_shdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5556 struct acl_expr *expr, struct acl_test *test)
5557{
5558 struct http_txn *txn = l7;
5559
5560 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5561 return 0;
5562
5563 return acl_fetch_hdr_val(px, l4, txn, txn->rsp.sol, expr, test);
5564}
5565
Willy Tarreau737b0c12007-06-10 21:28:46 +02005566/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at
5567 * the first '/' after the possible hostname, and ends before the possible '?'.
5568 */
5569static int
5570acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
5571 struct acl_expr *expr, struct acl_test *test)
5572{
5573 struct http_txn *txn = l7;
5574 char *ptr, *end;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005575
Willy Tarreauc11416f2007-06-17 16:58:38 +02005576 if (txn->req.msg_state != HTTP_MSG_BODY)
5577 return 0;
5578 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5579 /* ensure the indexes are not affected */
5580 return 0;
5581
Willy Tarreau21d2af32008-02-14 20:25:24 +01005582 end = txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
5583 ptr = http_get_path(txn);
5584 if (!ptr)
Willy Tarreau737b0c12007-06-10 21:28:46 +02005585 return 0;
5586
5587 /* OK, we got the '/' ! */
5588 test->ptr = ptr;
5589
5590 while (ptr < end && *ptr != '?')
5591 ptr++;
5592
5593 test->len = ptr - test->ptr;
5594
5595 /* we do not need to set READ_ONLY because the data is in a buffer */
5596 test->flags = ACL_TEST_F_VOL_1ST;
5597 return 1;
5598}
5599
5600
Willy Tarreau8797c062007-05-07 00:55:35 +02005601
5602/************************************************************************/
5603/* All supported keywords must be declared here. */
5604/************************************************************************/
5605
5606/* Note: must not be declared <const> as its list will be overwritten */
5607static struct acl_kw_list acl_kws = {{ },{
5608 { "method", acl_parse_meth, acl_fetch_meth, acl_match_meth },
5609 { "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str },
5610 { "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str },
Willy Tarreauae8b7962007-06-09 23:10:04 +02005611 { "status", acl_parse_int, acl_fetch_stcode, acl_match_int },
Willy Tarreau8797c062007-05-07 00:55:35 +02005612
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005613 { "url", acl_parse_str, acl_fetch_url, acl_match_str },
5614 { "url_beg", acl_parse_str, acl_fetch_url, acl_match_beg },
5615 { "url_end", acl_parse_str, acl_fetch_url, acl_match_end },
5616 { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub },
5617 { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir },
5618 { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom },
5619 { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg },
5620 { "url_ip", acl_parse_ip, acl_fetch_url_ip, acl_match_ip },
5621 { "url_port", acl_parse_int, acl_fetch_url_port, acl_match_int },
Willy Tarreau8797c062007-05-07 00:55:35 +02005622
Willy Tarreauc11416f2007-06-17 16:58:38 +02005623 { "hdr", acl_parse_str, acl_fetch_chdr, acl_match_str },
5624 { "hdr_reg", acl_parse_reg, acl_fetch_chdr, acl_match_reg },
5625 { "hdr_beg", acl_parse_str, acl_fetch_chdr, acl_match_beg },
5626 { "hdr_end", acl_parse_str, acl_fetch_chdr, acl_match_end },
5627 { "hdr_sub", acl_parse_str, acl_fetch_chdr, acl_match_sub },
5628 { "hdr_dir", acl_parse_str, acl_fetch_chdr, acl_match_dir },
5629 { "hdr_dom", acl_parse_str, acl_fetch_chdr, acl_match_dom },
5630 { "hdr_cnt", acl_parse_int, acl_fetch_chdr_cnt,acl_match_int },
5631 { "hdr_val", acl_parse_int, acl_fetch_chdr_val,acl_match_int },
5632
5633 { "shdr", acl_parse_str, acl_fetch_shdr, acl_match_str },
5634 { "shdr_reg", acl_parse_reg, acl_fetch_shdr, acl_match_reg },
5635 { "shdr_beg", acl_parse_str, acl_fetch_shdr, acl_match_beg },
5636 { "shdr_end", acl_parse_str, acl_fetch_shdr, acl_match_end },
5637 { "shdr_sub", acl_parse_str, acl_fetch_shdr, acl_match_sub },
5638 { "shdr_dir", acl_parse_str, acl_fetch_shdr, acl_match_dir },
5639 { "shdr_dom", acl_parse_str, acl_fetch_shdr, acl_match_dom },
5640 { "shdr_cnt", acl_parse_int, acl_fetch_shdr_cnt,acl_match_int },
5641 { "shdr_val", acl_parse_int, acl_fetch_shdr_val,acl_match_int },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005642
5643 { "path", acl_parse_str, acl_fetch_path, acl_match_str },
5644 { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg },
5645 { "path_beg", acl_parse_str, acl_fetch_path, acl_match_beg },
5646 { "path_end", acl_parse_str, acl_fetch_path, acl_match_end },
5647 { "path_sub", acl_parse_str, acl_fetch_path, acl_match_sub },
5648 { "path_dir", acl_parse_str, acl_fetch_path, acl_match_dir },
5649 { "path_dom", acl_parse_str, acl_fetch_path, acl_match_dom },
5650
Willy Tarreauf3d25982007-05-08 22:45:09 +02005651 { NULL, NULL, NULL, NULL },
5652
5653#if 0
Willy Tarreau8797c062007-05-07 00:55:35 +02005654 { "line", acl_parse_str, acl_fetch_line, acl_match_str },
5655 { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg },
5656 { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg },
5657 { "line_end", acl_parse_str, acl_fetch_line, acl_match_end },
5658 { "line_sub", acl_parse_str, acl_fetch_line, acl_match_sub },
5659 { "line_dir", acl_parse_str, acl_fetch_line, acl_match_dir },
5660 { "line_dom", acl_parse_str, acl_fetch_line, acl_match_dom },
5661
Willy Tarreau8797c062007-05-07 00:55:35 +02005662 { "cook", acl_parse_str, acl_fetch_cook, acl_match_str },
5663 { "cook_reg", acl_parse_reg, acl_fetch_cook, acl_match_reg },
5664 { "cook_beg", acl_parse_str, acl_fetch_cook, acl_match_beg },
5665 { "cook_end", acl_parse_str, acl_fetch_cook, acl_match_end },
5666 { "cook_sub", acl_parse_str, acl_fetch_cook, acl_match_sub },
5667 { "cook_dir", acl_parse_str, acl_fetch_cook, acl_match_dir },
5668 { "cook_dom", acl_parse_str, acl_fetch_cook, acl_match_dom },
5669 { "cook_pst", acl_parse_none, acl_fetch_cook, acl_match_pst },
5670
5671 { "auth_user", acl_parse_str, acl_fetch_user, acl_match_str },
5672 { "auth_regex", acl_parse_reg, acl_fetch_user, acl_match_reg },
5673 { "auth_clear", acl_parse_str, acl_fetch_auth, acl_match_str },
5674 { "auth_md5", acl_parse_str, acl_fetch_auth, acl_match_md5 },
5675 { NULL, NULL, NULL, NULL },
5676#endif
5677}};
5678
5679
5680__attribute__((constructor))
5681static void __http_protocol_init(void)
5682{
5683 acl_register_keywords(&acl_kws);
5684}
5685
5686
Willy Tarreau58f10d72006-12-04 02:26:12 +01005687/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02005688 * Local variables:
5689 * c-indent-level: 8
5690 * c-basic-offset: 8
5691 * End:
5692 */