blob: 89f32effa8fb2081f47830c319e99b21a18cf54a [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * HTTP protocol analyzer
3 *
Willy Tarreau7c669d72008-06-20 15:04:11 +02004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <syslog.h>
Willy Tarreau42250582007-04-01 01:30:43 +020020#include <time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020021
22#include <sys/socket.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25
Willy Tarreau2dd0d472006-06-29 17:53:05 +020026#include <common/appsession.h>
27#include <common/compat.h>
28#include <common/config.h>
Willy Tarreaua4cd1f52006-12-16 19:57:26 +010029#include <common/debug.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020030#include <common/memory.h>
31#include <common/mini-clist.h>
32#include <common/standard.h>
Willy Tarreau0c303ee2008-07-07 00:09:58 +020033#include <common/ticks.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020034#include <common/time.h>
35#include <common/uri_auth.h>
36#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020037
38#include <types/capture.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020039#include <types/global.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020040
Willy Tarreau8797c062007-05-07 00:55:35 +020041#include <proto/acl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020042#include <proto/backend.h>
43#include <proto/buffers.h>
Willy Tarreau91861262007-10-17 17:06:05 +020044#include <proto/dumpstats.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020045#include <proto/fd.h>
46#include <proto/log.h>
Willy Tarreau58f10d72006-12-04 02:26:12 +010047#include <proto/hdr_idx.h>
Willy Tarreaub6866442008-07-14 23:54:42 +020048#include <proto/proto_tcp.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020049#include <proto/proto_http.h>
50#include <proto/queue.h>
Willy Tarreau91861262007-10-17 17:06:05 +020051#include <proto/senddata.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020052#include <proto/session.h>
53#include <proto/task.h>
54
Willy Tarreau6d1a9882007-01-07 02:03:04 +010055#ifdef CONFIG_HAP_TCPSPLICE
56#include <libtcpsplice.h>
57#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020058
Willy Tarreau58f10d72006-12-04 02:26:12 +010059#define DEBUG_PARSE_NO_SPEEDUP
60#undef DEBUG_PARSE_NO_SPEEDUP
61
Willy Tarreau976f1ee2006-12-17 10:06:03 +010062/* This is used to perform a quick jump as an alternative to a break/continue
63 * instruction. The first argument is the label for normal operation, and the
64 * second one is the break/continue instruction in the no_speedup mode.
65 */
66
67#ifdef DEBUG_PARSE_NO_SPEEDUP
68#define QUICK_JUMP(x,y) y
69#else
70#define QUICK_JUMP(x,y) goto x
71#endif
72
Willy Tarreau1c47f852006-07-09 08:22:27 +020073/* This is used by remote monitoring */
Willy Tarreau0f772532006-12-23 20:51:41 +010074const char HTTP_200[] =
Willy Tarreau1c47f852006-07-09 08:22:27 +020075 "HTTP/1.0 200 OK\r\n"
76 "Cache-Control: no-cache\r\n"
77 "Connection: close\r\n"
78 "Content-Type: text/html\r\n"
79 "\r\n"
80 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
81
Willy Tarreau0f772532006-12-23 20:51:41 +010082const struct chunk http_200_chunk = {
83 .str = (char *)&HTTP_200,
84 .len = sizeof(HTTP_200)-1
85};
86
Willy Tarreaub463dfb2008-06-07 23:08:56 +020087const char *HTTP_301 =
88 "HTTP/1.0 301 Moved Permantenly\r\n"
89 "Cache-Control: no-cache\r\n"
90 "Connection: close\r\n"
91 "Location: "; /* not terminated since it will be concatenated with the URL */
92
Willy Tarreau0f772532006-12-23 20:51:41 +010093const char *HTTP_302 =
94 "HTTP/1.0 302 Found\r\n"
95 "Cache-Control: no-cache\r\n"
96 "Connection: close\r\n"
97 "Location: "; /* not terminated since it will be concatenated with the URL */
98
99/* same as 302 except that the browser MUST retry with the GET method */
100const char *HTTP_303 =
101 "HTTP/1.0 303 See Other\r\n"
102 "Cache-Control: no-cache\r\n"
103 "Connection: close\r\n"
104 "Location: "; /* not terminated since it will be concatenated with the URL */
105
Willy Tarreaubaaee002006-06-26 02:48:02 +0200106/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
107const char *HTTP_401_fmt =
108 "HTTP/1.0 401 Unauthorized\r\n"
109 "Cache-Control: no-cache\r\n"
110 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +0200111 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200112 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
113 "\r\n"
114 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
115
Willy Tarreau0f772532006-12-23 20:51:41 +0100116
117const int http_err_codes[HTTP_ERR_SIZE] = {
118 [HTTP_ERR_400] = 400,
119 [HTTP_ERR_403] = 403,
120 [HTTP_ERR_408] = 408,
121 [HTTP_ERR_500] = 500,
122 [HTTP_ERR_502] = 502,
123 [HTTP_ERR_503] = 503,
124 [HTTP_ERR_504] = 504,
125};
126
Willy Tarreau80587432006-12-24 17:47:20 +0100127static const char *http_err_msgs[HTTP_ERR_SIZE] = {
Willy Tarreau0f772532006-12-23 20:51:41 +0100128 [HTTP_ERR_400] =
Willy Tarreau80587432006-12-24 17:47:20 +0100129 "HTTP/1.0 400 Bad request\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +0100130 "Cache-Control: no-cache\r\n"
131 "Connection: close\r\n"
132 "Content-Type: text/html\r\n"
133 "\r\n"
134 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
135
136 [HTTP_ERR_403] =
137 "HTTP/1.0 403 Forbidden\r\n"
138 "Cache-Control: no-cache\r\n"
139 "Connection: close\r\n"
140 "Content-Type: text/html\r\n"
141 "\r\n"
142 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
143
144 [HTTP_ERR_408] =
145 "HTTP/1.0 408 Request Time-out\r\n"
146 "Cache-Control: no-cache\r\n"
147 "Connection: close\r\n"
148 "Content-Type: text/html\r\n"
149 "\r\n"
150 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
151
152 [HTTP_ERR_500] =
153 "HTTP/1.0 500 Server Error\r\n"
154 "Cache-Control: no-cache\r\n"
155 "Connection: close\r\n"
156 "Content-Type: text/html\r\n"
157 "\r\n"
158 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n",
159
160 [HTTP_ERR_502] =
161 "HTTP/1.0 502 Bad Gateway\r\n"
162 "Cache-Control: no-cache\r\n"
163 "Connection: close\r\n"
164 "Content-Type: text/html\r\n"
165 "\r\n"
166 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n",
167
168 [HTTP_ERR_503] =
169 "HTTP/1.0 503 Service Unavailable\r\n"
170 "Cache-Control: no-cache\r\n"
171 "Connection: close\r\n"
172 "Content-Type: text/html\r\n"
173 "\r\n"
174 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n",
175
176 [HTTP_ERR_504] =
177 "HTTP/1.0 504 Gateway Time-out\r\n"
178 "Cache-Control: no-cache\r\n"
179 "Connection: close\r\n"
180 "Content-Type: text/html\r\n"
181 "\r\n"
182 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n",
183
184};
185
Willy Tarreau80587432006-12-24 17:47:20 +0100186/* We must put the messages here since GCC cannot initialize consts depending
187 * on strlen().
188 */
189struct chunk http_err_chunks[HTTP_ERR_SIZE];
190
Willy Tarreau42250582007-04-01 01:30:43 +0200191#define FD_SETS_ARE_BITFIELDS
192#ifdef FD_SETS_ARE_BITFIELDS
193/*
194 * This map is used with all the FD_* macros to check whether a particular bit
195 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
196 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
197 * byte should be encoded. Be careful to always pass bytes from 0 to 255
198 * exclusively to the macros.
199 */
200fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
201fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
202
203#else
204#error "Check if your OS uses bitfields for fd_sets"
205#endif
206
Willy Tarreau80587432006-12-24 17:47:20 +0100207void init_proto_http()
208{
Willy Tarreau42250582007-04-01 01:30:43 +0200209 int i;
210 char *tmp;
Willy Tarreau80587432006-12-24 17:47:20 +0100211 int msg;
Willy Tarreau42250582007-04-01 01:30:43 +0200212
Willy Tarreau80587432006-12-24 17:47:20 +0100213 for (msg = 0; msg < HTTP_ERR_SIZE; msg++) {
214 if (!http_err_msgs[msg]) {
215 Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n", msg);
216 abort();
217 }
218
219 http_err_chunks[msg].str = (char *)http_err_msgs[msg];
220 http_err_chunks[msg].len = strlen(http_err_msgs[msg]);
221 }
Willy Tarreau42250582007-04-01 01:30:43 +0200222
223 /* initialize the log header encoding map : '{|}"#' should be encoded with
224 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
225 * URL encoding only requires '"', '#' to be encoded as well as non-
226 * printable characters above.
227 */
228 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
229 memset(url_encode_map, 0, sizeof(url_encode_map));
230 for (i = 0; i < 32; i++) {
231 FD_SET(i, hdr_encode_map);
232 FD_SET(i, url_encode_map);
233 }
234 for (i = 127; i < 256; i++) {
235 FD_SET(i, hdr_encode_map);
236 FD_SET(i, url_encode_map);
237 }
238
239 tmp = "\"#{|}";
240 while (*tmp) {
241 FD_SET(*tmp, hdr_encode_map);
242 tmp++;
243 }
244
245 tmp = "\"#";
246 while (*tmp) {
247 FD_SET(*tmp, url_encode_map);
248 tmp++;
249 }
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200250
251 /* memory allocations */
252 pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED);
Willy Tarreau086b3b42007-05-13 21:45:51 +0200253 pool2_capture = create_pool("capture", CAPTURE_LEN, MEM_F_SHARED);
Willy Tarreau80587432006-12-24 17:47:20 +0100254}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200255
Willy Tarreau53b6c742006-12-17 13:37:46 +0100256/*
257 * We have 26 list of methods (1 per first letter), each of which can have
258 * up to 3 entries (2 valid, 1 null).
259 */
260struct http_method_desc {
261 http_meth_t meth;
262 int len;
263 const char text[8];
264};
265
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100266const struct http_method_desc http_methods[26][3] = {
Willy Tarreau53b6c742006-12-17 13:37:46 +0100267 ['C' - 'A'] = {
268 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
269 },
270 ['D' - 'A'] = {
271 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
272 },
273 ['G' - 'A'] = {
274 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
275 },
276 ['H' - 'A'] = {
277 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
278 },
279 ['P' - 'A'] = {
280 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
281 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
282 },
283 ['T' - 'A'] = {
284 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
285 },
286 /* rest is empty like this :
287 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
288 */
289};
290
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100291/* It is about twice as fast on recent architectures to lookup a byte in a
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +0200292 * table than to perform a boolean AND or OR between two tests. Refer to
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100293 * RFC2616 for those chars.
294 */
295
296const char http_is_spht[256] = {
297 [' '] = 1, ['\t'] = 1,
298};
299
300const char http_is_crlf[256] = {
301 ['\r'] = 1, ['\n'] = 1,
302};
303
304const char http_is_lws[256] = {
305 [' '] = 1, ['\t'] = 1,
306 ['\r'] = 1, ['\n'] = 1,
307};
308
309const char http_is_sep[256] = {
310 ['('] = 1, [')'] = 1, ['<'] = 1, ['>'] = 1,
311 ['@'] = 1, [','] = 1, [';'] = 1, [':'] = 1,
312 ['"'] = 1, ['/'] = 1, ['['] = 1, [']'] = 1,
313 ['{'] = 1, ['}'] = 1, ['?'] = 1, ['='] = 1,
314 [' '] = 1, ['\t'] = 1, ['\\'] = 1,
315};
316
317const char http_is_ctl[256] = {
318 [0 ... 31] = 1,
319 [127] = 1,
320};
321
322/*
323 * A token is any ASCII char that is neither a separator nor a CTL char.
324 * Do not overwrite values in assignment since gcc-2.95 will not handle
325 * them correctly. Instead, define every non-CTL char's status.
326 */
327const char http_is_token[256] = {
328 [' '] = 0, ['!'] = 1, ['"'] = 0, ['#'] = 1,
329 ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1,
330 ['('] = 0, [')'] = 0, ['*'] = 1, ['+'] = 1,
331 [','] = 0, ['-'] = 1, ['.'] = 1, ['/'] = 0,
332 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1,
333 ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1,
334 ['8'] = 1, ['9'] = 1, [':'] = 0, [';'] = 0,
335 ['<'] = 0, ['='] = 0, ['>'] = 0, ['?'] = 0,
336 ['@'] = 0, ['A'] = 1, ['B'] = 1, ['C'] = 1,
337 ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1,
338 ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1,
339 ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1,
340 ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1,
341 ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1,
342 ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 0,
343 ['\\'] = 0, [']'] = 0, ['^'] = 1, ['_'] = 1,
344 ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1,
345 ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1,
346 ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1,
347 ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1,
348 ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1,
349 ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1,
350 ['x'] = 1, ['y'] = 1, ['z'] = 1, ['{'] = 0,
351 ['|'] = 1, ['}'] = 0, ['~'] = 1,
352};
353
354
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100355/*
356 * An http ver_token is any ASCII which can be found in an HTTP version,
357 * which includes 'H', 'T', 'P', '/', '.' and any digit.
358 */
359const char http_is_ver_token[256] = {
360 ['.'] = 1, ['/'] = 1,
361 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1,
362 ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1,
363 ['H'] = 1, ['P'] = 1, ['T'] = 1,
364};
365
366
Willy Tarreaubaaee002006-06-26 02:48:02 +0200367#ifdef DEBUG_FULL
368static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
369static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
370#endif
371
Willy Tarreau42250582007-04-01 01:30:43 +0200372static void http_sess_log(struct session *s);
373
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100374/*
375 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
376 * CRLF. Text length is measured first, so it cannot be NULL.
377 * The header is also automatically added to the index <hdr_idx>, and the end
378 * of headers is automatically adjusted. The number of bytes added is returned
379 * on success, otherwise <0 is returned indicating an error.
380 */
381int http_header_add_tail(struct buffer *b, struct http_msg *msg,
382 struct hdr_idx *hdr_idx, const char *text)
383{
384 int bytes, len;
385
386 len = strlen(text);
387 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
388 if (!bytes)
389 return -1;
390 msg->eoh += bytes;
391 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
392}
393
394/*
395 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
396 * CRLF. <len> bytes are copied, not counting the CRLF. If <text> is NULL, then
397 * the buffer is only opened and the space reserved, but nothing is copied.
398 * The header is also automatically added to the index <hdr_idx>, and the end
399 * of headers is automatically adjusted. The number of bytes added is returned
400 * on success, otherwise <0 is returned indicating an error.
401 */
402int http_header_add_tail2(struct buffer *b, struct http_msg *msg,
403 struct hdr_idx *hdr_idx, const char *text, int len)
404{
405 int bytes;
406
407 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
408 if (!bytes)
409 return -1;
410 msg->eoh += bytes;
411 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
412}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200413
414/*
Willy Tarreauaa9dce32007-03-18 23:50:16 +0100415 * Checks if <hdr> is exactly <name> for <len> chars, and ends with a colon.
416 * If so, returns the position of the first non-space character relative to
417 * <hdr>, or <end>-<hdr> if not found before. If no value is found, it tries
418 * to return a pointer to the place after the first space. Returns 0 if the
419 * header name does not match. Checks are case-insensitive.
420 */
421int http_header_match2(const char *hdr, const char *end,
422 const char *name, int len)
423{
424 const char *val;
425
426 if (hdr + len >= end)
427 return 0;
428 if (hdr[len] != ':')
429 return 0;
430 if (strncasecmp(hdr, name, len) != 0)
431 return 0;
432 val = hdr + len + 1;
433 while (val < end && HTTP_IS_SPHT(*val))
434 val++;
435 if ((val >= end) && (len + 2 <= end - hdr))
436 return len + 2; /* we may replace starting from second space */
437 return val - hdr;
438}
439
Willy Tarreau33a7e692007-06-10 19:45:56 +0200440/* Find the end of the header value contained between <s> and <e>.
441 * See RFC2616, par 2.2 for more information. Note that it requires
442 * a valid header to return a valid result.
443 */
444const char *find_hdr_value_end(const char *s, const char *e)
445{
446 int quoted, qdpair;
447
448 quoted = qdpair = 0;
449 for (; s < e; s++) {
450 if (qdpair) qdpair = 0;
451 else if (quoted && *s == '\\') qdpair = 1;
452 else if (quoted && *s == '"') quoted = 0;
453 else if (*s == '"') quoted = 1;
454 else if (*s == ',') return s;
455 }
456 return s;
457}
458
459/* Find the first or next occurrence of header <name> in message buffer <sol>
460 * using headers index <idx>, and return it in the <ctx> structure. This
461 * structure holds everything necessary to use the header and find next
462 * occurrence. If its <idx> member is 0, the header is searched from the
463 * beginning. Otherwise, the next occurrence is returned. The function returns
464 * 1 when it finds a value, and 0 when there is no more.
465 */
466int http_find_header2(const char *name, int len,
467 const char *sol, struct hdr_idx *idx,
468 struct hdr_ctx *ctx)
469{
470 __label__ return_hdr, next_hdr;
471 const char *eol, *sov;
472 int cur_idx;
473
474 if (ctx->idx) {
475 /* We have previously returned a value, let's search
476 * another one on the same line.
477 */
478 cur_idx = ctx->idx;
479 sol = ctx->line;
480 sov = sol + ctx->val + ctx->vlen;
481 eol = sol + idx->v[cur_idx].len;
482
483 if (sov >= eol)
484 /* no more values in this header */
485 goto next_hdr;
486
487 /* values remaining for this header, skip the comma */
488 sov++;
489 while (sov < eol && http_is_lws[(unsigned char)*sov])
490 sov++;
491
492 goto return_hdr;
493 }
494
495 /* first request for this header */
496 sol += hdr_idx_first_pos(idx);
497 cur_idx = hdr_idx_first_idx(idx);
498
499 while (cur_idx) {
500 eol = sol + idx->v[cur_idx].len;
501
Willy Tarreau1ad7c6d2007-06-10 21:42:55 +0200502 if (len == 0) {
503 /* No argument was passed, we want any header.
504 * To achieve this, we simply build a fake request. */
505 while (sol + len < eol && sol[len] != ':')
506 len++;
507 name = sol;
508 }
509
Willy Tarreau33a7e692007-06-10 19:45:56 +0200510 if ((len < eol - sol) &&
511 (sol[len] == ':') &&
512 (strncasecmp(sol, name, len) == 0)) {
513
514 sov = sol + len + 1;
515 while (sov < eol && http_is_lws[(unsigned char)*sov])
516 sov++;
517 return_hdr:
518 ctx->line = sol;
519 ctx->idx = cur_idx;
520 ctx->val = sov - sol;
521
522 eol = find_hdr_value_end(sov, eol);
523 ctx->vlen = eol - sov;
524 return 1;
525 }
526 next_hdr:
527 sol = eol + idx->v[cur_idx].cr + 1;
528 cur_idx = idx->v[cur_idx].next;
529 }
530 return 0;
531}
532
533int http_find_header(const char *name,
534 const char *sol, struct hdr_idx *idx,
535 struct hdr_ctx *ctx)
536{
537 return http_find_header2(name, strlen(name), sol, idx, ctx);
538}
539
Willy Tarreaubaaee002006-06-26 02:48:02 +0200540/* This function turns the server state into the SV_STCLOSE, and sets
Willy Tarreau0f772532006-12-23 20:51:41 +0100541 * indicators accordingly. Note that if <status> is 0, or if the message
542 * pointer is NULL, then no message is returned.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200543 */
544void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreau0f772532006-12-23 20:51:41 +0100545 int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200546{
547 t->srv_state = SV_STCLOSE;
Willy Tarreau89edf5e2008-08-03 17:25:14 +0200548 buffer_shutw_done(t->req);
549 buffer_shutr_done(t->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100550 if (status > 0 && msg) {
Willy Tarreau3bac9ff2007-03-18 17:31:28 +0100551 t->txn.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100552 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100553 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200554 }
555 if (!(t->flags & SN_ERR_MASK))
556 t->flags |= err;
557 if (!(t->flags & SN_FINST_MASK))
558 t->flags |= finst;
559}
560
Willy Tarreau80587432006-12-24 17:47:20 +0100561/* This function returns the appropriate error location for the given session
562 * and message.
563 */
564
565struct chunk *error_message(struct session *s, int msgnum)
566{
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200567 if (s->be->errmsg[msgnum].str)
568 return &s->be->errmsg[msgnum];
Willy Tarreau80587432006-12-24 17:47:20 +0100569 else if (s->fe->errmsg[msgnum].str)
570 return &s->fe->errmsg[msgnum];
571 else
572 return &http_err_chunks[msgnum];
573}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200574
Willy Tarreau53b6c742006-12-17 13:37:46 +0100575/*
576 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
577 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
578 */
579static http_meth_t find_http_meth(const char *str, const int len)
580{
581 unsigned char m;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100582 const struct http_method_desc *h;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100583
584 m = ((unsigned)*str - 'A');
585
586 if (m < 26) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100587 for (h = http_methods[m]; h->len > 0; h++) {
588 if (unlikely(h->len != len))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100589 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100590 if (likely(memcmp(str, h->text, h->len) == 0))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100591 return h->meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100592 };
593 return HTTP_METH_OTHER;
594 }
595 return HTTP_METH_NONE;
596
597}
598
Willy Tarreau21d2af32008-02-14 20:25:24 +0100599/* Parse the URI from the given transaction (which is assumed to be in request
600 * phase) and look for the "/" beginning the PATH. If not found, return NULL.
601 * It is returned otherwise.
602 */
603static char *
604http_get_path(struct http_txn *txn)
605{
606 char *ptr, *end;
607
608 ptr = txn->req.sol + txn->req.sl.rq.u;
609 end = ptr + txn->req.sl.rq.u_l;
610
611 if (ptr >= end)
612 return NULL;
613
614 /* RFC2616, par. 5.1.2 :
615 * Request-URI = "*" | absuri | abspath | authority
616 */
617
618 if (*ptr == '*')
619 return NULL;
620
621 if (isalpha((unsigned char)*ptr)) {
622 /* this is a scheme as described by RFC3986, par. 3.1 */
623 ptr++;
624 while (ptr < end &&
625 (isalnum((unsigned char)*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.'))
626 ptr++;
627 /* skip '://' */
628 if (ptr == end || *ptr++ != ':')
629 return NULL;
630 if (ptr == end || *ptr++ != '/')
631 return NULL;
632 if (ptr == end || *ptr++ != '/')
633 return NULL;
634 }
635 /* skip [user[:passwd]@]host[:[port]] */
636
637 while (ptr < end && *ptr != '/')
638 ptr++;
639
640 if (ptr == end)
641 return NULL;
642
643 /* OK, we got the '/' ! */
644 return ptr;
645}
646
Willy Tarreaubaaee002006-06-26 02:48:02 +0200647/* Processes the client and server jobs of a session task, then
648 * puts it back to the wait queue in a clean state, or
649 * cleans up its resources if it must be deleted. Returns
650 * the time the task accepts to wait, or TIME_ETERNITY for
651 * infinity.
652 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200653void process_session(struct task *t, int *next)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200654{
655 struct session *s = t->context;
656 int fsm_resync = 0;
657
658 do {
659 fsm_resync = 0;
660 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
661 fsm_resync |= process_cli(s);
662 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
663 fsm_resync |= process_srv(s);
664 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
665 } while (fsm_resync);
666
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200667 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100668
669 if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
670 session_process_counters(s);
671
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200672 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
673 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200674
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200675 t->expire = tick_first(tick_first(s->req->rex, s->req->wex),
676 tick_first(s->rep->rex, s->rep->wex));
677 t->expire = tick_first(t->expire, s->req->cex);
Willy Tarreau036fae02008-01-06 13:24:40 +0100678 if (s->cli_state == CL_STHEADERS)
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200679 t->expire = tick_first(t->expire, s->txn.exp);
Willy Tarreaub6866442008-07-14 23:54:42 +0200680 else if (s->cli_state == CL_STINSPECT)
681 t->expire = tick_first(t->expire, s->inspect_exp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200682
683 /* restore t to its place in the task list */
684 task_queue(t);
685
Willy Tarreaud825eef2007-05-12 22:35:00 +0200686 *next = t->expire;
687 return; /* nothing more to do */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200688 }
689
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100690 s->fe->feconn--;
691 if (s->flags & SN_BE_ASSIGNED)
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200692 s->be->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200693 actconn--;
694
Willy Tarreauf41d4b12007-04-28 23:26:14 +0200695 if (unlikely((global.mode & MODE_DEBUG) &&
696 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200697 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100698 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200699 s->uniq_id, s->be->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100700 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200701 write(1, trash, len);
702 }
703
Willy Tarreau42aae5c2007-04-29 17:43:56 +0200704 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +0100705 session_process_counters(s);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200706
707 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200708 if (s->logs.logwait &&
709 !(s->flags & SN_MONITOR) &&
Willy Tarreau42250582007-04-01 01:30:43 +0200710 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total)) {
711 if (s->fe->to_log & LW_REQ)
712 http_sess_log(s);
713 else
714 tcp_sess_log(s);
715 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200716
717 /* the task MUST not be in the run queue anymore */
718 task_delete(t);
719 session_free(s);
720 task_free(t);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200721 *next = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200722}
723
724
Willy Tarreau42250582007-04-01 01:30:43 +0200725extern const char sess_term_cond[8];
726extern const char sess_fin_state[8];
727extern const char *monthname[12];
728const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
729const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
730 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
731 unknown, Set-cookie Rewritten */
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200732struct pool_head *pool2_requri;
Willy Tarreau086b3b42007-05-13 21:45:51 +0200733struct pool_head *pool2_capture;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100734
Willy Tarreau42250582007-04-01 01:30:43 +0200735/*
736 * send a log for the session when we have enough info about it.
737 * Will not log if the frontend has no log defined.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100738 */
Willy Tarreau42250582007-04-01 01:30:43 +0200739static void http_sess_log(struct session *s)
740{
741 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
742 struct proxy *fe = s->fe;
743 struct proxy *be = s->be;
744 struct proxy *prx_log;
745 struct http_txn *txn = &s->txn;
746 int tolog;
747 char *uri, *h;
748 char *svid;
Willy Tarreaufe944602007-10-25 10:34:16 +0200749 struct tm tm;
Willy Tarreau42250582007-04-01 01:30:43 +0200750 static char tmpline[MAX_SYSLOG_LEN];
Willy Tarreau70089872008-06-13 21:12:51 +0200751 int t_request;
Willy Tarreau42250582007-04-01 01:30:43 +0200752 int hdr;
753
754 if (fe->logfac1 < 0 && fe->logfac2 < 0)
755 return;
756 prx_log = fe;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100757
Willy Tarreau42250582007-04-01 01:30:43 +0200758 if (s->cli_addr.ss_family == AF_INET)
759 inet_ntop(AF_INET,
760 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
761 pn, sizeof(pn));
762 else
763 inet_ntop(AF_INET6,
764 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
765 pn, sizeof(pn));
766
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200767 get_localtime(s->logs.accept_date.tv_sec, &tm);
Willy Tarreau42250582007-04-01 01:30:43 +0200768
769 /* FIXME: let's limit ourselves to frontend logging for now. */
770 tolog = fe->to_log;
771
772 h = tmpline;
773 if (fe->to_log & LW_REQHDR &&
774 txn->req.cap &&
775 (h < tmpline + sizeof(tmpline) - 10)) {
776 *(h++) = ' ';
777 *(h++) = '{';
778 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
779 if (hdr)
780 *(h++) = '|';
781 if (txn->req.cap[hdr] != NULL)
782 h = encode_string(h, tmpline + sizeof(tmpline) - 7,
783 '#', hdr_encode_map, txn->req.cap[hdr]);
784 }
785 *(h++) = '}';
786 }
787
788 if (fe->to_log & LW_RSPHDR &&
789 txn->rsp.cap &&
790 (h < tmpline + sizeof(tmpline) - 7)) {
791 *(h++) = ' ';
792 *(h++) = '{';
793 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
794 if (hdr)
795 *(h++) = '|';
796 if (txn->rsp.cap[hdr] != NULL)
797 h = encode_string(h, tmpline + sizeof(tmpline) - 4,
798 '#', hdr_encode_map, txn->rsp.cap[hdr]);
799 }
800 *(h++) = '}';
801 }
802
803 if (h < tmpline + sizeof(tmpline) - 4) {
804 *(h++) = ' ';
805 *(h++) = '"';
806 uri = txn->uri ? txn->uri : "<BADREQ>";
807 h = encode_string(h, tmpline + sizeof(tmpline) - 1,
808 '#', url_encode_map, uri);
809 *(h++) = '"';
810 }
811 *h = '\0';
812
813 svid = (tolog & LW_SVID) ?
814 (s->data_source != DATA_SRC_STATS) ?
815 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
816
Willy Tarreau70089872008-06-13 21:12:51 +0200817 t_request = -1;
818 if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
819 t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
820
Willy Tarreau42250582007-04-01 01:30:43 +0200821 send_log(prx_log, LOG_INFO,
822 "%s:%d [%02d/%s/%04d:%02d:%02d:%02d.%03d]"
823 " %s %s/%s %d/%d/%d/%d/%s%d %d %s%lld"
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100824 " %s %s %c%c%c%c %d/%d/%d/%d/%s%u %d/%d%s\n",
Willy Tarreau42250582007-04-01 01:30:43 +0200825 pn,
826 (s->cli_addr.ss_family == AF_INET) ?
827 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
828 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
Willy Tarreaufe944602007-10-25 10:34:16 +0200829 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200830 tm.tm_hour, tm.tm_min, tm.tm_sec, s->logs.accept_date.tv_usec/1000,
Willy Tarreau42250582007-04-01 01:30:43 +0200831 fe->id, be->id, svid,
Willy Tarreau70089872008-06-13 21:12:51 +0200832 t_request,
833 (s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1,
Willy Tarreau42250582007-04-01 01:30:43 +0200834 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
835 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
836 (tolog & LW_BYTES) ? "" : "+", s->logs.t_close,
837 txn->status,
Willy Tarreau8b3977f2008-01-18 11:16:32 +0100838 (tolog & LW_BYTES) ? "" : "+", s->logs.bytes_out,
Willy Tarreau42250582007-04-01 01:30:43 +0200839 txn->cli_cookie ? txn->cli_cookie : "-",
840 txn->srv_cookie ? txn->srv_cookie : "-",
841 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
842 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
843 (be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-',
844 (be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-',
845 actconn, fe->feconn, be->beconn, s->srv ? s->srv->cur_sess : 0,
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +0100846 (s->flags & SN_REDISP)?"+":"",
847 (s->conn_retries>0)?(be->conn_retries - s->conn_retries):be->conn_retries,
Willy Tarreau42250582007-04-01 01:30:43 +0200848 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
849
850 s->logs.logwait = 0;
851}
852
Willy Tarreau117f59e2007-03-04 18:17:17 +0100853
854/*
855 * Capture headers from message starting at <som> according to header list
856 * <cap_hdr>, and fill the <idx> structure appropriately.
857 */
858void capture_headers(char *som, struct hdr_idx *idx,
859 char **cap, struct cap_hdr *cap_hdr)
860{
861 char *eol, *sol, *col, *sov;
862 int cur_idx;
863 struct cap_hdr *h;
864 int len;
865
866 sol = som + hdr_idx_first_pos(idx);
867 cur_idx = hdr_idx_first_idx(idx);
868
869 while (cur_idx) {
870 eol = sol + idx->v[cur_idx].len;
871
872 col = sol;
873 while (col < eol && *col != ':')
874 col++;
875
876 sov = col + 1;
877 while (sov < eol && http_is_lws[(unsigned char)*sov])
878 sov++;
879
880 for (h = cap_hdr; h; h = h->next) {
881 if ((h->namelen == col - sol) &&
882 (strncasecmp(sol, h->name, h->namelen) == 0)) {
883 if (cap[h->index] == NULL)
884 cap[h->index] =
Willy Tarreaucf7f3202007-05-13 22:46:04 +0200885 pool_alloc2(h->pool);
Willy Tarreau117f59e2007-03-04 18:17:17 +0100886
887 if (cap[h->index] == NULL) {
888 Alert("HTTP capture : out of memory.\n");
889 continue;
890 }
891
892 len = eol - sov;
893 if (len > h->len)
894 len = h->len;
895
896 memcpy(cap[h->index], sov, len);
897 cap[h->index][len]=0;
898 }
899 }
900 sol = eol + idx->v[cur_idx].cr + 1;
901 cur_idx = idx->v[cur_idx].next;
902 }
903}
904
905
Willy Tarreau42250582007-04-01 01:30:43 +0200906/* either we find an LF at <ptr> or we jump to <bad>.
907 */
908#define EXPECT_LF_HERE(ptr, bad) do { if (unlikely(*(ptr) != '\n')) goto bad; } while (0)
909
910/* plays with variables <ptr>, <end> and <state>. Jumps to <good> if OK,
911 * otherwise to <http_msg_ood> with <state> set to <st>.
912 */
913#define EAT_AND_JUMP_OR_RETURN(good, st) do { \
914 ptr++; \
915 if (likely(ptr < end)) \
916 goto good; \
917 else { \
918 state = (st); \
919 goto http_msg_ood; \
920 } \
921 } while (0)
922
923
Willy Tarreaubaaee002006-06-26 02:48:02 +0200924/*
Willy Tarreaua15645d2007-03-18 16:22:39 +0100925 * This function parses a status line between <ptr> and <end>, starting with
Willy Tarreau8973c702007-01-21 23:58:29 +0100926 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
927 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
928 * will give undefined results.
929 * Note that it is upon the caller's responsibility to ensure that ptr < end,
930 * and that msg->sol points to the beginning of the response.
931 * If a complete line is found (which implies that at least one CR or LF is
932 * found before <end>, the updated <ptr> is returned, otherwise NULL is
933 * returned indicating an incomplete line (which does not mean that parts have
934 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
935 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
936 * upon next call.
937 *
Willy Tarreau9cdde232007-05-02 20:58:19 +0200938 * This function was intentionally designed to be called from
Willy Tarreau8973c702007-01-21 23:58:29 +0100939 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
940 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +0200941 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreau8973c702007-01-21 23:58:29 +0100942 */
Willy Tarreaue69eada2008-01-27 00:34:10 +0100943const char *http_parse_stsline(struct http_msg *msg, const char *msg_buf,
944 unsigned int state, const char *ptr, const char *end,
945 char **ret_ptr, unsigned int *ret_state)
Willy Tarreau8973c702007-01-21 23:58:29 +0100946{
947 __label__
948 http_msg_rpver,
949 http_msg_rpver_sp,
950 http_msg_rpcode,
951 http_msg_rpcode_sp,
952 http_msg_rpreason,
953 http_msg_rpline_eol,
954 http_msg_ood, /* out of data */
955 http_msg_invalid;
956
957 switch (state) {
958 http_msg_rpver:
959 case HTTP_MSG_RPVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100960 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8973c702007-01-21 23:58:29 +0100961 EAT_AND_JUMP_OR_RETURN(http_msg_rpver, HTTP_MSG_RPVER);
962
963 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +0100964 msg->sl.st.v_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +0100965 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
966 }
967 goto http_msg_invalid;
968
969 http_msg_rpver_sp:
970 case HTTP_MSG_RPVER_SP:
971 if (likely(!HTTP_IS_LWS(*ptr))) {
972 msg->sl.st.c = ptr - msg_buf;
973 goto http_msg_rpcode;
974 }
975 if (likely(HTTP_IS_SPHT(*ptr)))
976 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
977 /* so it's a CR/LF, this is invalid */
978 goto http_msg_invalid;
979
980 http_msg_rpcode:
981 case HTTP_MSG_RPCODE:
982 if (likely(!HTTP_IS_LWS(*ptr)))
983 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode, HTTP_MSG_RPCODE);
984
985 if (likely(HTTP_IS_SPHT(*ptr))) {
986 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
987 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
988 }
989
990 /* so it's a CR/LF, so there is no reason phrase */
991 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
992 http_msg_rsp_reason:
993 /* FIXME: should we support HTTP responses without any reason phrase ? */
994 msg->sl.st.r = ptr - msg_buf;
995 msg->sl.st.r_l = 0;
996 goto http_msg_rpline_eol;
997
998 http_msg_rpcode_sp:
999 case HTTP_MSG_RPCODE_SP:
1000 if (likely(!HTTP_IS_LWS(*ptr))) {
1001 msg->sl.st.r = ptr - msg_buf;
1002 goto http_msg_rpreason;
1003 }
1004 if (likely(HTTP_IS_SPHT(*ptr)))
1005 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1006 /* so it's a CR/LF, so there is no reason phrase */
1007 goto http_msg_rsp_reason;
1008
1009 http_msg_rpreason:
1010 case HTTP_MSG_RPREASON:
1011 if (likely(!HTTP_IS_CRLF(*ptr)))
1012 EAT_AND_JUMP_OR_RETURN(http_msg_rpreason, HTTP_MSG_RPREASON);
1013 msg->sl.st.r_l = (ptr - msg_buf) - msg->sl.st.r;
1014 http_msg_rpline_eol:
1015 /* We have seen the end of line. Note that we do not
1016 * necessarily have the \n yet, but at least we know that we
1017 * have EITHER \r OR \n, otherwise the response would not be
1018 * complete. We can then record the response length and return
1019 * to the caller which will be able to register it.
1020 */
1021 msg->sl.st.l = ptr - msg->sol;
1022 return ptr;
1023
1024#ifdef DEBUG_FULL
1025 default:
1026 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1027 exit(1);
1028#endif
1029 }
1030
1031 http_msg_ood:
1032 /* out of data */
1033 if (ret_state)
1034 *ret_state = state;
1035 if (ret_ptr)
1036 *ret_ptr = (char *)ptr;
1037 return NULL;
1038
1039 http_msg_invalid:
1040 /* invalid message */
1041 if (ret_state)
1042 *ret_state = HTTP_MSG_ERROR;
1043 return NULL;
1044}
1045
1046
1047/*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001048 * This function parses a request line between <ptr> and <end>, starting with
1049 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
1050 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
1051 * will give undefined results.
1052 * Note that it is upon the caller's responsibility to ensure that ptr < end,
1053 * and that msg->sol points to the beginning of the request.
1054 * If a complete line is found (which implies that at least one CR or LF is
1055 * found before <end>, the updated <ptr> is returned, otherwise NULL is
1056 * returned indicating an incomplete line (which does not mean that parts have
1057 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
1058 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
1059 * upon next call.
1060 *
Willy Tarreau9cdde232007-05-02 20:58:19 +02001061 * This function was intentionally designed to be called from
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001062 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
1063 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +02001064 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001065 */
Willy Tarreaue69eada2008-01-27 00:34:10 +01001066const char *http_parse_reqline(struct http_msg *msg, const char *msg_buf,
1067 unsigned int state, const char *ptr, const char *end,
1068 char **ret_ptr, unsigned int *ret_state)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001069{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001070 __label__
1071 http_msg_rqmeth,
1072 http_msg_rqmeth_sp,
1073 http_msg_rquri,
1074 http_msg_rquri_sp,
1075 http_msg_rqver,
1076 http_msg_rqline_eol,
1077 http_msg_ood, /* out of data */
1078 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001079
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001080 switch (state) {
1081 http_msg_rqmeth:
1082 case HTTP_MSG_RQMETH:
1083 if (likely(HTTP_IS_TOKEN(*ptr)))
1084 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth, HTTP_MSG_RQMETH);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001085
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001086 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001087 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001088 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1089 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001090
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001091 if (likely(HTTP_IS_CRLF(*ptr))) {
1092 /* HTTP 0.9 request */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001093 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001094 http_msg_req09_uri:
1095 msg->sl.rq.u = ptr - msg_buf;
1096 http_msg_req09_uri_e:
1097 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1098 http_msg_req09_ver:
1099 msg->sl.rq.v = ptr - msg_buf;
1100 msg->sl.rq.v_l = 0;
1101 goto http_msg_rqline_eol;
1102 }
1103 goto http_msg_invalid;
1104
1105 http_msg_rqmeth_sp:
1106 case HTTP_MSG_RQMETH_SP:
1107 if (likely(!HTTP_IS_LWS(*ptr))) {
1108 msg->sl.rq.u = ptr - msg_buf;
1109 goto http_msg_rquri;
1110 }
1111 if (likely(HTTP_IS_SPHT(*ptr)))
1112 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1113 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1114 goto http_msg_req09_uri;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001115
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001116 http_msg_rquri:
1117 case HTTP_MSG_RQURI:
1118 if (likely(!HTTP_IS_LWS(*ptr)))
1119 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001120
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001121 if (likely(HTTP_IS_SPHT(*ptr))) {
1122 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
1123 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1124 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001125
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001126 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1127 goto http_msg_req09_uri_e;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001128
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001129 http_msg_rquri_sp:
1130 case HTTP_MSG_RQURI_SP:
1131 if (likely(!HTTP_IS_LWS(*ptr))) {
1132 msg->sl.rq.v = ptr - msg_buf;
1133 goto http_msg_rqver;
1134 }
1135 if (likely(HTTP_IS_SPHT(*ptr)))
1136 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1137 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1138 goto http_msg_req09_ver;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001139
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001140 http_msg_rqver:
1141 case HTTP_MSG_RQVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001142 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001143 EAT_AND_JUMP_OR_RETURN(http_msg_rqver, HTTP_MSG_RQVER);
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001144
1145 if (likely(HTTP_IS_CRLF(*ptr))) {
1146 msg->sl.rq.v_l = (ptr - msg_buf) - msg->sl.rq.v;
1147 http_msg_rqline_eol:
1148 /* We have seen the end of line. Note that we do not
1149 * necessarily have the \n yet, but at least we know that we
1150 * have EITHER \r OR \n, otherwise the request would not be
1151 * complete. We can then record the request length and return
1152 * to the caller which will be able to register it.
1153 */
1154 msg->sl.rq.l = ptr - msg->sol;
1155 return ptr;
1156 }
1157
1158 /* neither an HTTP_VER token nor a CRLF */
1159 goto http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001160
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001161#ifdef DEBUG_FULL
1162 default:
1163 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1164 exit(1);
1165#endif
1166 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001167
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001168 http_msg_ood:
1169 /* out of data */
1170 if (ret_state)
1171 *ret_state = state;
1172 if (ret_ptr)
1173 *ret_ptr = (char *)ptr;
1174 return NULL;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001175
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001176 http_msg_invalid:
1177 /* invalid message */
1178 if (ret_state)
1179 *ret_state = HTTP_MSG_ERROR;
1180 return NULL;
1181}
Willy Tarreau58f10d72006-12-04 02:26:12 +01001182
1183
Willy Tarreau8973c702007-01-21 23:58:29 +01001184/*
1185 * This function parses an HTTP message, either a request or a response,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001186 * depending on the initial msg->msg_state. It can be preempted everywhere
Willy Tarreau8973c702007-01-21 23:58:29 +01001187 * when data are missing and recalled at the exact same location with no
1188 * information loss. The header index is re-initialized when switching from
Willy Tarreau9cdde232007-05-02 20:58:19 +02001189 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH. It modifies msg->sol among other
1190 * fields.
Willy Tarreau8973c702007-01-21 23:58:29 +01001191 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001192void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx *idx)
1193{
1194 __label__
1195 http_msg_rqbefore,
1196 http_msg_rqbefore_cr,
1197 http_msg_rqmeth,
1198 http_msg_rqline_end,
1199 http_msg_hdr_first,
1200 http_msg_hdr_name,
1201 http_msg_hdr_l1_sp,
1202 http_msg_hdr_l1_lf,
1203 http_msg_hdr_l1_lws,
1204 http_msg_hdr_val,
1205 http_msg_hdr_l2_lf,
1206 http_msg_hdr_l2_lws,
1207 http_msg_complete_header,
1208 http_msg_last_lf,
1209 http_msg_ood, /* out of data */
1210 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001211
Willy Tarreaue69eada2008-01-27 00:34:10 +01001212 unsigned int state; /* updated only when leaving the FSM */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001213 register char *ptr, *end; /* request pointers, to avoid dereferences */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001214
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001215 state = msg->msg_state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001216 ptr = buf->lr;
1217 end = buf->r;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001218
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001219 if (unlikely(ptr >= end))
1220 goto http_msg_ood;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001221
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001222 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +01001223 /*
1224 * First, states that are specific to the response only.
1225 * We check them first so that request and headers are
1226 * closer to each other (accessed more often).
1227 */
1228 http_msg_rpbefore:
1229 case HTTP_MSG_RPBEFORE:
1230 if (likely(HTTP_IS_TOKEN(*ptr))) {
1231 if (likely(ptr == buf->data)) {
1232 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001233 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001234 } else {
1235#if PARSE_PRESERVE_EMPTY_LINES
1236 /* only skip empty leading lines, don't remove them */
1237 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001238 msg->som = ptr - buf->data;
Willy Tarreau8973c702007-01-21 23:58:29 +01001239#else
1240 /* Remove empty leading lines, as recommended by
1241 * RFC2616. This takes a lot of time because we
1242 * must move all the buffer backwards, but this
1243 * is rarely needed. The method above will be
1244 * cleaner when we'll be able to start sending
1245 * the request from any place in the buffer.
1246 */
1247 buf->lr = ptr;
1248 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001249 msg->som = 0;
Willy Tarreau8973c702007-01-21 23:58:29 +01001250 msg->sol = buf->data;
1251 ptr = buf->data;
1252 end = buf->r;
1253#endif
1254 }
1255 hdr_idx_init(idx);
1256 state = HTTP_MSG_RPVER;
1257 goto http_msg_rpver;
1258 }
1259
1260 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1261 goto http_msg_invalid;
1262
1263 if (unlikely(*ptr == '\n'))
1264 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1265 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore_cr, HTTP_MSG_RPBEFORE_CR);
1266 /* stop here */
1267
1268 http_msg_rpbefore_cr:
1269 case HTTP_MSG_RPBEFORE_CR:
1270 EXPECT_LF_HERE(ptr, http_msg_invalid);
1271 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1272 /* stop here */
1273
1274 http_msg_rpver:
1275 case HTTP_MSG_RPVER:
1276 case HTTP_MSG_RPVER_SP:
1277 case HTTP_MSG_RPCODE:
1278 case HTTP_MSG_RPCODE_SP:
1279 case HTTP_MSG_RPREASON:
Willy Tarreaua15645d2007-03-18 16:22:39 +01001280 ptr = (char *)http_parse_stsline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001281 &buf->lr, &msg->msg_state);
Willy Tarreau8973c702007-01-21 23:58:29 +01001282 if (unlikely(!ptr))
1283 return;
1284
1285 /* we have a full response and we know that we have either a CR
1286 * or an LF at <ptr>.
1287 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001288 //fprintf(stderr,"som=%d rq.l=%d *ptr=0x%02x\n", msg->som, msg->sl.st.l, *ptr);
Willy Tarreau8973c702007-01-21 23:58:29 +01001289 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
1290
1291 msg->sol = ptr;
1292 if (likely(*ptr == '\r'))
1293 EAT_AND_JUMP_OR_RETURN(http_msg_rpline_end, HTTP_MSG_RPLINE_END);
1294 goto http_msg_rpline_end;
1295
1296 http_msg_rpline_end:
1297 case HTTP_MSG_RPLINE_END:
1298 /* msg->sol must point to the first of CR or LF. */
1299 EXPECT_LF_HERE(ptr, http_msg_invalid);
1300 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
1301 /* stop here */
1302
1303 /*
1304 * Second, states that are specific to the request only
1305 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001306 http_msg_rqbefore:
1307 case HTTP_MSG_RQBEFORE:
1308 if (likely(HTTP_IS_TOKEN(*ptr))) {
1309 if (likely(ptr == buf->data)) {
1310 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001311 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001312 } else {
1313#if PARSE_PRESERVE_EMPTY_LINES
1314 /* only skip empty leading lines, don't remove them */
1315 msg->sol = ptr;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001316 msg->som = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001317#else
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001318 /* Remove empty leading lines, as recommended by
1319 * RFC2616. This takes a lot of time because we
1320 * must move all the buffer backwards, but this
1321 * is rarely needed. The method above will be
1322 * cleaner when we'll be able to start sending
1323 * the request from any place in the buffer.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001324 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001325 buf->lr = ptr;
1326 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001327 msg->som = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001328 msg->sol = buf->data;
1329 ptr = buf->data;
1330 end = buf->r;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001331#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001332 }
Willy Tarreauf0d058e2007-01-25 12:03:42 +01001333 /* we will need this when keep-alive will be supported
1334 hdr_idx_init(idx);
1335 */
Willy Tarreau8973c702007-01-21 23:58:29 +01001336 state = HTTP_MSG_RQMETH;
1337 goto http_msg_rqmeth;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001338 }
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001339
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001340 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1341 goto http_msg_invalid;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001342
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001343 if (unlikely(*ptr == '\n'))
1344 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
1345 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore_cr, HTTP_MSG_RQBEFORE_CR);
Willy Tarreau8973c702007-01-21 23:58:29 +01001346 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001347
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001348 http_msg_rqbefore_cr:
1349 case HTTP_MSG_RQBEFORE_CR:
1350 EXPECT_LF_HERE(ptr, http_msg_invalid);
1351 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
Willy Tarreau8973c702007-01-21 23:58:29 +01001352 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001353
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001354 http_msg_rqmeth:
1355 case HTTP_MSG_RQMETH:
1356 case HTTP_MSG_RQMETH_SP:
1357 case HTTP_MSG_RQURI:
1358 case HTTP_MSG_RQURI_SP:
1359 case HTTP_MSG_RQVER:
1360 ptr = (char *)http_parse_reqline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001361 &buf->lr, &msg->msg_state);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001362 if (unlikely(!ptr))
1363 return;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001364
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001365 /* we have a full request and we know that we have either a CR
1366 * or an LF at <ptr>.
1367 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001368 //fprintf(stderr,"som=%d rq.l=%d *ptr=0x%02x\n", msg->som, msg->sl.rq.l, *ptr);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001369 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001370
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001371 msg->sol = ptr;
1372 if (likely(*ptr == '\r'))
1373 EAT_AND_JUMP_OR_RETURN(http_msg_rqline_end, HTTP_MSG_RQLINE_END);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001374 goto http_msg_rqline_end;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001375
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001376 http_msg_rqline_end:
1377 case HTTP_MSG_RQLINE_END:
1378 /* check for HTTP/0.9 request : no version information available.
1379 * msg->sol must point to the first of CR or LF.
1380 */
1381 if (unlikely(msg->sl.rq.v_l == 0))
1382 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001383
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001384 EXPECT_LF_HERE(ptr, http_msg_invalid);
1385 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
Willy Tarreau8973c702007-01-21 23:58:29 +01001386 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001387
Willy Tarreau8973c702007-01-21 23:58:29 +01001388 /*
1389 * Common states below
1390 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001391 http_msg_hdr_first:
1392 case HTTP_MSG_HDR_FIRST:
1393 msg->sol = ptr;
1394 if (likely(!HTTP_IS_CRLF(*ptr))) {
1395 goto http_msg_hdr_name;
1396 }
1397
1398 if (likely(*ptr == '\r'))
1399 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1400 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001401
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001402 http_msg_hdr_name:
1403 case HTTP_MSG_HDR_NAME:
1404 /* assumes msg->sol points to the first char */
1405 if (likely(HTTP_IS_TOKEN(*ptr)))
1406 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001407
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001408 if (likely(*ptr == ':')) {
1409 msg->col = ptr - buf->data;
1410 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
1411 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001412
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001413 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001414
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001415 http_msg_hdr_l1_sp:
1416 case HTTP_MSG_HDR_L1_SP:
1417 /* assumes msg->sol points to the first char and msg->col to the colon */
1418 if (likely(HTTP_IS_SPHT(*ptr)))
1419 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001420
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001421 /* header value can be basically anything except CR/LF */
1422 msg->sov = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001423
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001424 if (likely(!HTTP_IS_CRLF(*ptr))) {
1425 goto http_msg_hdr_val;
1426 }
1427
1428 if (likely(*ptr == '\r'))
1429 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lf, HTTP_MSG_HDR_L1_LF);
1430 goto http_msg_hdr_l1_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001431
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001432 http_msg_hdr_l1_lf:
1433 case HTTP_MSG_HDR_L1_LF:
1434 EXPECT_LF_HERE(ptr, http_msg_invalid);
1435 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lws, HTTP_MSG_HDR_L1_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001436
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001437 http_msg_hdr_l1_lws:
1438 case HTTP_MSG_HDR_L1_LWS:
1439 if (likely(HTTP_IS_SPHT(*ptr))) {
1440 /* replace HT,CR,LF with spaces */
1441 for (; buf->data+msg->sov < ptr; msg->sov++)
1442 buf->data[msg->sov] = ' ';
1443 goto http_msg_hdr_l1_sp;
1444 }
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001445 /* we had a header consisting only in spaces ! */
1446 msg->eol = buf->data + msg->sov;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001447 goto http_msg_complete_header;
1448
1449 http_msg_hdr_val:
1450 case HTTP_MSG_HDR_VAL:
1451 /* assumes msg->sol points to the first char, msg->col to the
1452 * colon, and msg->sov points to the first character of the
1453 * value.
1454 */
1455 if (likely(!HTTP_IS_CRLF(*ptr)))
1456 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001457
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001458 msg->eol = ptr;
1459 /* Note: we could also copy eol into ->eoh so that we have the
1460 * real header end in case it ends with lots of LWS, but is this
1461 * really needed ?
1462 */
1463 if (likely(*ptr == '\r'))
1464 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1465 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001466
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001467 http_msg_hdr_l2_lf:
1468 case HTTP_MSG_HDR_L2_LF:
1469 EXPECT_LF_HERE(ptr, http_msg_invalid);
1470 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001471
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001472 http_msg_hdr_l2_lws:
1473 case HTTP_MSG_HDR_L2_LWS:
1474 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1475 /* LWS: replace HT,CR,LF with spaces */
1476 for (; msg->eol < ptr; msg->eol++)
1477 *msg->eol = ' ';
1478 goto http_msg_hdr_val;
1479 }
1480 http_msg_complete_header:
1481 /*
1482 * It was a new header, so the last one is finished.
1483 * Assumes msg->sol points to the first char, msg->col to the
1484 * colon, msg->sov points to the first character of the value
1485 * and msg->eol to the first CR or LF so we know how the line
1486 * ends. We insert last header into the index.
1487 */
1488 /*
1489 fprintf(stderr,"registering %-2d bytes : ", msg->eol - msg->sol);
1490 write(2, msg->sol, msg->eol-msg->sol);
1491 fprintf(stderr,"\n");
1492 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001493
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001494 if (unlikely(hdr_idx_add(msg->eol - msg->sol, *msg->eol == '\r',
1495 idx, idx->tail) < 0))
1496 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001497
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001498 msg->sol = ptr;
1499 if (likely(!HTTP_IS_CRLF(*ptr))) {
1500 goto http_msg_hdr_name;
1501 }
1502
1503 if (likely(*ptr == '\r'))
1504 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1505 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001506
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001507 http_msg_last_lf:
1508 case HTTP_MSG_LAST_LF:
1509 /* Assumes msg->sol points to the first of either CR or LF */
1510 EXPECT_LF_HERE(ptr, http_msg_invalid);
1511 ptr++;
1512 buf->lr = ptr;
1513 msg->eoh = msg->sol - buf->data;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001514 msg->msg_state = HTTP_MSG_BODY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001515 return;
1516#ifdef DEBUG_FULL
1517 default:
1518 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1519 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001520#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001521 }
1522 http_msg_ood:
1523 /* out of data */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001524 msg->msg_state = state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001525 buf->lr = ptr;
1526 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001527
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001528 http_msg_invalid:
1529 /* invalid message */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001530 msg->msg_state = HTTP_MSG_ERROR;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001531 return;
1532}
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001533
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001534/*
1535 * manages the client FSM and its socket. BTW, it also tries to handle the
1536 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1537 * 0 else.
1538 */
1539int process_cli(struct session *t)
1540{
1541 int s = t->srv_state;
1542 int c = t->cli_state;
1543 struct buffer *req = t->req;
1544 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001545
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001546 DPRINTF(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
1547 cli_stnames[c], srv_stnames[s],
Willy Tarreauf161a342007-04-08 16:59:42 +02001548 EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001549 req->rex.tv_sec, req->rex.tv_usec,
1550 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001551
Willy Tarreaub6866442008-07-14 23:54:42 +02001552 if (c == CL_STINSPECT) {
1553 struct tcp_rule *rule;
1554 int partial;
1555
1556 /* We will abort if we encounter a read error. In theory,
1557 * we should not abort if we get a close, it might be
1558 * valid, also very unlikely. FIXME: we'll abort for now,
1559 * this will be easier to change later.
1560 */
1561 if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1562 t->inspect_exp = TICK_ETERNITY;
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001563 buffer_shutr_done(req);
1564 buffer_shutw_done(rep);
Willy Tarreaub6866442008-07-14 23:54:42 +02001565 fd_delete(t->cli_fd);
1566 t->cli_state = CL_STCLOSE;
1567 t->fe->failed_req++;
1568 if (!(t->flags & SN_ERR_MASK))
1569 t->flags |= SN_ERR_CLICL;
1570 if (!(t->flags & SN_FINST_MASK))
1571 t->flags |= SN_FINST_R;
1572 return 1;
1573 }
1574
1575 /* Abort if client read timeout has expired */
1576 else if (unlikely(tick_is_expired(req->rex, now_ms))) {
1577 t->inspect_exp = TICK_ETERNITY;
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001578 buffer_shutr_done(req);
1579 buffer_shutw_done(rep);
Willy Tarreaub6866442008-07-14 23:54:42 +02001580 fd_delete(t->cli_fd);
1581 t->cli_state = CL_STCLOSE;
1582 t->fe->failed_req++;
1583 if (!(t->flags & SN_ERR_MASK))
1584 t->flags |= SN_ERR_CLITO;
1585 if (!(t->flags & SN_FINST_MASK))
1586 t->flags |= SN_FINST_R;
1587 return 1;
1588 }
1589
1590 /* We don't know whether we have enough data, so must proceed
1591 * this way :
1592 * - iterate through all rules in their declaration order
1593 * - if one rule returns MISS, it means the inspect delay is
1594 * not over yet, then return immediately, otherwise consider
1595 * it as a non-match.
1596 * - if one rule returns OK, then return OK
1597 * - if one rule returns KO, then return KO
1598 */
1599
1600 if (tick_is_expired(t->inspect_exp, now_ms))
1601 partial = 0;
1602 else
1603 partial = ACL_PARTIAL;
1604
1605 list_for_each_entry(rule, &t->fe->tcp_req.inspect_rules, list) {
1606 int ret = ACL_PAT_PASS;
1607
1608 if (rule->cond) {
1609 ret = acl_exec_cond(rule->cond, t->fe, t, NULL, ACL_DIR_REQ | partial);
1610 if (ret == ACL_PAT_MISS) {
1611 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
1612 return 0;
1613 }
1614 ret = acl_pass(ret);
1615 if (rule->cond->pol == ACL_COND_UNLESS)
1616 ret = !ret;
1617 }
1618
1619 if (ret) {
1620 /* we have a matching rule. */
1621 if (rule->action == TCP_ACT_REJECT) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001622 buffer_shutr_done(req);
1623 buffer_shutw_done(rep);
Willy Tarreaub6866442008-07-14 23:54:42 +02001624 fd_delete(t->cli_fd);
1625 t->cli_state = CL_STCLOSE;
1626 t->fe->failed_req++;
1627 if (!(t->flags & SN_ERR_MASK))
1628 t->flags |= SN_ERR_PRXCOND;
1629 if (!(t->flags & SN_FINST_MASK))
1630 t->flags |= SN_FINST_R;
1631 t->inspect_exp = TICK_ETERNITY;
1632 return 1;
1633 }
1634 /* otherwise accept */
1635 break;
1636 }
1637 }
1638
1639 /* if we get there, it means we have no rule which matches, so
1640 * we apply the default accept.
1641 */
1642 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
1643 if (t->fe->mode == PR_MODE_HTTP) {
1644 t->cli_state = CL_STHEADERS;
1645 t->txn.exp = tick_add_ifset(now_ms, t->fe->timeout.httpreq);
1646 } else {
1647 t->cli_state = CL_STDATA;
1648 }
1649 t->inspect_exp = TICK_ETERNITY;
1650 return 1;
1651 }
1652 else if (c == CL_STHEADERS) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001653 /*
1654 * Now parse the partial (or complete) lines.
1655 * We will check the request syntax, and also join multi-line
1656 * headers. An index of all the lines will be elaborated while
1657 * parsing.
1658 *
Willy Tarreau8973c702007-01-21 23:58:29 +01001659 * For the parsing, we use a 28 states FSM.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001660 *
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001661 * Here is the information we currently have :
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001662 * req->data + req->som = beginning of request
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001663 * req->data + req->eoh = end of processed headers / start of current one
1664 * req->data + req->eol = end of current header or line (LF or CRLF)
1665 * req->lr = first non-visited byte
1666 * req->r = end of data
1667 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001668
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001669 int cur_idx;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001670 struct http_txn *txn = &t->txn;
1671 struct http_msg *msg = &txn->req;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001672 struct proxy *cur_proxy;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001673
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001674 if (likely(req->lr < req->r))
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001675 http_msg_analyzer(req, msg, &txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001676
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001677 /* 1: we might have to print this header in debug mode */
1678 if (unlikely((global.mode & MODE_DEBUG) &&
1679 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001680 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001681 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001682
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001683 sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001684 eol = sol + msg->sl.rq.l;
1685 debug_hdr("clireq", t, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001686
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001687 sol += hdr_idx_first_pos(&txn->hdr_idx);
1688 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001689
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001690 while (cur_idx) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001691 eol = sol + txn->hdr_idx.v[cur_idx].len;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001692 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001693 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
1694 cur_idx = txn->hdr_idx.v[cur_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001695 }
1696 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001697
Willy Tarreau58f10d72006-12-04 02:26:12 +01001698
1699 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001700 * Now we quickly check if we have found a full valid request.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001701 * If not so, we check the FD and buffer states before leaving.
1702 * A full request is indicated by the fact that we have seen
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001703 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
1704 * requests are checked first.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001705 *
1706 */
1707
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001708 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001709 /*
1710 * First, let's catch bad requests.
1711 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001712 if (unlikely(msg->msg_state == HTTP_MSG_ERROR))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001713 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001714
1715 /* 1: Since we are in header mode, if there's no space
1716 * left for headers, we won't be able to free more
1717 * later, so the session will never terminate. We
1718 * must terminate it now.
1719 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001720 if (unlikely(req->l >= req->rlim - req->data)) {
1721 /* FIXME: check if URI is set and return Status
1722 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001723 */
Willy Tarreau06619262006-12-17 08:37:22 +01001724 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001725 }
1726
1727 /* 2: have we encountered a read error or a close ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001728 else if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1729 /* read error, or last read : give up. */
Willy Tarreau89edf5e2008-08-03 17:25:14 +02001730 buffer_shutr_done(req);
1731 buffer_shutw_done(rep);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001732 fd_delete(t->cli_fd);
1733 t->cli_state = CL_STCLOSE;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001734 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001735 if (!(t->flags & SN_ERR_MASK))
1736 t->flags |= SN_ERR_CLICL;
1737 if (!(t->flags & SN_FINST_MASK))
1738 t->flags |= SN_FINST_R;
1739 return 1;
1740 }
1741
1742 /* 3: has the read timeout expired ? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001743 else if (unlikely(tick_is_expired(req->rex, now_ms) ||
1744 tick_is_expired(txn->exp, now_ms))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001745 /* read timeout : give up with an error message. */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001746 txn->status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +01001747 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001748 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001749 if (!(t->flags & SN_ERR_MASK))
1750 t->flags |= SN_ERR_CLITO;
1751 if (!(t->flags & SN_FINST_MASK))
1752 t->flags |= SN_FINST_R;
1753 return 1;
1754 }
1755
1756 /* 4: do we need to re-enable the read socket ? */
Willy Tarreau66319382007-04-08 17:17:37 +02001757 else if (unlikely(EV_FD_COND_S(t->cli_fd, DIR_RD))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02001758 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreau58f10d72006-12-04 02:26:12 +01001759 * full. We cannot loop here since stream_sock_read will disable it only if
1760 * req->l == rlim-data
1761 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001762 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001763 }
1764 return t->cli_state != CL_STHEADERS;
1765 }
1766
1767
1768 /****************************************************************
1769 * More interesting part now : we know that we have a complete *
1770 * request which at least looks like HTTP. We have an indicator *
1771 * of each header's length, so we can parse them quickly. *
1772 ****************************************************************/
1773
Willy Tarreau9cdde232007-05-02 20:58:19 +02001774 /* ensure we keep this pointer to the beginning of the message */
1775 msg->sol = req->data + msg->som;
1776
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001777 /*
1778 * 1: identify the method
1779 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001780 txn->meth = find_http_meth(&req->data[msg->som], msg->sl.rq.m_l);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001781
1782 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001783 * 2: check if the URI matches the monitor_uri.
Willy Tarreau06619262006-12-17 08:37:22 +01001784 * We have to do this for every request which gets in, because
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001785 * the monitor-uri is defined by the frontend.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001786 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001787 if (unlikely((t->fe->monitor_uri_len != 0) &&
1788 (t->fe->monitor_uri_len == msg->sl.rq.u_l) &&
1789 !memcmp(&req->data[msg->sl.rq.u],
1790 t->fe->monitor_uri,
1791 t->fe->monitor_uri_len))) {
1792 /*
1793 * We have found the monitor URI
1794 */
Willy Tarreaub80c2302007-11-30 20:51:32 +01001795 struct acl_cond *cond;
1796 cur_proxy = t->fe;
1797
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001798 t->flags |= SN_MONITOR;
Willy Tarreaub80c2302007-11-30 20:51:32 +01001799
1800 /* Check if we want to fail this monitor request or not */
1801 list_for_each_entry(cond, &cur_proxy->mon_fail_cond, list) {
1802 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001803
1804 ret = acl_pass(ret);
Willy Tarreaub80c2302007-11-30 20:51:32 +01001805 if (cond->pol == ACL_COND_UNLESS)
1806 ret = !ret;
1807
1808 if (ret) {
1809 /* we fail this request, let's return 503 service unavail */
1810 txn->status = 503;
1811 client_retnclose(t, error_message(t, HTTP_ERR_503));
1812 goto return_prx_cond;
1813 }
1814 }
1815
1816 /* nothing to fail, let's reply normaly */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001817 txn->status = 200;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001818 client_retnclose(t, &http_200_chunk);
1819 goto return_prx_cond;
1820 }
1821
1822 /*
1823 * 3: Maybe we have to copy the original REQURI for the logs ?
1824 * Note: we cannot log anymore if the request has been
1825 * classified as invalid.
1826 */
1827 if (unlikely(t->logs.logwait & LW_REQ)) {
1828 /* we have a complete HTTP request that we must log */
Willy Tarreau332f8bf2007-05-13 21:36:56 +02001829 if ((txn->uri = pool_alloc2(pool2_requri)) != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001830 int urilen = msg->sl.rq.l;
1831
1832 if (urilen >= REQURI_LEN)
1833 urilen = REQURI_LEN - 1;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01001834 memcpy(txn->uri, &req->data[msg->som], urilen);
1835 txn->uri[urilen] = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001836
1837 if (!(t->logs.logwait &= ~LW_REQ))
Willy Tarreau42250582007-04-01 01:30:43 +02001838 http_sess_log(t);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001839 } else {
1840 Alert("HTTP logging : out of memory.\n");
1841 }
1842 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001843
Willy Tarreau06619262006-12-17 08:37:22 +01001844
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001845 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
1846 if (unlikely(msg->sl.rq.v_l == 0)) {
1847 int delta;
1848 char *cur_end;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001849 msg->sol = req->data + msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001850 cur_end = msg->sol + msg->sl.rq.l;
1851 delta = 0;
Willy Tarreau06619262006-12-17 08:37:22 +01001852
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001853 if (msg->sl.rq.u_l == 0) {
1854 /* if no URI was set, add "/" */
1855 delta = buffer_replace2(req, cur_end, cur_end, " /", 2);
1856 cur_end += delta;
1857 msg->eoh += delta;
Willy Tarreau06619262006-12-17 08:37:22 +01001858 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001859 /* add HTTP version */
1860 delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
1861 msg->eoh += delta;
1862 cur_end += delta;
1863 cur_end = (char *)http_parse_reqline(msg, req->data,
1864 HTTP_MSG_RQMETH,
1865 msg->sol, cur_end + 1,
1866 NULL, NULL);
1867 if (unlikely(!cur_end))
1868 goto return_bad_req;
1869
1870 /* we have a full HTTP/1.0 request now and we know that
1871 * we have either a CR or an LF at <ptr>.
1872 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01001873 hdr_idx_set_start(&txn->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
Willy Tarreau58f10d72006-12-04 02:26:12 +01001874 }
1875
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001876
1877 /* 5: we may need to capture headers */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001878 if (unlikely((t->logs.logwait & LW_REQHDR) && t->fe->req_cap))
Willy Tarreau117f59e2007-03-04 18:17:17 +01001879 capture_headers(req->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001880 txn->req.cap, t->fe->req_cap);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001881
1882 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001883 * 6: we will have to evaluate the filters.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001884 * As opposed to version 1.2, now they will be evaluated in the
1885 * filters order and not in the header order. This means that
1886 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001887 *
1888 * We can now check whether we want to switch to another
1889 * backend, in which case we will re-check the backend's
1890 * filters and various options. In order to support 3-level
1891 * switching, here's how we should proceed :
1892 *
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001893 * a) run be.
Willy Tarreau830ff452006-12-17 19:31:23 +01001894 * if (switch) then switch ->be to the new backend.
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001895 * b) run be if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001896 * There cannot be any switch from there, so ->be cannot be
1897 * changed anymore.
1898 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001899 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001900 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001901 * The response path will be able to apply either ->be, or
1902 * ->be then ->fe filters in order to match the reverse of
1903 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001904 */
1905
Willy Tarreau06619262006-12-17 08:37:22 +01001906 do {
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001907 struct acl_cond *cond;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001908 struct redirect_rule *rule;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02001909 struct proxy *rule_set = t->be;
Willy Tarreau830ff452006-12-17 19:31:23 +01001910 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001911
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001912 /* first check whether we have some ACLs set to redirect this request */
1913 list_for_each_entry(rule, &cur_proxy->redirect_rules, list) {
1914 int ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001915
1916 ret = acl_pass(ret);
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001917 if (rule->cond->pol == ACL_COND_UNLESS)
1918 ret = !ret;
1919
1920 if (ret) {
1921 struct chunk rdr = { trash, 0 };
1922 const char *msg_fmt;
1923
1924 /* build redirect message */
1925 switch(rule->code) {
1926 case 303:
1927 rdr.len = strlen(HTTP_303);
1928 msg_fmt = HTTP_303;
1929 break;
1930 case 301:
1931 rdr.len = strlen(HTTP_301);
1932 msg_fmt = HTTP_301;
1933 break;
1934 case 302:
1935 default:
1936 rdr.len = strlen(HTTP_302);
1937 msg_fmt = HTTP_302;
1938 break;
1939 }
1940
1941 if (unlikely(rdr.len > sizeof(trash)))
1942 goto return_bad_req;
1943 memcpy(rdr.str, msg_fmt, rdr.len);
1944
1945 switch(rule->type) {
1946 case REDIRECT_TYPE_PREFIX: {
1947 const char *path;
1948 int pathlen;
1949
1950 path = http_get_path(txn);
1951 /* build message using path */
1952 if (path) {
1953 pathlen = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
1954 } else {
1955 path = "/";
1956 pathlen = 1;
1957 }
1958
1959 if (rdr.len + rule->rdr_len + pathlen > sizeof(trash) - 4)
1960 goto return_bad_req;
1961
1962 /* add prefix */
1963 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1964 rdr.len += rule->rdr_len;
1965
1966 /* add path */
1967 memcpy(rdr.str + rdr.len, path, pathlen);
1968 rdr.len += pathlen;
1969 break;
1970 }
1971 case REDIRECT_TYPE_LOCATION:
1972 default:
1973 if (rdr.len + rule->rdr_len > sizeof(trash) - 4)
1974 goto return_bad_req;
1975
1976 /* add location */
1977 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
1978 rdr.len += rule->rdr_len;
1979 break;
1980 }
1981
1982 /* add end of headers */
1983 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
1984 rdr.len += 4;
1985
1986 txn->status = rule->code;
1987 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02001988 t->logs.tv_request = now;
Willy Tarreaub463dfb2008-06-07 23:08:56 +02001989 client_retnclose(t, &rdr);
1990 goto return_prx_cond;
1991 }
1992 }
1993
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001994 /* first check whether we have some ACLs set to block this request */
1995 list_for_each_entry(cond, &cur_proxy->block_cond, list) {
Willy Tarreaud41f8d82007-06-10 10:06:18 +02001996 int ret = acl_exec_cond(cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02001997
1998 ret = acl_pass(ret);
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02001999 if (cond->pol == ACL_COND_UNLESS)
2000 ret = !ret;
2001
2002 if (ret) {
2003 txn->status = 403;
2004 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02002005 t->logs.tv_request = now;
Willy Tarreau5c8e3e02007-05-07 00:58:25 +02002006 client_retnclose(t, error_message(t, HTTP_ERR_403));
2007 goto return_prx_cond;
2008 }
2009 }
2010
Willy Tarreau06619262006-12-17 08:37:22 +01002011 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01002012 if (rule_set->req_exp != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002013 if (apply_filters_to_request(t, req, rule_set->req_exp) < 0)
2014 goto return_bad_req;
Willy Tarreau53b6c742006-12-17 13:37:46 +01002015 }
2016
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002017 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
2018 /* to ensure correct connection accounting on
2019 * the backend, we count the connection for the
2020 * one managing the queue.
2021 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002022 t->be->beconn++;
2023 if (t->be->beconn > t->be->beconn_max)
2024 t->be->beconn_max = t->be->beconn;
2025 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002026 t->flags |= SN_BE_ASSIGNED;
2027 }
2028
Willy Tarreau06619262006-12-17 08:37:22 +01002029 /* has the request been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01002030 if (txn->flags & TX_CLDENY) {
Willy Tarreau06619262006-12-17 08:37:22 +01002031 /* no need to go further */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002032 txn->status = 403;
Willy Tarreau06619262006-12-17 08:37:22 +01002033 /* let's log the request time */
Willy Tarreau70089872008-06-13 21:12:51 +02002034 t->logs.tv_request = now;
Willy Tarreau80587432006-12-24 17:47:20 +01002035 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01002036 goto return_prx_cond;
2037 }
2038
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002039 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002040 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002041 !(t->flags & SN_CONN_CLOSED)) {
2042 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002043 int cur_idx, old_idx, delta, val;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002044 struct hdr_idx_elem *cur_hdr;
Willy Tarreau06619262006-12-17 08:37:22 +01002045
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002046 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002047 old_idx = 0;
2048
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002049 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
2050 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002051 cur_ptr = cur_next;
2052 cur_end = cur_ptr + cur_hdr->len;
2053 cur_next = cur_end + cur_hdr->cr + 1;
2054
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002055 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
2056 if (val) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002057 /* 3 possibilities :
2058 * - we have already set Connection: close,
2059 * so we remove this line.
2060 * - we have not yet set Connection: close,
2061 * but this line indicates close. We leave
2062 * it untouched and set the flag.
2063 * - we have not yet set Connection: close,
2064 * and this line indicates non-close. We
2065 * replace it.
2066 */
2067 if (t->flags & SN_CONN_CLOSED) {
2068 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002069 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002070 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002071 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
2072 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002073 cur_hdr->len = 0;
2074 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01002075 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
2076 delta = buffer_replace2(req, cur_ptr + val, cur_end,
2077 "close", 5);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002078 cur_next += delta;
2079 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002080 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002081 }
2082 t->flags |= SN_CONN_CLOSED;
2083 }
2084 }
2085 old_idx = cur_idx;
2086 }
Willy Tarreauf2f0ee82007-03-30 12:02:43 +02002087 }
2088 /* add request headers from the rule sets in the same order */
2089 for (cur_idx = 0; cur_idx < rule_set->nb_reqadd; cur_idx++) {
2090 if (unlikely(http_header_add_tail(req,
2091 &txn->req,
2092 &txn->hdr_idx,
2093 rule_set->req_add[cur_idx])) < 0)
2094 goto return_bad_req;
Willy Tarreau06619262006-12-17 08:37:22 +01002095 }
Willy Tarreaub2513902006-12-17 14:52:38 +01002096
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002097 /* check if stats URI was requested, and if an auth is needed */
Willy Tarreau0214c3a2007-01-07 13:47:30 +01002098 if (rule_set->uri_auth != NULL &&
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002099 (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)) {
Willy Tarreaub2513902006-12-17 14:52:38 +01002100 /* we have to check the URI and auth for this request */
2101 if (stats_check_uri_auth(t, rule_set))
2102 return 1;
2103 }
2104
Willy Tarreau55ea7572007-06-17 19:56:27 +02002105 /* now check whether we have some switching rules for this request */
2106 if (!(t->flags & SN_BE_ASSIGNED)) {
2107 struct switching_rule *rule;
2108
2109 list_for_each_entry(rule, &cur_proxy->switching_rules, list) {
2110 int ret;
2111
2112 ret = acl_exec_cond(rule->cond, cur_proxy, t, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02002113
2114 ret = acl_pass(ret);
Willy Tarreaua8cfa342008-07-09 11:23:31 +02002115 if (rule->cond->pol == ACL_COND_UNLESS)
Willy Tarreau55ea7572007-06-17 19:56:27 +02002116 ret = !ret;
2117
2118 if (ret) {
2119 t->be = rule->be.backend;
2120 t->be->beconn++;
2121 if (t->be->beconn > t->be->beconn_max)
2122 t->be->beconn_max = t->be->beconn;
2123 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002124
2125 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002126 t->rep->rto = t->req->wto = t->be->timeout.server;
2127 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002128 t->conn_retries = t->be->conn_retries;
Willy Tarreau55ea7572007-06-17 19:56:27 +02002129 t->flags |= SN_BE_ASSIGNED;
2130 break;
2131 }
2132 }
2133 }
2134
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002135 if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
2136 /* No backend was set, but there was a default
2137 * backend set in the frontend, so we use it and
2138 * loop again.
2139 */
2140 t->be = cur_proxy->defbe.be;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002141 t->be->beconn++;
2142 if (t->be->beconn > t->be->beconn_max)
2143 t->be->beconn_max = t->be->beconn;
2144 t->be->cum_beconn++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002145
2146 /* assign new parameters to the session from the new backend */
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002147 t->rep->rto = t->req->wto = t->be->timeout.server;
2148 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002149 t->conn_retries = t->be->conn_retries;
Willy Tarreau5fdfb912007-01-01 23:11:07 +01002150 t->flags |= SN_BE_ASSIGNED;
2151 }
2152 } while (t->be != cur_proxy); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01002153
Willy Tarreau58f10d72006-12-04 02:26:12 +01002154
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002155 if (!(t->flags & SN_BE_ASSIGNED)) {
2156 /* To ensure correct connection accounting on
2157 * the backend, we count the connection for the
2158 * one managing the queue.
2159 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002160 t->be->beconn++;
2161 if (t->be->beconn > t->be->beconn_max)
2162 t->be->beconn_max = t->be->beconn;
2163 t->be->cum_beconn++;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002164 t->flags |= SN_BE_ASSIGNED;
2165 }
2166
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002167 /*
2168 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01002169 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01002170 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01002171 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01002172 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01002173
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01002174 /*
2175 * If HTTP PROXY is set we simply get remote server address
2176 * parsing incoming request.
2177 */
2178 if ((t->be->options & PR_O_HTTP_PROXY) && !(t->flags & SN_ADDR_SET)) {
2179 url2sa(req->data + msg->sl.rq.u, msg->sl.rq.u_l, &t->srv_addr);
2180 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002181
Willy Tarreau2a324282006-12-05 00:05:46 +01002182 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002183 * 7: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01002184 * so let's do the same now.
2185 */
2186
2187 /* It needs to look into the URI */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002188 if (t->be->appsession_name) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01002189 get_srv_from_appsession(t, &req->data[msg->som], msg->sl.rq.l);
Willy Tarreau06619262006-12-17 08:37:22 +01002190 }
2191
2192
2193 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002194 * 8: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01002195 * Note that doing so might move headers in the request, but
2196 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01002197 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01002198 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01002199 if ((t->be->cookie_name || t->be->appsession_name || t->be->capture_name)
2200 && !(txn->flags & (TX_CLDENY|TX_CLTARPIT)))
Willy Tarreau2a324282006-12-05 00:05:46 +01002201 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01002202
Willy Tarreau58f10d72006-12-04 02:26:12 +01002203
Willy Tarreau2a324282006-12-05 00:05:46 +01002204 /*
Willy Tarreaubb046ac2007-03-03 19:17:03 +01002205 * 9: add X-Forwarded-For if either the frontend or the backend
2206 * asks for it.
Willy Tarreau2a324282006-12-05 00:05:46 +01002207 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002208 if ((t->fe->options | t->be->options) & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002209 if (t->cli_addr.ss_family == AF_INET) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002210 /* Add an X-Forwarded-For header unless the source IP is
2211 * in the 'except' network range.
2212 */
2213 if ((!t->fe->except_mask.s_addr ||
2214 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->fe->except_mask.s_addr)
2215 != t->fe->except_net.s_addr) &&
2216 (!t->be->except_mask.s_addr ||
2217 (((struct sockaddr_in *)&t->cli_addr)->sin_addr.s_addr & t->be->except_mask.s_addr)
2218 != t->be->except_net.s_addr)) {
2219 int len;
2220 unsigned char *pn;
2221 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
Willy Tarreau45e73e32006-12-17 00:05:15 +01002222
Ross Westaf72a1d2008-08-03 10:51:45 +02002223 /* Note: we rely on the backend to get the header name to be used for
2224 * x-forwarded-for, because the header is really meant for the backends.
2225 * However, if the backend did not specify any option, we have to rely
2226 * on the frontend's header name.
2227 */
2228 if (t->be->fwdfor_hdr_len) {
2229 len = t->be->fwdfor_hdr_len;
2230 memcpy(trash, t->be->fwdfor_hdr_name, len);
2231 } else {
2232 len = t->fe->fwdfor_hdr_len;
2233 memcpy(trash, t->fe->fwdfor_hdr_name, len);
2234 }
2235 len += sprintf(trash + len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002236
Ross Westaf72a1d2008-08-03 10:51:45 +02002237 if (unlikely(http_header_add_tail2(req, &txn->req,
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002238 &txn->hdr_idx, trash, len)) < 0)
2239 goto return_bad_req;
2240 }
Willy Tarreau2a324282006-12-05 00:05:46 +01002241 }
2242 else if (t->cli_addr.ss_family == AF_INET6) {
Willy Tarreau7ac51f62007-03-25 16:00:04 +02002243 /* FIXME: for the sake of completeness, we should also support
2244 * 'except' here, although it is mostly useless in this case.
2245 */
Willy Tarreau2a324282006-12-05 00:05:46 +01002246 int len;
2247 char pn[INET6_ADDRSTRLEN];
2248 inet_ntop(AF_INET6,
2249 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
2250 pn, sizeof(pn));
Ross Westaf72a1d2008-08-03 10:51:45 +02002251
2252 /* Note: we rely on the backend to get the header name to be used for
2253 * x-forwarded-for, because the header is really meant for the backends.
2254 * However, if the backend did not specify any option, we have to rely
2255 * on the frontend's header name.
2256 */
2257 if (t->be->fwdfor_hdr_len) {
2258 len = t->be->fwdfor_hdr_len;
2259 memcpy(trash, t->be->fwdfor_hdr_name, len);
2260 } else {
2261 len = t->fe->fwdfor_hdr_len;
2262 memcpy(trash, t->fe->fwdfor_hdr_name, len);
2263 }
2264 len += sprintf(trash + len, ": %s", pn);
2265
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002266 if (unlikely(http_header_add_tail2(req, &txn->req,
2267 &txn->hdr_idx, trash, len)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002268 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01002269 }
2270 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002271
Willy Tarreau2a324282006-12-05 00:05:46 +01002272 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002273 * 10: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02002274 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaub2513902006-12-17 14:52:38 +01002275 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02002276 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01002277 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02002278 if ((unlikely(msg->sl.rq.v_l != 8) ||
2279 unlikely(req->data[msg->som + msg->sl.rq.v + 7] != '0')) &&
2280 unlikely(http_header_add_tail2(req, &txn->req, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01002281 "Connection: close", 17)) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01002282 goto return_bad_req;
Willy Tarreaua15645d2007-03-18 16:22:39 +01002283 t->flags |= SN_CONN_CLOSED;
Willy Tarreaue15d9132006-12-14 22:26:42 +01002284 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002285 /* Before we switch to data, was assignment set in manage_client_side_cookie?
2286 * If not assigned, perhaps we are balancing on url_param, but this is a
2287 * POST; and the parameters are in the body, maybe scan there to find our server.
2288 * (unless headers overflowed the buffer?)
2289 */
2290 if (!(t->flags & (SN_ASSIGNED|SN_DIRECT)) &&
2291 t->txn.meth == HTTP_METH_POST && t->be->url_param_name != NULL &&
2292 t->be->url_param_post_limit != 0 && req->total < BUFSIZE &&
2293 memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) {
2294 /* are there enough bytes here? total == l || r || rlim ?
2295 * len is unsigned, but eoh is int,
2296 * how many bytes of body have we received?
2297 * eoh is the first empty line of the header
2298 */
2299 /* already established CRLF or LF at eoh, move to start of message, find message length in buffer */
2300 unsigned long len = req->total - (msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 : msg->eoh + 1);
2301
2302 /* If we have HTTP/1.1 and Expect: 100-continue, then abort.
2303 * We can't assume responsibility for the server's decision,
2304 * on this URI and header set. See rfc2616: 14.20, 8.2.3,
2305 * We also can't change our mind later, about which server to choose, so round robin.
2306 */
2307 if ((likely(msg->sl.rq.v_l == 8) && req->data[msg->som + msg->sl.rq.v + 7] == '1')) {
2308 struct hdr_ctx ctx;
2309 ctx.idx = 0;
2310 /* Expect is allowed in 1.1, look for it */
2311 http_find_header2("Expect", 6, msg->sol, &txn->hdr_idx, &ctx);
2312 if (ctx.idx != 0 &&
2313 unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val,"100-continue",12)==0))
2314 /* We can't reliablly stall and wait for data, because of
2315 * .NET clients that don't conform to rfc2616; so, no need for
2316 * the next block to check length expectations.
2317 * We could send 100 status back to the client, but then we need to
2318 * re-write headers, and send the message. And this isn't the right
2319 * place for that action.
2320 * TODO: support Expect elsewhere and delete this block.
2321 */
2322 goto end_check_maybe_wait_for_body;
2323 }
2324 if ( likely(len > t->be->url_param_post_limit) ) {
2325 /* nothing to do, we got enough */
2326 } else {
2327 /* limit implies we are supposed to need this many bytes
2328 * to find the parameter. Let's see how many bytes we can wait for.
2329 */
2330 long long hint = len;
2331 struct hdr_ctx ctx;
2332 ctx.idx = 0;
2333 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
2334 if (unlikely(ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",7)==0)) {
2335 t->srv_state = SV_STANALYZE;
2336 } else {
2337 ctx.idx = 0;
2338 http_find_header2("Content-Length", 14, msg->sol, &txn->hdr_idx, &ctx);
2339 /* now if we have a length, we'll take the hint */
2340 if ( ctx.idx ) {
2341 /* We have Content-Length */
2342 if ( strl2llrc(ctx.line+ctx.val,ctx.vlen, &hint) )
2343 hint = 0; /* parse failure, untrusted client */
2344 else {
2345 if ( hint > 0 )
2346 msg->hdr_content_len = hint;
2347 else
2348 hint = 0; /* bad client, sent negative length */
2349 }
2350 }
2351 /* but limited to what we care about, maybe we don't expect any entity data (hint == 0) */
2352 if ( t->be->url_param_post_limit < hint )
2353 hint = t->be->url_param_post_limit;
2354 /* now do we really need to buffer more data? */
2355 if ( len < hint )
2356 t->srv_state = SV_STANALYZE;
2357 /* else... There are no body bytes to wait for */
2358 }
2359 }
2360 }
2361 end_check_maybe_wait_for_body:
Willy Tarreaubaaee002006-06-26 02:48:02 +02002362
Willy Tarreau2a324282006-12-05 00:05:46 +01002363 /*************************************************************
2364 * OK, that's finished for the headers. We have done what we *
2365 * could. Let's switch to the DATA state. *
2366 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02002367
Willy Tarreau2a324282006-12-05 00:05:46 +01002368 t->cli_state = CL_STDATA;
2369 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002370
Willy Tarreau70089872008-06-13 21:12:51 +02002371 t->logs.tv_request = now;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002372
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002373 if (!t->fe->timeout.client ||
2374 (t->srv_state < SV_STDATA && t->be->timeout.server)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002375 /* If the client has no timeout, or if the server is not ready yet,
2376 * and we know for sure that it can expire, then it's cleaner to
2377 * disable the timeout on the client side so that too low values
2378 * cannot make the sessions abort too early.
2379 *
2380 * FIXME-20050705: the server needs a way to re-enable this time-out
2381 * when it switches its state, otherwise a client can stay connected
2382 * indefinitely. This now seems to be OK.
2383 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002384 req->rex = TICK_ETERNITY;
Willy Tarreau2a324282006-12-05 00:05:46 +01002385 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002386
Willy Tarreau1fa31262007-12-03 00:36:16 +01002387 /* When a connection is tarpitted, we use the tarpit timeout,
2388 * which may be the same as the connect timeout if unspecified.
2389 * If unset, then set it to zero because we really want it to
2390 * eventually expire.
Willy Tarreau2a324282006-12-05 00:05:46 +01002391 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002392 if (txn->flags & TX_CLTARPIT) {
Willy Tarreau2a324282006-12-05 00:05:46 +01002393 t->req->l = 0;
2394 /* flush the request so that we can drop the connection early
2395 * if the client closes first.
2396 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002397 req->cex = tick_add_ifset(now_ms, t->be->timeout.tarpit);
2398 if (!req->cex)
2399 req->cex = now_ms;
Willy Tarreau2a324282006-12-05 00:05:46 +01002400 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002401
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002402 /* OK let's go on with the BODY now */
Willy Tarreau06619262006-12-17 08:37:22 +01002403 goto process_data;
2404
2405 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01002406 txn->req.msg_state = HTTP_MSG_ERROR;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01002407 txn->status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01002408 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002409 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01002410 return_prx_cond:
2411 if (!(t->flags & SN_ERR_MASK))
2412 t->flags |= SN_ERR_PRXCOND;
2413 if (!(t->flags & SN_FINST_MASK))
2414 t->flags |= SN_FINST_R;
2415 return 1;
2416
Willy Tarreaubaaee002006-06-26 02:48:02 +02002417 }
2418 else if (c == CL_STDATA) {
2419 process_data:
2420 /* FIXME: this error handling is partly buggy because we always report
2421 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
2422 * or HEADER phase. BTW, it's not logical to expire the client while
2423 * we're waiting for the server to connect.
2424 */
2425 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002426 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002427 buffer_shutr_done(req);
2428 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002429 fd_delete(t->cli_fd);
2430 t->cli_state = CL_STCLOSE;
2431 if (!(t->flags & SN_ERR_MASK))
2432 t->flags |= SN_ERR_CLICL;
2433 if (!(t->flags & SN_FINST_MASK)) {
2434 if (t->pend_pos)
2435 t->flags |= SN_FINST_Q;
2436 else if (s == SV_STCONN)
2437 t->flags |= SN_FINST_C;
2438 else
2439 t->flags |= SN_FINST_D;
2440 }
2441 return 1;
2442 }
2443 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002444 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002445 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002446 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002447 t->cli_state = CL_STSHUTR;
2448 return 1;
2449 }
2450 /* last server read and buffer empty */
2451 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002452 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002453 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002454 shutdown(t->cli_fd, SHUT_WR);
2455 /* We must ensure that the read part is still alive when switching
2456 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002457 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002458 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002459 t->cli_state = CL_STSHUTW;
2460 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2461 return 1;
2462 }
2463 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002464 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002465 EV_FD_CLR(t->cli_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02002466 buffer_shutr(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002467 t->cli_state = CL_STSHUTR;
2468 if (!(t->flags & SN_ERR_MASK))
2469 t->flags |= SN_ERR_CLITO;
2470 if (!(t->flags & SN_FINST_MASK)) {
2471 if (t->pend_pos)
2472 t->flags |= SN_FINST_Q;
2473 else if (s == SV_STCONN)
2474 t->flags |= SN_FINST_C;
2475 else
2476 t->flags |= SN_FINST_D;
2477 }
2478 return 1;
2479 }
2480 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002481 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02002482 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002483 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002484 shutdown(t->cli_fd, SHUT_WR);
2485 /* We must ensure that the read part is still alive when switching
2486 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02002487 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002488 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002489
2490 t->cli_state = CL_STSHUTW;
2491 if (!(t->flags & SN_ERR_MASK))
2492 t->flags |= SN_ERR_CLITO;
2493 if (!(t->flags & SN_FINST_MASK)) {
2494 if (t->pend_pos)
2495 t->flags |= SN_FINST_Q;
2496 else if (s == SV_STCONN)
2497 t->flags |= SN_FINST_C;
2498 else
2499 t->flags |= SN_FINST_D;
2500 }
2501 return 1;
2502 }
2503
2504 if (req->l >= req->rlim - req->data) {
2505 /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02002506 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002507 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002508 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002509 }
2510 } else {
2511 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002512 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002513 if (!t->fe->timeout.client ||
2514 (t->srv_state < SV_STDATA && t->be->timeout.server))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002515 /* If the client has no timeout, or if the server not ready yet, and we
2516 * know for sure that it can expire, then it's cleaner to disable the
2517 * timeout on the client side so that too low values cannot make the
2518 * sessions abort too early.
2519 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002520 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002521 else
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002522 req->rex = tick_add(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002523 }
2524 }
2525
2526 if ((rep->l == 0) ||
2527 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002528 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2529 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002530 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002531 }
2532 } else {
2533 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002534 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2535 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002536 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
2537 if (rep->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002538 /* FIXME: to prevent the client from expiring read timeouts during writes,
2539 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002540 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002541 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002542 }
2543 }
2544 return 0; /* other cases change nothing */
2545 }
2546 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002547 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002548 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002549 fd_delete(t->cli_fd);
2550 t->cli_state = CL_STCLOSE;
2551 if (!(t->flags & SN_ERR_MASK))
2552 t->flags |= SN_ERR_CLICL;
2553 if (!(t->flags & SN_FINST_MASK)) {
2554 if (t->pend_pos)
2555 t->flags |= SN_FINST_Q;
2556 else if (s == SV_STCONN)
2557 t->flags |= SN_FINST_C;
2558 else
2559 t->flags |= SN_FINST_D;
2560 }
2561 return 1;
2562 }
2563 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
2564 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002565 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002566 fd_delete(t->cli_fd);
2567 t->cli_state = CL_STCLOSE;
2568 return 1;
2569 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002570 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002571 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002572 fd_delete(t->cli_fd);
2573 t->cli_state = CL_STCLOSE;
2574 if (!(t->flags & SN_ERR_MASK))
2575 t->flags |= SN_ERR_CLITO;
2576 if (!(t->flags & SN_FINST_MASK)) {
2577 if (t->pend_pos)
2578 t->flags |= SN_FINST_Q;
2579 else if (s == SV_STCONN)
2580 t->flags |= SN_FINST_C;
2581 else
2582 t->flags |= SN_FINST_D;
2583 }
2584 return 1;
2585 }
2586
2587 if (t->flags & SN_SELF_GEN) {
2588 produce_content(t);
2589 if (rep->l == 0) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002590 buffer_shutw_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002591 fd_delete(t->cli_fd);
2592 t->cli_state = CL_STCLOSE;
2593 return 1;
2594 }
2595 }
2596
2597 if ((rep->l == 0)
2598 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau66319382007-04-08 17:17:37 +02002599 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
2600 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002601 rep->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002602 }
2603 } else {
2604 /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02002605 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
2606 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002607 rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002608 }
2609 }
2610 return 0;
2611 }
2612 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002613 if (req->flags & BF_READ_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002614 buffer_shutr_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002615 fd_delete(t->cli_fd);
2616 t->cli_state = CL_STCLOSE;
2617 if (!(t->flags & SN_ERR_MASK))
2618 t->flags |= SN_ERR_CLICL;
2619 if (!(t->flags & SN_FINST_MASK)) {
2620 if (t->pend_pos)
2621 t->flags |= SN_FINST_Q;
2622 else if (s == SV_STCONN)
2623 t->flags |= SN_FINST_C;
2624 else
2625 t->flags |= SN_FINST_D;
2626 }
2627 return 1;
2628 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002629 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002630 buffer_shutr_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002631 fd_delete(t->cli_fd);
2632 t->cli_state = CL_STCLOSE;
2633 return 1;
2634 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002635 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02002636 buffer_shutr_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002637 fd_delete(t->cli_fd);
2638 t->cli_state = CL_STCLOSE;
2639 if (!(t->flags & SN_ERR_MASK))
2640 t->flags |= SN_ERR_CLITO;
2641 if (!(t->flags & SN_FINST_MASK)) {
2642 if (t->pend_pos)
2643 t->flags |= SN_FINST_Q;
2644 else if (s == SV_STCONN)
2645 t->flags |= SN_FINST_C;
2646 else
2647 t->flags |= SN_FINST_D;
2648 }
2649 return 1;
2650 }
2651 else if (req->l >= req->rlim - req->data) {
2652 /* no room to read more data */
2653
2654 /* FIXME-20050705: is it possible for a client to maintain a session
2655 * after the timeout by sending more data after it receives a close ?
2656 */
2657
Willy Tarreau66319382007-04-08 17:17:37 +02002658 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002659 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002660 req->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002661 }
2662 } else {
2663 /* there's still some space in the buffer */
Willy Tarreau66319382007-04-08 17:17:37 +02002664 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002665 req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002666 }
2667 }
2668 return 0;
2669 }
2670 else { /* CL_STCLOSE: nothing to do */
2671 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2672 int len;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002673 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 +02002674 write(1, trash, len);
2675 }
2676 return 0;
2677 }
2678 return 0;
2679}
2680
2681
2682/*
2683 * manages the server FSM and its socket. It returns 1 if a state has changed
2684 * (and a resync may be needed), 0 else.
2685 */
2686int process_srv(struct session *t)
2687{
2688 int s = t->srv_state;
2689 int c = t->cli_state;
Willy Tarreau3d300592007-03-18 18:34:41 +01002690 struct http_txn *txn = &t->txn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002691 struct buffer *req = t->req;
2692 struct buffer *rep = t->rep;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002693 int conn_err;
2694
2695#ifdef DEBUG_FULL
2696 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
2697#endif
Willy Tarreauee991362007-05-14 14:37:50 +02002698
2699#if 0
2700 fprintf(stderr,"%s:%d fe->clito=%d.%d, fe->conto=%d.%d, fe->srvto=%d.%d\n",
2701 __FUNCTION__, __LINE__,
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002702 t->fe->timeout.client.tv_sec, t->fe->timeout.client.tv_usec,
2703 t->fe->timeout.connect.tv_sec, t->fe->timeout.connect.tv_usec,
2704 t->fe->timeout.server.tv_sec, t->fe->timeout.server.tv_usec);
Willy Tarreauee991362007-05-14 14:37:50 +02002705 fprintf(stderr,"%s:%d be->clito=%d.%d, be->conto=%d.%d, be->srvto=%d.%d\n",
2706 __FUNCTION__, __LINE__,
Willy Tarreaud7c30f92007-12-03 01:38:36 +01002707 t->be->timeout.client.tv_sec, t->be->timeout.client.tv_usec,
2708 t->be->timeout.connect.tv_sec, t->be->timeout.connect.tv_usec,
2709 t->be->timeout.server.tv_sec, t->be->timeout.server.tv_usec);
Willy Tarreauee991362007-05-14 14:37:50 +02002710
2711 fprintf(stderr,"%s:%d req->cto=%d.%d, req->rto=%d.%d, req->wto=%d.%d\n",
2712 __FUNCTION__, __LINE__,
2713 req->cto.tv_sec, req->cto.tv_usec,
2714 req->rto.tv_sec, req->rto.tv_usec,
2715 req->wto.tv_sec, req->wto.tv_usec);
2716
2717 fprintf(stderr,"%s:%d rep->cto=%d.%d, rep->rto=%d.%d, rep->wto=%d.%d\n",
2718 __FUNCTION__, __LINE__,
2719 rep->cto.tv_sec, rep->cto.tv_usec,
2720 rep->rto.tv_sec, rep->rto.tv_usec,
2721 rep->wto.tv_sec, rep->wto.tv_usec);
2722#endif
2723
Willy Tarreaubaaee002006-06-26 02:48:02 +02002724 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
Willy Tarreauf161a342007-04-08 16:59:42 +02002725 //EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
2726 //EV_FD_ISSET(t->srv_fd, DIR_RD), EV_FD_ISSET(t->srv_fd, DIR_WR)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002727 //);
2728 if (s == SV_STIDLE) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02002729 /* NOTE: The client processor may switch to SV_STANALYZE, which switches back SV_STIDLE.
2730 * This is logcially after CL_STHEADERS completed, CL_STDATA has started, but
2731 * we need to defer server selection until more data arrives, if possible.
2732 * This is rare, and only if balancing on parameter hash with values in the entity of a POST
2733 */
Willy Tarreaub6866442008-07-14 23:54:42 +02002734 if (c == CL_STHEADERS || c == CL_STINSPECT)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002735 return 0; /* stay in idle, waiting for data to reach the client side */
2736 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
2737 (c == CL_STSHUTR &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002738 (t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002739 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002740 if (t->pend_pos)
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002741 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002742 /* note that this must not return any error because it would be able to
2743 * overwrite the client_retnclose() output.
2744 */
Willy Tarreau3d300592007-03-18 18:34:41 +01002745 if (txn->flags & TX_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01002746 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02002747 else
Willy Tarreau0f772532006-12-23 20:51:41 +01002748 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002749
2750 return 1;
2751 }
2752 else {
Willy Tarreau3d300592007-03-18 18:34:41 +01002753 if (txn->flags & TX_CLTARPIT) {
Willy Tarreaub8750a82006-09-03 09:56:00 +02002754 /* This connection is being tarpitted. The CLIENT side has
2755 * already set the connect expiration date to the right
2756 * timeout. We just have to check that it has not expired.
2757 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002758 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreaub8750a82006-09-03 09:56:00 +02002759 return 0;
2760
2761 /* We will set the queue timer to the time spent, just for
2762 * logging purposes. We fake a 500 server error, so that the
2763 * attacker will not suspect his connection has been tarpitted.
2764 * It will not cause trouble to the logs because we can exclude
2765 * the tarpitted connections by filtering on the 'PT' status flags.
2766 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002767 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002768 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaub8750a82006-09-03 09:56:00 +02002769 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01002770 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02002771 return 1;
2772 }
2773
Willy Tarreaubaaee002006-06-26 02:48:02 +02002774 /* Right now, we will need to create a connection to the server.
2775 * We might already have tried, and got a connection pending, in
2776 * which case we will not do anything till it's pending. It's up
2777 * to any other session to release it and wake us up again.
2778 */
2779 if (t->pend_pos) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002780 if (!tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002781 return 0;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002782 } else {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002783 /* we've been waiting too long here */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002784 req->cex = TICK_ETERNITY;
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002785 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002786 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01002787 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002788 if (t->srv)
2789 t->srv->failed_conns++;
Willy Tarreau50fd1e12007-12-10 15:25:35 +01002790 t->be->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002791 return 1;
2792 }
2793 }
2794
2795 do {
2796 /* first, get a connection */
Willy Tarreau21d2af32008-02-14 20:25:24 +01002797 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
2798 t->flags |= SN_REDIRECTABLE;
2799
Willy Tarreaubaaee002006-06-26 02:48:02 +02002800 if (srv_redispatch_connect(t))
2801 return t->srv_state != SV_STIDLE;
2802
Willy Tarreau21d2af32008-02-14 20:25:24 +01002803 if ((t->flags & SN_REDIRECTABLE) && t->srv && t->srv->rdr_len) {
2804 /* Server supporting redirection and it is possible.
2805 * Invalid requests are reported as such. It concerns all
2806 * the largest ones.
2807 */
2808 struct chunk rdr;
2809 char *path;
2810 int len;
2811
2812 /* 1: create the response header */
2813 rdr.len = strlen(HTTP_302);
2814 rdr.str = trash;
2815 memcpy(rdr.str, HTTP_302, rdr.len);
2816
2817 /* 2: add the server's prefix */
2818 if (rdr.len + t->srv->rdr_len > sizeof(trash))
2819 goto cancel_redir;
2820
2821 memcpy(rdr.str + rdr.len, t->srv->rdr_pfx, t->srv->rdr_len);
2822 rdr.len += t->srv->rdr_len;
2823
2824 /* 3: add the request URI */
2825 path = http_get_path(txn);
2826 if (!path)
2827 goto cancel_redir;
2828 len = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
2829 if (rdr.len + len > sizeof(trash) - 4) /* 4 for CRLF-CRLF */
2830 goto cancel_redir;
2831
2832 memcpy(rdr.str + rdr.len, path, len);
2833 rdr.len += len;
2834 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
2835 rdr.len += 4;
2836
2837 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C, 302, &rdr);
2838 /* FIXME: we should increase a counter of redirects per server and per backend. */
2839 if (t->srv)
2840 t->srv->cum_sess++;
2841 return 1;
2842 cancel_redir:
2843 txn->status = 400;
2844 t->fe->failed_req++;
2845 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C,
2846 400, error_message(t, HTTP_ERR_400));
2847 return 1;
2848 }
2849
Willy Tarreaubaaee002006-06-26 02:48:02 +02002850 /* try to (re-)connect to the server, and fail if we expire the
2851 * number of retries.
2852 */
2853 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002854 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002855 return t->srv_state != SV_STIDLE;
2856 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002857 } while (1);
2858 }
2859 }
2860 else if (s == SV_STCONN) { /* connection in progress */
2861 if (c == CL_STCLOSE || c == CL_STSHUTW ||
2862 (c == CL_STSHUTR &&
Willy Tarreauc9b654b2007-05-08 14:46:53 +02002863 ((t->req->l == 0 && !(req->flags & BF_WRITE_STATUS)) ||
2864 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002865 req->cex = TICK_ETERNITY;
Willy Tarreauf899b942008-03-28 18:09:38 +01002866 if (!(t->flags & SN_CONN_TAR)) {
2867 /* if we are in turn-around, we have already closed the FD */
2868 fd_delete(t->srv_fd);
2869 if (t->srv) {
2870 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002871 sess_change_server(t, NULL);
Willy Tarreauf899b942008-03-28 18:09:38 +01002872 }
Willy Tarreau51406232008-03-10 22:04:20 +01002873 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002874
2875 /* note that this must not return any error because it would be able to
2876 * overwrite the client_retnclose() output.
2877 */
Willy Tarreau0f772532006-12-23 20:51:41 +01002878 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002879 return 1;
2880 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002881 if (!(req->flags & BF_WRITE_STATUS) && !tick_is_expired(req->cex, now_ms)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002882 return 0; /* nothing changed */
2883 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002884 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002885 /* timeout, asynchronous connect error or first write error */
2886 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2887
Willy Tarreau541b5c22008-01-06 23:34:21 +01002888 if (t->flags & SN_CONN_TAR) {
2889 /* We are doing a turn-around waiting for a new connection attempt. */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002890 if (!tick_is_expired(req->cex, now_ms))
Willy Tarreau541b5c22008-01-06 23:34:21 +01002891 return 0;
2892 t->flags &= ~SN_CONN_TAR;
2893 }
2894 else {
2895 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01002896 if (t->srv) {
Willy Tarreau541b5c22008-01-06 23:34:21 +01002897 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02002898 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01002899 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002900
Willy Tarreau541b5c22008-01-06 23:34:21 +01002901 if (!(req->flags & BF_WRITE_STATUS))
2902 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
2903 else
2904 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
2905
2906 /* ensure that we have enough retries left */
2907 if (srv_count_retry_down(t, conn_err))
2908 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002909
Willy Tarreau541b5c22008-01-06 23:34:21 +01002910 if (req->flags & BF_WRITE_ERROR) {
2911 /* we encountered an immediate connection error, and we
2912 * will have to retry connecting to the same server, most
2913 * likely leading to the same result. To avoid this, we
2914 * fake a connection timeout to retry after a turn-around
2915 * time of 1 second. We will wait in the previous if block.
2916 */
2917 t->flags |= SN_CONN_TAR;
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002918 req->cex = tick_add(now_ms, MS_TO_TICKS(1000));
Willy Tarreau541b5c22008-01-06 23:34:21 +01002919 return 0;
2920 }
2921 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002922
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002923 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002924 /* We're on our last chance, and the REDISP option was specified.
2925 * We will ignore cookie and force to balance or use the dispatcher.
2926 */
2927 /* let's try to offer this slot to anybody */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002928 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02002929 process_srv_queue(t->srv);
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002930
Krzysztof Piotr Oledzki5a329cf2008-02-22 03:50:19 +01002931 /* it's left to the dispatcher to choose a server */
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002932 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
Willy Tarreau7c669d72008-06-20 15:04:11 +02002933 t->prev_srv = t->srv;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002934
2935 /* first, get a connection */
2936 if (srv_redispatch_connect(t))
Willy Tarreau00559e72008-01-06 23:46:19 +01002937 return t->srv_state != SV_STCONN;
Krzysztof Piotr Oledzki626a19b2008-02-04 02:10:09 +01002938 } else {
2939 if (t->srv)
2940 t->srv->retries++;
2941 t->be->retries++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002942 }
2943
Willy Tarreaubaaee002006-06-26 02:48:02 +02002944 do {
2945 /* Now we will try to either reconnect to the same server or
2946 * connect to another server. If the connection gets queued
2947 * because all servers are saturated, then we will go back to
2948 * the SV_STIDLE state.
2949 */
2950 if (srv_retryable_connect(t)) {
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002951 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002952 return t->srv_state != SV_STCONN;
2953 }
2954
2955 /* we need to redispatch the connection to another server */
2956 if (srv_redispatch_connect(t))
2957 return t->srv_state != SV_STCONN;
2958 } while (1);
2959 }
2960 else { /* no error or write 0 */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02002961 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002962
2963 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2964 if (req->l == 0) /* nothing to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002965 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002966 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002967 } else /* need the right to write */ {
Willy Tarreauf161a342007-04-08 16:59:42 +02002968 EV_FD_SET(t->srv_fd, DIR_WR);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002969 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
2970 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002971 /* FIXME: to prevent the server from expiring read timeouts during writes,
2972 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002973 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002974 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002975 }
2976
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002977 if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreauf161a342007-04-08 16:59:42 +02002978 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02002979 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002980 t->srv_state = SV_STDATA;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002981 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
2982
2983 /* if the user wants to log as soon as possible, without counting
2984 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002985 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002986 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
Willy Tarreau42250582007-04-01 01:30:43 +02002987 tcp_sess_log(t);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002988 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002989#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02002990 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002991 /* TCP splicing supported by both FE and BE */
2992 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2993 }
2994#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002995 }
2996 else {
2997 t->srv_state = SV_STHEADERS;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002998 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
Willy Tarreaua15645d2007-03-18 16:22:39 +01002999 t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
3000 /* reset hdr_idx which was already initialized by the request.
3001 * right now, the http parser does it.
3002 * hdr_idx_init(&t->txn.hdr_idx);
3003 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003004 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003005 req->cex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003006 return 1;
3007 }
3008 }
3009 else if (s == SV_STHEADERS) { /* receiving server headers */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003010 /*
3011 * Now parse the partial (or complete) lines.
3012 * We will check the response syntax, and also join multi-line
3013 * headers. An index of all the lines will be elaborated while
3014 * parsing.
3015 *
3016 * For the parsing, we use a 28 states FSM.
3017 *
3018 * Here is the information we currently have :
3019 * rep->data + req->som = beginning of response
3020 * rep->data + req->eoh = end of processed headers / start of current one
3021 * rep->data + req->eol = end of current header or line (LF or CRLF)
3022 * rep->lr = first non-visited byte
3023 * rep->r = end of data
3024 */
3025
3026 int cur_idx;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003027 struct http_msg *msg = &txn->rsp;
3028 struct proxy *cur_proxy;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003029
Willy Tarreaua15645d2007-03-18 16:22:39 +01003030 if (likely(rep->lr < rep->r))
3031 http_msg_analyzer(rep, msg, &txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003032
Willy Tarreaua15645d2007-03-18 16:22:39 +01003033 /* 1: we might have to print this header in debug mode */
3034 if (unlikely((global.mode & MODE_DEBUG) &&
3035 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
3036 (msg->msg_state == HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
3037 char *eol, *sol;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003038
Willy Tarreaua15645d2007-03-18 16:22:39 +01003039 sol = rep->data + msg->som;
3040 eol = sol + msg->sl.rq.l;
3041 debug_hdr("srvrep", t, sol, eol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003042
Willy Tarreaua15645d2007-03-18 16:22:39 +01003043 sol += hdr_idx_first_pos(&txn->hdr_idx);
3044 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003045
Willy Tarreaua15645d2007-03-18 16:22:39 +01003046 while (cur_idx) {
3047 eol = sol + txn->hdr_idx.v[cur_idx].len;
3048 debug_hdr("srvhdr", t, sol, eol);
3049 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
3050 cur_idx = txn->hdr_idx.v[cur_idx].next;
3051 }
3052 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003053
Willy Tarreaubaaee002006-06-26 02:48:02 +02003054
Willy Tarreau66319382007-04-08 17:17:37 +02003055 if ((rep->l < rep->rlim - rep->data) && EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003056 /* fd in DIR_RD was disabled, perhaps because of a previous buffer
Willy Tarreaua15645d2007-03-18 16:22:39 +01003057 * full. We cannot loop here since stream_sock_read will disable it only if
3058 * rep->l == rlim-data
3059 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003060 req->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003061 }
3062
3063
3064 /*
3065 * Now we quickly check if we have found a full valid response.
3066 * If not so, we check the FD and buffer states before leaving.
3067 * A full response is indicated by the fact that we have seen
3068 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
3069 * responses are checked first.
3070 *
3071 * Depending on whether the client is still there or not, we
3072 * may send an error response back or not. Note that normally
3073 * we should only check for HTTP status there, and check I/O
3074 * errors somewhere else.
3075 */
3076
3077 if (unlikely(msg->msg_state != HTTP_MSG_BODY)) {
3078
3079 /* Invalid response, or read error or write error */
3080 if (unlikely((msg->msg_state == HTTP_MSG_ERROR) ||
3081 (req->flags & BF_WRITE_ERROR) ||
3082 (rep->flags & BF_READ_ERROR))) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003083 buffer_shutr_done(rep);
3084 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003085 fd_delete(t->srv_fd);
3086 if (t->srv) {
3087 t->srv->cur_sess--;
3088 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003089 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003090 }
3091 t->be->failed_resp++;
3092 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003093 txn->status = 502;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003094 client_return(t, error_message(t, HTTP_ERR_502));
3095 if (!(t->flags & SN_ERR_MASK))
3096 t->flags |= SN_ERR_SRVCL;
3097 if (!(t->flags & SN_FINST_MASK))
3098 t->flags |= SN_FINST_H;
3099 /* We used to have a free connection slot. Since we'll never use it,
3100 * we have to inform the server that it may be used by another session.
3101 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003102 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003103 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003104
Willy Tarreaua15645d2007-03-18 16:22:39 +01003105 return 1;
3106 }
3107
3108 /* end of client write or end of server read.
3109 * since we are in header mode, if there's no space left for headers, we
3110 * won't be able to free more later, so the session will never terminate.
3111 */
3112 else if (unlikely(rep->flags & BF_READ_NULL ||
3113 c == CL_STSHUTW || c == CL_STCLOSE ||
3114 rep->l >= rep->rlim - rep->data)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003115 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003116 buffer_shutr_done(rep);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003117 t->srv_state = SV_STSHUTR;
3118 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3119 return 1;
3120 }
3121
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003122 /* read timeout : return a 504 to the client. */
Willy Tarreauf161a342007-04-08 16:59:42 +02003123 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_RD) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003124 tick_is_expired(rep->rex, now_ms))) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003125 buffer_shutr_done(rep);
3126 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003127 fd_delete(t->srv_fd);
3128 if (t->srv) {
3129 t->srv->cur_sess--;
3130 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003131 sess_change_server(t, NULL);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003132 }
3133 t->be->failed_resp++;
3134 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003135 txn->status = 504;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003136 client_return(t, error_message(t, HTTP_ERR_504));
3137 if (!(t->flags & SN_ERR_MASK))
3138 t->flags |= SN_ERR_SRVTO;
3139 if (!(t->flags & SN_FINST_MASK))
3140 t->flags |= SN_FINST_H;
3141 /* We used to have a free connection slot. Since we'll never use it,
3142 * we have to inform the server that it may be used by another session.
3143 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003144 if (t->srv && may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003145 process_srv_queue(t->srv);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003146 return 1;
3147 }
3148
3149 /* last client read and buffer empty */
3150 /* FIXME!!! here, we don't want to switch to SHUTW if the
3151 * client shuts read too early, because we may still have
3152 * some work to do on the headers.
3153 * The side-effect is that if the client completely closes its
3154 * connection during SV_STHEADER, the connection to the server
3155 * is kept until a response comes back or the timeout is reached.
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003156 * FIXME!!! this code can never be called because the condition is
3157 * caught earlier (CL_STCLOSE).
Willy Tarreaua15645d2007-03-18 16:22:39 +01003158 */
3159 else if (unlikely((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) &&
3160 (req->l == 0))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003161 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003162 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003163
3164 /* We must ensure that the read part is still
3165 * alive when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003166 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003167 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003168
3169 shutdown(t->srv_fd, SHUT_WR);
3170 t->srv_state = SV_STSHUTW;
3171 return 1;
3172 }
3173
3174 /* write timeout */
3175 /* FIXME!!! here, we don't want to switch to SHUTW if the
3176 * client shuts read too early, because we may still have
3177 * some work to do on the headers.
3178 */
Willy Tarreauf161a342007-04-08 16:59:42 +02003179 else if (unlikely(EV_FD_ISSET(t->srv_fd, DIR_WR) &&
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003180 tick_is_expired(req->wex, now_ms))) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003181 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003182 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003183 shutdown(t->srv_fd, SHUT_WR);
3184 /* We must ensure that the read part is still alive
3185 * when switching to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003186 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003187 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003188
3189 t->srv_state = SV_STSHUTW;
3190 if (!(t->flags & SN_ERR_MASK))
3191 t->flags |= SN_ERR_SRVTO;
3192 if (!(t->flags & SN_FINST_MASK))
3193 t->flags |= SN_FINST_H;
3194 return 1;
3195 }
3196
3197 /*
3198 * And now the non-error cases.
3199 */
3200
3201 /* Data remaining in the request buffer.
3202 * This happens during the first pass here, and during
3203 * long posts.
3204 */
3205 else if (likely(req->l)) {
Willy Tarreau66319382007-04-08 17:17:37 +02003206 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3207 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003208 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3209 if (req->wex) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003210 /* FIXME: to prevent the server from expiring read timeouts during writes,
3211 * we refresh it. */
3212 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003213 }
3214 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003215 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003216
Willy Tarreaua15645d2007-03-18 16:22:39 +01003217 /* nothing left in the request buffer */
3218 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003219 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3220 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003221 req->wex = TICK_ETERNITY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003222 }
3223 }
3224
3225 return t->srv_state != SV_STHEADERS;
3226 }
3227
3228
3229 /*****************************************************************
3230 * More interesting part now : we know that we have a complete *
3231 * response which at least looks like HTTP. We have an indicator *
3232 * of each header's length, so we can parse them quickly. *
3233 ****************************************************************/
3234
Willy Tarreau9cdde232007-05-02 20:58:19 +02003235 /* ensure we keep this pointer to the beginning of the message */
3236 msg->sol = rep->data + msg->som;
3237
Willy Tarreaua15645d2007-03-18 16:22:39 +01003238 /*
3239 * 1: get the status code and check for cacheability.
3240 */
3241
3242 t->logs.logwait &= ~LW_RESP;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003243 txn->status = strl2ui(rep->data + msg->sl.st.c, msg->sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003244
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003245 switch (txn->status) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003246 case 200:
3247 case 203:
3248 case 206:
3249 case 300:
3250 case 301:
3251 case 410:
3252 /* RFC2616 @13.4:
3253 * "A response received with a status code of
3254 * 200, 203, 206, 300, 301 or 410 MAY be stored
3255 * by a cache (...) unless a cache-control
3256 * directive prohibits caching."
3257 *
3258 * RFC2616 @9.5: POST method :
3259 * "Responses to this method are not cacheable,
3260 * unless the response includes appropriate
3261 * Cache-Control or Expires header fields."
3262 */
3263 if (likely(txn->meth != HTTP_METH_POST) &&
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003264 (t->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
Willy Tarreau3d300592007-03-18 18:34:41 +01003265 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003266 break;
3267 default:
3268 break;
3269 }
3270
3271 /*
3272 * 2: we may need to capture headers
3273 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003274 if (unlikely((t->logs.logwait & LW_RSPHDR) && t->fe->rsp_cap))
Willy Tarreaua15645d2007-03-18 16:22:39 +01003275 capture_headers(rep->data + msg->som, &txn->hdr_idx,
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003276 txn->rsp.cap, t->fe->rsp_cap);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003277
3278 /*
3279 * 3: we will have to evaluate the filters.
3280 * As opposed to version 1.2, now they will be evaluated in the
3281 * filters order and not in the header order. This means that
3282 * each filter has to be validated among all headers.
3283 *
3284 * Filters are tried with ->be first, then with ->fe if it is
3285 * different from ->be.
3286 */
3287
3288 t->flags &= ~SN_CONN_CLOSED; /* prepare for inspection */
3289
3290 cur_proxy = t->be;
3291 while (1) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003292 struct proxy *rule_set = cur_proxy;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003293
3294 /* try headers filters */
3295 if (rule_set->rsp_exp != NULL) {
3296 if (apply_filters_to_response(t, rep, rule_set->rsp_exp) < 0) {
3297 return_bad_resp:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003298 if (t->srv) {
3299 t->srv->cur_sess--;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003300 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003301 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003302 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003303 cur_proxy->failed_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003304 return_srv_prx_502:
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003305 buffer_shutr_done(rep);
3306 buffer_shutw_done(req);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003307 fd_delete(t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003308 t->srv_state = SV_STCLOSE;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01003309 txn->status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01003310 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003311 if (!(t->flags & SN_ERR_MASK))
3312 t->flags |= SN_ERR_PRXCOND;
3313 if (!(t->flags & SN_FINST_MASK))
3314 t->flags |= SN_FINST_H;
3315 /* We used to have a free connection slot. Since we'll never use it,
3316 * we have to inform the server that it may be used by another session.
3317 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003318 if (t->srv && may_dequeue_tasks(t->srv, cur_proxy))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003319 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003320 return 1;
3321 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003322 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003323
Willy Tarreaua15645d2007-03-18 16:22:39 +01003324 /* has the response been denied ? */
Willy Tarreau3d300592007-03-18 18:34:41 +01003325 if (txn->flags & TX_SVDENY) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003326 if (t->srv) {
3327 t->srv->cur_sess--;
3328 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003329 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003330 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003331 cur_proxy->denied_resp++;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003332 goto return_srv_prx_502;
3333 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003334
Willy Tarreaua15645d2007-03-18 16:22:39 +01003335 /* We might have to check for "Connection:" */
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003336 if (((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01003337 !(t->flags & SN_CONN_CLOSED)) {
3338 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003339 int cur_idx, old_idx, delta, val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003340 struct hdr_idx_elem *cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003341
Willy Tarreaua15645d2007-03-18 16:22:39 +01003342 cur_next = rep->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
3343 old_idx = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003344
Willy Tarreaua15645d2007-03-18 16:22:39 +01003345 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
3346 cur_hdr = &txn->hdr_idx.v[cur_idx];
3347 cur_ptr = cur_next;
3348 cur_end = cur_ptr + cur_hdr->len;
3349 cur_next = cur_end + cur_hdr->cr + 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003350
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003351 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
3352 if (val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003353 /* 3 possibilities :
3354 * - we have already set Connection: close,
3355 * so we remove this line.
3356 * - we have not yet set Connection: close,
3357 * but this line indicates close. We leave
3358 * it untouched and set the flag.
3359 * - we have not yet set Connection: close,
3360 * and this line indicates non-close. We
3361 * replace it.
3362 */
3363 if (t->flags & SN_CONN_CLOSED) {
3364 delta = buffer_replace2(rep, cur_ptr, cur_next, NULL, 0);
3365 txn->rsp.eoh += delta;
3366 cur_next += delta;
3367 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
3368 txn->hdr_idx.used--;
3369 cur_hdr->len = 0;
3370 } else {
Willy Tarreauaa9dce32007-03-18 23:50:16 +01003371 if (strncasecmp(cur_ptr + val, "close", 5) != 0) {
3372 delta = buffer_replace2(rep, cur_ptr + val, cur_end,
3373 "close", 5);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003374 cur_next += delta;
3375 cur_hdr->len += delta;
3376 txn->rsp.eoh += delta;
3377 }
3378 t->flags |= SN_CONN_CLOSED;
3379 }
3380 }
3381 old_idx = cur_idx;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003382 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003383 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003384
Willy Tarreaua15645d2007-03-18 16:22:39 +01003385 /* add response headers from the rule sets in the same order */
3386 for (cur_idx = 0; cur_idx < rule_set->nb_rspadd; cur_idx++) {
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003387 if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx,
3388 rule_set->rsp_add[cur_idx])) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003389 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003390 }
3391
Willy Tarreaua15645d2007-03-18 16:22:39 +01003392 /* check whether we're already working on the frontend */
3393 if (cur_proxy == t->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003394 break;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003395 cur_proxy = t->fe;
3396 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003397
Willy Tarreaua15645d2007-03-18 16:22:39 +01003398 /*
3399 * 4: check for server cookie.
3400 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003401 if (t->be->cookie_name || t->be->appsession_name || t->be->capture_name
3402 || (t->be->options & PR_O_CHK_CACHE))
3403 manage_server_side_cookies(t, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003404
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003405
Willy Tarreaua15645d2007-03-18 16:22:39 +01003406 /*
Willy Tarreau396d2c62007-11-04 19:30:00 +01003407 * 5: check for cache-control or pragma headers if required.
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003408 */
Willy Tarreau396d2c62007-11-04 19:30:00 +01003409 if ((t->be->options & (PR_O_COOK_NOC | PR_O_CHK_CACHE)) != 0)
3410 check_response_for_cacheability(t, rep);
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003411
3412 /*
3413 * 6: add server cookie in the response if needed
Willy Tarreaua15645d2007-03-18 16:22:39 +01003414 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003415 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
3416 (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003417 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003418
Willy Tarreaua15645d2007-03-18 16:22:39 +01003419 /* the server is known, it's not the one the client requested, we have to
3420 * insert a set-cookie here, except if we want to insert only on POST
3421 * requests and this one isn't. Note that servers which don't have cookies
3422 * (eg: some backup servers) will return a full cookie removal request.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003423 */
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003424 len = sprintf(trash, "Set-Cookie: %s=%s; path=/",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003425 t->be->cookie_name,
Willy Tarreaua15645d2007-03-18 16:22:39 +01003426 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003427
Krzysztof Piotr Oledzki1acf2172008-05-29 23:03:34 +02003428 if (t->be->cookie_domain)
3429 len += sprintf(trash+len, "; domain=%s", t->be->cookie_domain);
Krzysztof Piotr Oledzkiefe3b6f2008-05-23 23:49:32 +02003430
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003431 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3432 trash, len)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003433 goto return_bad_resp;
Willy Tarreau3d300592007-03-18 18:34:41 +01003434 txn->flags |= TX_SCK_INSERTED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003435
Willy Tarreaua15645d2007-03-18 16:22:39 +01003436 /* Here, we will tell an eventual cache on the client side that we don't
3437 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
3438 * Some caches understand the correct form: 'no-cache="set-cookie"', but
3439 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
3440 */
Krzysztof Oledzki9198ab52007-10-11 18:56:27 +02003441 if ((t->be->options & PR_O_COOK_NOC) && (txn->flags & TX_CACHEABLE)) {
3442
3443 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
3444
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003445 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
3446 "Cache-control: private", 22)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003447 goto return_bad_resp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003448 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003449 }
3450
3451
3452 /*
Willy Tarreaua15645d2007-03-18 16:22:39 +01003453 * 7: check if result will be cacheable with a cookie.
3454 * We'll block the response if security checks have caught
3455 * nasty things such as a cacheable cookie.
3456 */
Willy Tarreau3d300592007-03-18 18:34:41 +01003457 if (((txn->flags & (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) ==
3458 (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003459 (t->be->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003460
Willy Tarreaua15645d2007-03-18 16:22:39 +01003461 /* we're in presence of a cacheable response containing
3462 * a set-cookie header. We'll block it as requested by
3463 * the 'checkcache' option, and send an alert.
3464 */
3465 if (t->srv) {
3466 t->srv->cur_sess--;
3467 t->srv->failed_secu++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003468 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003469 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003470 t->be->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003471
Willy Tarreaua15645d2007-03-18 16:22:39 +01003472 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003473 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003474 send_log(t->be, LOG_ALERT,
3475 "Blocking cacheable cookie in response from instance %s, server %s.\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003476 t->be->id, t->srv?t->srv->id:"<dispatch>");
Willy Tarreaua15645d2007-03-18 16:22:39 +01003477 goto return_srv_prx_502;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003478 }
3479
Willy Tarreaua15645d2007-03-18 16:22:39 +01003480 /*
3481 * 8: add "Connection: close" if needed and not yet set.
Willy Tarreau2807efd2007-03-25 23:47:23 +02003482 * Note that we do not need to add it in case of HTTP/1.0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003483 */
Willy Tarreau2807efd2007-03-25 23:47:23 +02003484 if (!(t->flags & SN_CONN_CLOSED) &&
Krzysztof Oledzki336d4752007-12-25 02:40:22 +01003485 ((t->fe->options | t->be->options) & (PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) {
Willy Tarreau2807efd2007-03-25 23:47:23 +02003486 if ((unlikely(msg->sl.st.v_l != 8) ||
3487 unlikely(req->data[msg->som + 7] != '0')) &&
3488 unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003489 "Connection: close", 17)) < 0)
Willy Tarreaua15645d2007-03-18 16:22:39 +01003490 goto return_bad_resp;
3491 t->flags |= SN_CONN_CLOSED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003492 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003493
Willy Tarreaubaaee002006-06-26 02:48:02 +02003494
Willy Tarreaua15645d2007-03-18 16:22:39 +01003495 /*************************************************************
3496 * OK, that's finished for the headers. We have done what we *
3497 * could. Let's switch to the DATA state. *
3498 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02003499
Willy Tarreaua15645d2007-03-18 16:22:39 +01003500 t->srv_state = SV_STDATA;
3501 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau42aae5c2007-04-29 17:43:56 +02003502 t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaua15645d2007-03-18 16:22:39 +01003503
3504 /* client connection already closed or option 'forceclose' required :
3505 * we close the server's outgoing connection right now.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003506 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003507 if ((req->l == 0) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003508 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->options & PR_O_FORCE_CLO)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003509 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003510 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003511
3512 /* We must ensure that the read part is still alive when switching
3513 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003514 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003515 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003516
Willy Tarreaua15645d2007-03-18 16:22:39 +01003517 shutdown(t->srv_fd, SHUT_WR);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003518 t->srv_state = SV_STSHUTW;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003519 }
3520
Willy Tarreaua15645d2007-03-18 16:22:39 +01003521#ifdef CONFIG_HAP_TCPSPLICE
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003522 if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01003523 /* TCP splicing supported by both FE and BE */
3524 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003525 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01003526#endif
3527 /* if the user wants to log as soon as possible, without counting
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003528 * bytes from the server, then this is the right moment. We have
3529 * to temporarily assign bytes_out to log what we currently have.
3530 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003531 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
3532 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreau8b3977f2008-01-18 11:16:32 +01003533 t->logs.bytes_out = txn->rsp.eoh;
Willy Tarreau42250582007-04-01 01:30:43 +02003534 if (t->fe->to_log & LW_REQ)
3535 http_sess_log(t);
3536 else
3537 tcp_sess_log(t);
Krzysztof Piotr Oledzkif1e1cb42008-01-20 23:27:02 +01003538 t->logs.bytes_out = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003539 }
3540
Willy Tarreaua15645d2007-03-18 16:22:39 +01003541 /* Note: we must not try to cheat by jumping directly to DATA,
3542 * otherwise we would not let the client side wake up.
Willy Tarreaubaaee002006-06-26 02:48:02 +02003543 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01003544
3545 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003546 }
3547 else if (s == SV_STDATA) {
3548 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003549 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003550 buffer_shutr_done(rep);
3551 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003552 fd_delete(t->srv_fd);
3553 if (t->srv) {
3554 t->srv->cur_sess--;
3555 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003556 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003557 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003558 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003559 t->srv_state = SV_STCLOSE;
3560 if (!(t->flags & SN_ERR_MASK))
3561 t->flags |= SN_ERR_SRVCL;
3562 if (!(t->flags & SN_FINST_MASK))
3563 t->flags |= SN_FINST_D;
3564 /* We used to have a free connection slot. Since we'll never use it,
3565 * we have to inform the server that it may be used by another session.
3566 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003567 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003568 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003569
3570 return 1;
3571 }
3572 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003573 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003574 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003575 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003576 t->srv_state = SV_STSHUTR;
3577 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
3578 return 1;
3579 }
3580 /* end of client read and no more data to send */
3581 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003582 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003583 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003584 shutdown(t->srv_fd, SHUT_WR);
3585 /* We must ensure that the read part is still alive when switching
3586 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003587 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003588 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003589
3590 t->srv_state = SV_STSHUTW;
3591 return 1;
3592 }
3593 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003594 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003595 EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreaufa645582007-06-03 15:59:52 +02003596 buffer_shutr(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003597 t->srv_state = SV_STSHUTR;
3598 if (!(t->flags & SN_ERR_MASK))
3599 t->flags |= SN_ERR_SRVTO;
3600 if (!(t->flags & SN_FINST_MASK))
3601 t->flags |= SN_FINST_D;
3602 return 1;
3603 }
3604 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003605 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003606 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003607 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003608 shutdown(t->srv_fd, SHUT_WR);
3609 /* We must ensure that the read part is still alive when switching
3610 * to shutw */
Willy Tarreauf161a342007-04-08 16:59:42 +02003611 EV_FD_SET(t->srv_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003612 rep->cex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003613 t->srv_state = SV_STSHUTW;
3614 if (!(t->flags & SN_ERR_MASK))
3615 t->flags |= SN_ERR_SRVTO;
3616 if (!(t->flags & SN_FINST_MASK))
3617 t->flags |= SN_FINST_D;
3618 return 1;
3619 }
3620
3621 /* recompute request time-outs */
3622 if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003623 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3624 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003625 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003626 }
3627 }
3628 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau66319382007-04-08 17:17:37 +02003629 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3630 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003631 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
3632 if (req->wex) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003633 /* FIXME: to prevent the server from expiring read timeouts during writes,
3634 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02003635 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003636 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003637 }
3638 }
3639
3640 /* recompute response time-outs */
3641 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003642 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003643 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003644 }
3645 }
3646 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003647 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003648 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003649 }
3650 }
3651
3652 return 0; /* other cases change nothing */
3653 }
3654 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003655 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003656 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003657 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003658 fd_delete(t->srv_fd);
3659 if (t->srv) {
3660 t->srv->cur_sess--;
3661 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003662 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003663 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003664 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003665 //close(t->srv_fd);
3666 t->srv_state = SV_STCLOSE;
3667 if (!(t->flags & SN_ERR_MASK))
3668 t->flags |= SN_ERR_SRVCL;
3669 if (!(t->flags & SN_FINST_MASK))
3670 t->flags |= SN_FINST_D;
3671 /* We used to have a free connection slot. Since we'll never use it,
3672 * we have to inform the server that it may be used by another session.
3673 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003674 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003675 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003676
3677 return 1;
3678 }
3679 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003680 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003681 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003682 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003683 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003684 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003685 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003686 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003687 //close(t->srv_fd);
3688 t->srv_state = SV_STCLOSE;
3689 /* We used to have a free connection slot. Since we'll never use it,
3690 * we have to inform the server that it may be used by another session.
3691 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003692 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003693 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003694
3695 return 1;
3696 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003697 else if (tick_is_expired(req->wex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003698 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003699 buffer_shutw_done(req);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003700 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003701 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003702 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003703 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003704 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003705 //close(t->srv_fd);
3706 t->srv_state = SV_STCLOSE;
3707 if (!(t->flags & SN_ERR_MASK))
3708 t->flags |= SN_ERR_SRVTO;
3709 if (!(t->flags & SN_FINST_MASK))
3710 t->flags |= SN_FINST_D;
3711 /* We used to have a free connection slot. Since we'll never use it,
3712 * we have to inform the server that it may be used by another session.
3713 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003714 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003715 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003716
3717 return 1;
3718 }
3719 else if (req->l == 0) {
Willy Tarreau66319382007-04-08 17:17:37 +02003720 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
3721 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003722 req->wex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003723 }
3724 }
3725 else { /* buffer not empty */
Willy Tarreau66319382007-04-08 17:17:37 +02003726 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
3727 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003728 req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003729 }
3730 }
3731 return 0;
3732 }
3733 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003734 if (rep->flags & BF_READ_ERROR) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003735 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003736 buffer_shutr_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003737 fd_delete(t->srv_fd);
3738 if (t->srv) {
3739 t->srv->cur_sess--;
3740 t->srv->failed_resp++;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003741 sess_change_server(t, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003742 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003743 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003744 //close(t->srv_fd);
3745 t->srv_state = SV_STCLOSE;
3746 if (!(t->flags & SN_ERR_MASK))
3747 t->flags |= SN_ERR_SRVCL;
3748 if (!(t->flags & SN_FINST_MASK))
3749 t->flags |= SN_FINST_D;
3750 /* We used to have a free connection slot. Since we'll never use it,
3751 * we have to inform the server that it may be used by another session.
3752 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003753 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003754 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003755
3756 return 1;
3757 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003758 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003759 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003760 buffer_shutr_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003761 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003762 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003763 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003764 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003765 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003766 //close(t->srv_fd);
3767 t->srv_state = SV_STCLOSE;
3768 /* We used to have a free connection slot. Since we'll never use it,
3769 * we have to inform the server that it may be used by another session.
3770 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003771 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003772 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003773
3774 return 1;
3775 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003776 else if (tick_is_expired(rep->rex, now_ms)) {
Willy Tarreauf161a342007-04-08 16:59:42 +02003777 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreau89edf5e2008-08-03 17:25:14 +02003778 buffer_shutr_done(rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003779 fd_delete(t->srv_fd);
Willy Tarreau51406232008-03-10 22:04:20 +01003780 if (t->srv) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02003781 t->srv->cur_sess--;
Willy Tarreau7c669d72008-06-20 15:04:11 +02003782 sess_change_server(t, NULL);
Willy Tarreau51406232008-03-10 22:04:20 +01003783 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003784 //close(t->srv_fd);
3785 t->srv_state = SV_STCLOSE;
3786 if (!(t->flags & SN_ERR_MASK))
3787 t->flags |= SN_ERR_SRVTO;
3788 if (!(t->flags & SN_FINST_MASK))
3789 t->flags |= SN_FINST_D;
3790 /* We used to have a free connection slot. Since we'll never use it,
3791 * we have to inform the server that it may be used by another session.
3792 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003793 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02003794 process_srv_queue(t->srv);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003795
3796 return 1;
3797 }
3798 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau66319382007-04-08 17:17:37 +02003799 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003800 rep->rex = TICK_ETERNITY;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003801 }
3802 }
3803 else {
Willy Tarreau66319382007-04-08 17:17:37 +02003804 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003805 rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003806 }
3807 }
3808 return 0;
3809 }
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003810 else if (s == SV_STANALYZE){
3811 /* this server state is set by the client to study the body for server assignment */
3812
3813 /* Have we been through this long enough to timeout? */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003814 if (!tick_is_expired(req->rex, now_ms)) {
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003815 /* balance url_param check_post should have been the only to get into this.
3816 * just wait for data, check to compare how much
3817 */
3818 struct http_msg * msg = &t->txn.req;
3819 unsigned long body = msg->sol[msg->eoh] == '\r' ? msg->eoh + 2 :msg->eoh + 1;
3820 unsigned long len = req->total - body;
3821 long long limit = t->be->url_param_post_limit;
3822 struct hdr_ctx ctx;
3823 ctx.idx = 0;
3824 /* now if we have a length, we'll take the hint */
3825 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx);
3826 if ( ctx.idx && strncasecmp(ctx.line+ctx.val,"chunked",ctx.vlen)==0) {
3827 unsigned int chunk = 0;
3828 while ( body < req->total && !HTTP_IS_CRLF(msg->sol[body])) {
3829 char c = msg->sol[body];
3830 if (ishex(c)) {
3831 unsigned int hex = toupper(c) - '0';
3832 if ( hex > 9 )
3833 hex -= 'A' - '9' - 1;
3834 chunk = (chunk << 4) | hex;
3835 }
3836 else break;
3837 body++;
3838 len--;
3839 }
3840 if ( body == req->total )
3841 return 0; /* end of buffer? data missing! */
3842
3843 if ( memcmp(msg->sol+body, "\r\n", 2) != 0 )
3844 return 0; /* chunked encoding len ends with CRLF, and we don't have it yet */
3845
3846 /* if we support more then one chunk here, we have to do it again when assigning server
3847 1. how much entity data do we have? new var
3848 2. should save entity_start, entity_cursor, elen & rlen in req; so we don't repeat scanning here
3849 3. test if elen > limit, or set new limit to elen if 0 (end of entity found)
3850 */
3851
3852 if ( chunk < limit )
3853 limit = chunk; /* only reading one chunk */
3854 } else {
3855 if ( msg->hdr_content_len < limit )
3856 limit = msg->hdr_content_len;
3857 }
3858 if ( len < limit )
3859 return 0;
3860 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +02003861 t->srv_state = SV_STIDLE;
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003862 return 1;
3863 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003864 else { /* SV_STCLOSE : nothing to do */
3865 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
3866 int len;
Willy Tarreaua15645d2007-03-18 16:22:39 +01003867 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003868 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003869 write(1, trash, len);
3870 }
3871 return 0;
3872 }
3873 return 0;
3874}
3875
3876
3877/*
3878 * Produces data for the session <s> depending on its source. Expects to be
3879 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3880 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3881 * session, which it uses to keep on being called when there is free space in
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003882 * the buffer, or simply by letting an empty buffer upon return. It returns 1
Willy Tarreaubaaee002006-06-26 02:48:02 +02003883 * if it changes the session state from CL_STSHUTR, otherwise 0.
3884 */
3885int produce_content(struct session *s)
3886{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003887 if (s->data_source == DATA_SRC_NONE) {
3888 s->flags &= ~SN_SELF_GEN;
3889 return 1;
3890 }
3891 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003892 /* dump server statistics */
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01003893 int ret = stats_dump_http(s, s->be->uri_auth);
Willy Tarreau91861262007-10-17 17:06:05 +02003894 if (ret >= 0)
3895 return ret;
3896 /* -1 indicates an error */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003897 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003898
Willy Tarreau91861262007-10-17 17:06:05 +02003899 /* unknown data source or internal error */
3900 s->txn.status = 500;
3901 client_retnclose(s, error_message(s, HTTP_ERR_500));
3902 if (!(s->flags & SN_ERR_MASK))
3903 s->flags |= SN_ERR_PRXCOND;
3904 if (!(s->flags & SN_FINST_MASK))
3905 s->flags |= SN_FINST_R;
3906 s->flags &= ~SN_SELF_GEN;
3907 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003908}
3909
3910
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003911/* Iterate the same filter through all request headers.
3912 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01003913 * Since it can manage the switch to another backend, it updates the per-proxy
3914 * DENY stats.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003915 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003916int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003917{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003918 char term;
3919 char *cur_ptr, *cur_end, *cur_next;
3920 int cur_idx, old_idx, last_hdr;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003921 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003922 struct hdr_idx_elem *cur_hdr;
3923 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003924
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003925 last_hdr = 0;
3926
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003927 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003928 old_idx = 0;
3929
3930 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01003931 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003932 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01003933 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003934 (exp->action == ACT_ALLOW ||
3935 exp->action == ACT_DENY ||
3936 exp->action == ACT_TARPIT))
3937 return 0;
3938
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003939 cur_idx = txn->hdr_idx.v[old_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003940 if (!cur_idx)
3941 break;
3942
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01003943 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003944 cur_ptr = cur_next;
3945 cur_end = cur_ptr + cur_hdr->len;
3946 cur_next = cur_end + cur_hdr->cr + 1;
3947
3948 /* Now we have one header between cur_ptr and cur_end,
3949 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003950 */
3951
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003952 /* The annoying part is that pattern matching needs
3953 * that we modify the contents to null-terminate all
3954 * strings before testing them.
3955 */
3956
3957 term = *cur_end;
3958 *cur_end = '\0';
3959
3960 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3961 switch (exp->action) {
3962 case ACT_SETBE:
3963 /* It is not possible to jump a second time.
3964 * FIXME: should we return an HTTP/500 here so that
3965 * the admin knows there's a problem ?
3966 */
3967 if (t->be != t->fe)
3968 break;
3969
3970 /* Swithing Proxy */
3971 t->be = (struct proxy *) exp->replace;
3972
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003973 /* right now, the backend switch is not overly complicated
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003974 * because we have associated req_cap and rsp_cap to the
3975 * frontend, and the beconn will be updated later.
3976 */
3977
Willy Tarreaud7c30f92007-12-03 01:38:36 +01003978 t->rep->rto = t->req->wto = t->be->timeout.server;
3979 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02003980 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003981 last_hdr = 1;
3982 break;
3983
3984 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01003985 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003986 last_hdr = 1;
3987 break;
3988
3989 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01003990 txn->flags |= TX_CLDENY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003991 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003992 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003993 break;
3994
3995 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01003996 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003997 last_hdr = 1;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02003998 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003999 break;
4000
4001 case ACT_REPLACE:
4002 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4003 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
4004 /* FIXME: if the user adds a newline in the replacement, the
4005 * index will not be recalculated for now, and the new line
4006 * will not be counted as a new header.
4007 */
4008
4009 cur_end += delta;
4010 cur_next += delta;
4011 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004012 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004013 break;
4014
4015 case ACT_REMOVE:
4016 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
4017 cur_next += delta;
4018
4019 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004020 txn->req.eoh += delta;
4021 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4022 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004023 cur_hdr->len = 0;
4024 cur_end = NULL; /* null-term has been rewritten */
4025 break;
4026
4027 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004028 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004029 if (cur_end)
4030 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004031
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004032 /* keep the link from this header to next one in case of later
4033 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004034 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004035 old_idx = cur_idx;
4036 }
4037 return 0;
4038}
4039
4040
4041/* Apply the filter to the request line.
4042 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4043 * or -1 if a replacement resulted in an invalid request line.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004044 * Since it can manage the switch to another backend, it updates the per-proxy
4045 * DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004046 */
4047int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
4048{
4049 char term;
4050 char *cur_ptr, *cur_end;
4051 int done;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004052 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004053 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004054
Willy Tarreau58f10d72006-12-04 02:26:12 +01004055
Willy Tarreau3d300592007-03-18 18:34:41 +01004056 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004057 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004058 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004059 (exp->action == ACT_ALLOW ||
4060 exp->action == ACT_DENY ||
4061 exp->action == ACT_TARPIT))
4062 return 0;
4063 else if (exp->action == ACT_REMOVE)
4064 return 0;
4065
4066 done = 0;
4067
Willy Tarreau9cdde232007-05-02 20:58:19 +02004068 cur_ptr = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004069 cur_end = cur_ptr + txn->req.sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004070
4071 /* Now we have the request line between cur_ptr and cur_end */
4072
4073 /* The annoying part is that pattern matching needs
4074 * that we modify the contents to null-terminate all
4075 * strings before testing them.
4076 */
4077
4078 term = *cur_end;
4079 *cur_end = '\0';
4080
4081 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4082 switch (exp->action) {
4083 case ACT_SETBE:
4084 /* It is not possible to jump a second time.
4085 * FIXME: should we return an HTTP/500 here so that
4086 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01004087 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004088 if (t->be != t->fe)
4089 break;
4090
4091 /* Swithing Proxy */
4092 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004093
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004094 /* right now, the backend switch is not too much complicated
4095 * because we have associated req_cap and rsp_cap to the
4096 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004097 */
4098
Willy Tarreaud7c30f92007-12-03 01:38:36 +01004099 t->rep->rto = t->req->wto = t->be->timeout.server;
4100 t->req->cto = t->be->timeout.connect;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02004101 t->conn_retries = t->be->conn_retries;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004102 done = 1;
4103 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004104
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004105 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004106 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004107 done = 1;
4108 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004109
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004110 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004111 txn->flags |= TX_CLDENY;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004112 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004113 done = 1;
4114 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004115
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004116 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01004117 txn->flags |= TX_CLTARPIT;
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004118 t->be->denied_req++;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004119 done = 1;
4120 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01004121
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004122 case ACT_REPLACE:
4123 *cur_end = term; /* restore the string terminator */
4124 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4125 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
4126 /* FIXME: if the user adds a newline in the replacement, the
4127 * index will not be recalculated for now, and the new line
4128 * will not be counted as a new header.
4129 */
Willy Tarreaua496b602006-12-17 23:15:24 +01004130
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004131 txn->req.eoh += delta;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004132 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01004133
Willy Tarreau9cdde232007-05-02 20:58:19 +02004134 txn->req.sol = req->data + txn->req.som; /* should be equal to txn->sol */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004135 cur_end = (char *)http_parse_reqline(&txn->req, req->data,
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004136 HTTP_MSG_RQMETH,
4137 cur_ptr, cur_end + 1,
4138 NULL, NULL);
4139 if (unlikely(!cur_end))
4140 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01004141
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004142 /* we have a full request and we know that we have either a CR
4143 * or an LF at <ptr>.
4144 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004145 txn->meth = find_http_meth(cur_ptr, txn->req.sl.rq.m_l);
4146 hdr_idx_set_start(&txn->hdr_idx, txn->req.sl.rq.l, *cur_end == '\r');
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004147 /* there is no point trying this regex on headers */
4148 return 1;
4149 }
4150 }
4151 *cur_end = term; /* restore the string terminator */
4152 return done;
4153}
Willy Tarreau97de6242006-12-27 17:18:38 +01004154
Willy Tarreau58f10d72006-12-04 02:26:12 +01004155
Willy Tarreau58f10d72006-12-04 02:26:12 +01004156
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004157/*
4158 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
4159 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
Willy Tarreaua15645d2007-03-18 16:22:39 +01004160 * unparsable request. Since it can manage the switch to another backend, it
4161 * updates the per-proxy DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004162 */
4163int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
4164{
Willy Tarreau3d300592007-03-18 18:34:41 +01004165 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004166 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004167 while (exp && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004168 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004169
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004170 /*
4171 * The interleaving of transformations and verdicts
4172 * makes it difficult to decide to continue or stop
4173 * the evaluation.
4174 */
4175
Willy Tarreau3d300592007-03-18 18:34:41 +01004176 if ((txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004177 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4178 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
4179 exp = exp->next;
4180 continue;
4181 }
4182
4183 /* Apply the filter to the request line. */
4184 ret = apply_filter_to_req_line(t, req, exp);
4185 if (unlikely(ret < 0))
4186 return -1;
4187
4188 if (likely(ret == 0)) {
4189 /* The filter did not match the request, it can be
4190 * iterated through all headers.
4191 */
4192 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004193 }
4194 exp = exp->next;
4195 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004196 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004197}
4198
4199
Willy Tarreaua15645d2007-03-18 16:22:39 +01004200
Willy Tarreau58f10d72006-12-04 02:26:12 +01004201/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004202 * Manage client-side cookie. It can impact performance by about 2% so it is
4203 * desirable to call it only when needed.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004204 */
4205void manage_client_side_cookies(struct session *t, struct buffer *req)
4206{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004207 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004208 char *p1, *p2, *p3, *p4;
4209 char *del_colon, *del_cookie, *colon;
4210 int app_cookies;
4211
4212 appsess *asession_temp = NULL;
4213 appsess local_asession;
4214
4215 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004216 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004217
Willy Tarreau2a324282006-12-05 00:05:46 +01004218 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004219 * we start with the start line.
4220 */
Willy Tarreau83969f42007-01-22 08:55:47 +01004221 old_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004222 cur_next = req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004223
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004224 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004225 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004226 int val;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004227
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004228 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01004229 cur_ptr = cur_next;
4230 cur_end = cur_ptr + cur_hdr->len;
4231 cur_next = cur_end + cur_hdr->cr + 1;
4232
4233 /* We have one full header between cur_ptr and cur_end, and the
4234 * next header starts at cur_next. We're only interested in
4235 * "Cookie:" headers.
4236 */
4237
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004238 val = http_header_match2(cur_ptr, cur_end, "Cookie", 6);
4239 if (!val) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004240 old_idx = cur_idx;
4241 continue;
4242 }
4243
4244 /* Now look for cookies. Conforming to RFC2109, we have to support
4245 * attributes whose name begin with a '$', and associate them with
4246 * the right cookie, if we want to delete this cookie.
4247 * So there are 3 cases for each cookie read :
4248 * 1) it's a special attribute, beginning with a '$' : ignore it.
4249 * 2) it's a server id cookie that we *MAY* want to delete : save
4250 * some pointers on it (last semi-colon, beginning of cookie...)
4251 * 3) it's an application cookie : we *MAY* have to delete a previous
4252 * "special" cookie.
4253 * At the end of loop, if a "special" cookie remains, we may have to
4254 * remove it. If no application cookie persists in the header, we
4255 * *MUST* delete it
4256 */
4257
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004258 colon = p1 = cur_ptr + val; /* first non-space char after 'Cookie:' */
Willy Tarreau58f10d72006-12-04 02:26:12 +01004259
Willy Tarreau58f10d72006-12-04 02:26:12 +01004260 /* del_cookie == NULL => nothing to be deleted */
4261 del_colon = del_cookie = NULL;
4262 app_cookies = 0;
4263
4264 while (p1 < cur_end) {
4265 /* skip spaces and colons, but keep an eye on these ones */
4266 while (p1 < cur_end) {
4267 if (*p1 == ';' || *p1 == ',')
4268 colon = p1;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004269 else if (!isspace((unsigned char)*p1))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004270 break;
4271 p1++;
4272 }
4273
4274 if (p1 == cur_end)
4275 break;
4276
4277 /* p1 is at the beginning of the cookie name */
4278 p2 = p1;
4279 while (p2 < cur_end && *p2 != '=')
4280 p2++;
4281
4282 if (p2 == cur_end)
4283 break;
4284
4285 p3 = p2 + 1; /* skips the '=' sign */
4286 if (p3 == cur_end)
4287 break;
4288
4289 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004290 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';' && *p4 != ',')
Willy Tarreau58f10d72006-12-04 02:26:12 +01004291 p4++;
4292
4293 /* here, we have the cookie name between p1 and p2,
4294 * and its value between p3 and p4.
4295 * we can process it :
4296 *
4297 * Cookie: NAME=VALUE;
4298 * | || || |
4299 * | || || +--> p4
4300 * | || |+-------> p3
4301 * | || +--------> p2
4302 * | |+------------> p1
4303 * | +-------------> colon
4304 * +--------------------> cur_ptr
4305 */
4306
4307 if (*p1 == '$') {
4308 /* skip this one */
4309 }
4310 else {
4311 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004312 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004313 txn->cli_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004314 (p4 - p1 >= t->fe->capture_namelen) &&
4315 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004316 int log_len = p4 - p1;
4317
Willy Tarreau086b3b42007-05-13 21:45:51 +02004318 if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004319 Alert("HTTP logging : out of memory.\n");
4320 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004321 if (log_len > t->fe->capture_len)
4322 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004323 memcpy(txn->cli_cookie, p1, log_len);
4324 txn->cli_cookie[log_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004325 }
4326 }
4327
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004328 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4329 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004330 /* Cool... it's the right one */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004331 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004332 char *delim;
4333
4334 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4335 * have the server ID betweek p3 and delim, and the original cookie between
4336 * delim+1 and p4. Otherwise, delim==p4 :
4337 *
4338 * Cookie: NAME=SRV~VALUE;
4339 * | || || | |
4340 * | || || | +--> p4
4341 * | || || +--------> delim
4342 * | || |+-----------> p3
4343 * | || +------------> p2
4344 * | |+----------------> p1
4345 * | +-----------------> colon
4346 * +------------------------> cur_ptr
4347 */
4348
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004349 if (t->be->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004350 for (delim = p3; delim < p4; delim++)
4351 if (*delim == COOKIE_DELIM)
4352 break;
4353 }
4354 else
4355 delim = p4;
4356
4357
4358 /* Here, we'll look for the first running server which supports the cookie.
4359 * This allows to share a same cookie between several servers, for example
4360 * to dedicate backup servers to specific servers only.
4361 * However, to prevent clients from sticking to cookie-less backup server
4362 * when they have incidentely learned an empty cookie, we simply ignore
4363 * empty cookies and mark them as invalid.
4364 */
4365 if (delim == p3)
4366 srv = NULL;
4367
4368 while (srv) {
Willy Tarreau92f2ab12007-02-02 22:14:47 +01004369 if (srv->cookie && (srv->cklen == delim - p3) &&
4370 !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004371 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004372 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004373 txn->flags &= ~TX_CK_MASK;
4374 txn->flags |= TX_CK_VALID;
4375 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004376 t->srv = srv;
4377 break;
4378 } else {
4379 /* we found a server, but it's down */
Willy Tarreau3d300592007-03-18 18:34:41 +01004380 txn->flags &= ~TX_CK_MASK;
4381 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004382 }
4383 }
4384 srv = srv->next;
4385 }
4386
Willy Tarreau3d300592007-03-18 18:34:41 +01004387 if (!srv && !(txn->flags & TX_CK_DOWN)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004388 /* no server matched this cookie */
Willy Tarreau3d300592007-03-18 18:34:41 +01004389 txn->flags &= ~TX_CK_MASK;
4390 txn->flags |= TX_CK_INVALID;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004391 }
4392
4393 /* depending on the cookie mode, we may have to either :
4394 * - delete the complete cookie if we're in insert+indirect mode, so that
4395 * the server never sees it ;
4396 * - remove the server id from the cookie value, and tag the cookie as an
4397 * application cookie so that it does not get accidentely removed later,
4398 * if we're in cookie prefix mode
4399 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004400 if ((t->be->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004401 int delta; /* negative */
4402
4403 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
4404 p4 += delta;
4405 cur_end += delta;
4406 cur_next += delta;
4407 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004408 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004409
4410 del_cookie = del_colon = NULL;
4411 app_cookies++; /* protect the header from deletion */
4412 }
4413 else if (del_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004414 (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 +01004415 del_cookie = p1;
4416 del_colon = colon;
4417 }
4418 } else {
4419 /* now we know that we must keep this cookie since it's
4420 * not ours. But if we wanted to delete our cookie
4421 * earlier, we cannot remove the complete header, but we
4422 * can remove the previous block itself.
4423 */
4424 app_cookies++;
4425
4426 if (del_cookie != NULL) {
4427 int delta; /* negative */
4428
4429 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
4430 p4 += delta;
4431 cur_end += delta;
4432 cur_next += delta;
4433 cur_hdr->len += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004434 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004435 del_cookie = del_colon = NULL;
4436 }
4437 }
4438
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004439 if ((t->be->appsession_name != NULL) &&
4440 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004441 /* first, let's see if the cookie is our appcookie*/
4442
4443 /* Cool... it's the right one */
4444
4445 asession_temp = &local_asession;
4446
Willy Tarreau63963c62007-05-13 21:29:55 +02004447 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004448 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4449 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4450 return;
4451 }
4452
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004453 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4454 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004455 asession_temp->serverid = NULL;
Willy Tarreau51041c72007-09-09 21:56:53 +02004456
Willy Tarreau58f10d72006-12-04 02:26:12 +01004457 /* only do insert, if lookup fails */
Willy Tarreau51041c72007-09-09 21:56:53 +02004458 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4459 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004460 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004461 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004462 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004463 Alert("Not enough memory process_cli():asession:calloc().\n");
4464 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4465 return;
4466 }
4467
4468 asession_temp->sessid = local_asession.sessid;
4469 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004470 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004471 } else {
4472 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004473 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004474 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01004475 if (asession_temp->serverid == NULL) {
4476 Alert("Found Application Session without matching server.\n");
4477 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004478 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004479 while (srv) {
4480 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004481 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004482 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01004483 txn->flags &= ~TX_CK_MASK;
4484 txn->flags |= TX_CK_VALID;
4485 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004486 t->srv = srv;
4487 break;
4488 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01004489 txn->flags &= ~TX_CK_MASK;
4490 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004491 }
4492 }
4493 srv = srv->next;
4494 }/* end while(srv) */
4495 }/* end else if server == NULL */
4496
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004497 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004498 }/* end if ((t->proxy->appsession_name != NULL) ... */
4499 }
4500
4501 /* we'll have to look for another cookie ... */
4502 p1 = p4;
4503 } /* while (p1 < cur_end) */
4504
4505 /* There's no more cookie on this line.
4506 * We may have marked the last one(s) for deletion.
4507 * We must do this now in two ways :
4508 * - if there is no app cookie, we simply delete the header ;
4509 * - if there are app cookies, we must delete the end of the
4510 * string properly, including the colon/semi-colon before
4511 * the cookie name.
4512 */
4513 if (del_cookie != NULL) {
4514 int delta;
4515 if (app_cookies) {
4516 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
4517 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004518 cur_hdr->len += delta;
4519 } else {
4520 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004521
4522 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004523 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4524 txn->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004525 cur_hdr->len = 0;
4526 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01004527 cur_next += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004528 txn->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004529 }
4530
4531 /* keep the link from this header to next one */
4532 old_idx = cur_idx;
4533 } /* end of cookie processing on this header */
4534}
4535
4536
Willy Tarreaua15645d2007-03-18 16:22:39 +01004537/* Iterate the same filter through all response headers contained in <rtr>.
4538 * Returns 1 if this filter can be stopped upon return, otherwise 0.
4539 */
4540int apply_filter_to_resp_headers(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4541{
4542 char term;
4543 char *cur_ptr, *cur_end, *cur_next;
4544 int cur_idx, old_idx, last_hdr;
4545 struct http_txn *txn = &t->txn;
4546 struct hdr_idx_elem *cur_hdr;
4547 int len, delta;
4548
4549 last_hdr = 0;
4550
4551 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4552 old_idx = 0;
4553
4554 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004555 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004556 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004557 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004558 (exp->action == ACT_ALLOW ||
4559 exp->action == ACT_DENY))
4560 return 0;
4561
4562 cur_idx = txn->hdr_idx.v[old_idx].next;
4563 if (!cur_idx)
4564 break;
4565
4566 cur_hdr = &txn->hdr_idx.v[cur_idx];
4567 cur_ptr = cur_next;
4568 cur_end = cur_ptr + cur_hdr->len;
4569 cur_next = cur_end + cur_hdr->cr + 1;
4570
4571 /* Now we have one header between cur_ptr and cur_end,
4572 * and the next header starts at cur_next.
4573 */
4574
4575 /* The annoying part is that pattern matching needs
4576 * that we modify the contents to null-terminate all
4577 * strings before testing them.
4578 */
4579
4580 term = *cur_end;
4581 *cur_end = '\0';
4582
4583 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4584 switch (exp->action) {
4585 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004586 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004587 last_hdr = 1;
4588 break;
4589
4590 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004591 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004592 last_hdr = 1;
4593 break;
4594
4595 case ACT_REPLACE:
4596 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4597 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4598 /* FIXME: if the user adds a newline in the replacement, the
4599 * index will not be recalculated for now, and the new line
4600 * will not be counted as a new header.
4601 */
4602
4603 cur_end += delta;
4604 cur_next += delta;
4605 cur_hdr->len += delta;
4606 txn->rsp.eoh += delta;
4607 break;
4608
4609 case ACT_REMOVE:
4610 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4611 cur_next += delta;
4612
4613 /* FIXME: this should be a separate function */
4614 txn->rsp.eoh += delta;
4615 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4616 txn->hdr_idx.used--;
4617 cur_hdr->len = 0;
4618 cur_end = NULL; /* null-term has been rewritten */
4619 break;
4620
4621 }
4622 }
4623 if (cur_end)
4624 *cur_end = term; /* restore the string terminator */
4625
4626 /* keep the link from this header to next one in case of later
4627 * removal of next header.
4628 */
4629 old_idx = cur_idx;
4630 }
4631 return 0;
4632}
4633
4634
4635/* Apply the filter to the status line in the response buffer <rtr>.
4636 * Returns 0 if nothing has been done, 1 if the filter has been applied,
4637 * or -1 if a replacement resulted in an invalid status line.
4638 */
4639int apply_filter_to_sts_line(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4640{
4641 char term;
4642 char *cur_ptr, *cur_end;
4643 int done;
4644 struct http_txn *txn = &t->txn;
4645 int len, delta;
4646
4647
Willy Tarreau3d300592007-03-18 18:34:41 +01004648 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004649 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004650 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004651 (exp->action == ACT_ALLOW ||
4652 exp->action == ACT_DENY))
4653 return 0;
4654 else if (exp->action == ACT_REMOVE)
4655 return 0;
4656
4657 done = 0;
4658
Willy Tarreau9cdde232007-05-02 20:58:19 +02004659 cur_ptr = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004660 cur_end = cur_ptr + txn->rsp.sl.rq.l;
4661
4662 /* Now we have the status line between cur_ptr and cur_end */
4663
4664 /* The annoying part is that pattern matching needs
4665 * that we modify the contents to null-terminate all
4666 * strings before testing them.
4667 */
4668
4669 term = *cur_end;
4670 *cur_end = '\0';
4671
4672 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
4673 switch (exp->action) {
4674 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01004675 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004676 done = 1;
4677 break;
4678
4679 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01004680 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004681 done = 1;
4682 break;
4683
4684 case ACT_REPLACE:
4685 *cur_end = term; /* restore the string terminator */
4686 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
4687 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
4688 /* FIXME: if the user adds a newline in the replacement, the
4689 * index will not be recalculated for now, and the new line
4690 * will not be counted as a new header.
4691 */
4692
4693 txn->rsp.eoh += delta;
4694 cur_end += delta;
4695
Willy Tarreau9cdde232007-05-02 20:58:19 +02004696 txn->rsp.sol = rtr->data + txn->rsp.som; /* should be equal to txn->sol */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004697 cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data,
Willy Tarreau02785762007-04-03 14:45:44 +02004698 HTTP_MSG_RPVER,
Willy Tarreaua15645d2007-03-18 16:22:39 +01004699 cur_ptr, cur_end + 1,
4700 NULL, NULL);
4701 if (unlikely(!cur_end))
4702 return -1;
4703
4704 /* we have a full respnse and we know that we have either a CR
4705 * or an LF at <ptr>.
4706 */
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004707 txn->status = strl2ui(rtr->data + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004708 hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.rq.l, *cur_end == '\r');
4709 /* there is no point trying this regex on headers */
4710 return 1;
4711 }
4712 }
4713 *cur_end = term; /* restore the string terminator */
4714 return done;
4715}
4716
4717
4718
4719/*
4720 * Apply all the resp filters <exp> to all headers in buffer <rtr> of session <t>.
4721 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
4722 * unparsable response.
4723 */
4724int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
4725{
Willy Tarreau3d300592007-03-18 18:34:41 +01004726 struct http_txn *txn = &t->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004727 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01004728 while (exp && !(txn->flags & TX_SVDENY)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004729 int ret;
4730
4731 /*
4732 * The interleaving of transformations and verdicts
4733 * makes it difficult to decide to continue or stop
4734 * the evaluation.
4735 */
4736
Willy Tarreau3d300592007-03-18 18:34:41 +01004737 if ((txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01004738 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
4739 exp->action == ACT_PASS)) {
4740 exp = exp->next;
4741 continue;
4742 }
4743
4744 /* Apply the filter to the status line. */
4745 ret = apply_filter_to_sts_line(t, rtr, exp);
4746 if (unlikely(ret < 0))
4747 return -1;
4748
4749 if (likely(ret == 0)) {
4750 /* The filter did not match the response, it can be
4751 * iterated through all headers.
4752 */
4753 apply_filter_to_resp_headers(t, rtr, exp);
4754 }
4755 exp = exp->next;
4756 }
4757 return 0;
4758}
4759
4760
4761
4762/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01004763 * Manage server-side cookies. It can impact performance by about 2% so it is
4764 * desirable to call it only when needed.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004765 */
4766void manage_server_side_cookies(struct session *t, struct buffer *rtr)
4767{
4768 struct http_txn *txn = &t->txn;
4769 char *p1, *p2, *p3, *p4;
4770
4771 appsess *asession_temp = NULL;
4772 appsess local_asession;
4773
4774 char *cur_ptr, *cur_end, *cur_next;
4775 int cur_idx, old_idx, delta;
4776
Willy Tarreaua15645d2007-03-18 16:22:39 +01004777 /* Iterate through the headers.
4778 * we start with the start line.
4779 */
4780 old_idx = 0;
4781 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4782
4783 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
4784 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004785 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004786
4787 cur_hdr = &txn->hdr_idx.v[cur_idx];
4788 cur_ptr = cur_next;
4789 cur_end = cur_ptr + cur_hdr->len;
4790 cur_next = cur_end + cur_hdr->cr + 1;
4791
4792 /* We have one full header between cur_ptr and cur_end, and the
4793 * next header starts at cur_next. We're only interested in
4794 * "Cookie:" headers.
4795 */
4796
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004797 val = http_header_match2(cur_ptr, cur_end, "Set-Cookie", 10);
4798 if (!val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004799 old_idx = cur_idx;
4800 continue;
4801 }
4802
4803 /* OK, right now we know we have a set-cookie at cur_ptr */
Willy Tarreau3d300592007-03-18 18:34:41 +01004804 txn->flags |= TX_SCK_ANY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004805
4806
4807 /* maybe we only wanted to see if there was a set-cookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004808 if (t->be->cookie_name == NULL &&
4809 t->be->appsession_name == NULL &&
4810 t->be->capture_name == NULL)
Willy Tarreaua15645d2007-03-18 16:22:39 +01004811 return;
4812
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004813 p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004814
4815 while (p1 < cur_end) { /* in fact, we'll break after the first cookie */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004816 if (p1 == cur_end || *p1 == ';') /* end of cookie */
4817 break;
4818
4819 /* p1 is at the beginning of the cookie name */
4820 p2 = p1;
4821
4822 while (p2 < cur_end && *p2 != '=' && *p2 != ';')
4823 p2++;
4824
4825 if (p2 == cur_end || *p2 == ';') /* next cookie */
4826 break;
4827
4828 p3 = p2 + 1; /* skip the '=' sign */
4829 if (p3 == cur_end)
4830 break;
4831
4832 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02004833 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';')
Willy Tarreaua15645d2007-03-18 16:22:39 +01004834 p4++;
4835
4836 /* here, we have the cookie name between p1 and p2,
4837 * and its value between p3 and p4.
4838 * we can process it.
4839 */
4840
4841 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004842 if (t->be->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004843 txn->srv_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004844 (p4 - p1 >= t->be->capture_namelen) &&
4845 memcmp(p1, t->be->capture_name, t->be->capture_namelen) == 0) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004846 int log_len = p4 - p1;
4847
Willy Tarreau086b3b42007-05-13 21:45:51 +02004848 if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004849 Alert("HTTP logging : out of memory.\n");
4850 }
4851
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004852 if (log_len > t->be->capture_len)
4853 log_len = t->be->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01004854 memcpy(txn->srv_cookie, p1, log_len);
4855 txn->srv_cookie[log_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004856 }
4857
4858 /* now check if we need to process it for persistence */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004859 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
4860 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004861 /* Cool... it's the right one */
Willy Tarreau3d300592007-03-18 18:34:41 +01004862 txn->flags |= TX_SCK_SEEN;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004863
4864 /* If the cookie is in insert mode on a known server, we'll delete
4865 * this occurrence because we'll insert another one later.
4866 * We'll delete it too if the "indirect" option is set and we're in
4867 * a direct access. */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004868 if (((t->srv) && (t->be->options & PR_O_COOK_INS)) ||
4869 ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004870 /* this header must be deleted */
4871 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
4872 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4873 txn->hdr_idx.used--;
4874 cur_hdr->len = 0;
4875 cur_next += delta;
4876 txn->rsp.eoh += delta;
4877
Willy Tarreau3d300592007-03-18 18:34:41 +01004878 txn->flags |= TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004879 }
4880 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004881 (t->be->options & PR_O_COOK_RW)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004882 /* replace bytes p3->p4 with the cookie name associated
4883 * with this server since we know it.
4884 */
4885 delta = buffer_replace2(rtr, p3, p4, t->srv->cookie, t->srv->cklen);
4886 cur_hdr->len += delta;
4887 cur_next += delta;
4888 txn->rsp.eoh += delta;
4889
Willy Tarreau3d300592007-03-18 18:34:41 +01004890 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004891 }
4892 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004893 (t->be->options & PR_O_COOK_PFX)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004894 /* insert the cookie name associated with this server
4895 * before existing cookie, and insert a delimitor between them..
4896 */
4897 delta = buffer_replace2(rtr, p3, p3, t->srv->cookie, t->srv->cklen + 1);
4898 cur_hdr->len += delta;
4899 cur_next += delta;
4900 txn->rsp.eoh += delta;
4901
4902 p3[t->srv->cklen] = COOKIE_DELIM;
Willy Tarreau3d300592007-03-18 18:34:41 +01004903 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004904 }
4905 }
4906 /* next, let's see if the cookie is our appcookie */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004907 else if ((t->be->appsession_name != NULL) &&
4908 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004909
4910 /* Cool... it's the right one */
4911
4912 size_t server_id_len = strlen(t->srv->id) + 1;
4913 asession_temp = &local_asession;
4914
Willy Tarreau63963c62007-05-13 21:29:55 +02004915 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004916 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4917 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4918 return;
4919 }
Willy Tarreaue2e27a52007-04-01 00:01:37 +02004920 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
4921 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004922 asession_temp->serverid = NULL;
4923
4924 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01004925 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
4926 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004927 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004928 Alert("Not enough Memory process_srv():asession:calloc().\n");
4929 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
4930 return;
4931 }
4932 asession_temp->sessid = local_asession.sessid;
4933 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02004934 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
4935 } else {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004936 /* free wasted memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02004937 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau51041c72007-09-09 21:56:53 +02004938 }
4939
Willy Tarreaua15645d2007-03-18 16:22:39 +01004940 if (asession_temp->serverid == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02004941 if ((asession_temp->serverid = pool_alloc2(apools.serverid)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01004942 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
4943 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
4944 return;
4945 }
4946 asession_temp->serverid[0] = '\0';
4947 }
4948
4949 if (asession_temp->serverid[0] == '\0')
4950 memcpy(asession_temp->serverid, t->srv->id, server_id_len);
4951
Willy Tarreau0c303ee2008-07-07 00:09:58 +02004952 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004953
4954#if defined(DEBUG_HASH)
Willy Tarreau51041c72007-09-09 21:56:53 +02004955 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreaua15645d2007-03-18 16:22:39 +01004956#endif
4957 }/* end if ((t->proxy->appsession_name != NULL) ... */
4958 break; /* we don't want to loop again since there cannot be another cookie on the same line */
4959 } /* we're now at the end of the cookie value */
4960
4961 /* keep the link from this header to next one */
4962 old_idx = cur_idx;
4963 } /* end of cookie processing on this header */
4964}
4965
4966
4967
4968/*
4969 * Check if response is cacheable or not. Updates t->flags.
4970 */
4971void check_response_for_cacheability(struct session *t, struct buffer *rtr)
4972{
4973 struct http_txn *txn = &t->txn;
4974 char *p1, *p2;
4975
4976 char *cur_ptr, *cur_end, *cur_next;
4977 int cur_idx;
4978
Willy Tarreau5df51872007-11-25 16:20:08 +01004979 if (!(txn->flags & TX_CACHEABLE))
Willy Tarreaua15645d2007-03-18 16:22:39 +01004980 return;
4981
4982 /* Iterate through the headers.
4983 * we start with the start line.
4984 */
4985 cur_idx = 0;
4986 cur_next = rtr->data + txn->rsp.som + hdr_idx_first_pos(&txn->hdr_idx);
4987
4988 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
4989 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01004990 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004991
4992 cur_hdr = &txn->hdr_idx.v[cur_idx];
4993 cur_ptr = cur_next;
4994 cur_end = cur_ptr + cur_hdr->len;
4995 cur_next = cur_end + cur_hdr->cr + 1;
4996
4997 /* We have one full header between cur_ptr and cur_end, and the
4998 * next header starts at cur_next. We're only interested in
4999 * "Cookie:" headers.
5000 */
5001
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005002 val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
5003 if (val) {
5004 if ((cur_end - (cur_ptr + val) >= 8) &&
5005 strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
5006 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
5007 return;
5008 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01005009 }
5010
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005011 val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
5012 if (!val)
Willy Tarreaua15645d2007-03-18 16:22:39 +01005013 continue;
5014
5015 /* OK, right now we know we have a cache-control header at cur_ptr */
5016
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005017 p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01005018
5019 if (p1 >= cur_end) /* no more info */
5020 continue;
5021
5022 /* p1 is at the beginning of the value */
5023 p2 = p1;
5024
Willy Tarreau8f8e6452007-06-17 21:51:38 +02005025 while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((unsigned char)*p2))
Willy Tarreaua15645d2007-03-18 16:22:39 +01005026 p2++;
5027
5028 /* we have a complete value between p1 and p2 */
5029 if (p2 < cur_end && *p2 == '=') {
5030 /* we have something of the form no-cache="set-cookie" */
5031 if ((cur_end - p1 >= 21) &&
5032 strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0
5033 && (p1[20] == '"' || p1[20] == ','))
Willy Tarreau3d300592007-03-18 18:34:41 +01005034 txn->flags &= ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005035 continue;
5036 }
5037
5038 /* OK, so we know that either p2 points to the end of string or to a comma */
5039 if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) ||
5040 ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) ||
5041 ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) ||
5042 ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005043 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005044 return;
5045 }
5046
5047 if ((p2 - p1 == 6) && strncasecmp(p1, "public", 6) == 0) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005048 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005049 continue;
5050 }
5051 }
5052}
5053
5054
Willy Tarreau58f10d72006-12-04 02:26:12 +01005055/*
5056 * Try to retrieve a known appsession in the URI, then the associated server.
5057 * If the server is found, it's assigned to the session.
5058 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005059void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01005060{
Willy Tarreau3d300592007-03-18 18:34:41 +01005061 struct http_txn *txn = &t->txn;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005062 appsess *asession_temp = NULL;
5063 appsess local_asession;
5064 char *request_line;
5065
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005066 if (t->be->appsession_name == NULL ||
Willy Tarreaub326fcc2007-03-03 13:54:32 +01005067 (t->txn.meth != HTTP_METH_GET && t->txn.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005068 (request_line = memchr(begin, ';', len)) == NULL ||
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005069 ((1 + t->be->appsession_name_len + 1 + t->be->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01005070 return;
5071
5072 /* skip ';' */
5073 request_line++;
5074
5075 /* look if we have a jsessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005076 if (strncasecmp(request_line, t->be->appsession_name, t->be->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01005077 return;
5078
5079 /* skip jsessionid= */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005080 request_line += t->be->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005081
5082 /* First try if we already have an appsession */
5083 asession_temp = &local_asession;
5084
Willy Tarreau63963c62007-05-13 21:29:55 +02005085 if ((asession_temp->sessid = pool_alloc2(apools.sessid)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005086 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
5087 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
5088 return;
5089 }
5090
5091 /* Copy the sessionid */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005092 memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
5093 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005094 asession_temp->serverid = NULL;
5095
5096 /* only do insert, if lookup fails */
Ryan Warnick6d0b1fa2008-02-17 11:24:35 +01005097 asession_temp = appsession_hash_lookup(&(t->be->htbl_proxy), asession_temp->sessid);
5098 if (asession_temp == NULL) {
Willy Tarreau63963c62007-05-13 21:29:55 +02005099 if ((asession_temp = pool_alloc2(pool2_appsess)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005100 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005101 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005102 Alert("Not enough memory process_cli():asession:calloc().\n");
5103 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
5104 return;
5105 }
5106 asession_temp->sessid = local_asession.sessid;
5107 asession_temp->serverid = local_asession.serverid;
Willy Tarreau51041c72007-09-09 21:56:53 +02005108 appsession_hash_insert(&(t->be->htbl_proxy), asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005109 }
5110 else {
5111 /* free previously allocated memory */
Willy Tarreau63963c62007-05-13 21:29:55 +02005112 pool_free2(apools.sessid, local_asession.sessid);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005113 }
Willy Tarreau51041c72007-09-09 21:56:53 +02005114
Willy Tarreau0c303ee2008-07-07 00:09:58 +02005115 asession_temp->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005116 asession_temp->request_count++;
Willy Tarreau51041c72007-09-09 21:56:53 +02005117
Willy Tarreau58f10d72006-12-04 02:26:12 +01005118#if defined(DEBUG_HASH)
Willy Tarreau51041c72007-09-09 21:56:53 +02005119 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreau58f10d72006-12-04 02:26:12 +01005120#endif
5121 if (asession_temp->serverid == NULL) {
5122 Alert("Found Application Session without matching server.\n");
5123 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005124 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005125 while (srv) {
5126 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005127 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005128 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01005129 txn->flags &= ~TX_CK_MASK;
5130 txn->flags |= TX_CK_VALID;
5131 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005132 t->srv = srv;
5133 break;
5134 } else {
Willy Tarreau3d300592007-03-18 18:34:41 +01005135 txn->flags &= ~TX_CK_MASK;
5136 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005137 }
5138 }
5139 srv = srv->next;
5140 }
5141 }
5142}
5143
5144
Willy Tarreaub2513902006-12-17 14:52:38 +01005145/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005146 * In a GET or HEAD request, check if the requested URI matches the stats uri
5147 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01005148 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005149 * It is assumed that the request is either a HEAD or GET and that the
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005150 * t->be->uri_auth field is valid. An HTTP/401 response may be sent, or
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005151 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01005152 *
5153 * Returns 1 if the session's state changes, otherwise 0.
5154 */
5155int stats_check_uri_auth(struct session *t, struct proxy *backend)
5156{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005157 struct http_txn *txn = &t->txn;
Willy Tarreaub2513902006-12-17 14:52:38 +01005158 struct uri_auth *uri_auth = backend->uri_auth;
5159 struct user_auth *user;
5160 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005161 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01005162
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005163 memset(&t->data_ctx.stats, 0, sizeof(t->data_ctx.stats));
5164
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005165 /* check URI size */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005166 if (uri_auth->uri_len > txn->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01005167 return 0;
5168
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005169 h = t->req->data + txn->req.sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005170
Willy Tarreau0214c3a2007-01-07 13:47:30 +01005171 /* the URI is in h */
5172 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01005173 return 0;
5174
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005175 h += uri_auth->uri_len;
5176 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 3) {
5177 if (memcmp(h, ";up", 3) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005178 t->data_ctx.stats.flags |= STAT_HIDE_DOWN;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005179 break;
5180 }
5181 h++;
5182 }
5183
5184 if (uri_auth->refresh) {
5185 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5186 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 10) {
5187 if (memcmp(h, ";norefresh", 10) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005188 t->data_ctx.stats.flags |= STAT_NO_REFRESH;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02005189 break;
5190 }
5191 h++;
5192 }
5193 }
5194
Willy Tarreau55bb8452007-10-17 18:44:57 +02005195 h = t->req->data + txn->req.sl.rq.u + uri_auth->uri_len;
5196 while (h <= t->req->data + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 4) {
5197 if (memcmp(h, ";csv", 4) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005198 t->data_ctx.stats.flags |= STAT_FMT_CSV;
Willy Tarreau55bb8452007-10-17 18:44:57 +02005199 break;
5200 }
5201 h++;
5202 }
5203
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005204 t->data_ctx.stats.flags |= STAT_SHOW_STAT | STAT_SHOW_INFO;
5205
Willy Tarreaub2513902006-12-17 14:52:38 +01005206 /* we are in front of a interceptable URI. Let's check
5207 * if there's an authentication and if it's valid.
5208 */
5209 user = uri_auth->users;
5210 if (!user) {
5211 /* no user auth required, it's OK */
5212 authenticated = 1;
5213 } else {
5214 authenticated = 0;
5215
5216 /* a user list is defined, we have to check.
5217 * skip 21 chars for "Authorization: Basic ".
5218 */
5219
5220 /* FIXME: this should move to an earlier place */
5221 cur_idx = 0;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005222 h = t->req->data + txn->req.som + hdr_idx_first_pos(&txn->hdr_idx);
5223 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
5224 int len = txn->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005225 if (len > 14 &&
5226 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005227 txn->auth_hdr.str = h;
5228 txn->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01005229 break;
5230 }
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005231 h += len + txn->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01005232 }
5233
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005234 if (txn->auth_hdr.len < 21 ||
5235 memcmp(txn->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01005236 user = NULL;
5237
5238 while (user) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005239 if ((txn->auth_hdr.len == user->user_len + 14 + 7)
5240 && !memcmp(txn->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01005241 user->user_pwd, user->user_len)) {
5242 authenticated = 1;
5243 break;
5244 }
5245 user = user->next;
5246 }
5247 }
5248
5249 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01005250 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01005251
5252 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01005253 msg.str = trash;
5254 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005255 txn->status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01005256 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01005257 if (!(t->flags & SN_ERR_MASK))
5258 t->flags |= SN_ERR_PRXCOND;
5259 if (!(t->flags & SN_FINST_MASK))
5260 t->flags |= SN_FINST_R;
5261 return 1;
5262 }
5263
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01005264 /* The request is valid, the user is authenticated. Let's start sending
Willy Tarreaub2513902006-12-17 14:52:38 +01005265 * data.
5266 */
Willy Tarreau284c7b32008-06-29 16:38:43 +02005267 EV_FD_CLR(t->cli_fd, DIR_RD);
5268 buffer_shutr(t->req);
5269 buffer_shutr(t->rep);
Willy Tarreaub2513902006-12-17 14:52:38 +01005270 t->cli_state = CL_STSHUTR;
5271 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreau70089872008-06-13 21:12:51 +02005272 t->logs.tv_request = now;
Willy Tarreaub2513902006-12-17 14:52:38 +01005273 t->data_source = DATA_SRC_STATS;
5274 t->data_state = DATA_ST_INIT;
Willy Tarreau91e99932008-06-30 07:51:00 +02005275 t->task->nice = -32; /* small boost for HTTP statistics */
Willy Tarreaub2513902006-12-17 14:52:38 +01005276 produce_content(t);
5277 return 1;
5278}
5279
5280
Willy Tarreaubaaee002006-06-26 02:48:02 +02005281/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01005282 * Print a debug line with a header
5283 */
5284void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
5285{
5286 int len, max;
5287 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
5288 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
5289 max = end - start;
5290 UBOUND(max, sizeof(trash) - len - 1);
5291 len += strlcpy2(trash + len, start, max + 1);
5292 trash[len++] = '\n';
5293 write(1, trash, len);
5294}
5295
5296
Willy Tarreau8797c062007-05-07 00:55:35 +02005297/************************************************************************/
5298/* The code below is dedicated to ACL parsing and matching */
5299/************************************************************************/
5300
5301
5302
5303
5304/* 1. Check on METHOD
5305 * We use the pre-parsed method if it is known, and store its number as an
5306 * integer. If it is unknown, we use the pointer and the length.
5307 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005308static int acl_parse_meth(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005309{
5310 int len, meth;
5311
Willy Tarreauae8b7962007-06-09 23:10:04 +02005312 len = strlen(*text);
5313 meth = find_http_meth(*text, len);
Willy Tarreau8797c062007-05-07 00:55:35 +02005314
5315 pattern->val.i = meth;
5316 if (meth == HTTP_METH_OTHER) {
Willy Tarreauae8b7962007-06-09 23:10:04 +02005317 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005318 if (!pattern->ptr.str)
5319 return 0;
5320 pattern->len = len;
5321 }
5322 return 1;
5323}
5324
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005325static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005326acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
5327 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005328{
5329 int meth;
5330 struct http_txn *txn = l7;
5331
Willy Tarreaub6866442008-07-14 23:54:42 +02005332 if (!txn)
5333 return 0;
5334
Willy Tarreauc11416f2007-06-17 16:58:38 +02005335 if (txn->req.msg_state != HTTP_MSG_BODY)
5336 return 0;
5337
Willy Tarreau8797c062007-05-07 00:55:35 +02005338 meth = txn->meth;
5339 test->i = meth;
5340 if (meth == HTTP_METH_OTHER) {
Willy Tarreauc11416f2007-06-17 16:58:38 +02005341 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5342 /* ensure the indexes are not affected */
5343 return 0;
Willy Tarreau8797c062007-05-07 00:55:35 +02005344 test->len = txn->req.sl.rq.m_l;
5345 test->ptr = txn->req.sol;
5346 }
5347 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5348 return 1;
5349}
5350
5351static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
5352{
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005353 int icase;
5354
Willy Tarreau8797c062007-05-07 00:55:35 +02005355 if (test->i != pattern->val.i)
Willy Tarreau11382812008-07-09 16:18:21 +02005356 return ACL_PAT_FAIL;
Willy Tarreau8797c062007-05-07 00:55:35 +02005357
5358 if (test->i != HTTP_METH_OTHER)
Willy Tarreau11382812008-07-09 16:18:21 +02005359 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005360
5361 /* Other method, we must compare the strings */
5362 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +02005363 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +02005364
5365 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
5366 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) != 0) ||
5367 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +02005368 return ACL_PAT_FAIL;
5369 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02005370}
5371
5372/* 2. Check on Request/Status Version
5373 * We simply compare strings here.
5374 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02005375static int acl_parse_ver(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02005376{
Willy Tarreauae8b7962007-06-09 23:10:04 +02005377 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005378 if (!pattern->ptr.str)
5379 return 0;
Willy Tarreauae8b7962007-06-09 23:10:04 +02005380 pattern->len = strlen(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02005381 return 1;
5382}
5383
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005384static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005385acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
5386 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005387{
5388 struct http_txn *txn = l7;
5389 char *ptr;
5390 int len;
5391
Willy Tarreaub6866442008-07-14 23:54:42 +02005392 if (!txn)
5393 return 0;
5394
Willy Tarreauc11416f2007-06-17 16:58:38 +02005395 if (txn->req.msg_state != HTTP_MSG_BODY)
5396 return 0;
5397
Willy Tarreau8797c062007-05-07 00:55:35 +02005398 len = txn->req.sl.rq.v_l;
5399 ptr = txn->req.sol + txn->req.sl.rq.v - txn->req.som;
5400
5401 while ((len-- > 0) && (*ptr++ != '/'));
5402 if (len <= 0)
5403 return 0;
5404
5405 test->ptr = ptr;
5406 test->len = len;
5407
5408 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5409 return 1;
5410}
5411
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005412static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005413acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
5414 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005415{
5416 struct http_txn *txn = l7;
5417 char *ptr;
5418 int len;
5419
Willy Tarreaub6866442008-07-14 23:54:42 +02005420 if (!txn)
5421 return 0;
5422
Willy Tarreauc11416f2007-06-17 16:58:38 +02005423 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5424 return 0;
5425
Willy Tarreau8797c062007-05-07 00:55:35 +02005426 len = txn->rsp.sl.st.v_l;
5427 ptr = txn->rsp.sol;
5428
5429 while ((len-- > 0) && (*ptr++ != '/'));
5430 if (len <= 0)
5431 return 0;
5432
5433 test->ptr = ptr;
5434 test->len = len;
5435
5436 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
5437 return 1;
5438}
5439
5440/* 3. Check on Status Code. We manipulate integers here. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005441static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005442acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, int dir,
5443 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005444{
5445 struct http_txn *txn = l7;
5446 char *ptr;
5447 int len;
5448
Willy Tarreaub6866442008-07-14 23:54:42 +02005449 if (!txn)
5450 return 0;
5451
Willy Tarreauc11416f2007-06-17 16:58:38 +02005452 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5453 return 0;
5454
Willy Tarreau8797c062007-05-07 00:55:35 +02005455 len = txn->rsp.sl.st.c_l;
5456 ptr = txn->rsp.sol + txn->rsp.sl.st.c - txn->rsp.som;
5457
5458 test->i = __strl2ui(ptr, len);
5459 test->flags = ACL_TEST_F_VOL_1ST;
5460 return 1;
5461}
5462
5463/* 4. Check on URL/URI. A pointer to the URI is stored. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02005464static int
Willy Tarreau97be1452007-06-10 11:47:14 +02005465acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
5466 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02005467{
5468 struct http_txn *txn = l7;
5469
Willy Tarreaub6866442008-07-14 23:54:42 +02005470 if (!txn)
5471 return 0;
5472
Willy Tarreauc11416f2007-06-17 16:58:38 +02005473 if (txn->req.msg_state != HTTP_MSG_BODY)
5474 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005475
Willy Tarreauc11416f2007-06-17 16:58:38 +02005476 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5477 /* ensure the indexes are not affected */
5478 return 0;
5479
Willy Tarreau8797c062007-05-07 00:55:35 +02005480 test->len = txn->req.sl.rq.u_l;
5481 test->ptr = txn->req.sol + txn->req.sl.rq.u;
5482
Willy Tarreauf3d25982007-05-08 22:45:09 +02005483 /* we do not need to set READ_ONLY because the data is in a buffer */
5484 test->flags = ACL_TEST_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +02005485 return 1;
5486}
5487
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005488static int
5489acl_fetch_url_ip(struct proxy *px, struct session *l4, void *l7, int dir,
5490 struct acl_expr *expr, struct acl_test *test)
5491{
5492 struct http_txn *txn = l7;
5493
Willy Tarreaub6866442008-07-14 23:54:42 +02005494 if (!txn)
5495 return 0;
5496
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005497 if (txn->req.msg_state != HTTP_MSG_BODY)
5498 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005499
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005500 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5501 /* ensure the indexes are not affected */
5502 return 0;
5503
5504 /* Parse HTTP request */
5505 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5506 test->ptr = (void *)&((struct sockaddr_in *)&l4->srv_addr)->sin_addr;
5507 test->i = AF_INET;
5508
5509 /*
5510 * If we are parsing url in frontend space, we prepare backend stage
5511 * to not parse again the same url ! optimization lazyness...
5512 */
5513 if (px->options & PR_O_HTTP_PROXY)
5514 l4->flags |= SN_ADDR_SET;
5515
5516 test->flags = ACL_TEST_F_READ_ONLY;
5517 return 1;
5518}
5519
5520static int
5521acl_fetch_url_port(struct proxy *px, struct session *l4, void *l7, int dir,
5522 struct acl_expr *expr, struct acl_test *test)
5523{
5524 struct http_txn *txn = l7;
5525
Willy Tarreaub6866442008-07-14 23:54:42 +02005526 if (!txn)
5527 return 0;
5528
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005529 if (txn->req.msg_state != HTTP_MSG_BODY)
5530 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005531
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01005532 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5533 /* ensure the indexes are not affected */
5534 return 0;
5535
5536 /* Same optimization as url_ip */
5537 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
5538 test->i = ntohs(((struct sockaddr_in *)&l4->srv_addr)->sin_port);
5539
5540 if (px->options & PR_O_HTTP_PROXY)
5541 l4->flags |= SN_ADDR_SET;
5542
5543 test->flags = ACL_TEST_F_READ_ONLY;
5544 return 1;
5545}
5546
Willy Tarreauc11416f2007-06-17 16:58:38 +02005547/* 5. Check on HTTP header. A pointer to the beginning of the value is returned.
5548 * This generic function is used by both acl_fetch_chdr() and acl_fetch_shdr().
5549 */
Willy Tarreau33a7e692007-06-10 19:45:56 +02005550static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005551acl_fetch_hdr(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005552 struct acl_expr *expr, struct acl_test *test)
5553{
5554 struct http_txn *txn = l7;
5555 struct hdr_idx *idx = &txn->hdr_idx;
5556 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005557
Willy Tarreaub6866442008-07-14 23:54:42 +02005558 if (!txn)
5559 return 0;
5560
Willy Tarreau33a7e692007-06-10 19:45:56 +02005561 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5562 /* search for header from the beginning */
5563 ctx->idx = 0;
5564
Willy Tarreau33a7e692007-06-10 19:45:56 +02005565 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5566 test->flags |= ACL_TEST_F_FETCH_MORE;
5567 test->flags |= ACL_TEST_F_VOL_HDR;
5568 test->len = ctx->vlen;
5569 test->ptr = (char *)ctx->line + ctx->val;
5570 return 1;
5571 }
5572
5573 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5574 test->flags |= ACL_TEST_F_VOL_HDR;
5575 return 0;
5576}
5577
Willy Tarreau33a7e692007-06-10 19:45:56 +02005578static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005579acl_fetch_chdr(struct proxy *px, struct session *l4, void *l7, int dir,
5580 struct acl_expr *expr, struct acl_test *test)
5581{
5582 struct http_txn *txn = l7;
5583
Willy Tarreaub6866442008-07-14 23:54:42 +02005584 if (!txn)
5585 return 0;
5586
Willy Tarreauc11416f2007-06-17 16:58:38 +02005587 if (txn->req.msg_state != HTTP_MSG_BODY)
5588 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005589
Willy Tarreauc11416f2007-06-17 16:58:38 +02005590 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5591 /* ensure the indexes are not affected */
5592 return 0;
5593
5594 return acl_fetch_hdr(px, l4, txn, txn->req.sol, expr, test);
5595}
5596
5597static int
5598acl_fetch_shdr(struct proxy *px, struct session *l4, void *l7, int dir,
5599 struct acl_expr *expr, struct acl_test *test)
5600{
5601 struct http_txn *txn = l7;
5602
Willy Tarreaub6866442008-07-14 23:54:42 +02005603 if (!txn)
5604 return 0;
5605
Willy Tarreauc11416f2007-06-17 16:58:38 +02005606 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5607 return 0;
5608
5609 return acl_fetch_hdr(px, l4, txn, txn->rsp.sol, expr, test);
5610}
5611
5612/* 6. Check on HTTP header count. The number of occurrences is returned.
5613 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
5614 */
5615static int
5616acl_fetch_hdr_cnt(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005617 struct acl_expr *expr, struct acl_test *test)
5618{
5619 struct http_txn *txn = l7;
5620 struct hdr_idx *idx = &txn->hdr_idx;
5621 struct hdr_ctx ctx;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005622 int cnt;
Willy Tarreau8797c062007-05-07 00:55:35 +02005623
Willy Tarreaub6866442008-07-14 23:54:42 +02005624 if (!txn)
5625 return 0;
5626
Willy Tarreau33a7e692007-06-10 19:45:56 +02005627 ctx.idx = 0;
5628 cnt = 0;
5629 while (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, &ctx))
5630 cnt++;
5631
5632 test->i = cnt;
5633 test->flags = ACL_TEST_F_VOL_HDR;
5634 return 1;
5635}
5636
Willy Tarreauc11416f2007-06-17 16:58:38 +02005637static int
5638acl_fetch_chdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5639 struct acl_expr *expr, struct acl_test *test)
5640{
5641 struct http_txn *txn = l7;
5642
Willy Tarreaub6866442008-07-14 23:54:42 +02005643 if (!txn)
5644 return 0;
5645
Willy Tarreauc11416f2007-06-17 16:58:38 +02005646 if (txn->req.msg_state != HTTP_MSG_BODY)
5647 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005648
Willy Tarreauc11416f2007-06-17 16:58:38 +02005649 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5650 /* ensure the indexes are not affected */
5651 return 0;
5652
5653 return acl_fetch_hdr_cnt(px, l4, txn, txn->req.sol, expr, test);
5654}
5655
5656static int
5657acl_fetch_shdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
5658 struct acl_expr *expr, struct acl_test *test)
5659{
5660 struct http_txn *txn = l7;
5661
Willy Tarreaub6866442008-07-14 23:54:42 +02005662 if (!txn)
5663 return 0;
5664
Willy Tarreauc11416f2007-06-17 16:58:38 +02005665 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5666 return 0;
5667
5668 return acl_fetch_hdr_cnt(px, l4, txn, txn->rsp.sol, expr, test);
5669}
5670
Willy Tarreau33a7e692007-06-10 19:45:56 +02005671/* 7. Check on HTTP header's integer value. The integer value is returned.
5672 * FIXME: the type is 'int', it may not be appropriate for everything.
Willy Tarreauc11416f2007-06-17 16:58:38 +02005673 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
Willy Tarreau33a7e692007-06-10 19:45:56 +02005674 */
5675static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02005676acl_fetch_hdr_val(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02005677 struct acl_expr *expr, struct acl_test *test)
5678{
5679 struct http_txn *txn = l7;
5680 struct hdr_idx *idx = &txn->hdr_idx;
5681 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005682
Willy Tarreaub6866442008-07-14 23:54:42 +02005683 if (!txn)
5684 return 0;
5685
Willy Tarreau33a7e692007-06-10 19:45:56 +02005686 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
5687 /* search for header from the beginning */
5688 ctx->idx = 0;
5689
Willy Tarreau33a7e692007-06-10 19:45:56 +02005690 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
5691 test->flags |= ACL_TEST_F_FETCH_MORE;
5692 test->flags |= ACL_TEST_F_VOL_HDR;
5693 test->i = strl2ic((char *)ctx->line + ctx->val, ctx->vlen);
5694 return 1;
5695 }
5696
5697 test->flags &= ~ACL_TEST_F_FETCH_MORE;
5698 test->flags |= ACL_TEST_F_VOL_HDR;
5699 return 0;
5700}
5701
Willy Tarreauc11416f2007-06-17 16:58:38 +02005702static int
5703acl_fetch_chdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5704 struct acl_expr *expr, struct acl_test *test)
5705{
5706 struct http_txn *txn = l7;
5707
Willy Tarreaub6866442008-07-14 23:54:42 +02005708 if (!txn)
5709 return 0;
5710
Willy Tarreauc11416f2007-06-17 16:58:38 +02005711 if (txn->req.msg_state != HTTP_MSG_BODY)
5712 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005713
Willy Tarreauc11416f2007-06-17 16:58:38 +02005714 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5715 /* ensure the indexes are not affected */
5716 return 0;
5717
5718 return acl_fetch_hdr_val(px, l4, txn, txn->req.sol, expr, test);
5719}
5720
5721static int
5722acl_fetch_shdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
5723 struct acl_expr *expr, struct acl_test *test)
5724{
5725 struct http_txn *txn = l7;
5726
Willy Tarreaub6866442008-07-14 23:54:42 +02005727 if (!txn)
5728 return 0;
5729
Willy Tarreauc11416f2007-06-17 16:58:38 +02005730 if (txn->rsp.msg_state != HTTP_MSG_BODY)
5731 return 0;
5732
5733 return acl_fetch_hdr_val(px, l4, txn, txn->rsp.sol, expr, test);
5734}
5735
Willy Tarreau737b0c12007-06-10 21:28:46 +02005736/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at
5737 * the first '/' after the possible hostname, and ends before the possible '?'.
5738 */
5739static int
5740acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
5741 struct acl_expr *expr, struct acl_test *test)
5742{
5743 struct http_txn *txn = l7;
5744 char *ptr, *end;
Willy Tarreau33a7e692007-06-10 19:45:56 +02005745
Willy Tarreaub6866442008-07-14 23:54:42 +02005746 if (!txn)
5747 return 0;
5748
Willy Tarreauc11416f2007-06-17 16:58:38 +02005749 if (txn->req.msg_state != HTTP_MSG_BODY)
5750 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02005751
Willy Tarreauc11416f2007-06-17 16:58:38 +02005752 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
5753 /* ensure the indexes are not affected */
5754 return 0;
5755
Willy Tarreau21d2af32008-02-14 20:25:24 +01005756 end = txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
5757 ptr = http_get_path(txn);
5758 if (!ptr)
Willy Tarreau737b0c12007-06-10 21:28:46 +02005759 return 0;
5760
5761 /* OK, we got the '/' ! */
5762 test->ptr = ptr;
5763
5764 while (ptr < end && *ptr != '?')
5765 ptr++;
5766
5767 test->len = ptr - test->ptr;
5768
5769 /* we do not need to set READ_ONLY because the data is in a buffer */
5770 test->flags = ACL_TEST_F_VOL_1ST;
5771 return 1;
5772}
5773
5774
Willy Tarreau8797c062007-05-07 00:55:35 +02005775
5776/************************************************************************/
5777/* All supported keywords must be declared here. */
5778/************************************************************************/
5779
5780/* Note: must not be declared <const> as its list will be overwritten */
5781static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005782 { "method", acl_parse_meth, acl_fetch_meth, acl_match_meth, ACL_USE_L7REQ_PERMANENT },
5783 { "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5784 { "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str, ACL_USE_L7RTR_VOLATILE },
5785 { "status", acl_parse_int, acl_fetch_stcode, acl_match_int, ACL_USE_L7RTR_PERMANENT },
Willy Tarreau8797c062007-05-07 00:55:35 +02005786
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005787 { "url", acl_parse_str, acl_fetch_url, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5788 { "url_beg", acl_parse_str, acl_fetch_url, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5789 { "url_end", acl_parse_str, acl_fetch_url, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5790 { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5791 { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5792 { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
5793 { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5794 { "url_ip", acl_parse_ip, acl_fetch_url_ip, acl_match_ip, ACL_USE_L7REQ_VOLATILE },
5795 { "url_port", acl_parse_int, acl_fetch_url_port, acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau8797c062007-05-07 00:55:35 +02005796
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005797 /* note: we should set hdr* to use ACL_USE_HDR_VOLATILE, and chdr* to use L7REQ_VOLATILE */
5798 { "hdr", acl_parse_str, acl_fetch_chdr, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5799 { "hdr_reg", acl_parse_reg, acl_fetch_chdr, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5800 { "hdr_beg", acl_parse_str, acl_fetch_chdr, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5801 { "hdr_end", acl_parse_str, acl_fetch_chdr, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5802 { "hdr_sub", acl_parse_str, acl_fetch_chdr, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5803 { "hdr_dir", acl_parse_str, acl_fetch_chdr, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5804 { "hdr_dom", acl_parse_str, acl_fetch_chdr, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
5805 { "hdr_cnt", acl_parse_int, acl_fetch_chdr_cnt,acl_match_int, ACL_USE_L7REQ_VOLATILE },
5806 { "hdr_val", acl_parse_int, acl_fetch_chdr_val,acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreauc11416f2007-06-17 16:58:38 +02005807
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005808 { "shdr", acl_parse_str, acl_fetch_shdr, acl_match_str, ACL_USE_L7RTR_VOLATILE },
5809 { "shdr_reg", acl_parse_reg, acl_fetch_shdr, acl_match_reg, ACL_USE_L7RTR_VOLATILE },
5810 { "shdr_beg", acl_parse_str, acl_fetch_shdr, acl_match_beg, ACL_USE_L7RTR_VOLATILE },
5811 { "shdr_end", acl_parse_str, acl_fetch_shdr, acl_match_end, ACL_USE_L7RTR_VOLATILE },
5812 { "shdr_sub", acl_parse_str, acl_fetch_shdr, acl_match_sub, ACL_USE_L7RTR_VOLATILE },
5813 { "shdr_dir", acl_parse_str, acl_fetch_shdr, acl_match_dir, ACL_USE_L7RTR_VOLATILE },
5814 { "shdr_dom", acl_parse_str, acl_fetch_shdr, acl_match_dom, ACL_USE_L7RTR_VOLATILE },
5815 { "shdr_cnt", acl_parse_int, acl_fetch_shdr_cnt,acl_match_int, ACL_USE_L7RTR_VOLATILE },
5816 { "shdr_val", acl_parse_int, acl_fetch_shdr_val,acl_match_int, ACL_USE_L7RTR_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005817
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02005818 { "path", acl_parse_str, acl_fetch_path, acl_match_str, ACL_USE_L7REQ_VOLATILE },
5819 { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
5820 { "path_beg", acl_parse_str, acl_fetch_path, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
5821 { "path_end", acl_parse_str, acl_fetch_path, acl_match_end, ACL_USE_L7REQ_VOLATILE },
5822 { "path_sub", acl_parse_str, acl_fetch_path, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
5823 { "path_dir", acl_parse_str, acl_fetch_path, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
5824 { "path_dom", acl_parse_str, acl_fetch_path, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02005825
Willy Tarreauf3d25982007-05-08 22:45:09 +02005826 { NULL, NULL, NULL, NULL },
5827
5828#if 0
Willy Tarreau8797c062007-05-07 00:55:35 +02005829 { "line", acl_parse_str, acl_fetch_line, acl_match_str },
5830 { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg },
5831 { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg },
5832 { "line_end", acl_parse_str, acl_fetch_line, acl_match_end },
5833 { "line_sub", acl_parse_str, acl_fetch_line, acl_match_sub },
5834 { "line_dir", acl_parse_str, acl_fetch_line, acl_match_dir },
5835 { "line_dom", acl_parse_str, acl_fetch_line, acl_match_dom },
5836
Willy Tarreau8797c062007-05-07 00:55:35 +02005837 { "cook", acl_parse_str, acl_fetch_cook, acl_match_str },
5838 { "cook_reg", acl_parse_reg, acl_fetch_cook, acl_match_reg },
5839 { "cook_beg", acl_parse_str, acl_fetch_cook, acl_match_beg },
5840 { "cook_end", acl_parse_str, acl_fetch_cook, acl_match_end },
5841 { "cook_sub", acl_parse_str, acl_fetch_cook, acl_match_sub },
5842 { "cook_dir", acl_parse_str, acl_fetch_cook, acl_match_dir },
5843 { "cook_dom", acl_parse_str, acl_fetch_cook, acl_match_dom },
5844 { "cook_pst", acl_parse_none, acl_fetch_cook, acl_match_pst },
5845
5846 { "auth_user", acl_parse_str, acl_fetch_user, acl_match_str },
5847 { "auth_regex", acl_parse_reg, acl_fetch_user, acl_match_reg },
5848 { "auth_clear", acl_parse_str, acl_fetch_auth, acl_match_str },
5849 { "auth_md5", acl_parse_str, acl_fetch_auth, acl_match_md5 },
5850 { NULL, NULL, NULL, NULL },
5851#endif
5852}};
5853
5854
5855__attribute__((constructor))
5856static void __http_protocol_init(void)
5857{
5858 acl_register_keywords(&acl_kws);
5859}
5860
5861
Willy Tarreau58f10d72006-12-04 02:26:12 +01005862/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02005863 * Local variables:
5864 * c-indent-level: 8
5865 * c-basic-offset: 8
5866 * End:
5867 */