blob: 2cf5572e9b0ba64d6e886f444d0752e90096d347 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * HTTP protocol analyzer
3 *
Willy Tarreaudeb9ed82010-01-03 21:03:22 +01004 * Copyright 2000-2010 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>
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +010044#include <proto/checks.h>
Maik Broemme2850cb42009-04-17 18:53:21 +020045#include <proto/client.h>
Willy Tarreau91861262007-10-17 17:06:05 +020046#include <proto/dumpstats.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020047#include <proto/fd.h>
48#include <proto/log.h>
Willy Tarreau58f10d72006-12-04 02:26:12 +010049#include <proto/hdr_idx.h>
Willy Tarreaub6866442008-07-14 23:54:42 +020050#include <proto/proto_tcp.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020051#include <proto/proto_http.h>
Willy Tarreau7f062c42009-03-05 18:43:00 +010052#include <proto/proxy.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020053#include <proto/queue.h>
Willy Tarreau7f062c42009-03-05 18:43:00 +010054#include <proto/server.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020055#include <proto/session.h>
Willy Tarreaucff64112008-11-03 06:26:53 +010056#include <proto/stream_interface.h>
Willy Tarreau2d212792008-08-27 21:41:35 +020057#include <proto/stream_sock.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020058#include <proto/task.h>
59
Willy Tarreau522d6c02009-12-06 18:49:18 +010060const char HTTP_100[] =
61 "HTTP/1.1 100 Continue\r\n\r\n";
62
63const struct chunk http_100_chunk = {
64 .str = (char *)&HTTP_100,
65 .len = sizeof(HTTP_100)-1
66};
67
Willy Tarreau1c47f852006-07-09 08:22:27 +020068/* This is used by remote monitoring */
Willy Tarreau0f772532006-12-23 20:51:41 +010069const char HTTP_200[] =
Willy Tarreau1c47f852006-07-09 08:22:27 +020070 "HTTP/1.0 200 OK\r\n"
71 "Cache-Control: no-cache\r\n"
72 "Connection: close\r\n"
73 "Content-Type: text/html\r\n"
74 "\r\n"
75 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
76
Willy Tarreau0f772532006-12-23 20:51:41 +010077const struct chunk http_200_chunk = {
78 .str = (char *)&HTTP_200,
79 .len = sizeof(HTTP_200)-1
80};
81
Willy Tarreaua9679ac2010-01-03 17:32:57 +010082/* Warning: no "connection" header is provided with the 3xx messages below */
Willy Tarreaub463dfb2008-06-07 23:08:56 +020083const char *HTTP_301 =
Willy Tarreaubc5aa192010-01-03 15:09:36 +010084 "HTTP/1.1 301 Moved Permanently\r\n"
Willy Tarreaub463dfb2008-06-07 23:08:56 +020085 "Cache-Control: no-cache\r\n"
Willy Tarreaubc5aa192010-01-03 15:09:36 +010086 "Content-length: 0\r\n"
Willy Tarreaub463dfb2008-06-07 23:08:56 +020087 "Location: "; /* not terminated since it will be concatenated with the URL */
88
Willy Tarreau0f772532006-12-23 20:51:41 +010089const char *HTTP_302 =
Willy Tarreaubc5aa192010-01-03 15:09:36 +010090 "HTTP/1.1 302 Found\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +010091 "Cache-Control: no-cache\r\n"
Willy Tarreaubc5aa192010-01-03 15:09:36 +010092 "Content-length: 0\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +010093 "Location: "; /* not terminated since it will be concatenated with the URL */
94
95/* same as 302 except that the browser MUST retry with the GET method */
96const char *HTTP_303 =
Willy Tarreaubc5aa192010-01-03 15:09:36 +010097 "HTTP/1.1 303 See Other\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +010098 "Cache-Control: no-cache\r\n"
Willy Tarreaubc5aa192010-01-03 15:09:36 +010099 "Content-length: 0\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +0100100 "Location: "; /* not terminated since it will be concatenated with the URL */
101
Willy Tarreaubaaee002006-06-26 02:48:02 +0200102/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
103const char *HTTP_401_fmt =
104 "HTTP/1.0 401 Unauthorized\r\n"
105 "Cache-Control: no-cache\r\n"
106 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +0200107 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200108 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
109 "\r\n"
110 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
111
Willy Tarreau0f772532006-12-23 20:51:41 +0100112
113const int http_err_codes[HTTP_ERR_SIZE] = {
114 [HTTP_ERR_400] = 400,
115 [HTTP_ERR_403] = 403,
116 [HTTP_ERR_408] = 408,
117 [HTTP_ERR_500] = 500,
118 [HTTP_ERR_502] = 502,
119 [HTTP_ERR_503] = 503,
120 [HTTP_ERR_504] = 504,
121};
122
Willy Tarreau80587432006-12-24 17:47:20 +0100123static const char *http_err_msgs[HTTP_ERR_SIZE] = {
Willy Tarreau0f772532006-12-23 20:51:41 +0100124 [HTTP_ERR_400] =
Willy Tarreau80587432006-12-24 17:47:20 +0100125 "HTTP/1.0 400 Bad request\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +0100126 "Cache-Control: no-cache\r\n"
127 "Connection: close\r\n"
128 "Content-Type: text/html\r\n"
129 "\r\n"
130 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
131
132 [HTTP_ERR_403] =
133 "HTTP/1.0 403 Forbidden\r\n"
134 "Cache-Control: no-cache\r\n"
135 "Connection: close\r\n"
136 "Content-Type: text/html\r\n"
137 "\r\n"
138 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
139
140 [HTTP_ERR_408] =
141 "HTTP/1.0 408 Request Time-out\r\n"
142 "Cache-Control: no-cache\r\n"
143 "Connection: close\r\n"
144 "Content-Type: text/html\r\n"
145 "\r\n"
146 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
147
148 [HTTP_ERR_500] =
149 "HTTP/1.0 500 Server Error\r\n"
150 "Cache-Control: no-cache\r\n"
151 "Connection: close\r\n"
152 "Content-Type: text/html\r\n"
153 "\r\n"
154 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n",
155
156 [HTTP_ERR_502] =
157 "HTTP/1.0 502 Bad Gateway\r\n"
158 "Cache-Control: no-cache\r\n"
159 "Connection: close\r\n"
160 "Content-Type: text/html\r\n"
161 "\r\n"
162 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n",
163
164 [HTTP_ERR_503] =
165 "HTTP/1.0 503 Service Unavailable\r\n"
166 "Cache-Control: no-cache\r\n"
167 "Connection: close\r\n"
168 "Content-Type: text/html\r\n"
169 "\r\n"
170 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n",
171
172 [HTTP_ERR_504] =
173 "HTTP/1.0 504 Gateway Time-out\r\n"
174 "Cache-Control: no-cache\r\n"
175 "Connection: close\r\n"
176 "Content-Type: text/html\r\n"
177 "\r\n"
178 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n",
179
180};
181
Willy Tarreau80587432006-12-24 17:47:20 +0100182/* We must put the messages here since GCC cannot initialize consts depending
183 * on strlen().
184 */
185struct chunk http_err_chunks[HTTP_ERR_SIZE];
186
Willy Tarreau42250582007-04-01 01:30:43 +0200187#define FD_SETS_ARE_BITFIELDS
188#ifdef FD_SETS_ARE_BITFIELDS
189/*
190 * This map is used with all the FD_* macros to check whether a particular bit
191 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
192 * which should be encoded. When FD_ISSET() returns non-zero, it means that the
193 * byte should be encoded. Be careful to always pass bytes from 0 to 255
194 * exclusively to the macros.
195 */
196fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
197fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
198
199#else
200#error "Check if your OS uses bitfields for fd_sets"
201#endif
202
Willy Tarreau80587432006-12-24 17:47:20 +0100203void init_proto_http()
204{
Willy Tarreau42250582007-04-01 01:30:43 +0200205 int i;
206 char *tmp;
Willy Tarreau80587432006-12-24 17:47:20 +0100207 int msg;
Willy Tarreau42250582007-04-01 01:30:43 +0200208
Willy Tarreau80587432006-12-24 17:47:20 +0100209 for (msg = 0; msg < HTTP_ERR_SIZE; msg++) {
210 if (!http_err_msgs[msg]) {
211 Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n", msg);
212 abort();
213 }
214
215 http_err_chunks[msg].str = (char *)http_err_msgs[msg];
216 http_err_chunks[msg].len = strlen(http_err_msgs[msg]);
217 }
Willy Tarreau42250582007-04-01 01:30:43 +0200218
219 /* initialize the log header encoding map : '{|}"#' should be encoded with
220 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
221 * URL encoding only requires '"', '#' to be encoded as well as non-
222 * printable characters above.
223 */
224 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
225 memset(url_encode_map, 0, sizeof(url_encode_map));
226 for (i = 0; i < 32; i++) {
227 FD_SET(i, hdr_encode_map);
228 FD_SET(i, url_encode_map);
229 }
230 for (i = 127; i < 256; i++) {
231 FD_SET(i, hdr_encode_map);
232 FD_SET(i, url_encode_map);
233 }
234
235 tmp = "\"#{|}";
236 while (*tmp) {
237 FD_SET(*tmp, hdr_encode_map);
238 tmp++;
239 }
240
241 tmp = "\"#";
242 while (*tmp) {
243 FD_SET(*tmp, url_encode_map);
244 tmp++;
245 }
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200246
247 /* memory allocations */
248 pool2_requri = create_pool("requri", REQURI_LEN, MEM_F_SHARED);
Willy Tarreau086b3b42007-05-13 21:45:51 +0200249 pool2_capture = create_pool("capture", CAPTURE_LEN, MEM_F_SHARED);
Willy Tarreau80587432006-12-24 17:47:20 +0100250}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200251
Willy Tarreau53b6c742006-12-17 13:37:46 +0100252/*
253 * We have 26 list of methods (1 per first letter), each of which can have
254 * up to 3 entries (2 valid, 1 null).
255 */
256struct http_method_desc {
257 http_meth_t meth;
258 int len;
259 const char text[8];
260};
261
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100262const struct http_method_desc http_methods[26][3] = {
Willy Tarreau53b6c742006-12-17 13:37:46 +0100263 ['C' - 'A'] = {
264 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
265 },
266 ['D' - 'A'] = {
267 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
268 },
269 ['G' - 'A'] = {
270 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
271 },
272 ['H' - 'A'] = {
273 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
274 },
275 ['P' - 'A'] = {
276 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
277 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
278 },
279 ['T' - 'A'] = {
280 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
281 },
282 /* rest is empty like this :
283 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
284 */
285};
286
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100287/* It is about twice as fast on recent architectures to lookup a byte in a
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +0200288 * table than to perform a boolean AND or OR between two tests. Refer to
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100289 * RFC2616 for those chars.
290 */
291
292const char http_is_spht[256] = {
293 [' '] = 1, ['\t'] = 1,
294};
295
296const char http_is_crlf[256] = {
297 ['\r'] = 1, ['\n'] = 1,
298};
299
300const char http_is_lws[256] = {
301 [' '] = 1, ['\t'] = 1,
302 ['\r'] = 1, ['\n'] = 1,
303};
304
305const char http_is_sep[256] = {
306 ['('] = 1, [')'] = 1, ['<'] = 1, ['>'] = 1,
307 ['@'] = 1, [','] = 1, [';'] = 1, [':'] = 1,
308 ['"'] = 1, ['/'] = 1, ['['] = 1, [']'] = 1,
309 ['{'] = 1, ['}'] = 1, ['?'] = 1, ['='] = 1,
310 [' '] = 1, ['\t'] = 1, ['\\'] = 1,
311};
312
313const char http_is_ctl[256] = {
314 [0 ... 31] = 1,
315 [127] = 1,
316};
317
318/*
319 * A token is any ASCII char that is neither a separator nor a CTL char.
320 * Do not overwrite values in assignment since gcc-2.95 will not handle
321 * them correctly. Instead, define every non-CTL char's status.
322 */
323const char http_is_token[256] = {
324 [' '] = 0, ['!'] = 1, ['"'] = 0, ['#'] = 1,
325 ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1,
326 ['('] = 0, [')'] = 0, ['*'] = 1, ['+'] = 1,
327 [','] = 0, ['-'] = 1, ['.'] = 1, ['/'] = 0,
328 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1,
329 ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1,
330 ['8'] = 1, ['9'] = 1, [':'] = 0, [';'] = 0,
331 ['<'] = 0, ['='] = 0, ['>'] = 0, ['?'] = 0,
332 ['@'] = 0, ['A'] = 1, ['B'] = 1, ['C'] = 1,
333 ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1,
334 ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1,
335 ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1,
336 ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1,
337 ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1,
338 ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 0,
339 ['\\'] = 0, [']'] = 0, ['^'] = 1, ['_'] = 1,
340 ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1,
341 ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1,
342 ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1,
343 ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1,
344 ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1,
345 ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1,
346 ['x'] = 1, ['y'] = 1, ['z'] = 1, ['{'] = 0,
347 ['|'] = 1, ['}'] = 0, ['~'] = 1,
348};
349
350
Willy Tarreau4b89ad42007-03-04 18:13:58 +0100351/*
352 * An http ver_token is any ASCII which can be found in an HTTP version,
353 * which includes 'H', 'T', 'P', '/', '.' and any digit.
354 */
355const char http_is_ver_token[256] = {
356 ['.'] = 1, ['/'] = 1,
357 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1,
358 ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1,
359 ['H'] = 1, ['P'] = 1, ['T'] = 1,
360};
361
362
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100363/*
Willy Tarreaue988a792010-01-04 21:13:14 +0100364 * Silent debug that outputs only in strace, using fd #-1. Trash is modified.
365 */
366#if defined(DEBUG_FSM)
367static void http_silent_debug(int line, struct session *s)
368{
369 int size = 0;
370 size += snprintf(trash + size, sizeof(trash) - size,
371 "[%04d] req: p=%d(%d) s=%d bf=%08x an=%08x data=%p size=%d l=%d w=%p r=%p lr=%p sm=%d fw=%ld tf=%08x\n",
372 line,
373 s->si[0].state, s->si[0].fd, s->txn.req.msg_state, s->req->flags, s->req->analysers,
374 s->req->data, s->req->size, s->req->l, s->req->w, s->req->r, s->req->lr, s->req->send_max, s->req->to_forward, s->txn.flags);
375 write(-1, trash, size);
376 size = 0;
377 size += snprintf(trash + size, sizeof(trash) - size,
378 " %04d rep: p=%d(%d) s=%d bf=%08x an=%08x data=%p size=%d l=%d w=%p r=%p lr=%p sm=%d fw=%ld\n",
379 line,
380 s->si[1].state, s->si[1].fd, s->txn.rsp.msg_state, s->rep->flags, s->rep->analysers,
381 s->rep->data, s->rep->size, s->rep->l, s->rep->w, s->rep->r, s->rep->lr, s->rep->send_max, s->rep->to_forward);
382
383 write(-1, trash, size);
384}
385#else
386#define http_silent_debug(l,s) do { } while (0)
387#endif
388
389/*
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100390 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
391 * CRLF. Text length is measured first, so it cannot be NULL.
392 * The header is also automatically added to the index <hdr_idx>, and the end
393 * of headers is automatically adjusted. The number of bytes added is returned
394 * on success, otherwise <0 is returned indicating an error.
395 */
396int http_header_add_tail(struct buffer *b, struct http_msg *msg,
397 struct hdr_idx *hdr_idx, const char *text)
398{
399 int bytes, len;
400
401 len = strlen(text);
402 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
403 if (!bytes)
404 return -1;
Willy Tarreaufa355d42009-11-29 18:12:29 +0100405 http_msg_move_end(msg, bytes);
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100406 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
407}
408
409/*
410 * Adds a header and its CRLF at the tail of buffer <b>, just before the last
411 * CRLF. <len> bytes are copied, not counting the CRLF. If <text> is NULL, then
412 * the buffer is only opened and the space reserved, but nothing is copied.
413 * The header is also automatically added to the index <hdr_idx>, and the end
414 * of headers is automatically adjusted. The number of bytes added is returned
415 * on success, otherwise <0 is returned indicating an error.
416 */
417int http_header_add_tail2(struct buffer *b, struct http_msg *msg,
418 struct hdr_idx *hdr_idx, const char *text, int len)
419{
420 int bytes;
421
422 bytes = buffer_insert_line2(b, b->data + msg->eoh, text, len);
423 if (!bytes)
424 return -1;
Willy Tarreaufa355d42009-11-29 18:12:29 +0100425 http_msg_move_end(msg, bytes);
Willy Tarreau4af6f3a2007-03-18 22:36:26 +0100426 return hdr_idx_add(len, 1, hdr_idx, hdr_idx->tail);
427}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200428
429/*
Willy Tarreauaa9dce32007-03-18 23:50:16 +0100430 * Checks if <hdr> is exactly <name> for <len> chars, and ends with a colon.
431 * If so, returns the position of the first non-space character relative to
432 * <hdr>, or <end>-<hdr> if not found before. If no value is found, it tries
433 * to return a pointer to the place after the first space. Returns 0 if the
434 * header name does not match. Checks are case-insensitive.
435 */
436int http_header_match2(const char *hdr, const char *end,
437 const char *name, int len)
438{
439 const char *val;
440
441 if (hdr + len >= end)
442 return 0;
443 if (hdr[len] != ':')
444 return 0;
445 if (strncasecmp(hdr, name, len) != 0)
446 return 0;
447 val = hdr + len + 1;
448 while (val < end && HTTP_IS_SPHT(*val))
449 val++;
450 if ((val >= end) && (len + 2 <= end - hdr))
451 return len + 2; /* we may replace starting from second space */
452 return val - hdr;
453}
454
Willy Tarreau68085d82010-01-18 14:54:04 +0100455/* Find the end of the header value contained between <s> and <e>. See RFC2616,
456 * par 2.2 for more information. Note that it requires a valid header to return
457 * a valid result. This works for headers defined as comma-separated lists.
Willy Tarreau33a7e692007-06-10 19:45:56 +0200458 */
Willy Tarreau68085d82010-01-18 14:54:04 +0100459char *find_hdr_value_end(char *s, const char *e)
Willy Tarreau33a7e692007-06-10 19:45:56 +0200460{
461 int quoted, qdpair;
462
463 quoted = qdpair = 0;
464 for (; s < e; s++) {
465 if (qdpair) qdpair = 0;
466 else if (quoted && *s == '\\') qdpair = 1;
467 else if (quoted && *s == '"') quoted = 0;
468 else if (*s == '"') quoted = 1;
469 else if (*s == ',') return s;
470 }
471 return s;
472}
473
474/* Find the first or next occurrence of header <name> in message buffer <sol>
475 * using headers index <idx>, and return it in the <ctx> structure. This
476 * structure holds everything necessary to use the header and find next
477 * occurrence. If its <idx> member is 0, the header is searched from the
478 * beginning. Otherwise, the next occurrence is returned. The function returns
Willy Tarreau68085d82010-01-18 14:54:04 +0100479 * 1 when it finds a value, and 0 when there is no more. It is designed to work
480 * with headers defined as comma-separated lists. As a special case, if ctx->val
481 * is NULL when searching for a new values of a header, the current header is
482 * rescanned. This allows rescanning after a header deletion.
Willy Tarreau33a7e692007-06-10 19:45:56 +0200483 */
484int http_find_header2(const char *name, int len,
Willy Tarreau68085d82010-01-18 14:54:04 +0100485 char *sol, struct hdr_idx *idx,
Willy Tarreau33a7e692007-06-10 19:45:56 +0200486 struct hdr_ctx *ctx)
487{
Willy Tarreau68085d82010-01-18 14:54:04 +0100488 char *eol, *sov;
489 int cur_idx, old_idx;
Willy Tarreau33a7e692007-06-10 19:45:56 +0200490
Willy Tarreau68085d82010-01-18 14:54:04 +0100491 cur_idx = ctx->idx;
492 if (cur_idx) {
Willy Tarreau33a7e692007-06-10 19:45:56 +0200493 /* We have previously returned a value, let's search
494 * another one on the same line.
495 */
Willy Tarreau33a7e692007-06-10 19:45:56 +0200496 sol = ctx->line;
Willy Tarreau68085d82010-01-18 14:54:04 +0100497 ctx->del = ctx->val + ctx->vlen;
498 sov = sol + ctx->del;
Willy Tarreau33a7e692007-06-10 19:45:56 +0200499 eol = sol + idx->v[cur_idx].len;
500
501 if (sov >= eol)
502 /* no more values in this header */
503 goto next_hdr;
504
Willy Tarreau68085d82010-01-18 14:54:04 +0100505 /* values remaining for this header, skip the comma but save it
506 * for later use (eg: for header deletion).
507 */
Willy Tarreau33a7e692007-06-10 19:45:56 +0200508 sov++;
509 while (sov < eol && http_is_lws[(unsigned char)*sov])
510 sov++;
511
512 goto return_hdr;
513 }
514
515 /* first request for this header */
516 sol += hdr_idx_first_pos(idx);
Willy Tarreau68085d82010-01-18 14:54:04 +0100517 old_idx = 0;
Willy Tarreau33a7e692007-06-10 19:45:56 +0200518 cur_idx = hdr_idx_first_idx(idx);
Willy Tarreau33a7e692007-06-10 19:45:56 +0200519 while (cur_idx) {
520 eol = sol + idx->v[cur_idx].len;
521
Willy Tarreau1ad7c6d2007-06-10 21:42:55 +0200522 if (len == 0) {
523 /* No argument was passed, we want any header.
524 * To achieve this, we simply build a fake request. */
525 while (sol + len < eol && sol[len] != ':')
526 len++;
527 name = sol;
528 }
529
Willy Tarreau33a7e692007-06-10 19:45:56 +0200530 if ((len < eol - sol) &&
531 (sol[len] == ':') &&
532 (strncasecmp(sol, name, len) == 0)) {
Willy Tarreau68085d82010-01-18 14:54:04 +0100533 ctx->del = len;
Willy Tarreau33a7e692007-06-10 19:45:56 +0200534 sov = sol + len + 1;
535 while (sov < eol && http_is_lws[(unsigned char)*sov])
536 sov++;
Willy Tarreau68085d82010-01-18 14:54:04 +0100537
Willy Tarreau33a7e692007-06-10 19:45:56 +0200538 ctx->line = sol;
Willy Tarreau68085d82010-01-18 14:54:04 +0100539 ctx->prev = old_idx;
540 return_hdr:
Willy Tarreau33a7e692007-06-10 19:45:56 +0200541 ctx->idx = cur_idx;
542 ctx->val = sov - sol;
543
544 eol = find_hdr_value_end(sov, eol);
545 ctx->vlen = eol - sov;
546 return 1;
547 }
548 next_hdr:
549 sol = eol + idx->v[cur_idx].cr + 1;
Willy Tarreau68085d82010-01-18 14:54:04 +0100550 old_idx = cur_idx;
Willy Tarreau33a7e692007-06-10 19:45:56 +0200551 cur_idx = idx->v[cur_idx].next;
552 }
553 return 0;
554}
555
556int http_find_header(const char *name,
Willy Tarreau68085d82010-01-18 14:54:04 +0100557 char *sol, struct hdr_idx *idx,
Willy Tarreau33a7e692007-06-10 19:45:56 +0200558 struct hdr_ctx *ctx)
559{
560 return http_find_header2(name, strlen(name), sol, idx, ctx);
561}
562
Willy Tarreau68085d82010-01-18 14:54:04 +0100563/* Remove one value of a header. This only works on a <ctx> returned by one of
564 * the http_find_header functions. The value is removed, as well as surrounding
565 * commas if any. If the removed value was alone, the whole header is removed.
566 * The ctx is always updated accordingly, as well as buffer <buf> and HTTP
567 * message <msg>. The new index is returned. If it is zero, it means there is
568 * no more header, so any processing may stop. The ctx is always left in a form
569 * that can be handled by http_find_header2() to find next occurrence.
570 */
571int http_remove_header2(struct http_msg *msg, struct buffer *buf,
572 struct hdr_idx *idx, struct hdr_ctx *ctx)
573{
574 int cur_idx = ctx->idx;
575 char *sol = ctx->line;
576 struct hdr_idx_elem *hdr;
577 int delta, skip_comma;
578
579 if (!cur_idx)
580 return 0;
581
582 hdr = &idx->v[cur_idx];
583 if (sol[ctx->del] == ':' && ctx->val + ctx->vlen == hdr->len) {
584 /* This was the only value of the header, we must now remove it entirely. */
585 delta = buffer_replace2(buf, sol, sol + hdr->len + hdr->cr + 1, NULL, 0);
586 http_msg_move_end(msg, delta);
587 idx->used--;
588 hdr->len = 0; /* unused entry */
589 idx->v[ctx->prev].next = idx->v[ctx->idx].next;
590 ctx->idx = ctx->prev; /* walk back to the end of previous header */
591 ctx->line -= idx->v[ctx->idx].len + idx->v[cur_idx].cr + 1;
592 ctx->val = idx->v[ctx->idx].len; /* point to end of previous header */
593 ctx->vlen = 0;
594 return ctx->idx;
595 }
596
597 /* This was not the only value of this header. We have to remove between
598 * ctx->del+1 and ctx->val+ctx->vlen+1 included. If it is the last entry
599 * of the list, we remove the last separator.
600 */
601
602 skip_comma = (ctx->val + ctx->vlen == hdr->len) ? 0 : 1;
603 delta = buffer_replace2(buf, sol + ctx->del + skip_comma,
604 sol + ctx->val + ctx->vlen + skip_comma,
605 NULL, 0);
606 hdr->len += delta;
607 http_msg_move_end(msg, delta);
608 ctx->val = ctx->del;
609 ctx->vlen = 0;
610 return ctx->idx;
611}
612
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100613/* This function handles a server error at the stream interface level. The
614 * stream interface is assumed to be already in a closed state. An optional
615 * message is copied into the input buffer, and an HTTP status code stored.
616 * The error flags are set to the values in arguments. Any pending request
Willy Tarreau6f0aa472009-03-08 20:33:29 +0100617 * in this buffer will be lost.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200618 */
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100619static void http_server_error(struct session *t, struct stream_interface *si,
620 int err, int finst, int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200621{
Willy Tarreau6f0aa472009-03-08 20:33:29 +0100622 buffer_erase(si->ob);
623 buffer_erase(si->ib);
Willy Tarreau520d95e2009-09-19 21:04:57 +0200624 buffer_auto_close(si->ib);
Willy Tarreau90deb182010-01-07 00:20:41 +0100625 buffer_auto_read(si->ib);
Willy Tarreau0f772532006-12-23 20:51:41 +0100626 if (status > 0 && msg) {
Willy Tarreau3bac9ff2007-03-18 17:31:28 +0100627 t->txn.status = status;
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100628 buffer_write(si->ib, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200629 }
630 if (!(t->flags & SN_ERR_MASK))
631 t->flags |= err;
632 if (!(t->flags & SN_FINST_MASK))
633 t->flags |= finst;
634}
635
Willy Tarreau80587432006-12-24 17:47:20 +0100636/* This function returns the appropriate error location for the given session
637 * and message.
638 */
639
640struct chunk *error_message(struct session *s, int msgnum)
641{
Willy Tarreaue2e27a52007-04-01 00:01:37 +0200642 if (s->be->errmsg[msgnum].str)
643 return &s->be->errmsg[msgnum];
Willy Tarreau80587432006-12-24 17:47:20 +0100644 else if (s->fe->errmsg[msgnum].str)
645 return &s->fe->errmsg[msgnum];
646 else
647 return &http_err_chunks[msgnum];
648}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200649
Willy Tarreau53b6c742006-12-17 13:37:46 +0100650/*
651 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
652 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
653 */
654static http_meth_t find_http_meth(const char *str, const int len)
655{
656 unsigned char m;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100657 const struct http_method_desc *h;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100658
659 m = ((unsigned)*str - 'A');
660
661 if (m < 26) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100662 for (h = http_methods[m]; h->len > 0; h++) {
663 if (unlikely(h->len != len))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100664 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100665 if (likely(memcmp(str, h->text, h->len) == 0))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100666 return h->meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100667 };
668 return HTTP_METH_OTHER;
669 }
670 return HTTP_METH_NONE;
671
672}
673
Willy Tarreau21d2af32008-02-14 20:25:24 +0100674/* Parse the URI from the given transaction (which is assumed to be in request
675 * phase) and look for the "/" beginning the PATH. If not found, return NULL.
676 * It is returned otherwise.
677 */
678static char *
679http_get_path(struct http_txn *txn)
680{
681 char *ptr, *end;
682
Willy Tarreau962c3f42010-01-10 00:15:35 +0100683 ptr = txn->req.sol + txn->req.sl.rq.u;
Willy Tarreau21d2af32008-02-14 20:25:24 +0100684 end = ptr + txn->req.sl.rq.u_l;
685
686 if (ptr >= end)
687 return NULL;
688
689 /* RFC2616, par. 5.1.2 :
690 * Request-URI = "*" | absuri | abspath | authority
691 */
692
693 if (*ptr == '*')
694 return NULL;
695
696 if (isalpha((unsigned char)*ptr)) {
697 /* this is a scheme as described by RFC3986, par. 3.1 */
698 ptr++;
699 while (ptr < end &&
700 (isalnum((unsigned char)*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.'))
701 ptr++;
702 /* skip '://' */
703 if (ptr == end || *ptr++ != ':')
704 return NULL;
705 if (ptr == end || *ptr++ != '/')
706 return NULL;
707 if (ptr == end || *ptr++ != '/')
708 return NULL;
709 }
710 /* skip [user[:passwd]@]host[:[port]] */
711
712 while (ptr < end && *ptr != '/')
713 ptr++;
714
715 if (ptr == end)
716 return NULL;
717
718 /* OK, we got the '/' ! */
719 return ptr;
720}
721
Willy Tarreauefb453c2008-10-26 20:49:47 +0100722/* Returns a 302 for a redirectable request. This may only be called just after
723 * the stream interface has moved to SI_ST_ASS. Unprocessable requests are
724 * left unchanged and will follow normal proxy processing.
725 */
Willy Tarreau55a8d0e2008-11-30 18:47:21 +0100726void perform_http_redirect(struct session *s, struct stream_interface *si)
Willy Tarreauefb453c2008-10-26 20:49:47 +0100727{
728 struct http_txn *txn;
729 struct chunk rdr;
730 char *path;
731 int len;
732
733 /* 1: create the response header */
734 rdr.len = strlen(HTTP_302);
735 rdr.str = trash;
Willy Tarreau59e0b0f2010-01-09 21:29:23 +0100736 rdr.size = sizeof(trash);
Willy Tarreauefb453c2008-10-26 20:49:47 +0100737 memcpy(rdr.str, HTTP_302, rdr.len);
738
739 /* 2: add the server's prefix */
Krzysztof Piotr Oledzki78abe612009-09-27 13:23:20 +0200740 if (rdr.len + s->srv->rdr_len > rdr.size)
Willy Tarreauefb453c2008-10-26 20:49:47 +0100741 return;
742
Willy Tarreaudcb75c42010-01-10 00:24:22 +0100743 /* special prefix "/" means don't change URL */
744 if (s->srv->rdr_len != 1 || *s->srv->rdr_pfx != '/') {
745 memcpy(rdr.str + rdr.len, s->srv->rdr_pfx, s->srv->rdr_len);
746 rdr.len += s->srv->rdr_len;
747 }
Willy Tarreauefb453c2008-10-26 20:49:47 +0100748
749 /* 3: add the request URI */
750 txn = &s->txn;
751 path = http_get_path(txn);
752 if (!path)
753 return;
754
Willy Tarreau962c3f42010-01-10 00:15:35 +0100755 len = txn->req.sl.rq.u_l + (txn->req.sol + txn->req.sl.rq.u) - path;
Krzysztof Piotr Oledzki78abe612009-09-27 13:23:20 +0200756 if (rdr.len + len > rdr.size - 4) /* 4 for CRLF-CRLF */
Willy Tarreauefb453c2008-10-26 20:49:47 +0100757 return;
758
759 memcpy(rdr.str + rdr.len, path, len);
760 rdr.len += len;
Willy Tarreaua9679ac2010-01-03 17:32:57 +0100761 memcpy(rdr.str + rdr.len, "\r\nConnection: close\r\n\r\n", 23);
762 rdr.len += 23;
Willy Tarreauefb453c2008-10-26 20:49:47 +0100763
764 /* prepare to return without error. */
Willy Tarreau99126c32008-11-27 10:30:51 +0100765 si->shutr(si);
766 si->shutw(si);
Willy Tarreauefb453c2008-10-26 20:49:47 +0100767 si->err_type = SI_ET_NONE;
768 si->err_loc = NULL;
769 si->state = SI_ST_CLO;
770
771 /* send the message */
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100772 http_server_error(s, si, SN_ERR_PRXCOND, SN_FINST_C, 302, &rdr);
Willy Tarreauefb453c2008-10-26 20:49:47 +0100773
774 /* FIXME: we should increase a counter of redirects per server and per backend. */
775 if (s->srv)
Willy Tarreau7f062c42009-03-05 18:43:00 +0100776 srv_inc_sess_ctr(s->srv);
Willy Tarreauefb453c2008-10-26 20:49:47 +0100777}
778
Willy Tarreau0cac36f2008-11-30 20:44:17 +0100779/* Return the error message corresponding to si->err_type. It is assumed
Willy Tarreauefb453c2008-10-26 20:49:47 +0100780 * that the server side is closed. Note that err_type is actually a
781 * bitmask, where almost only aborts may be cumulated with other
782 * values. We consider that aborted operations are more important
783 * than timeouts or errors due to the fact that nobody else in the
784 * logs might explain incomplete retries. All others should avoid
785 * being cumulated. It should normally not be possible to have multiple
786 * aborts at once, but just in case, the first one in sequence is reported.
787 */
Willy Tarreau0cac36f2008-11-30 20:44:17 +0100788void http_return_srv_error(struct session *s, struct stream_interface *si)
Willy Tarreauefb453c2008-10-26 20:49:47 +0100789{
Willy Tarreau0cac36f2008-11-30 20:44:17 +0100790 int err_type = si->err_type;
Willy Tarreauefb453c2008-10-26 20:49:47 +0100791
792 if (err_type & SI_ET_QUEUE_ABRT)
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100793 http_server_error(s, si, SN_ERR_CLICL, SN_FINST_Q,
794 503, error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100795 else if (err_type & SI_ET_CONN_ABRT)
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100796 http_server_error(s, si, SN_ERR_CLICL, SN_FINST_C,
797 503, error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100798 else if (err_type & SI_ET_QUEUE_TO)
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100799 http_server_error(s, si, SN_ERR_SRVTO, SN_FINST_Q,
800 503, error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100801 else if (err_type & SI_ET_QUEUE_ERR)
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100802 http_server_error(s, si, SN_ERR_SRVCL, SN_FINST_Q,
803 503, error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100804 else if (err_type & SI_ET_CONN_TO)
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100805 http_server_error(s, si, SN_ERR_SRVTO, SN_FINST_C,
806 503, error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100807 else if (err_type & SI_ET_CONN_ERR)
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100808 http_server_error(s, si, SN_ERR_SRVCL, SN_FINST_C,
809 503, error_message(s, HTTP_ERR_503));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100810 else /* SI_ET_CONN_OTHER and others */
Willy Tarreau2d3d94c2008-11-30 20:20:08 +0100811 http_server_error(s, si, SN_ERR_INTERNAL, SN_FINST_C,
812 500, error_message(s, HTTP_ERR_500));
Willy Tarreauefb453c2008-10-26 20:49:47 +0100813}
814
Willy Tarreau42250582007-04-01 01:30:43 +0200815extern const char sess_term_cond[8];
816extern const char sess_fin_state[8];
817extern const char *monthname[12];
818const char sess_cookie[4] = "NIDV"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie */
819const char sess_set_cookie[8] = "N1I3PD5R"; /* No set-cookie, unknown, Set-Cookie Inserted, unknown,
820 Set-cookie seen and left unchanged (passive), Set-cookie Deleted,
821 unknown, Set-cookie Rewritten */
Willy Tarreau332f8bf2007-05-13 21:36:56 +0200822struct pool_head *pool2_requri;
Willy Tarreau086b3b42007-05-13 21:45:51 +0200823struct pool_head *pool2_capture;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100824
Emeric Brun3a058f32009-06-30 18:26:00 +0200825void http_sess_clflog(struct session *s)
826{
827 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
828 struct proxy *fe = s->fe;
829 struct proxy *be = s->be;
830 struct proxy *prx_log;
831 struct http_txn *txn = &s->txn;
832 int tolog, level, err;
833 char *uri, *h;
834 char *svid;
835 struct tm tm;
836 static char tmpline[MAX_SYSLOG_LEN];
837 int hdr;
838 size_t w;
839 int t_request;
840
841 prx_log = fe;
842 err = (s->flags & (SN_ERR_MASK | SN_REDISP)) ||
843 (s->conn_retries != be->conn_retries) ||
844 txn->status >= 500;
845
846 if (s->cli_addr.ss_family == AF_INET)
847 inet_ntop(AF_INET,
848 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
849 pn, sizeof(pn));
850 else
851 inet_ntop(AF_INET6,
852 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
853 pn, sizeof(pn));
854
855 get_gmtime(s->logs.accept_date.tv_sec, &tm);
856
857 /* FIXME: let's limit ourselves to frontend logging for now. */
858 tolog = fe->to_log;
859
860 h = tmpline;
861
862 w = snprintf(h, sizeof(tmpline),
863 "%s - - [%02d/%s/%04d:%02d:%02d:%02d +0000]",
864 pn,
865 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
866 tm.tm_hour, tm.tm_min, tm.tm_sec);
867 if (w < 0 || w >= sizeof(tmpline) - (h - tmpline))
868 goto trunc;
869 h += w;
870
871 if (h >= tmpline + sizeof(tmpline) - 4)
872 goto trunc;
873
874 *(h++) = ' ';
875 *(h++) = '\"';
876 uri = txn->uri ? txn->uri : "<BADREQ>";
877 h = encode_string(h, tmpline + sizeof(tmpline) - 1,
878 '#', url_encode_map, uri);
879 *(h++) = '\"';
880
881 w = snprintf(h, sizeof(tmpline) - (h - tmpline), " %d %lld", txn->status, s->logs.bytes_out);
882 if (w < 0 || w >= sizeof(tmpline) - (h - tmpline))
883 goto trunc;
884 h += w;
885
886 if (h >= tmpline + sizeof(tmpline) - 9)
887 goto trunc;
888 memcpy(h, " \"-\" \"-\"", 8);
889 h += 8;
890
891 w = snprintf(h, sizeof(tmpline) - (h - tmpline),
892 " %d %03d",
893 (s->cli_addr.ss_family == AF_INET) ?
894 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
895 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
896 (int)s->logs.accept_date.tv_usec/1000);
897 if (w < 0 || w >= sizeof(tmpline) - (h - tmpline))
898 goto trunc;
899 h += w;
900
901 w = strlen(fe->id);
902 if (h >= tmpline + sizeof(tmpline) - 4 - w)
903 goto trunc;
904 *(h++) = ' ';
905 *(h++) = '\"';
906 memcpy(h, fe->id, w);
907 h += w;
908 *(h++) = '\"';
909
910 w = strlen(be->id);
911 if (h >= tmpline + sizeof(tmpline) - 4 - w)
912 goto trunc;
913 *(h++) = ' ';
914 *(h++) = '\"';
915 memcpy(h, be->id, w);
916 h += w;
917 *(h++) = '\"';
918
919 svid = (tolog & LW_SVID) ?
920 (s->data_source != DATA_SRC_STATS) ?
921 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
922
923 w = strlen(svid);
924 if (h >= tmpline + sizeof(tmpline) - 4 - w)
925 goto trunc;
926 *(h++) = ' ';
927 *(h++) = '\"';
928 memcpy(h, svid, w);
929 h += w;
930 *(h++) = '\"';
931
932 t_request = -1;
933 if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
934 t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
935 w = snprintf(h, sizeof(tmpline) - (h - tmpline),
936 " %d %ld %ld %ld %ld",
937 t_request,
938 (s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1,
939 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
940 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
941 s->logs.t_close);
942 if (w < 0 || w >= sizeof(tmpline) - (h - tmpline))
943 goto trunc;
944 h += w;
945
946 if (h >= tmpline + sizeof(tmpline) - 8)
947 goto trunc;
948 *(h++) = ' ';
949 *(h++) = '\"';
950 *(h++) = sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT];
951 *(h++) = sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT];
952 *(h++) = (be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-',
953 *(h++) = (be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-';
954 *(h++) = '\"';
955
956 w = snprintf(h, sizeof(tmpline) - (h - tmpline),
957 " %d %d %d %d %d %ld %ld",
958 actconn, fe->feconn, be->beconn, s->srv ? s->srv->cur_sess : 0,
959 (s->conn_retries > 0) ? (be->conn_retries - s->conn_retries) : be->conn_retries,
960 s->logs.srv_queue_size, s->logs.prx_queue_size);
961
962 if (w < 0 || w >= sizeof(tmpline) - (h - tmpline))
963 goto trunc;
964 h += w;
965
966 if (txn->cli_cookie) {
967 w = strlen(txn->cli_cookie);
968 if (h >= tmpline + sizeof(tmpline) - 4 - w)
969 goto trunc;
970 *(h++) = ' ';
971 *(h++) = '\"';
972 memcpy(h, txn->cli_cookie, w);
973 h += w;
974 *(h++) = '\"';
975 } else {
976 if (h >= tmpline + sizeof(tmpline) - 5)
977 goto trunc;
978 memcpy(h, " \"-\"", 4);
979 h += 4;
980 }
981
982 if (txn->srv_cookie) {
983 w = strlen(txn->srv_cookie);
984 if (h >= tmpline + sizeof(tmpline) - 4 - w)
985 goto trunc;
986 *(h++) = ' ';
987 *(h++) = '\"';
988 memcpy(h, txn->srv_cookie, w);
989 h += w;
990 *(h++) = '\"';
991 } else {
992 if (h >= tmpline + sizeof(tmpline) - 5)
993 goto trunc;
994 memcpy(h, " \"-\"", 4);
995 h += 4;
996 }
997
998 if ((fe->to_log & LW_REQHDR) && txn->req.cap) {
999 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
1000 if (h >= sizeof (tmpline) + tmpline - 4)
1001 goto trunc;
1002 *(h++) = ' ';
1003 *(h++) = '\"';
1004 h = encode_string(h, tmpline + sizeof(tmpline) - 2,
1005 '#', hdr_encode_map, txn->req.cap[hdr]);
1006 *(h++) = '\"';
1007 }
1008 }
1009
1010 if ((fe->to_log & LW_RSPHDR) && txn->rsp.cap) {
1011 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
1012 if (h >= sizeof (tmpline) + tmpline - 4)
1013 goto trunc;
1014 *(h++) = ' ';
1015 *(h++) = '\"';
1016 h = encode_string(h, tmpline + sizeof(tmpline) - 2,
1017 '#', hdr_encode_map, txn->rsp.cap[hdr]);
1018 *(h++) = '\"';
1019 }
1020 }
1021
1022trunc:
1023 *h = '\0';
1024
1025 level = LOG_INFO;
1026 if (err && (fe->options2 & PR_O2_LOGERRORS))
1027 level = LOG_ERR;
1028
1029 send_log(prx_log, level, "%s\n", tmpline);
1030
1031 s->logs.logwait = 0;
1032}
1033
Willy Tarreau42250582007-04-01 01:30:43 +02001034/*
1035 * send a log for the session when we have enough info about it.
1036 * Will not log if the frontend has no log defined.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001037 */
Willy Tarreau55a8d0e2008-11-30 18:47:21 +01001038void http_sess_log(struct session *s)
Willy Tarreau42250582007-04-01 01:30:43 +02001039{
1040 char pn[INET6_ADDRSTRLEN + strlen(":65535")];
1041 struct proxy *fe = s->fe;
1042 struct proxy *be = s->be;
1043 struct proxy *prx_log;
1044 struct http_txn *txn = &s->txn;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02001045 int tolog, level, err;
Willy Tarreau42250582007-04-01 01:30:43 +02001046 char *uri, *h;
1047 char *svid;
Willy Tarreaufe944602007-10-25 10:34:16 +02001048 struct tm tm;
Willy Tarreau42250582007-04-01 01:30:43 +02001049 static char tmpline[MAX_SYSLOG_LEN];
Willy Tarreau70089872008-06-13 21:12:51 +02001050 int t_request;
Willy Tarreau42250582007-04-01 01:30:43 +02001051 int hdr;
1052
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02001053 /* if we don't want to log normal traffic, return now */
1054 err = (s->flags & (SN_ERR_MASK | SN_REDISP)) ||
1055 (s->conn_retries != be->conn_retries) ||
1056 txn->status >= 500;
1057 if (!err && (fe->options2 & PR_O2_NOLOGNORM))
1058 return;
1059
Willy Tarreau42250582007-04-01 01:30:43 +02001060 if (fe->logfac1 < 0 && fe->logfac2 < 0)
1061 return;
1062 prx_log = fe;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001063
Emeric Brun3a058f32009-06-30 18:26:00 +02001064 if (prx_log->options2 & PR_O2_CLFLOG)
1065 return http_sess_clflog(s);
1066
Willy Tarreau42250582007-04-01 01:30:43 +02001067 if (s->cli_addr.ss_family == AF_INET)
1068 inet_ntop(AF_INET,
1069 (const void *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr,
1070 pn, sizeof(pn));
1071 else
1072 inet_ntop(AF_INET6,
1073 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
1074 pn, sizeof(pn));
1075
Willy Tarreaub7f694f2008-06-22 17:18:02 +02001076 get_localtime(s->logs.accept_date.tv_sec, &tm);
Willy Tarreau42250582007-04-01 01:30:43 +02001077
1078 /* FIXME: let's limit ourselves to frontend logging for now. */
1079 tolog = fe->to_log;
1080
1081 h = tmpline;
1082 if (fe->to_log & LW_REQHDR &&
1083 txn->req.cap &&
1084 (h < tmpline + sizeof(tmpline) - 10)) {
1085 *(h++) = ' ';
1086 *(h++) = '{';
1087 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
1088 if (hdr)
1089 *(h++) = '|';
1090 if (txn->req.cap[hdr] != NULL)
1091 h = encode_string(h, tmpline + sizeof(tmpline) - 7,
1092 '#', hdr_encode_map, txn->req.cap[hdr]);
1093 }
1094 *(h++) = '}';
1095 }
1096
1097 if (fe->to_log & LW_RSPHDR &&
1098 txn->rsp.cap &&
1099 (h < tmpline + sizeof(tmpline) - 7)) {
1100 *(h++) = ' ';
1101 *(h++) = '{';
1102 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
1103 if (hdr)
1104 *(h++) = '|';
1105 if (txn->rsp.cap[hdr] != NULL)
1106 h = encode_string(h, tmpline + sizeof(tmpline) - 4,
1107 '#', hdr_encode_map, txn->rsp.cap[hdr]);
1108 }
1109 *(h++) = '}';
1110 }
1111
1112 if (h < tmpline + sizeof(tmpline) - 4) {
1113 *(h++) = ' ';
1114 *(h++) = '"';
1115 uri = txn->uri ? txn->uri : "<BADREQ>";
1116 h = encode_string(h, tmpline + sizeof(tmpline) - 1,
1117 '#', url_encode_map, uri);
1118 *(h++) = '"';
1119 }
1120 *h = '\0';
1121
1122 svid = (tolog & LW_SVID) ?
1123 (s->data_source != DATA_SRC_STATS) ?
1124 (s->srv != NULL) ? s->srv->id : "<NOSRV>" : "<STATS>" : "-";
1125
Willy Tarreau70089872008-06-13 21:12:51 +02001126 t_request = -1;
1127 if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
1128 t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
1129
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02001130 level = LOG_INFO;
1131 if (err && (fe->options2 & PR_O2_LOGERRORS))
1132 level = LOG_ERR;
1133
1134 send_log(prx_log, level,
Willy Tarreau42250582007-04-01 01:30:43 +02001135 "%s:%d [%02d/%s/%04d:%02d:%02d:%02d.%03d]"
Willy Tarreau1772ece2009-04-03 14:49:12 +02001136 " %s %s/%s %d/%ld/%ld/%ld/%s%ld %d %s%lld"
1137 " %s %s %c%c%c%c %d/%d/%d/%d/%s%u %ld/%ld%s\n",
Willy Tarreau42250582007-04-01 01:30:43 +02001138 pn,
1139 (s->cli_addr.ss_family == AF_INET) ?
1140 ntohs(((struct sockaddr_in *)&s->cli_addr)->sin_port) :
1141 ntohs(((struct sockaddr_in6 *)&s->cli_addr)->sin6_port),
Willy Tarreaufe944602007-10-25 10:34:16 +02001142 tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
Willy Tarreau1772ece2009-04-03 14:49:12 +02001143 tm.tm_hour, tm.tm_min, tm.tm_sec, (int)s->logs.accept_date.tv_usec/1000,
Willy Tarreau42250582007-04-01 01:30:43 +02001144 fe->id, be->id, svid,
Willy Tarreau70089872008-06-13 21:12:51 +02001145 t_request,
1146 (s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1,
Willy Tarreau42250582007-04-01 01:30:43 +02001147 (s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1,
1148 (s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1,
1149 (tolog & LW_BYTES) ? "" : "+", s->logs.t_close,
1150 txn->status,
Willy Tarreau8b3977f2008-01-18 11:16:32 +01001151 (tolog & LW_BYTES) ? "" : "+", s->logs.bytes_out,
Willy Tarreau42250582007-04-01 01:30:43 +02001152 txn->cli_cookie ? txn->cli_cookie : "-",
1153 txn->srv_cookie ? txn->srv_cookie : "-",
1154 sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT],
1155 sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT],
1156 (be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-',
1157 (be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-',
1158 actconn, fe->feconn, be->beconn, s->srv ? s->srv->cur_sess : 0,
Krzysztof Piotr Oledzki25b501a2008-01-06 16:36:16 +01001159 (s->flags & SN_REDISP)?"+":"",
1160 (s->conn_retries>0)?(be->conn_retries - s->conn_retries):be->conn_retries,
Willy Tarreau42250582007-04-01 01:30:43 +02001161 s->logs.srv_queue_size, s->logs.prx_queue_size, tmpline);
1162
1163 s->logs.logwait = 0;
1164}
1165
Willy Tarreau117f59e2007-03-04 18:17:17 +01001166
1167/*
1168 * Capture headers from message starting at <som> according to header list
1169 * <cap_hdr>, and fill the <idx> structure appropriately.
1170 */
1171void capture_headers(char *som, struct hdr_idx *idx,
1172 char **cap, struct cap_hdr *cap_hdr)
1173{
1174 char *eol, *sol, *col, *sov;
1175 int cur_idx;
1176 struct cap_hdr *h;
1177 int len;
1178
1179 sol = som + hdr_idx_first_pos(idx);
1180 cur_idx = hdr_idx_first_idx(idx);
1181
1182 while (cur_idx) {
1183 eol = sol + idx->v[cur_idx].len;
1184
1185 col = sol;
1186 while (col < eol && *col != ':')
1187 col++;
1188
1189 sov = col + 1;
1190 while (sov < eol && http_is_lws[(unsigned char)*sov])
1191 sov++;
1192
1193 for (h = cap_hdr; h; h = h->next) {
1194 if ((h->namelen == col - sol) &&
1195 (strncasecmp(sol, h->name, h->namelen) == 0)) {
1196 if (cap[h->index] == NULL)
1197 cap[h->index] =
Willy Tarreaucf7f3202007-05-13 22:46:04 +02001198 pool_alloc2(h->pool);
Willy Tarreau117f59e2007-03-04 18:17:17 +01001199
1200 if (cap[h->index] == NULL) {
1201 Alert("HTTP capture : out of memory.\n");
1202 continue;
1203 }
1204
1205 len = eol - sov;
1206 if (len > h->len)
1207 len = h->len;
1208
1209 memcpy(cap[h->index], sov, len);
1210 cap[h->index][len]=0;
1211 }
1212 }
1213 sol = eol + idx->v[cur_idx].cr + 1;
1214 cur_idx = idx->v[cur_idx].next;
1215 }
1216}
1217
1218
Willy Tarreau42250582007-04-01 01:30:43 +02001219/* either we find an LF at <ptr> or we jump to <bad>.
1220 */
1221#define EXPECT_LF_HERE(ptr, bad) do { if (unlikely(*(ptr) != '\n')) goto bad; } while (0)
1222
1223/* plays with variables <ptr>, <end> and <state>. Jumps to <good> if OK,
1224 * otherwise to <http_msg_ood> with <state> set to <st>.
1225 */
1226#define EAT_AND_JUMP_OR_RETURN(good, st) do { \
1227 ptr++; \
1228 if (likely(ptr < end)) \
1229 goto good; \
1230 else { \
1231 state = (st); \
1232 goto http_msg_ood; \
1233 } \
1234 } while (0)
1235
1236
Willy Tarreaubaaee002006-06-26 02:48:02 +02001237/*
Willy Tarreaua15645d2007-03-18 16:22:39 +01001238 * This function parses a status line between <ptr> and <end>, starting with
Willy Tarreau8973c702007-01-21 23:58:29 +01001239 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
1240 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
1241 * will give undefined results.
1242 * Note that it is upon the caller's responsibility to ensure that ptr < end,
1243 * and that msg->sol points to the beginning of the response.
1244 * If a complete line is found (which implies that at least one CR or LF is
1245 * found before <end>, the updated <ptr> is returned, otherwise NULL is
1246 * returned indicating an incomplete line (which does not mean that parts have
1247 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
1248 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
1249 * upon next call.
1250 *
Willy Tarreau9cdde232007-05-02 20:58:19 +02001251 * This function was intentionally designed to be called from
Willy Tarreau8973c702007-01-21 23:58:29 +01001252 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
1253 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +02001254 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreau8973c702007-01-21 23:58:29 +01001255 */
Willy Tarreaue69eada2008-01-27 00:34:10 +01001256const char *http_parse_stsline(struct http_msg *msg, const char *msg_buf,
1257 unsigned int state, const char *ptr, const char *end,
1258 char **ret_ptr, unsigned int *ret_state)
Willy Tarreau8973c702007-01-21 23:58:29 +01001259{
Willy Tarreau8973c702007-01-21 23:58:29 +01001260 switch (state) {
1261 http_msg_rpver:
1262 case HTTP_MSG_RPVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001263 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8973c702007-01-21 23:58:29 +01001264 EAT_AND_JUMP_OR_RETURN(http_msg_rpver, HTTP_MSG_RPVER);
1265
1266 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001267 msg->sl.st.v_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +01001268 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
1269 }
Willy Tarreau7552c032009-03-01 11:10:40 +01001270 state = HTTP_MSG_ERROR;
1271 break;
1272
Willy Tarreau8973c702007-01-21 23:58:29 +01001273 http_msg_rpver_sp:
1274 case HTTP_MSG_RPVER_SP:
1275 if (likely(!HTTP_IS_LWS(*ptr))) {
Willy Tarreau962c3f42010-01-10 00:15:35 +01001276 msg->sl.st.c = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +01001277 goto http_msg_rpcode;
1278 }
1279 if (likely(HTTP_IS_SPHT(*ptr)))
1280 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
1281 /* so it's a CR/LF, this is invalid */
Willy Tarreau7552c032009-03-01 11:10:40 +01001282 state = HTTP_MSG_ERROR;
1283 break;
Willy Tarreau8973c702007-01-21 23:58:29 +01001284
1285 http_msg_rpcode:
1286 case HTTP_MSG_RPCODE:
1287 if (likely(!HTTP_IS_LWS(*ptr)))
1288 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode, HTTP_MSG_RPCODE);
1289
1290 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreau962c3f42010-01-10 00:15:35 +01001291 msg->sl.st.c_l = (ptr - msg_buf) - msg->som - msg->sl.st.c;
Willy Tarreau8973c702007-01-21 23:58:29 +01001292 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1293 }
1294
1295 /* so it's a CR/LF, so there is no reason phrase */
Willy Tarreau962c3f42010-01-10 00:15:35 +01001296 msg->sl.st.c_l = (ptr - msg_buf) - msg->som - msg->sl.st.c;
Willy Tarreau8973c702007-01-21 23:58:29 +01001297 http_msg_rsp_reason:
1298 /* FIXME: should we support HTTP responses without any reason phrase ? */
Willy Tarreau962c3f42010-01-10 00:15:35 +01001299 msg->sl.st.r = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +01001300 msg->sl.st.r_l = 0;
1301 goto http_msg_rpline_eol;
1302
1303 http_msg_rpcode_sp:
1304 case HTTP_MSG_RPCODE_SP:
1305 if (likely(!HTTP_IS_LWS(*ptr))) {
Willy Tarreau962c3f42010-01-10 00:15:35 +01001306 msg->sl.st.r = (ptr - msg_buf) - msg->som;
Willy Tarreau8973c702007-01-21 23:58:29 +01001307 goto http_msg_rpreason;
1308 }
1309 if (likely(HTTP_IS_SPHT(*ptr)))
1310 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
1311 /* so it's a CR/LF, so there is no reason phrase */
1312 goto http_msg_rsp_reason;
1313
1314 http_msg_rpreason:
1315 case HTTP_MSG_RPREASON:
1316 if (likely(!HTTP_IS_CRLF(*ptr)))
1317 EAT_AND_JUMP_OR_RETURN(http_msg_rpreason, HTTP_MSG_RPREASON);
Willy Tarreau962c3f42010-01-10 00:15:35 +01001318 msg->sl.st.r_l = (ptr - msg_buf) - msg->som - msg->sl.st.r;
Willy Tarreau8973c702007-01-21 23:58:29 +01001319 http_msg_rpline_eol:
1320 /* We have seen the end of line. Note that we do not
1321 * necessarily have the \n yet, but at least we know that we
1322 * have EITHER \r OR \n, otherwise the response would not be
1323 * complete. We can then record the response length and return
1324 * to the caller which will be able to register it.
1325 */
1326 msg->sl.st.l = ptr - msg->sol;
1327 return ptr;
1328
1329#ifdef DEBUG_FULL
1330 default:
1331 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1332 exit(1);
1333#endif
1334 }
1335
1336 http_msg_ood:
Willy Tarreau7552c032009-03-01 11:10:40 +01001337 /* out of valid data */
Willy Tarreau8973c702007-01-21 23:58:29 +01001338 if (ret_state)
1339 *ret_state = state;
1340 if (ret_ptr)
1341 *ret_ptr = (char *)ptr;
1342 return NULL;
Willy Tarreau8973c702007-01-21 23:58:29 +01001343}
1344
1345
1346/*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001347 * This function parses a request line between <ptr> and <end>, starting with
1348 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
1349 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
1350 * will give undefined results.
1351 * Note that it is upon the caller's responsibility to ensure that ptr < end,
1352 * and that msg->sol points to the beginning of the request.
1353 * If a complete line is found (which implies that at least one CR or LF is
1354 * found before <end>, the updated <ptr> is returned, otherwise NULL is
1355 * returned indicating an incomplete line (which does not mean that parts have
1356 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
1357 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
1358 * upon next call.
1359 *
Willy Tarreau9cdde232007-05-02 20:58:19 +02001360 * This function was intentionally designed to be called from
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001361 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
1362 * within its state machine and use the same macros, hence the need for same
Willy Tarreau9cdde232007-05-02 20:58:19 +02001363 * labels and variable names. Note that msg->sol is left unchanged.
Willy Tarreaubaaee002006-06-26 02:48:02 +02001364 */
Willy Tarreaue69eada2008-01-27 00:34:10 +01001365const char *http_parse_reqline(struct http_msg *msg, const char *msg_buf,
1366 unsigned int state, const char *ptr, const char *end,
1367 char **ret_ptr, unsigned int *ret_state)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001368{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001369 switch (state) {
1370 http_msg_rqmeth:
1371 case HTTP_MSG_RQMETH:
1372 if (likely(HTTP_IS_TOKEN(*ptr)))
1373 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth, HTTP_MSG_RQMETH);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001374
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001375 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001376 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001377 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1378 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001379
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001380 if (likely(HTTP_IS_CRLF(*ptr))) {
1381 /* HTTP 0.9 request */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001382 msg->sl.rq.m_l = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001383 http_msg_req09_uri:
Willy Tarreau962c3f42010-01-10 00:15:35 +01001384 msg->sl.rq.u = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001385 http_msg_req09_uri_e:
Willy Tarreau962c3f42010-01-10 00:15:35 +01001386 msg->sl.rq.u_l = (ptr - msg_buf) - msg->som - msg->sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001387 http_msg_req09_ver:
Willy Tarreau962c3f42010-01-10 00:15:35 +01001388 msg->sl.rq.v = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001389 msg->sl.rq.v_l = 0;
1390 goto http_msg_rqline_eol;
1391 }
Willy Tarreau7552c032009-03-01 11:10:40 +01001392 state = HTTP_MSG_ERROR;
1393 break;
1394
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001395 http_msg_rqmeth_sp:
1396 case HTTP_MSG_RQMETH_SP:
1397 if (likely(!HTTP_IS_LWS(*ptr))) {
Willy Tarreau962c3f42010-01-10 00:15:35 +01001398 msg->sl.rq.u = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001399 goto http_msg_rquri;
1400 }
1401 if (likely(HTTP_IS_SPHT(*ptr)))
1402 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
1403 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1404 goto http_msg_req09_uri;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001405
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001406 http_msg_rquri:
1407 case HTTP_MSG_RQURI:
1408 if (likely(!HTTP_IS_LWS(*ptr)))
1409 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001410
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001411 if (likely(HTTP_IS_SPHT(*ptr))) {
Willy Tarreau962c3f42010-01-10 00:15:35 +01001412 msg->sl.rq.u_l = (ptr - msg_buf) - msg->som - msg->sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001413 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1414 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001415
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001416 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1417 goto http_msg_req09_uri_e;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001418
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001419 http_msg_rquri_sp:
1420 case HTTP_MSG_RQURI_SP:
1421 if (likely(!HTTP_IS_LWS(*ptr))) {
Willy Tarreau962c3f42010-01-10 00:15:35 +01001422 msg->sl.rq.v = (ptr - msg_buf) - msg->som;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001423 goto http_msg_rqver;
1424 }
1425 if (likely(HTTP_IS_SPHT(*ptr)))
1426 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
1427 /* so it's a CR/LF, meaning an HTTP 0.9 request */
1428 goto http_msg_req09_ver;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001429
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001430 http_msg_rqver:
1431 case HTTP_MSG_RQVER:
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001432 if (likely(HTTP_IS_VER_TOKEN(*ptr)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001433 EAT_AND_JUMP_OR_RETURN(http_msg_rqver, HTTP_MSG_RQVER);
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001434
1435 if (likely(HTTP_IS_CRLF(*ptr))) {
Willy Tarreau962c3f42010-01-10 00:15:35 +01001436 msg->sl.rq.v_l = (ptr - msg_buf) - msg->som - msg->sl.rq.v;
Willy Tarreau4b89ad42007-03-04 18:13:58 +01001437 http_msg_rqline_eol:
1438 /* We have seen the end of line. Note that we do not
1439 * necessarily have the \n yet, but at least we know that we
1440 * have EITHER \r OR \n, otherwise the request would not be
1441 * complete. We can then record the request length and return
1442 * to the caller which will be able to register it.
1443 */
1444 msg->sl.rq.l = ptr - msg->sol;
1445 return ptr;
1446 }
1447
1448 /* neither an HTTP_VER token nor a CRLF */
Willy Tarreau7552c032009-03-01 11:10:40 +01001449 state = HTTP_MSG_ERROR;
1450 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001451
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001452#ifdef DEBUG_FULL
1453 default:
1454 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1455 exit(1);
1456#endif
1457 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001458
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001459 http_msg_ood:
Willy Tarreau7552c032009-03-01 11:10:40 +01001460 /* out of valid data */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001461 if (ret_state)
1462 *ret_state = state;
1463 if (ret_ptr)
1464 *ret_ptr = (char *)ptr;
1465 return NULL;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001466}
Willy Tarreau58f10d72006-12-04 02:26:12 +01001467
1468
Willy Tarreau8973c702007-01-21 23:58:29 +01001469/*
1470 * This function parses an HTTP message, either a request or a response,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001471 * depending on the initial msg->msg_state. It can be preempted everywhere
Willy Tarreau8973c702007-01-21 23:58:29 +01001472 * when data are missing and recalled at the exact same location with no
1473 * information loss. The header index is re-initialized when switching from
Willy Tarreau9cdde232007-05-02 20:58:19 +02001474 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH. It modifies msg->sol among other
Willy Tarreau15de77e2010-01-02 21:59:16 +01001475 * fields. Note that msg->som and msg->sol will be initialized after completing
1476 * the first state, so that none of the msg pointers has to be initialized
1477 * prior to the first call.
Willy Tarreau8973c702007-01-21 23:58:29 +01001478 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001479void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx *idx)
1480{
Willy Tarreaue69eada2008-01-27 00:34:10 +01001481 unsigned int state; /* updated only when leaving the FSM */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001482 register char *ptr, *end; /* request pointers, to avoid dereferences */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001483
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001484 state = msg->msg_state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001485 ptr = buf->lr;
1486 end = buf->r;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001487
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001488 if (unlikely(ptr >= end))
1489 goto http_msg_ood;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001490
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001491 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +01001492 /*
1493 * First, states that are specific to the response only.
1494 * We check them first so that request and headers are
1495 * closer to each other (accessed more often).
1496 */
1497 http_msg_rpbefore:
1498 case HTTP_MSG_RPBEFORE:
1499 if (likely(HTTP_IS_TOKEN(*ptr))) {
Willy Tarreau15de77e2010-01-02 21:59:16 +01001500 /* we have a start of message, but we have to check
1501 * first if we need to remove some CRLF. We can only
1502 * do this when send_max=0.
1503 */
1504 char *beg = buf->w + buf->send_max;
1505 if (beg >= buf->data + buf->size)
1506 beg -= buf->size;
1507 if (unlikely(ptr != beg)) {
1508 if (buf->send_max)
1509 goto http_msg_ood;
Willy Tarreau1d3bcce2009-12-27 15:50:06 +01001510 /* Remove empty leading lines, as recommended by RFC2616. */
Willy Tarreau15de77e2010-01-02 21:59:16 +01001511 buffer_ignore(buf, ptr - beg);
Willy Tarreau8973c702007-01-21 23:58:29 +01001512 }
Willy Tarreau15de77e2010-01-02 21:59:16 +01001513 msg->som = ptr - buf->data;
Willy Tarreau816b9792009-09-15 21:25:21 +02001514 msg->sol = ptr;
Willy Tarreau8973c702007-01-21 23:58:29 +01001515 hdr_idx_init(idx);
1516 state = HTTP_MSG_RPVER;
1517 goto http_msg_rpver;
1518 }
1519
1520 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1521 goto http_msg_invalid;
1522
1523 if (unlikely(*ptr == '\n'))
1524 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1525 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore_cr, HTTP_MSG_RPBEFORE_CR);
1526 /* stop here */
1527
1528 http_msg_rpbefore_cr:
1529 case HTTP_MSG_RPBEFORE_CR:
1530 EXPECT_LF_HERE(ptr, http_msg_invalid);
1531 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
1532 /* stop here */
1533
1534 http_msg_rpver:
1535 case HTTP_MSG_RPVER:
1536 case HTTP_MSG_RPVER_SP:
1537 case HTTP_MSG_RPCODE:
1538 case HTTP_MSG_RPCODE_SP:
1539 case HTTP_MSG_RPREASON:
Willy Tarreaua15645d2007-03-18 16:22:39 +01001540 ptr = (char *)http_parse_stsline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001541 &buf->lr, &msg->msg_state);
Willy Tarreau8973c702007-01-21 23:58:29 +01001542 if (unlikely(!ptr))
1543 return;
1544
1545 /* we have a full response and we know that we have either a CR
1546 * or an LF at <ptr>.
1547 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001548 //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 +01001549 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
1550
1551 msg->sol = ptr;
1552 if (likely(*ptr == '\r'))
1553 EAT_AND_JUMP_OR_RETURN(http_msg_rpline_end, HTTP_MSG_RPLINE_END);
1554 goto http_msg_rpline_end;
1555
1556 http_msg_rpline_end:
1557 case HTTP_MSG_RPLINE_END:
1558 /* msg->sol must point to the first of CR or LF. */
1559 EXPECT_LF_HERE(ptr, http_msg_invalid);
1560 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
1561 /* stop here */
1562
1563 /*
1564 * Second, states that are specific to the request only
1565 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001566 http_msg_rqbefore:
1567 case HTTP_MSG_RQBEFORE:
1568 if (likely(HTTP_IS_TOKEN(*ptr))) {
Willy Tarreau15de77e2010-01-02 21:59:16 +01001569 /* we have a start of message, but we have to check
1570 * first if we need to remove some CRLF. We can only
1571 * do this when send_max=0.
1572 */
1573 char *beg = buf->w + buf->send_max;
1574 if (beg >= buf->data + buf->size)
1575 beg -= buf->size;
1576 if (likely(ptr != beg)) {
1577 if (buf->send_max)
1578 goto http_msg_ood;
Willy Tarreau1d3bcce2009-12-27 15:50:06 +01001579 /* Remove empty leading lines, as recommended by RFC2616. */
Willy Tarreau15de77e2010-01-02 21:59:16 +01001580 buffer_ignore(buf, ptr - beg);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001581 }
Willy Tarreau15de77e2010-01-02 21:59:16 +01001582 msg->som = ptr - buf->data;
Willy Tarreau1d3bcce2009-12-27 15:50:06 +01001583 msg->sol = ptr;
Willy Tarreauf0d058e2007-01-25 12:03:42 +01001584 /* we will need this when keep-alive will be supported
1585 hdr_idx_init(idx);
1586 */
Willy Tarreau8973c702007-01-21 23:58:29 +01001587 state = HTTP_MSG_RQMETH;
1588 goto http_msg_rqmeth;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001589 }
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001590
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001591 if (unlikely(!HTTP_IS_CRLF(*ptr)))
1592 goto http_msg_invalid;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001593
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001594 if (unlikely(*ptr == '\n'))
1595 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
1596 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore_cr, HTTP_MSG_RQBEFORE_CR);
Willy Tarreau8973c702007-01-21 23:58:29 +01001597 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001598
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001599 http_msg_rqbefore_cr:
1600 case HTTP_MSG_RQBEFORE_CR:
1601 EXPECT_LF_HERE(ptr, http_msg_invalid);
1602 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
Willy Tarreau8973c702007-01-21 23:58:29 +01001603 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001604
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001605 http_msg_rqmeth:
1606 case HTTP_MSG_RQMETH:
1607 case HTTP_MSG_RQMETH_SP:
1608 case HTTP_MSG_RQURI:
1609 case HTTP_MSG_RQURI_SP:
1610 case HTTP_MSG_RQVER:
1611 ptr = (char *)http_parse_reqline(msg, buf->data, state, ptr, end,
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001612 &buf->lr, &msg->msg_state);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001613 if (unlikely(!ptr))
1614 return;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001615
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001616 /* we have a full request and we know that we have either a CR
1617 * or an LF at <ptr>.
1618 */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001619 //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 +01001620 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001621
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001622 msg->sol = ptr;
1623 if (likely(*ptr == '\r'))
1624 EAT_AND_JUMP_OR_RETURN(http_msg_rqline_end, HTTP_MSG_RQLINE_END);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001625 goto http_msg_rqline_end;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001626
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001627 http_msg_rqline_end:
1628 case HTTP_MSG_RQLINE_END:
1629 /* check for HTTP/0.9 request : no version information available.
1630 * msg->sol must point to the first of CR or LF.
1631 */
1632 if (unlikely(msg->sl.rq.v_l == 0))
1633 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001634
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001635 EXPECT_LF_HERE(ptr, http_msg_invalid);
1636 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
Willy Tarreau8973c702007-01-21 23:58:29 +01001637 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001638
Willy Tarreau8973c702007-01-21 23:58:29 +01001639 /*
1640 * Common states below
1641 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001642 http_msg_hdr_first:
1643 case HTTP_MSG_HDR_FIRST:
1644 msg->sol = ptr;
1645 if (likely(!HTTP_IS_CRLF(*ptr))) {
1646 goto http_msg_hdr_name;
1647 }
1648
1649 if (likely(*ptr == '\r'))
1650 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1651 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001652
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001653 http_msg_hdr_name:
1654 case HTTP_MSG_HDR_NAME:
1655 /* assumes msg->sol points to the first char */
1656 if (likely(HTTP_IS_TOKEN(*ptr)))
1657 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001658
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001659 if (likely(*ptr == ':')) {
1660 msg->col = ptr - buf->data;
1661 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
1662 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001663
Willy Tarreau32a4ec02009-04-02 11:35:18 +02001664 if (likely(msg->err_pos < -1) || *ptr == '\n')
1665 goto http_msg_invalid;
1666
1667 if (msg->err_pos == -1) /* capture error pointer */
1668 msg->err_pos = ptr - buf->data; /* >= 0 now */
1669
1670 /* and we still accept this non-token character */
1671 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001672
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001673 http_msg_hdr_l1_sp:
1674 case HTTP_MSG_HDR_L1_SP:
1675 /* assumes msg->sol points to the first char and msg->col to the colon */
1676 if (likely(HTTP_IS_SPHT(*ptr)))
1677 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001678
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001679 /* header value can be basically anything except CR/LF */
1680 msg->sov = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001681
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001682 if (likely(!HTTP_IS_CRLF(*ptr))) {
1683 goto http_msg_hdr_val;
1684 }
1685
1686 if (likely(*ptr == '\r'))
1687 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lf, HTTP_MSG_HDR_L1_LF);
1688 goto http_msg_hdr_l1_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001689
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001690 http_msg_hdr_l1_lf:
1691 case HTTP_MSG_HDR_L1_LF:
1692 EXPECT_LF_HERE(ptr, http_msg_invalid);
1693 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lws, HTTP_MSG_HDR_L1_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001694
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001695 http_msg_hdr_l1_lws:
1696 case HTTP_MSG_HDR_L1_LWS:
1697 if (likely(HTTP_IS_SPHT(*ptr))) {
1698 /* replace HT,CR,LF with spaces */
1699 for (; buf->data+msg->sov < ptr; msg->sov++)
1700 buf->data[msg->sov] = ' ';
1701 goto http_msg_hdr_l1_sp;
1702 }
Willy Tarreauaa9dce32007-03-18 23:50:16 +01001703 /* we had a header consisting only in spaces ! */
1704 msg->eol = buf->data + msg->sov;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001705 goto http_msg_complete_header;
1706
1707 http_msg_hdr_val:
1708 case HTTP_MSG_HDR_VAL:
1709 /* assumes msg->sol points to the first char, msg->col to the
1710 * colon, and msg->sov points to the first character of the
1711 * value.
1712 */
1713 if (likely(!HTTP_IS_CRLF(*ptr)))
1714 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001715
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001716 msg->eol = ptr;
1717 /* Note: we could also copy eol into ->eoh so that we have the
1718 * real header end in case it ends with lots of LWS, but is this
1719 * really needed ?
1720 */
1721 if (likely(*ptr == '\r'))
1722 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1723 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001724
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001725 http_msg_hdr_l2_lf:
1726 case HTTP_MSG_HDR_L2_LF:
1727 EXPECT_LF_HERE(ptr, http_msg_invalid);
1728 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001729
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001730 http_msg_hdr_l2_lws:
1731 case HTTP_MSG_HDR_L2_LWS:
1732 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1733 /* LWS: replace HT,CR,LF with spaces */
1734 for (; msg->eol < ptr; msg->eol++)
1735 *msg->eol = ' ';
1736 goto http_msg_hdr_val;
1737 }
1738 http_msg_complete_header:
1739 /*
1740 * It was a new header, so the last one is finished.
1741 * Assumes msg->sol points to the first char, msg->col to the
1742 * colon, msg->sov points to the first character of the value
1743 * and msg->eol to the first CR or LF so we know how the line
1744 * ends. We insert last header into the index.
1745 */
1746 /*
1747 fprintf(stderr,"registering %-2d bytes : ", msg->eol - msg->sol);
1748 write(2, msg->sol, msg->eol-msg->sol);
1749 fprintf(stderr,"\n");
1750 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001751
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001752 if (unlikely(hdr_idx_add(msg->eol - msg->sol, *msg->eol == '\r',
1753 idx, idx->tail) < 0))
1754 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001755
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001756 msg->sol = ptr;
1757 if (likely(!HTTP_IS_CRLF(*ptr))) {
1758 goto http_msg_hdr_name;
1759 }
1760
1761 if (likely(*ptr == '\r'))
1762 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1763 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001764
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001765 http_msg_last_lf:
1766 case HTTP_MSG_LAST_LF:
1767 /* Assumes msg->sol points to the first of either CR or LF */
1768 EXPECT_LF_HERE(ptr, http_msg_invalid);
1769 ptr++;
1770 buf->lr = ptr;
Willy Tarreaufa355d42009-11-29 18:12:29 +01001771 msg->col = msg->sov = buf->lr - buf->data;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001772 msg->eoh = msg->sol - buf->data;
Willy Tarreau962c3f42010-01-10 00:15:35 +01001773 msg->sol = buf->data + msg->som;
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001774 msg->msg_state = HTTP_MSG_BODY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001775 return;
1776#ifdef DEBUG_FULL
1777 default:
1778 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1779 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001780#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001781 }
1782 http_msg_ood:
1783 /* out of data */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001784 msg->msg_state = state;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001785 buf->lr = ptr;
1786 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001787
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001788 http_msg_invalid:
1789 /* invalid message */
Willy Tarreaub326fcc2007-03-03 13:54:32 +01001790 msg->msg_state = HTTP_MSG_ERROR;
Willy Tarreau7552c032009-03-01 11:10:40 +01001791 buf->lr = ptr;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001792 return;
1793}
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01001794
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001795/* convert an HTTP/0.9 request into an HTTP/1.0 request. Returns 1 if the
1796 * conversion succeeded, 0 in case of error. If the request was already 1.X,
1797 * nothing is done and 1 is returned.
1798 */
1799static int http_upgrade_v09_to_v10(struct buffer *req, struct http_msg *msg, struct http_txn *txn)
1800{
1801 int delta;
1802 char *cur_end;
1803
1804 if (msg->sl.rq.v_l != 0)
1805 return 1;
1806
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001807 cur_end = msg->sol + msg->sl.rq.l;
1808 delta = 0;
1809
1810 if (msg->sl.rq.u_l == 0) {
1811 /* if no URI was set, add "/" */
1812 delta = buffer_replace2(req, cur_end, cur_end, " /", 2);
1813 cur_end += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01001814 http_msg_move_end(msg, delta);
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001815 }
1816 /* add HTTP version */
1817 delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
Willy Tarreaufa355d42009-11-29 18:12:29 +01001818 http_msg_move_end(msg, delta);
Willy Tarreau2492d5b2009-07-11 00:06:00 +02001819 cur_end += delta;
1820 cur_end = (char *)http_parse_reqline(msg, req->data,
1821 HTTP_MSG_RQMETH,
1822 msg->sol, cur_end + 1,
1823 NULL, NULL);
1824 if (unlikely(!cur_end))
1825 return 0;
1826
1827 /* we have a full HTTP/1.0 request now and we know that
1828 * we have either a CR or an LF at <ptr>.
1829 */
1830 hdr_idx_set_start(&txn->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
1831 return 1;
1832}
1833
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001834/* Parse the Connection: header of an HTTP request, looking for both "close"
1835 * and "keep-alive" values. If a buffer is provided and we already know that
1836 * some headers may safely be removed, we remove them now. The <to_del> flags
1837 * are used for that :
1838 * - bit 0 means remove "close" headers (in HTTP/1.0 requests/responses)
1839 * - bit 1 means remove "keep-alive" headers (in HTTP/1.1 reqs/resp to 1.1).
1840 * The TX_HDR_CONN_* flags are adjusted in txn->flags depending on what was
1841 * found, and TX_CON_*_SET is adjusted depending on what is left so only
1842 * harmless combinations may be removed. Do not call that after changes have
1843 * been processed. If unused, the buffer can be NULL, and no data will be
1844 * changed.
Willy Tarreau5b154472009-12-21 20:11:07 +01001845 */
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001846void http_parse_connection_header(struct http_txn *txn, struct http_msg *msg, struct buffer *buf, int to_del)
Willy Tarreau5b154472009-12-21 20:11:07 +01001847{
Willy Tarreau5b154472009-12-21 20:11:07 +01001848 struct hdr_ctx ctx;
Willy Tarreau5b154472009-12-21 20:11:07 +01001849
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001850 if (txn->flags & TX_HDR_CONN_PRS)
Willy Tarreau5b154472009-12-21 20:11:07 +01001851 return;
1852
Willy Tarreau5b154472009-12-21 20:11:07 +01001853 ctx.idx = 0;
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001854 txn->flags &= ~(TX_CON_KAL_SET|TX_CON_CLO_SET);
Willy Tarreau5b154472009-12-21 20:11:07 +01001855 while (http_find_header2("Connection", 10, msg->sol, &txn->hdr_idx, &ctx)) {
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001856 if (ctx.vlen >= 10 && word_match(ctx.line + ctx.val, ctx.vlen, "keep-alive", 10)) {
1857 txn->flags |= TX_HDR_CONN_KAL;
1858 if ((to_del & 2) && buf)
1859 http_remove_header2(msg, buf, &txn->hdr_idx, &ctx);
1860 else
1861 txn->flags |= TX_CON_KAL_SET;
1862 }
1863 else if (ctx.vlen >= 5 && word_match(ctx.line + ctx.val, ctx.vlen, "close", 5)) {
1864 txn->flags |= TX_HDR_CONN_CLO;
1865 if ((to_del & 1) && buf)
1866 http_remove_header2(msg, buf, &txn->hdr_idx, &ctx);
1867 else
1868 txn->flags |= TX_CON_CLO_SET;
1869 }
Willy Tarreau5b154472009-12-21 20:11:07 +01001870 }
1871
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001872 txn->flags |= TX_HDR_CONN_PRS;
1873 return;
1874}
Willy Tarreau5b154472009-12-21 20:11:07 +01001875
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001876/* Apply desired changes on the Connection: header. Values may be removed and/or
1877 * added depending on the <wanted> flags, which are exclusively composed of
1878 * TX_CON_CLO_SET and TX_CON_KAL_SET, depending on what flags are desired. The
1879 * TX_CON_*_SET flags are adjusted in txn->flags depending on what is left.
1880 */
1881void http_change_connection_header(struct http_txn *txn, struct http_msg *msg, struct buffer *buf, int wanted)
1882{
1883 struct hdr_ctx ctx;
1884
1885 ctx.idx = 0;
1886
1887 txn->flags &= ~(TX_CON_CLO_SET | TX_CON_KAL_SET);
1888 while (http_find_header2("Connection", 10, msg->sol, &txn->hdr_idx, &ctx)) {
1889 if (ctx.vlen >= 10 && word_match(ctx.line + ctx.val, ctx.vlen, "keep-alive", 10)) {
1890 if (wanted & TX_CON_KAL_SET)
1891 txn->flags |= TX_CON_KAL_SET;
1892 else
1893 http_remove_header2(msg, buf, &txn->hdr_idx, &ctx);
Willy Tarreau5b154472009-12-21 20:11:07 +01001894 }
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001895 else if (ctx.vlen >= 5 && word_match(ctx.line + ctx.val, ctx.vlen, "close", 5)) {
1896 if (wanted & TX_CON_CLO_SET)
1897 txn->flags |= TX_CON_CLO_SET;
1898 else
1899 http_remove_header2(msg, buf, &txn->hdr_idx, &ctx);
Willy Tarreau0dfdf192010-01-05 11:33:11 +01001900 }
Willy Tarreau5b154472009-12-21 20:11:07 +01001901 }
Willy Tarreaubbf0b372010-01-18 16:54:40 +01001902
1903 if (wanted == (txn->flags & (TX_CON_CLO_SET|TX_CON_KAL_SET)))
1904 return;
1905
1906 if ((wanted & TX_CON_CLO_SET) && !(txn->flags & TX_CON_CLO_SET)) {
1907 txn->flags |= TX_CON_CLO_SET;
1908 http_header_add_tail2(buf, msg, &txn->hdr_idx, "Connection: close", 17);
1909 }
1910
1911 if ((wanted & TX_CON_KAL_SET) && !(txn->flags & TX_CON_KAL_SET)) {
1912 txn->flags |= TX_CON_KAL_SET;
1913 http_header_add_tail2(buf, msg, &txn->hdr_idx, "Connection: keep-alive", 22);
1914 }
1915 return;
Willy Tarreau5b154472009-12-21 20:11:07 +01001916}
1917
Willy Tarreaud98cf932009-12-27 22:54:55 +01001918/* Parse the chunk size at buf->lr. Once done, it adjusts ->lr to point to the
1919 * first byte of body, and increments msg->sov by the number of bytes parsed,
1920 * so that we know we can forward between ->som and ->sov. Note that due to
1921 * possible wrapping at the end of the buffer, it is possible that msg->sov is
1922 * lower than msg->som.
Willy Tarreau115acb92009-12-26 13:56:06 +01001923 * Return >0 on success, 0 when some data is missing, <0 on error.
Willy Tarreaud98cf932009-12-27 22:54:55 +01001924 * Note: this function is designed to parse wrapped CRLF at the end of the buffer.
Willy Tarreau115acb92009-12-26 13:56:06 +01001925 */
Willy Tarreaud98cf932009-12-27 22:54:55 +01001926int http_parse_chunk_size(struct buffer *buf, struct http_msg *msg)
Willy Tarreau115acb92009-12-26 13:56:06 +01001927{
Willy Tarreaud98cf932009-12-27 22:54:55 +01001928 char *ptr = buf->lr;
1929 char *end = buf->data + buf->size;
Willy Tarreau115acb92009-12-26 13:56:06 +01001930 unsigned int chunk = 0;
1931
1932 /* The chunk size is in the following form, though we are only
1933 * interested in the size and CRLF :
1934 * 1*HEXDIGIT *WSP *[ ';' extensions ] CRLF
1935 */
1936 while (1) {
1937 int c;
Willy Tarreaud98cf932009-12-27 22:54:55 +01001938 if (ptr == buf->r)
Willy Tarreau115acb92009-12-26 13:56:06 +01001939 return 0;
Willy Tarreaud98cf932009-12-27 22:54:55 +01001940 c = hex2i(*ptr);
Willy Tarreau115acb92009-12-26 13:56:06 +01001941 if (c < 0) /* not a hex digit anymore */
1942 break;
Willy Tarreaud98cf932009-12-27 22:54:55 +01001943 if (++ptr >= end)
1944 ptr = buf->data;
Willy Tarreau115acb92009-12-26 13:56:06 +01001945 if (chunk & 0xF000000) /* overflow will occur */
1946 return -1;
1947 chunk = (chunk << 4) + c;
1948 }
1949
Willy Tarreaud98cf932009-12-27 22:54:55 +01001950 /* empty size not allowed */
1951 if (ptr == buf->lr)
1952 return -1;
1953
1954 while (http_is_spht[(unsigned char)*ptr]) {
1955 if (++ptr >= end)
1956 ptr = buf->data;
1957 if (ptr == buf->r)
Willy Tarreau115acb92009-12-26 13:56:06 +01001958 return 0;
Willy Tarreau115acb92009-12-26 13:56:06 +01001959 }
1960
Willy Tarreaud98cf932009-12-27 22:54:55 +01001961 /* Up to there, we know that at least one byte is present at *ptr. Check
1962 * for the end of chunk size.
1963 */
1964 while (1) {
1965 if (likely(HTTP_IS_CRLF(*ptr))) {
1966 /* we now have a CR or an LF at ptr */
1967 if (likely(*ptr == '\r')) {
1968 if (++ptr >= end)
1969 ptr = buf->data;
1970 if (ptr == buf->r)
1971 return 0;
1972 }
Willy Tarreau115acb92009-12-26 13:56:06 +01001973
Willy Tarreaud98cf932009-12-27 22:54:55 +01001974 if (*ptr != '\n')
1975 return -1;
1976 if (++ptr >= end)
1977 ptr = buf->data;
1978 /* done */
1979 break;
1980 }
1981 else if (*ptr == ';') {
1982 /* chunk extension, ends at next CRLF */
1983 if (++ptr >= end)
1984 ptr = buf->data;
1985 if (ptr == buf->r)
Willy Tarreau115acb92009-12-26 13:56:06 +01001986 return 0;
Willy Tarreaud98cf932009-12-27 22:54:55 +01001987
1988 while (!HTTP_IS_CRLF(*ptr)) {
1989 if (++ptr >= end)
1990 ptr = buf->data;
1991 if (ptr == buf->r)
1992 return 0;
1993 }
1994 /* we have a CRLF now, loop above */
1995 continue;
Willy Tarreau115acb92009-12-26 13:56:06 +01001996 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01001997 else
Willy Tarreau115acb92009-12-26 13:56:06 +01001998 return -1;
Willy Tarreau115acb92009-12-26 13:56:06 +01001999 }
2000
Willy Tarreaud98cf932009-12-27 22:54:55 +01002001 /* OK we found our CRLF and now <ptr> points to the next byte,
2002 * which may or may not be present. We save that into ->lr and
2003 * ->sov.
Willy Tarreau115acb92009-12-26 13:56:06 +01002004 */
Willy Tarreaud98cf932009-12-27 22:54:55 +01002005 msg->sov += ptr - buf->lr;
2006 buf->lr = ptr;
Willy Tarreau115acb92009-12-26 13:56:06 +01002007 msg->hdr_content_len = chunk;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002008 msg->msg_state = chunk ? HTTP_MSG_DATA : HTTP_MSG_TRAILERS;
Willy Tarreau115acb92009-12-26 13:56:06 +01002009 return 1;
2010}
2011
Willy Tarreaud98cf932009-12-27 22:54:55 +01002012/* This function skips trailers in the buffer <buf> associated with HTTP
2013 * message <msg>. The first visited position is buf->lr. If the end of
2014 * the trailers is found, it is automatically scheduled to be forwarded,
2015 * msg->msg_state switches to HTTP_MSG_DONE, and the function returns >0.
2016 * If not enough data are available, the function does not change anything
Willy Tarreau638cd022010-01-03 07:42:04 +01002017 * except maybe buf->lr and msg->sov if it could parse some lines, and returns
2018 * zero. If a parse error is encountered, the function returns < 0 and does not
2019 * change anything except maybe buf->lr and msg->sov. Note that the message
2020 * must already be in HTTP_MSG_TRAILERS state before calling this function,
2021 * which implies that all non-trailers data have already been scheduled for
2022 * forwarding, and that the difference between msg->som and msg->sov exactly
2023 * matches the length of trailers already parsed and not forwarded. It is also
2024 * important to note that this function is designed to be able to parse wrapped
2025 * headers at end of buffer.
Willy Tarreaud98cf932009-12-27 22:54:55 +01002026 */
2027int http_forward_trailers(struct buffer *buf, struct http_msg *msg)
2028{
2029 /* we have buf->lr which points to next line. Look for CRLF. */
2030 while (1) {
2031 char *p1 = NULL, *p2 = NULL;
2032 char *ptr = buf->lr;
Willy Tarreau638cd022010-01-03 07:42:04 +01002033 int bytes;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002034
2035 /* scan current line and stop at LF or CRLF */
2036 while (1) {
2037 if (ptr == buf->r)
2038 return 0;
2039
2040 if (*ptr == '\n') {
2041 if (!p1)
2042 p1 = ptr;
2043 p2 = ptr;
2044 break;
2045 }
2046
2047 if (*ptr == '\r') {
2048 if (p1)
2049 return -1;
2050 p1 = ptr;
2051 }
2052
2053 ptr++;
2054 if (ptr >= buf->data + buf->size)
2055 ptr = buf->data;
2056 }
2057
2058 /* after LF; point to beginning of next line */
2059 p2++;
2060 if (p2 >= buf->data + buf->size)
2061 p2 = buf->data;
2062
Willy Tarreau638cd022010-01-03 07:42:04 +01002063 bytes = p2 - buf->lr;
2064 if (bytes < 0)
2065 bytes += buf->size;
2066
2067 /* schedule this line for forwarding */
2068 msg->sov += bytes;
2069 if (msg->sov >= buf->size)
2070 msg->sov -= buf->size;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002071
Willy Tarreau638cd022010-01-03 07:42:04 +01002072 if (p1 == buf->lr) {
2073 /* LF/CRLF at beginning of line => end of trailers at p2.
2074 * Everything was scheduled for forwarding, there's nothing
2075 * left from this message.
Willy Tarreau5523b322009-12-29 12:05:52 +01002076 */
Willy Tarreau638cd022010-01-03 07:42:04 +01002077 buf->lr = p2;
Willy Tarreaud98cf932009-12-27 22:54:55 +01002078 msg->msg_state = HTTP_MSG_DONE;
2079 return 1;
2080 }
2081 /* OK, next line then */
2082 buf->lr = p2;
2083 }
2084}
2085
2086/* This function may be called only in HTTP_MSG_DATA_CRLF. It reads the CRLF or
2087 * a possible LF alone at the end of a chunk. It automatically adjusts msg->sov,
2088 * ->som, buf->lr in order to include this part into the next forwarding phase.
2089 * It also sets msg_state to HTTP_MSG_CHUNK_SIZE and returns >0 on success. If
2090 * not enough data are available, the function does not change anything and
2091 * returns zero. If a parse error is encountered, the function returns < 0 and
2092 * does not change anything. Note: this function is designed to parse wrapped
2093 * CRLF at the end of the buffer.
2094 */
2095int http_skip_chunk_crlf(struct buffer *buf, struct http_msg *msg)
2096{
2097 char *ptr;
2098 int bytes;
2099
2100 /* NB: we'll check data availabilty at the end. It's not a
2101 * problem because whatever we match first will be checked
2102 * against the correct length.
2103 */
2104 bytes = 1;
2105 ptr = buf->lr;
2106 if (*ptr == '\r') {
2107 bytes++;
2108 ptr++;
2109 if (ptr >= buf->data + buf->size)
2110 ptr = buf->data;
2111 }
2112
2113 if (buf->l < bytes)
2114 return 0;
2115
2116 if (*ptr != '\n')
2117 return -1;
2118
2119 ptr++;
2120 if (ptr >= buf->data + buf->size)
2121 ptr = buf->data;
2122 buf->lr = ptr;
2123 /* prepare the CRLF to be forwarded. msg->som may be before data but we don't care */
2124 msg->sov = ptr - buf->data;
2125 msg->som = msg->sov - bytes;
2126 msg->msg_state = HTTP_MSG_CHUNK_SIZE;
2127 return 1;
2128}
Willy Tarreau5b154472009-12-21 20:11:07 +01002129
Willy Tarreau83e3af02009-12-28 17:39:57 +01002130void http_buffer_heavy_realign(struct buffer *buf, struct http_msg *msg)
2131{
2132 char *end = buf->data + buf->size;
2133 int off = buf->data + buf->size - buf->w;
2134
2135 /* two possible cases :
2136 * - the buffer is in one contiguous block, we move it in-place
2137 * - the buffer is in two blocks, we move it via the trash
2138 */
2139 if (buf->l) {
2140 int block1 = buf->l;
2141 int block2 = 0;
2142 if (buf->r <= buf->w) {
2143 /* non-contiguous block */
2144 block1 = buf->data + buf->size - buf->w;
2145 block2 = buf->r - buf->data;
2146 }
2147 if (block2)
2148 memcpy(trash, buf->data, block2);
2149 memmove(buf->data, buf->w, block1);
2150 if (block2)
2151 memcpy(buf->data + block1, trash, block2);
2152 }
2153
2154 /* adjust all known pointers */
2155 buf->w = buf->data;
2156 buf->lr += off; if (buf->lr >= end) buf->lr -= buf->size;
2157 buf->r += off; if (buf->r >= end) buf->r -= buf->size;
2158 msg->sol += off; if (msg->sol >= end) msg->sol -= buf->size;
2159 msg->eol += off; if (msg->eol >= end) msg->eol -= buf->size;
2160
2161 /* adjust relative pointers */
2162 msg->som = 0;
2163 msg->eoh += off; if (msg->eoh >= buf->size) msg->eoh -= buf->size;
2164 msg->col += off; if (msg->col >= buf->size) msg->col -= buf->size;
2165 msg->sov += off; if (msg->sov >= buf->size) msg->sov -= buf->size;
2166
Willy Tarreau83e3af02009-12-28 17:39:57 +01002167 if (msg->err_pos >= 0) {
2168 msg->err_pos += off;
2169 if (msg->err_pos >= buf->size)
2170 msg->err_pos -= buf->size;
2171 }
2172
2173 buf->flags &= ~BF_FULL;
2174 if (buf->l >= buffer_max_len(buf))
2175 buf->flags |= BF_FULL;
2176}
2177
Willy Tarreaud787e662009-07-07 10:14:51 +02002178/* This stream analyser waits for a complete HTTP request. It returns 1 if the
2179 * processing can continue on next analysers, or zero if it either needs more
2180 * data or wants to immediately abort the request (eg: timeout, error, ...). It
2181 * is tied to AN_REQ_WAIT_HTTP and may may remove itself from s->req->analysers
2182 * when it has nothing left to do, and may remove any analyser when it wants to
2183 * abort.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002184 */
Willy Tarreau3a816292009-07-07 10:55:49 +02002185int http_wait_for_request(struct session *s, struct buffer *req, int an_bit)
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002186{
Willy Tarreau59234e92008-11-30 23:51:27 +01002187 /*
2188 * We will parse the partial (or complete) lines.
2189 * We will check the request syntax, and also join multi-line
2190 * headers. An index of all the lines will be elaborated while
2191 * parsing.
2192 *
2193 * For the parsing, we use a 28 states FSM.
2194 *
2195 * Here is the information we currently have :
Willy Tarreauf073a832009-03-01 23:21:47 +01002196 * req->data + msg->som = beginning of request
Willy Tarreau83e3af02009-12-28 17:39:57 +01002197 * req->data + msg->eoh = end of processed headers / start of current one
2198 * msg->eol = end of current header or line (LF or CRLF)
Willy Tarreau59234e92008-11-30 23:51:27 +01002199 * req->lr = first non-visited byte
2200 * req->r = end of data
Willy Tarreaud787e662009-07-07 10:14:51 +02002201 *
2202 * At end of parsing, we may perform a capture of the error (if any), and
2203 * we will set a few fields (msg->sol, txn->meth, sn->flags/SN_REDIRECTABLE).
2204 * We also check for monitor-uri, logging, HTTP/0.9 to 1.0 conversion, and
2205 * finally headers capture.
Willy Tarreau59234e92008-11-30 23:51:27 +01002206 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01002207
Willy Tarreau59234e92008-11-30 23:51:27 +01002208 int cur_idx;
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002209 int use_close_only;
Willy Tarreau59234e92008-11-30 23:51:27 +01002210 struct http_txn *txn = &s->txn;
2211 struct http_msg *msg = &txn->req;
Willy Tarreau32b47f42009-10-18 20:55:02 +02002212 struct hdr_ctx ctx;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01002213
Willy Tarreau6bf17362009-02-24 10:48:35 +01002214 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
2215 now_ms, __FUNCTION__,
2216 s,
2217 req,
2218 req->rex, req->wex,
2219 req->flags,
2220 req->l,
2221 req->analysers);
2222
Willy Tarreau52a0c602009-08-16 22:45:38 +02002223 /* we're speaking HTTP here, so let's speak HTTP to the client */
2224 s->srv_error = http_return_srv_error;
2225
Willy Tarreau83e3af02009-12-28 17:39:57 +01002226 /* There's a protected area at the end of the buffer for rewriting
2227 * purposes. We don't want to start to parse the request if the
2228 * protected area is affected, because we may have to move processed
2229 * data later, which is much more complicated.
2230 */
Willy Tarreau2ab6eb12010-01-02 22:04:45 +01002231 if (req->l && msg->msg_state < HTTP_MSG_ERROR) {
Willy Tarreau065e8332010-01-08 00:30:20 +01002232 if ((txn->flags & TX_NOT_FIRST) &&
2233 unlikely((req->flags & BF_FULL) ||
Willy Tarreau2ab6eb12010-01-02 22:04:45 +01002234 req->r < req->lr ||
2235 req->r > req->data + req->size - global.tune.maxrewrite)) {
2236 if (req->send_max) {
2237 /* some data has still not left the buffer, wake us once that's done */
2238 buffer_dont_connect(req);
2239 req->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */
2240 return 0;
2241 }
2242 if (req->l <= req->size - global.tune.maxrewrite)
2243 http_buffer_heavy_realign(req, msg);
Willy Tarreau83e3af02009-12-28 17:39:57 +01002244 }
2245
Willy Tarreau065e8332010-01-08 00:30:20 +01002246 /* Note that we have the same problem with the response ; we
2247 * may want to send a redirect, error or anything which requires
2248 * some spare space. So we'll ensure that we have at least
2249 * maxrewrite bytes available in the response buffer before
2250 * processing that one. This will only affect pipelined
2251 * keep-alive requests.
2252 */
2253 if ((txn->flags & TX_NOT_FIRST) &&
2254 unlikely((s->rep->flags & BF_FULL) ||
2255 s->rep->r < s->rep->lr ||
2256 s->rep->r > s->rep->data + s->rep->size - global.tune.maxrewrite)) {
2257 if (s->rep->send_max) {
2258 /* don't let a connection request be initiated */
2259 buffer_dont_connect(req);
2260 return 0;
2261 }
2262 }
2263
Willy Tarreau2ab6eb12010-01-02 22:04:45 +01002264 if (likely(req->lr < req->r))
2265 http_msg_analyzer(req, msg, &txn->hdr_idx);
Willy Tarreau83e3af02009-12-28 17:39:57 +01002266 }
2267
Willy Tarreau59234e92008-11-30 23:51:27 +01002268 /* 1: we might have to print this header in debug mode */
2269 if (unlikely((global.mode & MODE_DEBUG) &&
2270 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
Willy Tarreau655dce92009-11-08 13:10:58 +01002271 (msg->msg_state >= HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
Willy Tarreau59234e92008-11-30 23:51:27 +01002272 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01002273
Willy Tarreau962c3f42010-01-10 00:15:35 +01002274 sol = msg->sol;
Willy Tarreau59234e92008-11-30 23:51:27 +01002275 eol = sol + msg->sl.rq.l;
2276 debug_hdr("clireq", s, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01002277
Willy Tarreau59234e92008-11-30 23:51:27 +01002278 sol += hdr_idx_first_pos(&txn->hdr_idx);
2279 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01002280
Willy Tarreau59234e92008-11-30 23:51:27 +01002281 while (cur_idx) {
2282 eol = sol + txn->hdr_idx.v[cur_idx].len;
2283 debug_hdr("clihdr", s, sol, eol);
2284 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
2285 cur_idx = txn->hdr_idx.v[cur_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002286 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002287 }
2288
Willy Tarreau58f10d72006-12-04 02:26:12 +01002289
Willy Tarreau59234e92008-11-30 23:51:27 +01002290 /*
2291 * Now we quickly check if we have found a full valid request.
2292 * If not so, we check the FD and buffer states before leaving.
2293 * A full request is indicated by the fact that we have seen
Willy Tarreau655dce92009-11-08 13:10:58 +01002294 * the double LF/CRLF, so the state is >= HTTP_MSG_BODY. Invalid
Willy Tarreaud3c343f2010-01-16 10:26:19 +01002295 * requests are checked first. When waiting for a second request
2296 * on a keep-alive session, if we encounter and error, close, t/o,
2297 * we note the error in the session flags but don't set any state.
2298 * Since the error will be noted there, it will not be counted by
2299 * process_session() as a frontend error.
Willy Tarreau59234e92008-11-30 23:51:27 +01002300 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01002301
Willy Tarreau655dce92009-11-08 13:10:58 +01002302 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01002303 /*
Willy Tarreau59234e92008-11-30 23:51:27 +01002304 * First, let's catch bad requests.
Willy Tarreau58f10d72006-12-04 02:26:12 +01002305 */
Willy Tarreau59234e92008-11-30 23:51:27 +01002306 if (unlikely(msg->msg_state == HTTP_MSG_ERROR))
2307 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01002308
Willy Tarreau59234e92008-11-30 23:51:27 +01002309 /* 1: Since we are in header mode, if there's no space
2310 * left for headers, we won't be able to free more
2311 * later, so the session will never terminate. We
2312 * must terminate it now.
2313 */
2314 if (unlikely(req->flags & BF_FULL)) {
2315 /* FIXME: check if URI is set and return Status
2316 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01002317 */
Willy Tarreau59234e92008-11-30 23:51:27 +01002318 goto return_bad_req;
2319 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002320
Willy Tarreau59234e92008-11-30 23:51:27 +01002321 /* 2: have we encountered a read error ? */
2322 else if (req->flags & BF_READ_ERROR) {
Willy Tarreaud3c343f2010-01-16 10:26:19 +01002323 if (!(s->flags & SN_ERR_MASK))
2324 s->flags |= SN_ERR_CLICL;
2325
Willy Tarreaufcffa692010-01-10 14:21:19 +01002326 if (txn->flags & TX_WAIT_NEXT_RQ)
Willy Tarreaub608feb2010-01-02 22:47:18 +01002327 goto failed_keep_alive;
2328
Willy Tarreau59234e92008-11-30 23:51:27 +01002329 /* we cannot return any message on error */
Willy Tarreau4076a152009-04-02 15:18:36 +02002330 if (msg->err_pos >= 0)
2331 http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
Willy Tarreau59234e92008-11-30 23:51:27 +01002332 msg->msg_state = HTTP_MSG_ERROR;
2333 req->analysers = 0;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002334
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02002335 s->fe->counters.failed_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002336 if (s->listener->counters)
2337 s->listener->counters->failed_req++;
2338
Willy Tarreau59234e92008-11-30 23:51:27 +01002339 if (!(s->flags & SN_FINST_MASK))
2340 s->flags |= SN_FINST_R;
2341 return 0;
2342 }
Willy Tarreauf9839bd2008-08-27 23:57:16 +02002343
Willy Tarreau59234e92008-11-30 23:51:27 +01002344 /* 3: has the read timeout expired ? */
2345 else if (req->flags & BF_READ_TIMEOUT || tick_is_expired(req->analyse_exp, now_ms)) {
Willy Tarreaud3c343f2010-01-16 10:26:19 +01002346 if (!(s->flags & SN_ERR_MASK))
2347 s->flags |= SN_ERR_CLITO;
2348
Willy Tarreaufcffa692010-01-10 14:21:19 +01002349 if (txn->flags & TX_WAIT_NEXT_RQ)
Willy Tarreaub608feb2010-01-02 22:47:18 +01002350 goto failed_keep_alive;
2351
Willy Tarreau59234e92008-11-30 23:51:27 +01002352 /* read timeout : give up with an error message. */
Willy Tarreau4076a152009-04-02 15:18:36 +02002353 if (msg->err_pos >= 0)
2354 http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
Willy Tarreau59234e92008-11-30 23:51:27 +01002355 txn->status = 408;
2356 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_408));
2357 msg->msg_state = HTTP_MSG_ERROR;
2358 req->analysers = 0;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002359
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02002360 s->fe->counters.failed_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002361 if (s->listener->counters)
2362 s->listener->counters->failed_req++;
2363
Willy Tarreau59234e92008-11-30 23:51:27 +01002364 if (!(s->flags & SN_FINST_MASK))
2365 s->flags |= SN_FINST_R;
2366 return 0;
2367 }
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02002368
Willy Tarreau59234e92008-11-30 23:51:27 +01002369 /* 4: have we encountered a close ? */
2370 else if (req->flags & BF_SHUTR) {
Willy Tarreaud3c343f2010-01-16 10:26:19 +01002371 if (!(s->flags & SN_ERR_MASK))
2372 s->flags |= SN_ERR_CLICL;
2373
Willy Tarreaufcffa692010-01-10 14:21:19 +01002374 if (txn->flags & TX_WAIT_NEXT_RQ)
Willy Tarreaub608feb2010-01-02 22:47:18 +01002375 goto failed_keep_alive;
2376
Willy Tarreau4076a152009-04-02 15:18:36 +02002377 if (msg->err_pos >= 0)
2378 http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
Willy Tarreau59234e92008-11-30 23:51:27 +01002379 txn->status = 400;
2380 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
2381 msg->msg_state = HTTP_MSG_ERROR;
2382 req->analysers = 0;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002383
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02002384 s->fe->counters.failed_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002385 if (s->listener->counters)
2386 s->listener->counters->failed_req++;
2387
Willy Tarreau59234e92008-11-30 23:51:27 +01002388 if (!(s->flags & SN_FINST_MASK))
2389 s->flags |= SN_FINST_R;
Willy Tarreaudafde432008-08-17 01:00:46 +02002390 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01002391 }
2392
Willy Tarreau520d95e2009-09-19 21:04:57 +02002393 buffer_dont_connect(req);
Willy Tarreau1b194fe2009-03-21 21:10:04 +01002394 req->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */
2395
Willy Tarreaufcffa692010-01-10 14:21:19 +01002396 if ((msg->msg_state != HTTP_MSG_RQBEFORE) && (txn->flags & TX_WAIT_NEXT_RQ)) {
2397 /* If the client starts to talk, let's fall back to
2398 * request timeout processing.
2399 */
2400 txn->flags &= ~TX_WAIT_NEXT_RQ;
Willy Tarreaub16a5742010-01-10 14:46:16 +01002401 req->analyse_exp = TICK_ETERNITY;
Willy Tarreaufcffa692010-01-10 14:21:19 +01002402 }
2403
Willy Tarreau59234e92008-11-30 23:51:27 +01002404 /* just set the request timeout once at the beginning of the request */
Willy Tarreaub16a5742010-01-10 14:46:16 +01002405 if (!tick_isset(req->analyse_exp)) {
2406 if ((msg->msg_state == HTTP_MSG_RQBEFORE) &&
2407 (txn->flags & TX_WAIT_NEXT_RQ) &&
2408 tick_isset(s->be->timeout.httpka))
2409 req->analyse_exp = tick_add(now_ms, s->be->timeout.httpka);
2410 else
2411 req->analyse_exp = tick_add_ifset(now_ms, s->be->timeout.httpreq);
2412 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002413
Willy Tarreau59234e92008-11-30 23:51:27 +01002414 /* we're not ready yet */
2415 return 0;
Willy Tarreaub608feb2010-01-02 22:47:18 +01002416
2417 failed_keep_alive:
2418 /* Here we process low-level errors for keep-alive requests. In
2419 * short, if the request is not the first one and it experiences
2420 * a timeout, read error or shutdown, we just silently close so
2421 * that the client can try again.
2422 */
2423 txn->status = 0;
2424 msg->msg_state = HTTP_MSG_RQBEFORE;
2425 req->analysers = 0;
2426 s->logs.logwait = 0;
Willy Tarreau148d0992010-01-10 10:21:21 +01002427 stream_int_retnclose(req->prod, NULL);
Willy Tarreaub608feb2010-01-02 22:47:18 +01002428 return 0;
Willy Tarreau59234e92008-11-30 23:51:27 +01002429 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01002430
Willy Tarreaud787e662009-07-07 10:14:51 +02002431 /* OK now we have a complete HTTP request with indexed headers. Let's
2432 * complete the request parsing by setting a few fields we will need
Willy Tarreaufa355d42009-11-29 18:12:29 +01002433 * later. At this point, we have the last CRLF at req->data + msg->eoh.
2434 * If the request is in HTTP/0.9 form, the rule is still true, and eoh
2435 * points to the CRLF of the request line. req->lr points to the first
2436 * byte after the last LF. msg->col and msg->sov point to the first
2437 * byte of data. msg->eol cannot be trusted because it may have been
2438 * left uninitialized (for instance in the absence of headers).
Willy Tarreaud787e662009-07-07 10:14:51 +02002439 */
Willy Tarreau9cdde232007-05-02 20:58:19 +02002440
Willy Tarreaub16a5742010-01-10 14:46:16 +01002441 if (txn->flags & TX_WAIT_NEXT_RQ) {
2442 /* kill the pending keep-alive timeout */
2443 txn->flags &= ~TX_WAIT_NEXT_RQ;
2444 req->analyse_exp = TICK_ETERNITY;
2445 }
2446
2447
Willy Tarreaud787e662009-07-07 10:14:51 +02002448 /* Maybe we found in invalid header name while we were configured not
2449 * to block on that, so we have to capture it now.
2450 */
2451 if (unlikely(msg->err_pos >= 0))
Willy Tarreau4076a152009-04-02 15:18:36 +02002452 http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
2453
Willy Tarreau59234e92008-11-30 23:51:27 +01002454 /*
2455 * 1: identify the method
2456 */
Willy Tarreau962c3f42010-01-10 00:15:35 +01002457 txn->meth = find_http_meth(msg->sol, msg->sl.rq.m_l);
Willy Tarreau59234e92008-11-30 23:51:27 +01002458
2459 /* we can make use of server redirect on GET and HEAD */
2460 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
2461 s->flags |= SN_REDIRECTABLE;
Willy Tarreaufa7e1022008-10-19 07:30:41 +02002462
Willy Tarreau59234e92008-11-30 23:51:27 +01002463 /*
2464 * 2: check if the URI matches the monitor_uri.
2465 * We have to do this for every request which gets in, because
2466 * the monitor-uri is defined by the frontend.
2467 */
2468 if (unlikely((s->fe->monitor_uri_len != 0) &&
2469 (s->fe->monitor_uri_len == msg->sl.rq.u_l) &&
Willy Tarreau962c3f42010-01-10 00:15:35 +01002470 !memcmp(msg->sol + msg->sl.rq.u,
Willy Tarreau59234e92008-11-30 23:51:27 +01002471 s->fe->monitor_uri,
2472 s->fe->monitor_uri_len))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01002473 /*
Willy Tarreau59234e92008-11-30 23:51:27 +01002474 * We have found the monitor URI
Willy Tarreau58f10d72006-12-04 02:26:12 +01002475 */
Willy Tarreau59234e92008-11-30 23:51:27 +01002476 struct acl_cond *cond;
Willy Tarreaub80c2302007-11-30 20:51:32 +01002477
Willy Tarreau59234e92008-11-30 23:51:27 +01002478 s->flags |= SN_MONITOR;
Willy Tarreaub80c2302007-11-30 20:51:32 +01002479
Willy Tarreau59234e92008-11-30 23:51:27 +01002480 /* Check if we want to fail this monitor request or not */
Willy Tarreaud787e662009-07-07 10:14:51 +02002481 list_for_each_entry(cond, &s->fe->mon_fail_cond, list) {
2482 int ret = acl_exec_cond(cond, s->fe, s, txn, ACL_DIR_REQ);
Willy Tarreau11382812008-07-09 16:18:21 +02002483
Willy Tarreau59234e92008-11-30 23:51:27 +01002484 ret = acl_pass(ret);
2485 if (cond->pol == ACL_COND_UNLESS)
2486 ret = !ret;
Willy Tarreaub80c2302007-11-30 20:51:32 +01002487
Willy Tarreau59234e92008-11-30 23:51:27 +01002488 if (ret) {
2489 /* we fail this request, let's return 503 service unavail */
2490 txn->status = 503;
2491 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_503));
2492 goto return_prx_cond;
Willy Tarreaub80c2302007-11-30 20:51:32 +01002493 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002494 }
Willy Tarreaua5555ec2008-11-30 19:02:32 +01002495
Willy Tarreau59234e92008-11-30 23:51:27 +01002496 /* nothing to fail, let's reply normaly */
2497 txn->status = 200;
2498 stream_int_retnclose(req->prod, &http_200_chunk);
2499 goto return_prx_cond;
2500 }
2501
2502 /*
2503 * 3: Maybe we have to copy the original REQURI for the logs ?
2504 * Note: we cannot log anymore if the request has been
2505 * classified as invalid.
2506 */
2507 if (unlikely(s->logs.logwait & LW_REQ)) {
2508 /* we have a complete HTTP request that we must log */
2509 if ((txn->uri = pool_alloc2(pool2_requri)) != NULL) {
2510 int urilen = msg->sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002511
Willy Tarreau59234e92008-11-30 23:51:27 +01002512 if (urilen >= REQURI_LEN)
2513 urilen = REQURI_LEN - 1;
2514 memcpy(txn->uri, &req->data[msg->som], urilen);
2515 txn->uri[urilen] = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002516
Willy Tarreau59234e92008-11-30 23:51:27 +01002517 if (!(s->logs.logwait &= ~LW_REQ))
2518 s->do_log(s);
2519 } else {
2520 Alert("HTTP logging : out of memory.\n");
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01002521 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002522 }
Willy Tarreau06619262006-12-17 08:37:22 +01002523
Willy Tarreau59234e92008-11-30 23:51:27 +01002524 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
Willy Tarreau2492d5b2009-07-11 00:06:00 +02002525 if (unlikely(msg->sl.rq.v_l == 0) && !http_upgrade_v09_to_v10(req, msg, txn))
2526 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01002527
Willy Tarreau5b154472009-12-21 20:11:07 +01002528 /* ... and check if the request is HTTP/1.1 or above */
2529 if ((msg->sl.rq.v_l == 8) &&
Willy Tarreau962c3f42010-01-10 00:15:35 +01002530 ((msg->sol[msg->sl.rq.v + 5] > '1') ||
2531 ((msg->sol[msg->sl.rq.v + 5] == '1') &&
2532 (msg->sol[msg->sl.rq.v + 7] >= '1'))))
Willy Tarreau5b154472009-12-21 20:11:07 +01002533 txn->flags |= TX_REQ_VER_11;
2534
2535 /* "connection" has not been parsed yet */
Willy Tarreaubbf0b372010-01-18 16:54:40 +01002536 txn->flags &= ~(TX_HDR_CONN_PRS | TX_HDR_CONN_CLO | TX_HDR_CONN_KAL);
Willy Tarreau5b154472009-12-21 20:11:07 +01002537
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002538 /* transfer length unknown*/
2539 txn->flags &= ~TX_REQ_XFER_LEN;
2540
Willy Tarreau59234e92008-11-30 23:51:27 +01002541 /* 5: we may need to capture headers */
2542 if (unlikely((s->logs.logwait & LW_REQHDR) && s->fe->req_cap))
Willy Tarreau962c3f42010-01-10 00:15:35 +01002543 capture_headers(msg->sol, &txn->hdr_idx,
Willy Tarreau59234e92008-11-30 23:51:27 +01002544 txn->req.cap, s->fe->req_cap);
Willy Tarreau11382812008-07-09 16:18:21 +02002545
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002546 /* 6: determine the transfer-length.
2547 * According to RFC2616 #4.4, amended by the HTTPbis working group,
2548 * the presence of a message-body in a REQUEST and its transfer length
2549 * must be determined that way (in order of precedence) :
2550 * 1. The presence of a message-body in a request is signaled by the
2551 * inclusion of a Content-Length or Transfer-Encoding header field
2552 * in the request's header fields. When a request message contains
2553 * both a message-body of non-zero length and a method that does
2554 * not define any semantics for that request message-body, then an
2555 * origin server SHOULD either ignore the message-body or respond
2556 * with an appropriate error message (e.g., 413). A proxy or
2557 * gateway, when presented the same request, SHOULD either forward
2558 * the request inbound with the message- body or ignore the
2559 * message-body when determining a response.
2560 *
2561 * 2. If a Transfer-Encoding header field (Section 9.7) is present
2562 * and the "chunked" transfer-coding (Section 6.2) is used, the
2563 * transfer-length is defined by the use of this transfer-coding.
2564 * If a Transfer-Encoding header field is present and the "chunked"
2565 * transfer-coding is not present, the transfer-length is defined
2566 * by the sender closing the connection.
Willy Tarreau32b47f42009-10-18 20:55:02 +02002567 *
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002568 * 3. If a Content-Length header field is present, its decimal value in
2569 * OCTETs represents both the entity-length and the transfer-length.
2570 * If a message is received with both a Transfer-Encoding header
2571 * field and a Content-Length header field, the latter MUST be ignored.
Willy Tarreau32b47f42009-10-18 20:55:02 +02002572 *
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002573 * 4. By the server closing the connection. (Closing the connection
2574 * cannot be used to indicate the end of a request body, since that
2575 * would leave no possibility for the server to send back a response.)
2576 *
2577 * Whenever a transfer-coding is applied to a message-body, the set of
2578 * transfer-codings MUST include "chunked", unless the message indicates
2579 * it is terminated by closing the connection. When the "chunked"
2580 * transfer-coding is used, it MUST be the last transfer-coding applied
2581 * to the message-body.
Willy Tarreau32b47f42009-10-18 20:55:02 +02002582 */
2583
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002584 /* CONNECT sets a tunnel and ignores everything else */
2585 if (txn->meth == HTTP_METH_CONNECT)
2586 goto skip_xfer_len;
2587
2588 use_close_only = 0;
Willy Tarreau32b47f42009-10-18 20:55:02 +02002589 ctx.idx = 0;
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002590 /* set TE_CHNK and XFER_LEN only if "chunked" is seen last */
Willy Tarreau9e13c3c2009-12-22 09:59:58 +01002591 while ((txn->flags & TX_REQ_VER_11) &&
2592 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx)) {
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002593 if (ctx.vlen == 7 && strncasecmp(ctx.line + ctx.val, "chunked", 7) == 0)
2594 txn->flags |= (TX_REQ_TE_CHNK | TX_REQ_XFER_LEN);
2595 else if (txn->flags & TX_REQ_TE_CHNK) {
2596 /* bad transfer-encoding (chunked followed by something else) */
2597 use_close_only = 1;
2598 txn->flags &= ~(TX_REQ_TE_CHNK | TX_REQ_XFER_LEN);
2599 break;
2600 }
Willy Tarreau32b47f42009-10-18 20:55:02 +02002601 }
2602
Willy Tarreau32b47f42009-10-18 20:55:02 +02002603 ctx.idx = 0;
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002604 while (!(txn->flags & TX_REQ_TE_CHNK) && !use_close_only &&
Willy Tarreau32b47f42009-10-18 20:55:02 +02002605 http_find_header2("Content-Length", 14, msg->sol, &txn->hdr_idx, &ctx)) {
2606 signed long long cl;
2607
2608 if (!ctx.vlen)
2609 goto return_bad_req;
2610
2611 if (strl2llrc(ctx.line + ctx.val, ctx.vlen, &cl))
2612 goto return_bad_req; /* parse failure */
2613
2614 if (cl < 0)
2615 goto return_bad_req;
2616
2617 if ((txn->flags & TX_REQ_CNT_LEN) && (msg->hdr_content_len != cl))
2618 goto return_bad_req; /* already specified, was different */
2619
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002620 txn->flags |= TX_REQ_CNT_LEN | TX_REQ_XFER_LEN;
Willy Tarreau32b47f42009-10-18 20:55:02 +02002621 msg->hdr_content_len = cl;
2622 }
2623
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002624 /* bodyless requests have a known length */
2625 if (!use_close_only)
2626 txn->flags |= TX_REQ_XFER_LEN;
2627
2628 skip_xfer_len:
Willy Tarreaud787e662009-07-07 10:14:51 +02002629 /* end of job, return OK */
Willy Tarreau3a816292009-07-07 10:55:49 +02002630 req->analysers &= ~an_bit;
Willy Tarreaud787e662009-07-07 10:14:51 +02002631 req->analyse_exp = TICK_ETERNITY;
2632 return 1;
2633
2634 return_bad_req:
2635 /* We centralize bad requests processing here */
2636 if (unlikely(msg->msg_state == HTTP_MSG_ERROR) || msg->err_pos >= 0) {
2637 /* we detected a parsing error. We want to archive this request
2638 * in the dedicated proxy area for later troubleshooting.
2639 */
2640 http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
2641 }
2642
2643 txn->req.msg_state = HTTP_MSG_ERROR;
2644 txn->status = 400;
2645 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002646
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02002647 s->fe->counters.failed_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002648 if (s->listener->counters)
2649 s->listener->counters->failed_req++;
Willy Tarreaud787e662009-07-07 10:14:51 +02002650
2651 return_prx_cond:
2652 if (!(s->flags & SN_ERR_MASK))
2653 s->flags |= SN_ERR_PRXCOND;
2654 if (!(s->flags & SN_FINST_MASK))
2655 s->flags |= SN_FINST_R;
2656
2657 req->analysers = 0;
2658 req->analyse_exp = TICK_ETERNITY;
2659 return 0;
2660}
2661
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002662/* This stream analyser runs all HTTP request processing which is common to
2663 * frontends and backends, which means blocking ACLs, filters, connection-close,
2664 * reqadd, stats and redirects. This is performed for the designated proxy.
Willy Tarreaud787e662009-07-07 10:14:51 +02002665 * It returns 1 if the processing can continue on next analysers, or zero if it
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002666 * either needs more data or wants to immediately abort the request (eg: deny,
2667 * error, ...).
Willy Tarreaud787e662009-07-07 10:14:51 +02002668 */
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002669int http_process_req_common(struct session *s, struct buffer *req, int an_bit, struct proxy *px)
Willy Tarreaud787e662009-07-07 10:14:51 +02002670{
Willy Tarreaud787e662009-07-07 10:14:51 +02002671 struct http_txn *txn = &s->txn;
2672 struct http_msg *msg = &txn->req;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002673 struct acl_cond *cond;
2674 struct redirect_rule *rule;
Willy Tarreaudeb9ed82010-01-03 21:03:22 +01002675 struct wordlist *wl;
Willy Tarreaubbf0b372010-01-18 16:54:40 +01002676 int del_ka, del_cl;
Willy Tarreaud787e662009-07-07 10:14:51 +02002677
Willy Tarreau655dce92009-11-08 13:10:58 +01002678 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
Willy Tarreau51aecc72009-07-12 09:47:04 +02002679 /* we need more data */
Willy Tarreau520d95e2009-09-19 21:04:57 +02002680 buffer_dont_connect(req);
Willy Tarreau51aecc72009-07-12 09:47:04 +02002681 return 0;
2682 }
2683
Willy Tarreau3a816292009-07-07 10:55:49 +02002684 req->analysers &= ~an_bit;
Willy Tarreaud787e662009-07-07 10:14:51 +02002685 req->analyse_exp = TICK_ETERNITY;
2686
2687 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
2688 now_ms, __FUNCTION__,
2689 s,
2690 req,
2691 req->rex, req->wex,
2692 req->flags,
2693 req->l,
2694 req->analysers);
2695
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002696 /* first check whether we have some ACLs set to block this request */
2697 list_for_each_entry(cond, &px->block_cond, list) {
2698 int ret = acl_exec_cond(cond, px, s, txn, ACL_DIR_REQ);
Willy Tarreaub463dfb2008-06-07 23:08:56 +02002699
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002700 ret = acl_pass(ret);
2701 if (cond->pol == ACL_COND_UNLESS)
2702 ret = !ret;
Willy Tarreau53b6c742006-12-17 13:37:46 +01002703
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002704 if (ret) {
2705 txn->status = 403;
2706 /* let's log the request time */
2707 s->logs.tv_request = now;
2708 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_403));
2709 goto return_prx_cond;
Willy Tarreau59234e92008-11-30 23:51:27 +01002710 }
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002711 }
Willy Tarreau59234e92008-11-30 23:51:27 +01002712
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002713 /* try headers filters */
2714 if (px->req_exp != NULL) {
2715 if (apply_filters_to_request(s, req, px->req_exp) < 0)
2716 goto return_bad_req;
Willy Tarreau06619262006-12-17 08:37:22 +01002717
Willy Tarreau59234e92008-11-30 23:51:27 +01002718 /* has the request been denied ? */
2719 if (txn->flags & TX_CLDENY) {
2720 /* no need to go further */
2721 txn->status = 403;
2722 /* let's log the request time */
2723 s->logs.tv_request = now;
2724 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_403));
2725 goto return_prx_cond;
2726 }
Willy Tarreauc465fd72009-08-31 00:17:18 +02002727
2728 /* When a connection is tarpitted, we use the tarpit timeout,
2729 * which may be the same as the connect timeout if unspecified.
2730 * If unset, then set it to zero because we really want it to
2731 * eventually expire. We build the tarpit as an analyser.
2732 */
2733 if (txn->flags & TX_CLTARPIT) {
2734 buffer_erase(s->req);
2735 /* wipe the request out so that we can drop the connection early
2736 * if the client closes first.
2737 */
Willy Tarreau520d95e2009-09-19 21:04:57 +02002738 buffer_dont_connect(req);
Willy Tarreauc465fd72009-08-31 00:17:18 +02002739 req->analysers = 0; /* remove switching rules etc... */
2740 req->analysers |= AN_REQ_HTTP_TARPIT;
2741 req->analyse_exp = tick_add_ifset(now_ms, s->be->timeout.tarpit);
2742 if (!req->analyse_exp)
2743 req->analyse_exp = tick_add(now_ms, 0);
2744 return 1;
2745 }
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002746 }
Willy Tarreau06619262006-12-17 08:37:22 +01002747
Willy Tarreau5b154472009-12-21 20:11:07 +01002748 /* Until set to anything else, the connection mode is set as TUNNEL. It will
2749 * only change if both the request and the config reference something else.
Willy Tarreau0dfdf192010-01-05 11:33:11 +01002750 * Option httpclose by itself does not set a mode, it remains a tunnel mode
2751 * in which headers are mangled. However, if another mode is set, it will
Willy Tarreaubbf0b372010-01-18 16:54:40 +01002752 * affect it (eg: server-close/keep-alive + httpclose = close). Note that we
2753 * avoid to redo the same work if FE and BE have the same settings (common).
2754 * The method consists in checking if options changed between the two calls
2755 * (implying that either one is non-null, or one of them is non-null and we
2756 * are there for the first time.
Willy Tarreau42736642009-10-18 21:04:35 +02002757 */
Willy Tarreau5b154472009-12-21 20:11:07 +01002758
Willy Tarreaubbf0b372010-01-18 16:54:40 +01002759 del_cl = del_ka = 0;
2760
Willy Tarreaue8e785b2009-12-26 15:34:26 +01002761 if ((txn->meth != HTTP_METH_CONNECT) &&
Willy Tarreaubbf0b372010-01-18 16:54:40 +01002762 ((!(txn->flags & TX_HDR_CONN_PRS) &&
2763 (s->fe->options & (PR_O_KEEPALIVE|PR_O_SERVER_CLO|PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))) ||
2764 ((s->fe->options & (PR_O_KEEPALIVE|PR_O_SERVER_CLO|PR_O_HTTP_CLOSE|PR_O_FORCE_CLO)) !=
2765 (s->be->options & (PR_O_KEEPALIVE|PR_O_SERVER_CLO|PR_O_HTTP_CLOSE|PR_O_FORCE_CLO))))) {
Willy Tarreau5b154472009-12-21 20:11:07 +01002766 int tmp = TX_CON_WANT_TUN;
Willy Tarreaubbf0b372010-01-18 16:54:40 +01002767
Willy Tarreau5b154472009-12-21 20:11:07 +01002768 if ((s->fe->options|s->be->options) & PR_O_KEEPALIVE)
2769 tmp = TX_CON_WANT_KAL;
Willy Tarreaub608feb2010-01-02 22:47:18 +01002770 if ((s->fe->options|s->be->options) & PR_O_SERVER_CLO)
2771 tmp = TX_CON_WANT_SCL;
Willy Tarreau0dfdf192010-01-05 11:33:11 +01002772 if ((s->fe->options|s->be->options) & PR_O_FORCE_CLO)
Willy Tarreau5b154472009-12-21 20:11:07 +01002773 tmp = TX_CON_WANT_CLO;
2774
Willy Tarreau5b154472009-12-21 20:11:07 +01002775 if ((txn->flags & TX_CON_WANT_MSK) < tmp)
2776 txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | tmp;
Willy Tarreau0dfdf192010-01-05 11:33:11 +01002777
Willy Tarreaubbf0b372010-01-18 16:54:40 +01002778 if (!(txn->flags & TX_HDR_CONN_PRS)) {
2779 /* parse the Connection header and possibly clean it */
2780 int to_del = 0;
2781 if ((txn->flags & TX_REQ_VER_11) ||
2782 (txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL)
2783 to_del |= 2; /* remove "keep-alive" */
2784 if (!(txn->flags & TX_REQ_VER_11))
2785 to_del |= 1; /* remove "close" */
2786 http_parse_connection_header(txn, msg, req, to_del);
Willy Tarreau0dfdf192010-01-05 11:33:11 +01002787 }
Willy Tarreau5b154472009-12-21 20:11:07 +01002788
Willy Tarreaubbf0b372010-01-18 16:54:40 +01002789 /* check if client or config asks for explicit close in KAL/SCL */
2790 if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL ||
2791 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) &&
2792 ((txn->flags & TX_HDR_CONN_CLO) || /* "connection: close" */
2793 (txn->flags & (TX_REQ_VER_11|TX_HDR_CONN_KAL)) == 0 || /* no "connection: k-a" in 1.0 */
2794 ((s->fe->options|s->be->options) & PR_O_HTTP_CLOSE) || /* httpclose + any = forceclose */
2795 !(txn->flags & TX_REQ_XFER_LEN))) /* no length known => close */
2796 txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
2797 }
Willy Tarreau78599912009-10-17 20:12:21 +02002798
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002799 /* add request headers from the rule sets in the same order */
Willy Tarreaudeb9ed82010-01-03 21:03:22 +01002800 list_for_each_entry(wl, &px->req_add, list) {
2801 if (unlikely(http_header_add_tail(req, &txn->req, &txn->hdr_idx, wl->s) < 0))
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002802 goto return_bad_req;
2803 }
Willy Tarreaub2513902006-12-17 14:52:38 +01002804
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002805 /* check if stats URI was requested, and if an auth is needed */
2806 if (px->uri_auth != NULL &&
2807 (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)) {
2808 /* we have to check the URI and auth for this request.
2809 * FIXME!!! that one is rather dangerous, we want to
2810 * make it follow standard rules (eg: clear req->analysers).
2811 */
2812 if (stats_check_uri_auth(s, px)) {
2813 req->analysers = 0;
2814 return 0;
Willy Tarreau59234e92008-11-30 23:51:27 +01002815 }
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002816 }
Willy Tarreaub2513902006-12-17 14:52:38 +01002817
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002818 /* check whether we have some ACLs set to redirect this request */
2819 list_for_each_entry(rule, &px->redirect_rules, list) {
Willy Tarreauf285f542010-01-03 20:03:03 +01002820 int ret = ACL_PAT_PASS;
Willy Tarreau06b917c2009-07-06 16:34:52 +02002821
Willy Tarreauf285f542010-01-03 20:03:03 +01002822 if (rule->cond) {
2823 ret = acl_exec_cond(rule->cond, px, s, txn, ACL_DIR_REQ);
2824 ret = acl_pass(ret);
2825 if (rule->cond->pol == ACL_COND_UNLESS)
2826 ret = !ret;
2827 }
Willy Tarreau06b917c2009-07-06 16:34:52 +02002828
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002829 if (ret) {
Willy Tarreau3bb9c232010-01-03 12:24:37 +01002830 struct chunk rdr = { .str = trash, .size = sizeof(trash), .len = 0 };
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002831 const char *msg_fmt;
Willy Tarreau06b917c2009-07-06 16:34:52 +02002832
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002833 /* build redirect message */
2834 switch(rule->code) {
2835 case 303:
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002836 msg_fmt = HTTP_303;
2837 break;
2838 case 301:
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002839 msg_fmt = HTTP_301;
2840 break;
2841 case 302:
2842 default:
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002843 msg_fmt = HTTP_302;
2844 break;
2845 }
Willy Tarreau06b917c2009-07-06 16:34:52 +02002846
Willy Tarreau3bb9c232010-01-03 12:24:37 +01002847 if (unlikely(!chunk_strcpy(&rdr, msg_fmt)))
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002848 goto return_bad_req;
Willy Tarreau06b917c2009-07-06 16:34:52 +02002849
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002850 switch(rule->type) {
2851 case REDIRECT_TYPE_PREFIX: {
2852 const char *path;
2853 int pathlen;
Willy Tarreau06b917c2009-07-06 16:34:52 +02002854
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002855 path = http_get_path(txn);
2856 /* build message using path */
2857 if (path) {
Willy Tarreau962c3f42010-01-10 00:15:35 +01002858 pathlen = txn->req.sl.rq.u_l + (txn->req.sol + txn->req.sl.rq.u) - path;
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002859 if (rule->flags & REDIRECT_FLAG_DROP_QS) {
2860 int qs = 0;
2861 while (qs < pathlen) {
2862 if (path[qs] == '?') {
2863 pathlen = qs;
2864 break;
Willy Tarreau06b917c2009-07-06 16:34:52 +02002865 }
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002866 qs++;
Willy Tarreau06b917c2009-07-06 16:34:52 +02002867 }
Willy Tarreau06b917c2009-07-06 16:34:52 +02002868 }
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002869 } else {
2870 path = "/";
2871 pathlen = 1;
Willy Tarreau06b917c2009-07-06 16:34:52 +02002872 }
Willy Tarreau06b917c2009-07-06 16:34:52 +02002873
Krzysztof Piotr Oledzki78abe612009-09-27 13:23:20 +02002874 if (rdr.len + rule->rdr_len + pathlen > rdr.size - 4)
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002875 goto return_bad_req;
2876
2877 /* add prefix. Note that if prefix == "/", we don't want to
2878 * add anything, otherwise it makes it hard for the user to
2879 * configure a self-redirection.
2880 */
2881 if (rule->rdr_len != 1 || *rule->rdr_str != '/') {
Willy Tarreau06b917c2009-07-06 16:34:52 +02002882 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
2883 rdr.len += rule->rdr_len;
Willy Tarreau06b917c2009-07-06 16:34:52 +02002884 }
2885
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002886 /* add path */
2887 memcpy(rdr.str + rdr.len, path, pathlen);
2888 rdr.len += pathlen;
Willy Tarreau81e3b4f2010-01-10 00:42:19 +01002889
2890 /* append a slash at the end of the location is needed and missing */
2891 if (rdr.len && rdr.str[rdr.len - 1] != '/' &&
2892 (rule->flags & REDIRECT_FLAG_APPEND_SLASH)) {
2893 if (rdr.len > rdr.size - 5)
2894 goto return_bad_req;
2895 rdr.str[rdr.len] = '/';
2896 rdr.len++;
2897 }
2898
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002899 break;
2900 }
2901 case REDIRECT_TYPE_LOCATION:
2902 default:
Krzysztof Piotr Oledzki78abe612009-09-27 13:23:20 +02002903 if (rdr.len + rule->rdr_len > rdr.size - 4)
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002904 goto return_bad_req;
Willy Tarreau06b917c2009-07-06 16:34:52 +02002905
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002906 /* add location */
2907 memcpy(rdr.str + rdr.len, rule->rdr_str, rule->rdr_len);
2908 rdr.len += rule->rdr_len;
2909 break;
2910 }
Willy Tarreau06b917c2009-07-06 16:34:52 +02002911
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002912 if (rule->cookie_len) {
2913 memcpy(rdr.str + rdr.len, "\r\nSet-Cookie: ", 14);
2914 rdr.len += 14;
2915 memcpy(rdr.str + rdr.len, rule->cookie_str, rule->cookie_len);
2916 rdr.len += rule->cookie_len;
2917 memcpy(rdr.str + rdr.len, "\r\n", 2);
2918 rdr.len += 2;
Willy Tarreau06b917c2009-07-06 16:34:52 +02002919 }
Willy Tarreau06b917c2009-07-06 16:34:52 +02002920
Willy Tarreaua9679ac2010-01-03 17:32:57 +01002921 /* add end of headers and the keep-alive/close status.
2922 * We may choose to set keep-alive if the Location begins
2923 * with a slash, because the client will come back to the
2924 * same server.
2925 */
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002926 txn->status = rule->code;
2927 /* let's log the request time */
2928 s->logs.tv_request = now;
Willy Tarreaua9679ac2010-01-03 17:32:57 +01002929
2930 if (rule->rdr_len >= 1 && *rule->rdr_str == '/' &&
2931 (txn->flags & TX_REQ_XFER_LEN) &&
2932 !(txn->flags & TX_REQ_TE_CHNK) && !txn->req.hdr_content_len &&
2933 ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL ||
2934 (txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL)) {
2935 /* keep-alive possible */
Willy Tarreau75661452010-01-10 10:35:01 +01002936 if (!(txn->flags & TX_REQ_VER_11)) {
2937 memcpy(rdr.str + rdr.len, "\r\nConnection: keep-alive", 24);
2938 rdr.len += 24;
2939 }
2940 memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
2941 rdr.len += 4;
Willy Tarreaua9679ac2010-01-03 17:32:57 +01002942 buffer_write(req->prod->ob, rdr.str, rdr.len);
2943 /* "eat" the request */
2944 buffer_ignore(req, msg->sov - msg->som);
2945 msg->som = msg->sov;
2946 req->analysers = AN_REQ_HTTP_XFER_BODY;
Willy Tarreau9300fb22010-01-05 00:58:24 +01002947 s->rep->analysers = AN_RES_HTTP_XFER_BODY;
2948 txn->req.msg_state = HTTP_MSG_CLOSED;
2949 txn->rsp.msg_state = HTTP_MSG_DONE;
Willy Tarreaua9679ac2010-01-03 17:32:57 +01002950 break;
2951 } else {
2952 /* keep-alive not possible */
2953 memcpy(rdr.str + rdr.len, "\r\nConnection: close\r\n\r\n", 23);
2954 rdr.len += 23;
Willy Tarreau148d0992010-01-10 10:21:21 +01002955 stream_int_retnclose(req->prod, &rdr);
Willy Tarreaua9679ac2010-01-03 17:32:57 +01002956 goto return_prx_cond;
2957 }
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002958 }
2959 }
Willy Tarreau55ea7572007-06-17 19:56:27 +02002960
Willy Tarreau2be39392010-01-03 17:24:51 +01002961 /* POST requests may be accompanied with an "Expect: 100-Continue" header.
2962 * If this happens, then the data will not come immediately, so we must
2963 * send all what we have without waiting. Note that due to the small gain
2964 * in waiting for the body of the request, it's easier to simply put the
2965 * BF_SEND_DONTWAIT flag any time. It's a one-shot flag so it will remove
2966 * itself once used.
2967 */
2968 req->flags |= BF_SEND_DONTWAIT;
2969
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002970 /* that's OK for us now, let's move on to next analysers */
2971 return 1;
Willy Tarreau11382812008-07-09 16:18:21 +02002972
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002973 return_bad_req:
2974 /* We centralize bad requests processing here */
2975 if (unlikely(msg->msg_state == HTTP_MSG_ERROR) || msg->err_pos >= 0) {
2976 /* we detected a parsing error. We want to archive this request
2977 * in the dedicated proxy area for later troubleshooting.
2978 */
2979 http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
2980 }
Willy Tarreau55ea7572007-06-17 19:56:27 +02002981
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002982 txn->req.msg_state = HTTP_MSG_ERROR;
2983 txn->status = 400;
2984 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002985
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02002986 s->fe->counters.failed_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02002987 if (s->listener->counters)
2988 s->listener->counters->failed_req++;
Willy Tarreau6e4261e2007-09-18 18:36:05 +02002989
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002990 return_prx_cond:
2991 if (!(s->flags & SN_ERR_MASK))
2992 s->flags |= SN_ERR_PRXCOND;
2993 if (!(s->flags & SN_FINST_MASK))
2994 s->flags |= SN_FINST_R;
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002995
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02002996 req->analysers = 0;
2997 req->analyse_exp = TICK_ETERNITY;
2998 return 0;
2999}
Willy Tarreau58f10d72006-12-04 02:26:12 +01003000
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02003001/* This function performs all the processing enabled for the current request.
3002 * It returns 1 if the processing can continue on next analysers, or zero if it
3003 * needs more data, encounters an error, or wants to immediately abort the
3004 * request. It relies on buffers flags, and updates s->req->analysers.
3005 */
3006int http_process_request(struct session *s, struct buffer *req, int an_bit)
3007{
3008 struct http_txn *txn = &s->txn;
3009 struct http_msg *msg = &txn->req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003010
Willy Tarreau655dce92009-11-08 13:10:58 +01003011 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
Willy Tarreau51aecc72009-07-12 09:47:04 +02003012 /* we need more data */
Willy Tarreau520d95e2009-09-19 21:04:57 +02003013 buffer_dont_connect(req);
Willy Tarreau51aecc72009-07-12 09:47:04 +02003014 return 0;
3015 }
3016
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02003017 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
3018 now_ms, __FUNCTION__,
3019 s,
3020 req,
3021 req->rex, req->wex,
3022 req->flags,
3023 req->l,
3024 req->analysers);
Willy Tarreau06619262006-12-17 08:37:22 +01003025
Willy Tarreau59234e92008-11-30 23:51:27 +01003026 /*
3027 * Right now, we know that we have processed the entire headers
3028 * and that unwanted requests have been filtered out. We can do
3029 * whatever we want with the remaining request. Also, now we
3030 * may have separate values for ->fe, ->be.
3031 */
Willy Tarreau06619262006-12-17 08:37:22 +01003032
Willy Tarreau59234e92008-11-30 23:51:27 +01003033 /*
3034 * If HTTP PROXY is set we simply get remote server address
3035 * parsing incoming request.
3036 */
3037 if ((s->be->options & PR_O_HTTP_PROXY) && !(s->flags & SN_ADDR_SET)) {
Willy Tarreau962c3f42010-01-10 00:15:35 +01003038 url2sa(msg->sol + msg->sl.rq.u, msg->sl.rq.u_l, &s->srv_addr);
Willy Tarreau59234e92008-11-30 23:51:27 +01003039 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01003040
Willy Tarreau59234e92008-11-30 23:51:27 +01003041 /*
Cyril Bontéb21570a2009-11-29 20:04:48 +01003042 * 7: Now we can work with the cookies.
Willy Tarreau59234e92008-11-30 23:51:27 +01003043 * Note that doing so might move headers in the request, but
3044 * the fields will stay coherent and the URI will not move.
3045 * This should only be performed in the backend.
3046 */
Willy Tarreaufd39dda2008-10-17 12:01:58 +02003047 if ((s->be->cookie_name || s->be->appsession_name || s->fe->capture_name)
Willy Tarreau59234e92008-11-30 23:51:27 +01003048 && !(txn->flags & (TX_CLDENY|TX_CLTARPIT)))
3049 manage_client_side_cookies(s, req);
Willy Tarreau7ac51f62007-03-25 16:00:04 +02003050
Willy Tarreau59234e92008-11-30 23:51:27 +01003051 /*
Cyril Bontéb21570a2009-11-29 20:04:48 +01003052 * 8: the appsession cookie was looked up very early in 1.2,
3053 * so let's do the same now.
3054 */
3055
3056 /* It needs to look into the URI */
Willy Tarreaua3377ee2010-01-10 10:49:11 +01003057 if ((txn->sessid == NULL) && s->be->appsession_name) {
Willy Tarreau962c3f42010-01-10 00:15:35 +01003058 get_srv_from_appsession(s, msg->sol + msg->sl.rq.u, msg->sl.rq.u_l);
Cyril Bontéb21570a2009-11-29 20:04:48 +01003059 }
3060
3061 /*
Willy Tarreau59234e92008-11-30 23:51:27 +01003062 * 9: add X-Forwarded-For if either the frontend or the backend
3063 * asks for it.
3064 */
3065 if ((s->fe->options | s->be->options) & PR_O_FWDFOR) {
3066 if (s->cli_addr.ss_family == AF_INET) {
3067 /* Add an X-Forwarded-For header unless the source IP is
3068 * in the 'except' network range.
3069 */
3070 if ((!s->fe->except_mask.s_addr ||
3071 (((struct sockaddr_in *)&s->cli_addr)->sin_addr.s_addr & s->fe->except_mask.s_addr)
3072 != s->fe->except_net.s_addr) &&
3073 (!s->be->except_mask.s_addr ||
3074 (((struct sockaddr_in *)&s->cli_addr)->sin_addr.s_addr & s->be->except_mask.s_addr)
3075 != s->be->except_net.s_addr)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01003076 int len;
Willy Tarreau59234e92008-11-30 23:51:27 +01003077 unsigned char *pn;
3078 pn = (unsigned char *)&((struct sockaddr_in *)&s->cli_addr)->sin_addr;
Ross Westaf72a1d2008-08-03 10:51:45 +02003079
3080 /* Note: we rely on the backend to get the header name to be used for
3081 * x-forwarded-for, because the header is really meant for the backends.
3082 * However, if the backend did not specify any option, we have to rely
3083 * on the frontend's header name.
3084 */
Willy Tarreau59234e92008-11-30 23:51:27 +01003085 if (s->be->fwdfor_hdr_len) {
3086 len = s->be->fwdfor_hdr_len;
3087 memcpy(trash, s->be->fwdfor_hdr_name, len);
Ross Westaf72a1d2008-08-03 10:51:45 +02003088 } else {
Willy Tarreau59234e92008-11-30 23:51:27 +01003089 len = s->fe->fwdfor_hdr_len;
3090 memcpy(trash, s->fe->fwdfor_hdr_name, len);
Willy Tarreaub86db342009-11-30 11:50:16 +01003091 }
Willy Tarreau59234e92008-11-30 23:51:27 +01003092 len += sprintf(trash + len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
Willy Tarreauedcf6682008-11-30 23:15:34 +01003093
Willy Tarreau4af6f3a2007-03-18 22:36:26 +01003094 if (unlikely(http_header_add_tail2(req, &txn->req,
Willy Tarreau58cc8722009-12-28 06:57:33 +01003095 &txn->hdr_idx, trash, len) < 0))
Willy Tarreau06619262006-12-17 08:37:22 +01003096 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01003097 }
3098 }
Willy Tarreau59234e92008-11-30 23:51:27 +01003099 else if (s->cli_addr.ss_family == AF_INET6) {
3100 /* FIXME: for the sake of completeness, we should also support
3101 * 'except' here, although it is mostly useless in this case.
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003102 */
Willy Tarreau59234e92008-11-30 23:51:27 +01003103 int len;
3104 char pn[INET6_ADDRSTRLEN];
3105 inet_ntop(AF_INET6,
3106 (const void *)&((struct sockaddr_in6 *)(&s->cli_addr))->sin6_addr,
3107 pn, sizeof(pn));
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003108
Willy Tarreau59234e92008-11-30 23:51:27 +01003109 /* Note: we rely on the backend to get the header name to be used for
3110 * x-forwarded-for, because the header is really meant for the backends.
3111 * However, if the backend did not specify any option, we have to rely
3112 * on the frontend's header name.
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003113 */
Willy Tarreau59234e92008-11-30 23:51:27 +01003114 if (s->be->fwdfor_hdr_len) {
3115 len = s->be->fwdfor_hdr_len;
3116 memcpy(trash, s->be->fwdfor_hdr_name, len);
3117 } else {
3118 len = s->fe->fwdfor_hdr_len;
3119 memcpy(trash, s->fe->fwdfor_hdr_name, len);
matt.farnsworth@nokia.com1c2ab962008-04-14 20:47:37 +02003120 }
Willy Tarreau59234e92008-11-30 23:51:27 +01003121 len += sprintf(trash + len, ": %s", pn);
Willy Tarreauadfb8562008-08-11 15:24:42 +02003122
Willy Tarreau59234e92008-11-30 23:51:27 +01003123 if (unlikely(http_header_add_tail2(req, &txn->req,
Willy Tarreau58cc8722009-12-28 06:57:33 +01003124 &txn->hdr_idx, trash, len) < 0))
Willy Tarreau59234e92008-11-30 23:51:27 +01003125 goto return_bad_req;
3126 }
3127 }
3128
3129 /*
Maik Broemme2850cb42009-04-17 18:53:21 +02003130 * 10: add X-Original-To if either the frontend or the backend
3131 * asks for it.
3132 */
3133 if ((s->fe->options | s->be->options) & PR_O_ORGTO) {
3134
3135 /* FIXME: don't know if IPv6 can handle that case too. */
3136 if (s->cli_addr.ss_family == AF_INET) {
3137 /* Add an X-Original-To header unless the destination IP is
3138 * in the 'except' network range.
3139 */
3140 if (!(s->flags & SN_FRT_ADDR_SET))
3141 get_frt_addr(s);
3142
3143 if ((!s->fe->except_mask_to.s_addr ||
3144 (((struct sockaddr_in *)&s->frt_addr)->sin_addr.s_addr & s->fe->except_mask_to.s_addr)
3145 != s->fe->except_to.s_addr) &&
3146 (!s->be->except_mask_to.s_addr ||
3147 (((struct sockaddr_in *)&s->frt_addr)->sin_addr.s_addr & s->be->except_mask_to.s_addr)
3148 != s->be->except_to.s_addr)) {
3149 int len;
3150 unsigned char *pn;
3151 pn = (unsigned char *)&((struct sockaddr_in *)&s->frt_addr)->sin_addr;
3152
3153 /* Note: we rely on the backend to get the header name to be used for
3154 * x-original-to, because the header is really meant for the backends.
3155 * However, if the backend did not specify any option, we have to rely
3156 * on the frontend's header name.
3157 */
3158 if (s->be->orgto_hdr_len) {
3159 len = s->be->orgto_hdr_len;
3160 memcpy(trash, s->be->orgto_hdr_name, len);
3161 } else {
3162 len = s->fe->orgto_hdr_len;
3163 memcpy(trash, s->fe->orgto_hdr_name, len);
Willy Tarreaub86db342009-11-30 11:50:16 +01003164 }
Maik Broemme2850cb42009-04-17 18:53:21 +02003165 len += sprintf(trash + len, ": %d.%d.%d.%d", pn[0], pn[1], pn[2], pn[3]);
3166
3167 if (unlikely(http_header_add_tail2(req, &txn->req,
Willy Tarreau58cc8722009-12-28 06:57:33 +01003168 &txn->hdr_idx, trash, len) < 0))
Maik Broemme2850cb42009-04-17 18:53:21 +02003169 goto return_bad_req;
3170 }
3171 }
3172 }
3173
Willy Tarreaubbf0b372010-01-18 16:54:40 +01003174 /* 11: add "Connection: close" or "Connection: keep-alive" if needed and not yet set. */
3175 if (((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) ||
3176 ((s->fe->options|s->be->options) & PR_O_HTTP_CLOSE)) {
3177 unsigned int want_flags = 0;
3178
3179 if (txn->flags & TX_REQ_VER_11) {
3180 if ((txn->flags & TX_CON_WANT_MSK) >= TX_CON_WANT_SCL ||
3181 ((s->fe->options|s->be->options) & PR_O_HTTP_CLOSE))
3182 want_flags |= TX_CON_CLO_SET;
3183 } else {
3184 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_KAL)
3185 want_flags |= TX_CON_KAL_SET;
3186 }
3187
3188 if (want_flags != (txn->flags & (TX_CON_CLO_SET|TX_CON_KAL_SET)))
3189 http_change_connection_header(txn, msg, req, want_flags);
Willy Tarreau59234e92008-11-30 23:51:27 +01003190 }
Willy Tarreau522d6c02009-12-06 18:49:18 +01003191
Willy Tarreaubbf0b372010-01-18 16:54:40 +01003192
Willy Tarreau522d6c02009-12-06 18:49:18 +01003193 /* If we have no server assigned yet and we're balancing on url_param
3194 * with a POST request, we may be interested in checking the body for
3195 * that parameter. This will be done in another analyser.
Willy Tarreau59234e92008-11-30 23:51:27 +01003196 */
3197 if (!(s->flags & (SN_ASSIGNED|SN_DIRECT)) &&
3198 s->txn.meth == HTTP_METH_POST && s->be->url_param_name != NULL &&
Willy Tarreau522d6c02009-12-06 18:49:18 +01003199 s->be->url_param_post_limit != 0 &&
3200 (txn->flags & (TX_REQ_CNT_LEN|TX_REQ_TE_CHNK)) &&
Willy Tarreau962c3f42010-01-10 00:15:35 +01003201 memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) {
Willy Tarreau522d6c02009-12-06 18:49:18 +01003202 buffer_dont_connect(req);
3203 req->analysers |= AN_REQ_HTTP_BODY;
Willy Tarreau59234e92008-11-30 23:51:27 +01003204 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003205
Willy Tarreaud98cf932009-12-27 22:54:55 +01003206 if (txn->flags & TX_REQ_XFER_LEN)
3207 req->analysers |= AN_REQ_HTTP_XFER_BODY;
Willy Tarreau03945942009-12-22 16:50:27 +01003208
Willy Tarreau59234e92008-11-30 23:51:27 +01003209 /*************************************************************
3210 * OK, that's finished for the headers. We have done what we *
3211 * could. Let's switch to the DATA state. *
3212 ************************************************************/
Willy Tarreau522d6c02009-12-06 18:49:18 +01003213 req->analyse_exp = TICK_ETERNITY;
3214 req->analysers &= ~an_bit;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003215
Willy Tarreau59234e92008-11-30 23:51:27 +01003216 s->logs.tv_request = now;
Willy Tarreau59234e92008-11-30 23:51:27 +01003217 /* OK let's go on with the BODY now */
3218 return 1;
Willy Tarreau06619262006-12-17 08:37:22 +01003219
Willy Tarreau59234e92008-11-30 23:51:27 +01003220 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau4076a152009-04-02 15:18:36 +02003221 if (unlikely(msg->msg_state == HTTP_MSG_ERROR) || msg->err_pos >= 0) {
Willy Tarreauf073a832009-03-01 23:21:47 +01003222 /* we detected a parsing error. We want to archive this request
3223 * in the dedicated proxy area for later troubleshooting.
3224 */
Willy Tarreau4076a152009-04-02 15:18:36 +02003225 http_capture_bad_message(&s->fe->invalid_req, s, req, msg, s->fe);
Willy Tarreauf073a832009-03-01 23:21:47 +01003226 }
Willy Tarreau4076a152009-04-02 15:18:36 +02003227
Willy Tarreau59234e92008-11-30 23:51:27 +01003228 txn->req.msg_state = HTTP_MSG_ERROR;
3229 txn->status = 400;
3230 req->analysers = 0;
3231 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02003232
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02003233 s->fe->counters.failed_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02003234 if (s->listener->counters)
3235 s->listener->counters->failed_req++;
Willy Tarreauadfb8562008-08-11 15:24:42 +02003236
Willy Tarreau59234e92008-11-30 23:51:27 +01003237 if (!(s->flags & SN_ERR_MASK))
3238 s->flags |= SN_ERR_PRXCOND;
3239 if (!(s->flags & SN_FINST_MASK))
3240 s->flags |= SN_FINST_R;
Willy Tarreaudafde432008-08-17 01:00:46 +02003241 return 0;
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02003242}
Willy Tarreauadfb8562008-08-11 15:24:42 +02003243
Willy Tarreau60b85b02008-11-30 23:28:40 +01003244/* This function is an analyser which processes the HTTP tarpit. It always
3245 * returns zero, at the beginning because it prevents any other processing
3246 * from occurring, and at the end because it terminates the request.
3247 */
Willy Tarreau3a816292009-07-07 10:55:49 +02003248int http_process_tarpit(struct session *s, struct buffer *req, int an_bit)
Willy Tarreau60b85b02008-11-30 23:28:40 +01003249{
3250 struct http_txn *txn = &s->txn;
3251
3252 /* This connection is being tarpitted. The CLIENT side has
3253 * already set the connect expiration date to the right
3254 * timeout. We just have to check that the client is still
3255 * there and that the timeout has not expired.
3256 */
Willy Tarreau520d95e2009-09-19 21:04:57 +02003257 buffer_dont_connect(req);
Willy Tarreau60b85b02008-11-30 23:28:40 +01003258 if ((req->flags & (BF_SHUTR|BF_READ_ERROR)) == 0 &&
3259 !tick_is_expired(req->analyse_exp, now_ms))
3260 return 0;
3261
3262 /* We will set the queue timer to the time spent, just for
3263 * logging purposes. We fake a 500 server error, so that the
3264 * attacker will not suspect his connection has been tarpitted.
3265 * It will not cause trouble to the logs because we can exclude
3266 * the tarpitted connections by filtering on the 'PT' status flags.
3267 */
Willy Tarreau60b85b02008-11-30 23:28:40 +01003268 s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
3269
3270 txn->status = 500;
3271 if (req->flags != BF_READ_ERROR)
3272 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_500));
3273
3274 req->analysers = 0;
3275 req->analyse_exp = TICK_ETERNITY;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02003276
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02003277 s->fe->counters.failed_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02003278 if (s->listener->counters)
3279 s->listener->counters->failed_req++;
Willy Tarreau60b85b02008-11-30 23:28:40 +01003280
Willy Tarreau60b85b02008-11-30 23:28:40 +01003281 if (!(s->flags & SN_ERR_MASK))
3282 s->flags |= SN_ERR_PRXCOND;
3283 if (!(s->flags & SN_FINST_MASK))
3284 s->flags |= SN_FINST_T;
3285 return 0;
3286}
3287
Willy Tarreaud34af782008-11-30 23:36:37 +01003288/* This function is an analyser which processes the HTTP request body. It looks
3289 * for parameters to be used for the load balancing algorithm (url_param). It
3290 * must only be called after the standard HTTP request processing has occurred,
3291 * because it expects the request to be parsed. It returns zero if it needs to
3292 * read more data, or 1 once it has completed its analysis.
3293 */
Willy Tarreau3a816292009-07-07 10:55:49 +02003294int http_process_request_body(struct session *s, struct buffer *req, int an_bit)
Willy Tarreaud34af782008-11-30 23:36:37 +01003295{
Willy Tarreau522d6c02009-12-06 18:49:18 +01003296 struct http_txn *txn = &s->txn;
Willy Tarreaud34af782008-11-30 23:36:37 +01003297 struct http_msg *msg = &s->txn.req;
Willy Tarreaud34af782008-11-30 23:36:37 +01003298 long long limit = s->be->url_param_post_limit;
Willy Tarreaud34af782008-11-30 23:36:37 +01003299
3300 /* We have to parse the HTTP request body to find any required data.
3301 * "balance url_param check_post" should have been the only way to get
3302 * into this. We were brought here after HTTP header analysis, so all
3303 * related structures are ready.
3304 */
3305
Willy Tarreau522d6c02009-12-06 18:49:18 +01003306 if (unlikely(msg->msg_state < HTTP_MSG_BODY))
3307 goto missing_data;
3308
3309 if (msg->msg_state < HTTP_MSG_100_SENT) {
3310 /* If we have HTTP/1.1 and Expect: 100-continue, then we must
3311 * send an HTTP/1.1 100 Continue intermediate response.
3312 */
Willy Tarreau9e13c3c2009-12-22 09:59:58 +01003313 if (txn->flags & TX_REQ_VER_11) {
Willy Tarreau522d6c02009-12-06 18:49:18 +01003314 struct hdr_ctx ctx;
3315 ctx.idx = 0;
3316 /* Expect is allowed in 1.1, look for it */
3317 if (http_find_header2("Expect", 6, msg->sol, &txn->hdr_idx, &ctx) &&
3318 unlikely(ctx.vlen == 12 && strncasecmp(ctx.line+ctx.val, "100-continue", 12) == 0)) {
3319 buffer_write(s->rep, http_100_chunk.str, http_100_chunk.len);
3320 }
3321 }
3322 msg->msg_state = HTTP_MSG_100_SENT;
3323 }
3324
3325 if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) {
Willy Tarreaud98cf932009-12-27 22:54:55 +01003326 /* we have msg->col and msg->sov which both point to the first
3327 * byte of message body. msg->som still points to the beginning
3328 * of the message. We must save the body in req->lr because it
3329 * survives buffer re-alignments.
3330 */
3331 req->lr = req->data + msg->sov;
Willy Tarreau522d6c02009-12-06 18:49:18 +01003332 if (txn->flags & TX_REQ_TE_CHNK)
3333 msg->msg_state = HTTP_MSG_CHUNK_SIZE;
3334 else
3335 msg->msg_state = HTTP_MSG_DATA;
3336 }
3337
3338 if (msg->msg_state == HTTP_MSG_CHUNK_SIZE) {
Willy Tarreau115acb92009-12-26 13:56:06 +01003339 /* read the chunk size and assign it to ->hdr_content_len, then
Willy Tarreaud98cf932009-12-27 22:54:55 +01003340 * set ->sov and ->lr to point to the body and switch to DATA or
3341 * TRAILERS state.
Willy Tarreau115acb92009-12-26 13:56:06 +01003342 */
3343 int ret = http_parse_chunk_size(req, msg);
Willy Tarreaud34af782008-11-30 23:36:37 +01003344
Willy Tarreau115acb92009-12-26 13:56:06 +01003345 if (!ret)
3346 goto missing_data;
3347 else if (ret < 0)
Willy Tarreau522d6c02009-12-06 18:49:18 +01003348 goto return_bad_req;
Willy Tarreaud34af782008-11-30 23:36:37 +01003349 }
3350
Willy Tarreaud98cf932009-12-27 22:54:55 +01003351 /* Now we're in HTTP_MSG_DATA or HTTP_MSG_TRAILERS state.
Willy Tarreau522d6c02009-12-06 18:49:18 +01003352 * We have the first non-header byte in msg->col, which is either the
3353 * beginning of the chunk size or of the data. The first data byte is in
3354 * msg->sov, which is equal to msg->col when not using transfer-encoding.
3355 * We're waiting for at least <url_param_post_limit> bytes after msg->sov.
Willy Tarreaud34af782008-11-30 23:36:37 +01003356 */
Willy Tarreau522d6c02009-12-06 18:49:18 +01003357
3358 if (msg->hdr_content_len < limit)
3359 limit = msg->hdr_content_len;
3360
Willy Tarreau7c96f672009-12-27 22:47:25 +01003361 if (req->l - (msg->sov - msg->som) >= limit) /* we have enough bytes now */
Willy Tarreau522d6c02009-12-06 18:49:18 +01003362 goto http_end;
3363
3364 missing_data:
3365 /* we get here if we need to wait for more data */
Willy Tarreau115acb92009-12-26 13:56:06 +01003366 if (req->flags & BF_FULL)
3367 goto return_bad_req;
3368
Willy Tarreau522d6c02009-12-06 18:49:18 +01003369 if ((req->flags & BF_READ_TIMEOUT) || tick_is_expired(req->analyse_exp, now_ms)) {
3370 txn->status = 408;
3371 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_408));
3372 goto return_err_msg;
Willy Tarreaud34af782008-11-30 23:36:37 +01003373 }
Willy Tarreau522d6c02009-12-06 18:49:18 +01003374
3375 /* we get here if we need to wait for more data */
3376 if (!(req->flags & (BF_FULL | BF_READ_ERROR | BF_SHUTR))) {
Willy Tarreaud34af782008-11-30 23:36:37 +01003377 /* Not enough data. We'll re-use the http-request
3378 * timeout here. Ideally, we should set the timeout
3379 * relative to the accept() date. We just set the
3380 * request timeout once at the beginning of the
3381 * request.
3382 */
Willy Tarreau520d95e2009-09-19 21:04:57 +02003383 buffer_dont_connect(req);
Willy Tarreaud34af782008-11-30 23:36:37 +01003384 if (!tick_isset(req->analyse_exp))
Willy Tarreaucd7afc02009-07-12 10:03:17 +02003385 req->analyse_exp = tick_add_ifset(now_ms, s->be->timeout.httpreq);
Willy Tarreaud34af782008-11-30 23:36:37 +01003386 return 0;
3387 }
Willy Tarreau522d6c02009-12-06 18:49:18 +01003388
3389 http_end:
3390 /* The situation will not evolve, so let's give up on the analysis. */
3391 s->logs.tv_request = now; /* update the request timer to reflect full request */
3392 req->analysers &= ~an_bit;
3393 req->analyse_exp = TICK_ETERNITY;
3394 return 1;
3395
3396 return_bad_req: /* let's centralize all bad requests */
3397 txn->req.msg_state = HTTP_MSG_ERROR;
3398 txn->status = 400;
3399 stream_int_retnclose(req->prod, error_message(s, HTTP_ERR_400));
3400
3401 return_err_msg:
3402 req->analysers = 0;
3403 s->fe->counters.failed_req++;
3404 if (s->listener->counters)
3405 s->listener->counters->failed_req++;
3406
3407 if (!(s->flags & SN_ERR_MASK))
3408 s->flags |= SN_ERR_PRXCOND;
3409 if (!(s->flags & SN_FINST_MASK))
3410 s->flags |= SN_FINST_R;
3411 return 0;
Willy Tarreaud34af782008-11-30 23:36:37 +01003412}
3413
Willy Tarreau610ecce2010-01-04 21:15:02 +01003414/* Terminate current transaction and prepare a new one. This is very tricky
3415 * right now but it works.
3416 */
3417void http_end_txn_clean_session(struct session *s)
3418{
3419 /* FIXME: We need a more portable way of releasing a backend's and a
3420 * server's connections. We need a safer way to reinitialize buffer
3421 * flags. We also need a more accurate method for computing per-request
3422 * data.
3423 */
3424 http_silent_debug(__LINE__, s);
3425
3426 s->req->cons->flags |= SI_FL_NOLINGER;
3427 s->req->cons->shutr(s->req->cons);
3428 s->req->cons->shutw(s->req->cons);
3429
3430 http_silent_debug(__LINE__, s);
3431
3432 if (s->flags & SN_BE_ASSIGNED)
3433 s->be->beconn--;
3434
3435 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
3436 session_process_counters(s);
3437
3438 if (s->txn.status) {
3439 int n;
3440
3441 n = s->txn.status / 100;
3442 if (n < 1 || n > 5)
3443 n = 0;
3444
3445 if (s->fe->mode == PR_MODE_HTTP)
3446 s->fe->counters.p.http.rsp[n]++;
3447
3448 if ((s->flags & SN_BE_ASSIGNED) && (s->fe != s->be) &&
3449 (s->be->mode == PR_MODE_HTTP))
3450 s->be->counters.p.http.rsp[n]++;
3451 }
3452
3453 /* don't count other requests' data */
3454 s->logs.bytes_in -= s->req->l - s->req->send_max;
3455 s->logs.bytes_out -= s->rep->l - s->rep->send_max;
3456
3457 /* let's do a final log if we need it */
3458 if (s->logs.logwait &&
3459 !(s->flags & SN_MONITOR) &&
3460 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total)) {
3461 s->do_log(s);
3462 }
3463
3464 s->logs.accept_date = date; /* user-visible date for logging */
3465 s->logs.tv_accept = now; /* corrected date for internal use */
3466 tv_zero(&s->logs.tv_request);
3467 s->logs.t_queue = -1;
3468 s->logs.t_connect = -1;
3469 s->logs.t_data = -1;
3470 s->logs.t_close = 0;
3471 s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
3472 s->logs.srv_queue_size = 0; /* we will get this number soon */
3473
3474 s->logs.bytes_in = s->req->total = s->req->l - s->req->send_max;
3475 s->logs.bytes_out = s->rep->total = s->rep->l - s->rep->send_max;
3476
3477 if (s->pend_pos)
3478 pendconn_free(s->pend_pos);
3479
3480 if (s->srv) {
3481 if (s->flags & SN_CURR_SESS) {
3482 s->flags &= ~SN_CURR_SESS;
3483 s->srv->cur_sess--;
3484 }
3485 if (may_dequeue_tasks(s->srv, s->be))
3486 process_srv_queue(s->srv);
3487 }
3488
3489 if (unlikely(s->srv_conn))
3490 sess_change_server(s, NULL);
3491 s->srv = NULL;
3492
3493 s->req->cons->state = s->req->cons->prev_state = SI_ST_INI;
3494 s->req->cons->fd = -1; /* just to help with debugging */
3495 s->req->cons->err_type = SI_ET_NONE;
3496 s->req->cons->err_loc = NULL;
3497 s->req->cons->exp = TICK_ETERNITY;
3498 s->req->cons->flags = SI_FL_NONE;
Willy Tarreau90deb182010-01-07 00:20:41 +01003499 s->req->flags &= ~(BF_SHUTW|BF_SHUTW_NOW|BF_AUTO_CONNECT|BF_WRITE_ERROR|BF_STREAMER|BF_STREAMER_FAST);
3500 s->rep->flags &= ~(BF_SHUTR|BF_SHUTR_NOW|BF_READ_ATTACHED|BF_READ_ERROR|BF_READ_NOEXP|BF_STREAMER|BF_STREAMER_FAST|BF_WRITE_PARTIAL);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003501 s->flags &= ~(SN_DIRECT|SN_ASSIGNED|SN_ADDR_SET|SN_BE_ASSIGNED);
3502 s->flags &= ~(SN_CURR_SESS|SN_REDIRECTABLE);
3503 s->txn.meth = 0;
3504 http_reset_txn(s);
Willy Tarreaufcffa692010-01-10 14:21:19 +01003505 s->txn.flags |= TX_NOT_FIRST | TX_WAIT_NEXT_RQ;
Willy Tarreau610ecce2010-01-04 21:15:02 +01003506 if (s->be->options2 & PR_O2_INDEPSTR)
3507 s->req->cons->flags |= SI_FL_INDEP_STR;
3508
3509 /* if the request buffer is not empty, it means we're
3510 * about to process another request, so send pending
3511 * data with MSG_MORE to merge TCP packets when possible.
Willy Tarreau065e8332010-01-08 00:30:20 +01003512 * Just don't do this if the buffer is close to be full,
3513 * because the request will wait for it to flush a little
3514 * bit before proceeding.
Willy Tarreau610ecce2010-01-04 21:15:02 +01003515 */
Willy Tarreau065e8332010-01-08 00:30:20 +01003516 if (s->req->l > s->req->send_max) {
3517 if (s->rep->send_max &&
3518 !(s->rep->flags & BF_FULL) &&
3519 s->rep->lr <= s->rep->r &&
3520 s->rep->r <= s->rep->data + s->rep->size - global.tune.maxrewrite)
3521 s->rep->flags |= BF_EXPECT_MORE;
3522 }
Willy Tarreau90deb182010-01-07 00:20:41 +01003523
3524 /* we're removing the analysers, we MUST re-enable events detection */
3525 buffer_auto_read(s->req);
3526 buffer_auto_close(s->req);
3527 buffer_auto_read(s->rep);
3528 buffer_auto_close(s->rep);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003529
3530 /* make ->lr point to the first non-forwarded byte */
3531 s->req->lr = s->req->w + s->req->send_max;
3532 if (s->req->lr >= s->req->data + s->req->size)
3533 s->req->lr -= s->req->size;
3534 s->rep->lr = s->rep->w + s->rep->send_max;
3535 if (s->rep->lr >= s->rep->data + s->rep->size)
3536 s->rep->lr -= s->req->size;
3537
3538 s->req->analysers |= s->fe->fe_req_ana;
3539 s->rep->analysers = 0;
3540
3541 http_silent_debug(__LINE__, s);
3542}
3543
3544
3545/* This function updates the request state machine according to the response
3546 * state machine and buffer flags. It returns 1 if it changes anything (flag
3547 * or state), otherwise zero. It ignores any state before HTTP_MSG_DONE, as
3548 * it is only used to find when a request/response couple is complete. Both
3549 * this function and its equivalent should loop until both return zero. It
3550 * can set its own state to DONE, CLOSING, CLOSED, TUNNEL, ERROR.
3551 */
3552int http_sync_req_state(struct session *s)
3553{
3554 struct buffer *buf = s->req;
3555 struct http_txn *txn = &s->txn;
3556 unsigned int old_flags = buf->flags;
3557 unsigned int old_state = txn->req.msg_state;
3558
3559 http_silent_debug(__LINE__, s);
3560 if (unlikely(txn->req.msg_state < HTTP_MSG_BODY))
3561 return 0;
3562
3563 if (txn->req.msg_state == HTTP_MSG_DONE) {
Willy Tarreau90deb182010-01-07 00:20:41 +01003564 /* No need to read anymore, the request was completely parsed.
3565 * We can shut the read side unless we want to abort_on_close.
3566 */
3567 if (buf->cons->state == SI_ST_EST || !(s->be->options & PR_O_ABRT_CLOSE))
3568 buffer_dont_read(buf);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003569
3570 if (txn->rsp.msg_state == HTTP_MSG_ERROR)
3571 goto wait_other_side;
3572
3573 if (txn->rsp.msg_state < HTTP_MSG_DONE) {
3574 /* The server has not finished to respond, so we
3575 * don't want to move in order not to upset it.
3576 */
3577 goto wait_other_side;
3578 }
3579
3580 if (txn->rsp.msg_state == HTTP_MSG_TUNNEL) {
3581 /* if any side switches to tunnel mode, the other one does too */
Willy Tarreau90deb182010-01-07 00:20:41 +01003582 buffer_auto_read(buf);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003583 txn->req.msg_state = HTTP_MSG_TUNNEL;
3584 goto wait_other_side;
3585 }
3586
3587 /* When we get here, it means that both the request and the
3588 * response have finished receiving. Depending on the connection
3589 * mode, we'll have to wait for the last bytes to leave in either
3590 * direction, and sometimes for a close to be effective.
3591 */
3592
Willy Tarreaucce7fa42010-01-16 23:19:39 +01003593 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) {
3594 /* Server-close mode : queue a connection close to the server */
3595 if (!(buf->flags & (BF_SHUTW|BF_SHUTW_NOW)))
Willy Tarreau610ecce2010-01-04 21:15:02 +01003596 buffer_shutw_now(buf);
Willy Tarreaucce7fa42010-01-16 23:19:39 +01003597 }
3598 else if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO) {
3599 /* Option forceclose is set, or either side wants to close,
3600 * let's enforce it now that we're not expecting any new
3601 * data to come. The caller knows the session is complete
3602 * once both states are CLOSED.
3603 */
3604 if (!(buf->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01003605 buffer_shutr_now(buf);
3606 buffer_shutw_now(buf);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003607 }
Willy Tarreaucce7fa42010-01-16 23:19:39 +01003608 }
3609 else {
3610 /* The last possible modes are keep-alive and tunnel. Since tunnel
3611 * mode does not set the body analyser, we can't reach this place
3612 * in tunnel mode, so we're left with keep-alive only.
3613 * This mode is currently not implemented, we switch to tunnel mode.
3614 */
3615 buffer_auto_read(buf);
3616 txn->req.msg_state = HTTP_MSG_TUNNEL;
Willy Tarreau610ecce2010-01-04 21:15:02 +01003617 }
3618
3619 if (buf->flags & (BF_SHUTW|BF_SHUTW_NOW)) {
3620 /* if we've just closed an output, let's switch */
Willy Tarreaucce7fa42010-01-16 23:19:39 +01003621 buf->cons->flags |= SI_FL_NOLINGER; /* we want to close ASAP */
3622
Willy Tarreau610ecce2010-01-04 21:15:02 +01003623 if (!(buf->flags & BF_OUT_EMPTY)) {
3624 txn->req.msg_state = HTTP_MSG_CLOSING;
3625 goto http_msg_closing;
3626 }
3627 else {
3628 txn->req.msg_state = HTTP_MSG_CLOSED;
3629 goto http_msg_closed;
3630 }
3631 }
Willy Tarreaucce7fa42010-01-16 23:19:39 +01003632 goto wait_other_side;
Willy Tarreau610ecce2010-01-04 21:15:02 +01003633 }
3634
3635 if (txn->req.msg_state == HTTP_MSG_CLOSING) {
3636 http_msg_closing:
3637 /* nothing else to forward, just waiting for the output buffer
3638 * to be empty and for the shutw_now to take effect.
3639 */
3640 if (buf->flags & BF_OUT_EMPTY) {
3641 txn->req.msg_state = HTTP_MSG_CLOSED;
3642 goto http_msg_closed;
3643 }
3644 else if (buf->flags & BF_SHUTW) {
3645 txn->req.msg_state = HTTP_MSG_ERROR;
3646 goto wait_other_side;
3647 }
3648 }
3649
3650 if (txn->req.msg_state == HTTP_MSG_CLOSED) {
3651 http_msg_closed:
3652 goto wait_other_side;
3653 }
3654
3655 wait_other_side:
3656 http_silent_debug(__LINE__, s);
3657 return txn->req.msg_state != old_state || buf->flags != old_flags;
3658}
3659
3660
3661/* This function updates the response state machine according to the request
3662 * state machine and buffer flags. It returns 1 if it changes anything (flag
3663 * or state), otherwise zero. It ignores any state before HTTP_MSG_DONE, as
3664 * it is only used to find when a request/response couple is complete. Both
3665 * this function and its equivalent should loop until both return zero. It
3666 * can set its own state to DONE, CLOSING, CLOSED, TUNNEL, ERROR.
3667 */
3668int http_sync_res_state(struct session *s)
3669{
3670 struct buffer *buf = s->rep;
3671 struct http_txn *txn = &s->txn;
3672 unsigned int old_flags = buf->flags;
3673 unsigned int old_state = txn->rsp.msg_state;
3674
3675 http_silent_debug(__LINE__, s);
3676 if (unlikely(txn->rsp.msg_state < HTTP_MSG_BODY))
3677 return 0;
3678
3679 if (txn->rsp.msg_state == HTTP_MSG_DONE) {
3680 /* In theory, we don't need to read anymore, but we must
Willy Tarreau90deb182010-01-07 00:20:41 +01003681 * still monitor the server connection for a possible close
3682 * while the request is being uploaded, so we don't disable
3683 * reading.
Willy Tarreau610ecce2010-01-04 21:15:02 +01003684 */
Willy Tarreau90deb182010-01-07 00:20:41 +01003685 /* buffer_dont_read(buf); */
Willy Tarreau610ecce2010-01-04 21:15:02 +01003686
3687 if (txn->req.msg_state == HTTP_MSG_ERROR)
3688 goto wait_other_side;
3689
3690 if (txn->req.msg_state < HTTP_MSG_DONE) {
3691 /* The client seems to still be sending data, probably
3692 * because we got an error response during an upload.
3693 * We have the choice of either breaking the connection
3694 * or letting it pass through. Let's do the later.
3695 */
3696 goto wait_other_side;
3697 }
3698
3699 if (txn->req.msg_state == HTTP_MSG_TUNNEL) {
3700 /* if any side switches to tunnel mode, the other one does too */
Willy Tarreau90deb182010-01-07 00:20:41 +01003701 buffer_auto_read(buf);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003702 txn->rsp.msg_state = HTTP_MSG_TUNNEL;
3703 goto wait_other_side;
3704 }
3705
3706 /* When we get here, it means that both the request and the
3707 * response have finished receiving. Depending on the connection
3708 * mode, we'll have to wait for the last bytes to leave in either
3709 * direction, and sometimes for a close to be effective.
3710 */
3711
3712 if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) {
3713 /* Server-close mode : shut read and wait for the request
3714 * side to close its output buffer. The caller will detect
3715 * when we're in DONE and the other is in CLOSED and will
3716 * catch that for the final cleanup.
3717 */
3718 if (!(buf->flags & (BF_SHUTR|BF_SHUTR_NOW)))
3719 buffer_shutr_now(buf);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003720 }
Willy Tarreaucce7fa42010-01-16 23:19:39 +01003721 else if ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO) {
3722 /* Option forceclose is set, or either side wants to close,
3723 * let's enforce it now that we're not expecting any new
3724 * data to come. The caller knows the session is complete
3725 * once both states are CLOSED.
Willy Tarreau610ecce2010-01-04 21:15:02 +01003726 */
Willy Tarreaucce7fa42010-01-16 23:19:39 +01003727 if (!(buf->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
3728 buffer_shutr_now(buf);
3729 buffer_shutw_now(buf);
3730 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01003731 }
3732 else {
Willy Tarreaucce7fa42010-01-16 23:19:39 +01003733 /* The last possible modes are keep-alive and tunnel. Since tunnel
3734 * mode does not set the body analyser, we can't reach this place
3735 * in tunnel mode, so we're left with keep-alive only.
3736 * This mode is currently not implemented, we switch to tunnel mode.
Willy Tarreau610ecce2010-01-04 21:15:02 +01003737 */
Willy Tarreau90deb182010-01-07 00:20:41 +01003738 buffer_auto_read(buf);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003739 txn->rsp.msg_state = HTTP_MSG_TUNNEL;
Willy Tarreau610ecce2010-01-04 21:15:02 +01003740 }
3741
3742 if (buf->flags & (BF_SHUTW|BF_SHUTW_NOW)) {
3743 /* if we've just closed an output, let's switch */
3744 if (!(buf->flags & BF_OUT_EMPTY)) {
3745 txn->rsp.msg_state = HTTP_MSG_CLOSING;
3746 goto http_msg_closing;
3747 }
3748 else {
3749 txn->rsp.msg_state = HTTP_MSG_CLOSED;
3750 goto http_msg_closed;
3751 }
3752 }
3753 goto wait_other_side;
3754 }
3755
3756 if (txn->rsp.msg_state == HTTP_MSG_CLOSING) {
3757 http_msg_closing:
3758 /* nothing else to forward, just waiting for the output buffer
3759 * to be empty and for the shutw_now to take effect.
3760 */
3761 if (buf->flags & BF_OUT_EMPTY) {
3762 txn->rsp.msg_state = HTTP_MSG_CLOSED;
3763 goto http_msg_closed;
3764 }
3765 else if (buf->flags & BF_SHUTW) {
3766 txn->rsp.msg_state = HTTP_MSG_ERROR;
3767 goto wait_other_side;
3768 }
3769 }
3770
3771 if (txn->rsp.msg_state == HTTP_MSG_CLOSED) {
3772 http_msg_closed:
3773 /* drop any pending data */
3774 buffer_ignore(buf, buf->l - buf->send_max);
3775 buffer_auto_close(buf);
Willy Tarreau90deb182010-01-07 00:20:41 +01003776 buffer_auto_read(buf);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003777 goto wait_other_side;
3778 }
3779
3780 wait_other_side:
3781 http_silent_debug(__LINE__, s);
3782 return txn->rsp.msg_state != old_state || buf->flags != old_flags;
3783}
3784
3785
3786/* Resync the request and response state machines. Return 1 if either state
3787 * changes.
3788 */
3789int http_resync_states(struct session *s)
3790{
3791 struct http_txn *txn = &s->txn;
3792 int old_req_state = txn->req.msg_state;
3793 int old_res_state = txn->rsp.msg_state;
3794
3795 http_silent_debug(__LINE__, s);
3796 http_sync_req_state(s);
3797 while (1) {
Willy Tarreau90deb182010-01-07 00:20:41 +01003798 http_silent_debug(__LINE__, s);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003799 if (!http_sync_res_state(s))
3800 break;
Willy Tarreau90deb182010-01-07 00:20:41 +01003801 http_silent_debug(__LINE__, s);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003802 if (!http_sync_req_state(s))
3803 break;
3804 }
3805 http_silent_debug(__LINE__, s);
3806 /* OK, both state machines agree on a compatible state.
3807 * There are a few cases we're interested in :
3808 * - HTTP_MSG_TUNNEL on either means we have to disable both analysers
3809 * - HTTP_MSG_CLOSED on both sides means we've reached the end in both
3810 * directions, so let's simply disable both analysers.
3811 * - HTTP_MSG_CLOSED on the response only means we must abort the
3812 * request.
3813 * - HTTP_MSG_CLOSED on the request and HTTP_MSG_DONE on the response
3814 * with server-close mode means we've completed one request and we
3815 * must re-initialize the server connection.
3816 */
3817
3818 if (txn->req.msg_state == HTTP_MSG_TUNNEL ||
3819 txn->rsp.msg_state == HTTP_MSG_TUNNEL ||
3820 (txn->req.msg_state == HTTP_MSG_CLOSED &&
3821 txn->rsp.msg_state == HTTP_MSG_CLOSED)) {
3822 s->req->analysers = 0;
Willy Tarreau2fa144c2010-01-04 23:13:26 +01003823 buffer_auto_close(s->req);
Willy Tarreau90deb182010-01-07 00:20:41 +01003824 buffer_auto_read(s->req);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003825 s->rep->analysers = 0;
Willy Tarreau2fa144c2010-01-04 23:13:26 +01003826 buffer_auto_close(s->rep);
Willy Tarreau90deb182010-01-07 00:20:41 +01003827 buffer_auto_read(s->rep);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003828 }
Willy Tarreau2fa144c2010-01-04 23:13:26 +01003829 else if (txn->rsp.msg_state == HTTP_MSG_CLOSED ||
3830 txn->rsp.msg_state == HTTP_MSG_ERROR ||
3831 (s->rep->flags & BF_SHUTW)) {
Willy Tarreau90deb182010-01-07 00:20:41 +01003832 s->rep->analysers = 0;
3833 buffer_auto_close(s->rep);
3834 buffer_auto_read(s->rep);
3835 s->req->analysers = 0;
Willy Tarreau610ecce2010-01-04 21:15:02 +01003836 buffer_abort(s->req);
3837 buffer_auto_close(s->req);
Willy Tarreau90deb182010-01-07 00:20:41 +01003838 buffer_auto_read(s->req);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003839 buffer_ignore(s->req, s->req->l - s->req->send_max);
Willy Tarreau610ecce2010-01-04 21:15:02 +01003840 }
3841 else if (txn->req.msg_state == HTTP_MSG_CLOSED &&
3842 txn->rsp.msg_state == HTTP_MSG_DONE &&
3843 ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL)) {
3844 /* server-close: terminate this server connection and
3845 * reinitialize a fresh-new transaction.
3846 */
3847 http_end_txn_clean_session(s);
3848 }
3849
3850 http_silent_debug(__LINE__, s);
3851 return txn->req.msg_state != old_req_state ||
3852 txn->rsp.msg_state != old_res_state;
3853}
3854
Willy Tarreaud98cf932009-12-27 22:54:55 +01003855/* This function is an analyser which forwards request body (including chunk
3856 * sizes if any). It is called as soon as we must forward, even if we forward
3857 * zero byte. The only situation where it must not be called is when we're in
3858 * tunnel mode and we want to forward till the close. It's used both to forward
3859 * remaining data and to resync after end of body. It expects the msg_state to
3860 * be between MSG_BODY and MSG_DONE (inclusive). It returns zero if it needs to
3861 * read more data, or 1 once we can go on with next request or end the session.
3862 * When in MSG_DATA or MSG_TRAILERS, it will automatically forward hdr_content_len
3863 * bytes of pending data + the headers if not already done (between som and sov).
3864 * It eventually adjusts som to match sov after the data in between have been sent.
3865 */
3866int http_request_forward_body(struct session *s, struct buffer *req, int an_bit)
3867{
3868 struct http_txn *txn = &s->txn;
3869 struct http_msg *msg = &s->txn.req;
3870
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01003871 if (unlikely(msg->msg_state < HTTP_MSG_BODY))
3872 return 0;
3873
Willy Tarreau6c2cbe12010-01-03 17:07:49 +01003874 if ((req->flags & (BF_READ_ERROR|BF_READ_TIMEOUT|BF_WRITE_ERROR|BF_WRITE_TIMEOUT)) ||
3875 ((req->flags & BF_SHUTW) && (req->to_forward || req->send_max))) {
3876 /* Output closed while we were sending data. We must abort. */
3877 buffer_ignore(req, req->l - req->send_max);
Willy Tarreau90deb182010-01-07 00:20:41 +01003878 buffer_auto_read(req);
3879 buffer_auto_close(req);
Willy Tarreau082b01c2010-01-02 23:58:04 +01003880 req->analysers &= ~an_bit;
3881 return 1;
3882 }
3883
Willy Tarreaud3347ee2010-01-04 02:02:25 +01003884 buffer_dont_close(req);
Willy Tarreaud98cf932009-12-27 22:54:55 +01003885
3886 /* Note that we don't have to send 100-continue back because we don't
3887 * need the data to complete our job, and it's up to the server to
3888 * decide whether to return 100, 417 or anything else in return of
3889 * an "Expect: 100-continue" header.
3890 */
3891
3892 if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) {
3893 /* we have msg->col and msg->sov which both point to the first
3894 * byte of message body. msg->som still points to the beginning
3895 * of the message. We must save the body in req->lr because it
3896 * survives buffer re-alignments.
3897 */
3898 req->lr = req->data + msg->sov;
3899 if (txn->flags & TX_REQ_TE_CHNK)
3900 msg->msg_state = HTTP_MSG_CHUNK_SIZE;
3901 else {
3902 msg->msg_state = HTTP_MSG_DATA;
3903 }
3904 }
3905
Willy Tarreaud98cf932009-12-27 22:54:55 +01003906 while (1) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01003907 http_silent_debug(__LINE__, s);
Willy Tarreau638cd022010-01-03 07:42:04 +01003908 /* we may have some data pending */
3909 if (msg->hdr_content_len || msg->som != msg->sov) {
3910 int bytes = msg->sov - msg->som;
3911 if (bytes < 0) /* sov may have wrapped at the end */
3912 bytes += req->size;
3913 buffer_forward(req, bytes + msg->hdr_content_len);
3914 msg->hdr_content_len = 0; /* don't forward that again */
3915 msg->som = msg->sov;
3916 }
Willy Tarreau5523b322009-12-29 12:05:52 +01003917
Willy Tarreaucaabe412010-01-03 23:08:28 +01003918 if (msg->msg_state == HTTP_MSG_DATA) {
3919 /* must still forward */
3920 if (req->to_forward)
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01003921 goto missing_data;
Willy Tarreaucaabe412010-01-03 23:08:28 +01003922
3923 /* nothing left to forward */
3924 if (txn->flags & TX_REQ_TE_CHNK)
3925 msg->msg_state = HTTP_MSG_DATA_CRLF;
Willy Tarreau610ecce2010-01-04 21:15:02 +01003926 else
Willy Tarreaucaabe412010-01-03 23:08:28 +01003927 msg->msg_state = HTTP_MSG_DONE;
Willy Tarreaucaabe412010-01-03 23:08:28 +01003928 }
3929 else if (msg->msg_state == HTTP_MSG_CHUNK_SIZE) {
Willy Tarreaud98cf932009-12-27 22:54:55 +01003930 /* read the chunk size and assign it to ->hdr_content_len, then
3931 * set ->sov and ->lr to point to the body and switch to DATA or
3932 * TRAILERS state.
3933 */
3934 int ret = http_parse_chunk_size(req, msg);
3935
3936 if (!ret)
3937 goto missing_data;
3938 else if (ret < 0)
3939 goto return_bad_req;
3940 /* otherwise we're in HTTP_MSG_DATA or HTTP_MSG_TRAILERS state */
Willy Tarreaud98cf932009-12-27 22:54:55 +01003941 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01003942 else if (msg->msg_state == HTTP_MSG_DATA_CRLF) {
3943 /* we want the CRLF after the data */
3944 int ret;
3945
Willy Tarreaud3347ee2010-01-04 02:02:25 +01003946 req->lr = req->w + req->send_max;
3947 if (req->lr >= req->data + req->size)
3948 req->lr -= req->size;
3949
Willy Tarreaud98cf932009-12-27 22:54:55 +01003950 ret = http_skip_chunk_crlf(req, msg);
3951
3952 if (ret == 0)
3953 goto missing_data;
3954 else if (ret < 0)
3955 goto return_bad_req;
3956 /* we're in MSG_CHUNK_SIZE now */
3957 }
3958 else if (msg->msg_state == HTTP_MSG_TRAILERS) {
3959 int ret = http_forward_trailers(req, msg);
3960
3961 if (ret == 0)
3962 goto missing_data;
3963 else if (ret < 0)
3964 goto return_bad_req;
3965 /* we're in HTTP_MSG_DONE now */
3966 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01003967 else {
3968 /* other states, DONE...TUNNEL */
3969 if (http_resync_states(s)) {
3970 /* some state changes occurred, maybe the analyser
3971 * was disabled too.
Willy Tarreauface8392010-01-03 11:37:54 +01003972 */
Willy Tarreau610ecce2010-01-04 21:15:02 +01003973 if (unlikely(msg->msg_state == HTTP_MSG_ERROR))
3974 goto return_bad_req;
3975 return 1;
Willy Tarreaub608feb2010-01-02 22:47:18 +01003976 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01003977 return 0;
Willy Tarreaud98cf932009-12-27 22:54:55 +01003978 }
3979 }
3980
Willy Tarreaud98cf932009-12-27 22:54:55 +01003981 missing_data:
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01003982 /* stop waiting for data if the input is closed before the end */
3983 if (req->flags & BF_SHUTR)
3984 goto return_bad_req;
3985
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01003986 /* waiting for the last bits to leave the buffer */
3987 if (req->flags & BF_SHUTW)
3988 goto return_bad_req;
Willy Tarreau610ecce2010-01-04 21:15:02 +01003989
3990 http_silent_debug(__LINE__, s);
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01003991 return 0;
3992
Willy Tarreaud98cf932009-12-27 22:54:55 +01003993 return_bad_req: /* let's centralize all bad requests */
3994 txn->req.msg_state = HTTP_MSG_ERROR;
3995 txn->status = 400;
3996 /* Note: we don't send any error if some data were already sent */
Willy Tarreau148d0992010-01-10 10:21:21 +01003997 stream_int_retnclose(req->prod, (txn->rsp.msg_state < HTTP_MSG_BODY) ? error_message(s, HTTP_ERR_400) : NULL);
Willy Tarreaud98cf932009-12-27 22:54:55 +01003998 req->analysers = 0;
3999 s->fe->counters.failed_req++;
4000 if (s->listener->counters)
4001 s->listener->counters->failed_req++;
4002
4003 if (!(s->flags & SN_ERR_MASK))
4004 s->flags |= SN_ERR_PRXCOND;
4005 if (!(s->flags & SN_FINST_MASK))
4006 s->flags |= SN_FINST_R;
Willy Tarreau610ecce2010-01-04 21:15:02 +01004007 http_silent_debug(__LINE__, s);
Willy Tarreaud98cf932009-12-27 22:54:55 +01004008 return 0;
4009}
4010
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004011/* This stream analyser waits for a complete HTTP response. It returns 1 if the
4012 * processing can continue on next analysers, or zero if it either needs more
4013 * data or wants to immediately abort the response (eg: timeout, error, ...). It
4014 * is tied to AN_RES_WAIT_HTTP and may may remove itself from s->rep->analysers
4015 * when it has nothing left to do, and may remove any analyser when it wants to
4016 * abort.
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02004017 */
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004018int http_wait_for_response(struct session *s, struct buffer *rep, int an_bit)
Willy Tarreauc65a3ba2008-08-11 23:42:50 +02004019{
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004020 struct http_txn *txn = &s->txn;
4021 struct http_msg *msg = &txn->rsp;
Willy Tarreaub8c82c22009-10-18 23:45:12 +02004022 struct hdr_ctx ctx;
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004023 int use_close_only;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004024 int cur_idx;
Krzysztof Piotr Oledzki5fb18822009-10-13 21:14:09 +02004025 int n;
Willy Tarreauadfb8562008-08-11 15:24:42 +02004026
Willy Tarreau3a16b2c2008-08-28 08:54:27 +02004027 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
Willy Tarreaufa7e1022008-10-19 07:30:41 +02004028 now_ms, __FUNCTION__,
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004029 s,
Willy Tarreau3a16b2c2008-08-28 08:54:27 +02004030 rep,
4031 rep->rex, rep->wex,
4032 rep->flags,
4033 rep->l,
4034 rep->analysers);
Willy Tarreau67f0eea2008-08-10 22:55:22 +02004035
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004036 /*
4037 * Now parse the partial (or complete) lines.
4038 * We will check the response syntax, and also join multi-line
4039 * headers. An index of all the lines will be elaborated while
4040 * parsing.
4041 *
4042 * For the parsing, we use a 28 states FSM.
4043 *
4044 * Here is the information we currently have :
Willy Tarreau83e3af02009-12-28 17:39:57 +01004045 * rep->data + msg->som = beginning of response
4046 * rep->data + msg->eoh = end of processed headers / start of current one
4047 * msg->eol = end of current header or line (LF or CRLF)
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004048 * rep->lr = first non-visited byte
4049 * rep->r = end of data
Willy Tarreau962c3f42010-01-10 00:15:35 +01004050 * Once we reach MSG_BODY, rep->sol = rep->data + msg->som
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004051 */
4052
Willy Tarreau83e3af02009-12-28 17:39:57 +01004053 /* There's a protected area at the end of the buffer for rewriting
4054 * purposes. We don't want to start to parse the request if the
4055 * protected area is affected, because we may have to move processed
4056 * data later, which is much more complicated.
4057 */
Willy Tarreau2ab6eb12010-01-02 22:04:45 +01004058 if (rep->l && msg->msg_state < HTTP_MSG_ERROR) {
4059 if (unlikely((rep->flags & BF_FULL) ||
4060 rep->r < rep->lr ||
4061 rep->r > rep->data + rep->size - global.tune.maxrewrite)) {
4062 if (rep->send_max) {
4063 /* some data has still not left the buffer, wake us once that's done */
4064 buffer_dont_close(rep);
4065 rep->flags |= BF_READ_DONTWAIT; /* try to get back here ASAP */
4066 return 0;
4067 }
4068 if (rep->l <= rep->size - global.tune.maxrewrite)
4069 http_buffer_heavy_realign(rep, msg);
Willy Tarreau83e3af02009-12-28 17:39:57 +01004070 }
4071
Willy Tarreau2ab6eb12010-01-02 22:04:45 +01004072 if (likely(rep->lr < rep->r))
4073 http_msg_analyzer(rep, msg, &txn->hdr_idx);
Willy Tarreau83e3af02009-12-28 17:39:57 +01004074 }
4075
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004076 /* 1: we might have to print this header in debug mode */
4077 if (unlikely((global.mode & MODE_DEBUG) &&
4078 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
Willy Tarreau655dce92009-11-08 13:10:58 +01004079 (msg->msg_state >= HTTP_MSG_BODY || msg->msg_state == HTTP_MSG_ERROR))) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004080 char *eol, *sol;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004081
Willy Tarreau962c3f42010-01-10 00:15:35 +01004082 sol = msg->sol;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004083 eol = sol + msg->sl.rq.l;
4084 debug_hdr("srvrep", s, sol, eol);
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004085
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004086 sol += hdr_idx_first_pos(&txn->hdr_idx);
4087 cur_idx = hdr_idx_first_idx(&txn->hdr_idx);
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004088
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004089 while (cur_idx) {
4090 eol = sol + txn->hdr_idx.v[cur_idx].len;
4091 debug_hdr("srvhdr", s, sol, eol);
4092 sol = eol + txn->hdr_idx.v[cur_idx].cr + 1;
4093 cur_idx = txn->hdr_idx.v[cur_idx].next;
4094 }
4095 }
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004096
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004097 /*
4098 * Now we quickly check if we have found a full valid response.
4099 * If not so, we check the FD and buffer states before leaving.
4100 * A full response is indicated by the fact that we have seen
Willy Tarreau655dce92009-11-08 13:10:58 +01004101 * the double LF/CRLF, so the state is >= HTTP_MSG_BODY. Invalid
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004102 * responses are checked first.
4103 *
4104 * Depending on whether the client is still there or not, we
4105 * may send an error response back or not. Note that normally
4106 * we should only check for HTTP status there, and check I/O
4107 * errors somewhere else.
4108 */
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004109
Willy Tarreau655dce92009-11-08 13:10:58 +01004110 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004111 /* Invalid response */
4112 if (unlikely(msg->msg_state == HTTP_MSG_ERROR)) {
4113 /* we detected a parsing error. We want to archive this response
4114 * in the dedicated proxy area for later troubleshooting.
4115 */
4116 hdr_response_bad:
4117 if (msg->msg_state == HTTP_MSG_ERROR || msg->err_pos >= 0)
4118 http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, s->fe);
4119
4120 s->be->counters.failed_resp++;
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01004121 if (s->srv) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004122 s->srv->counters.failed_resp++;
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01004123 health_adjust(s->srv, HANA_STATUS_HTTP_HDRRSP);
4124 }
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004125
Willy Tarreau90deb182010-01-07 00:20:41 +01004126 buffer_auto_close(rep);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004127 rep->analysers = 0;
4128 txn->status = 502;
Willy Tarreauc88ea682009-12-29 14:56:36 +01004129 rep->prod->flags |= SI_FL_NOLINGER;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004130 stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_502));
4131
4132 if (!(s->flags & SN_ERR_MASK))
4133 s->flags |= SN_ERR_PRXCOND;
4134 if (!(s->flags & SN_FINST_MASK))
4135 s->flags |= SN_FINST_H;
4136
4137 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02004138 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02004139
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004140 /* too large response does not fit in buffer. */
4141 else if (rep->flags & BF_FULL) {
4142 goto hdr_response_bad;
4143 }
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004144
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004145 /* read error */
4146 else if (rep->flags & BF_READ_ERROR) {
4147 if (msg->err_pos >= 0)
4148 http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, s->fe);
Willy Tarreau4076a152009-04-02 15:18:36 +02004149
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004150 s->be->counters.failed_resp++;
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01004151 if (s->srv) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004152 s->srv->counters.failed_resp++;
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01004153 health_adjust(s->srv, HANA_STATUS_HTTP_READ_ERROR);
4154 }
Willy Tarreau461f6622008-08-15 23:43:19 +02004155
Willy Tarreau90deb182010-01-07 00:20:41 +01004156 buffer_auto_close(rep);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004157 rep->analysers = 0;
4158 txn->status = 502;
Willy Tarreauc88ea682009-12-29 14:56:36 +01004159 rep->prod->flags |= SI_FL_NOLINGER;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004160 stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_502));
Willy Tarreau816b9792009-09-15 21:25:21 +02004161
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004162 if (!(s->flags & SN_ERR_MASK))
4163 s->flags |= SN_ERR_SRVCL;
4164 if (!(s->flags & SN_FINST_MASK))
4165 s->flags |= SN_FINST_H;
Willy Tarreaucebf57e2008-08-15 18:16:37 +02004166 return 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004167 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02004168
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004169 /* read timeout : return a 504 to the client. */
4170 else if (rep->flags & BF_READ_TIMEOUT) {
4171 if (msg->err_pos >= 0)
4172 http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, s->fe);
Willy Tarreau21d2af32008-02-14 20:25:24 +01004173
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004174 s->be->counters.failed_resp++;
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01004175 if (s->srv) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004176 s->srv->counters.failed_resp++;
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01004177 health_adjust(s->srv, HANA_STATUS_HTTP_READ_TIMEOUT);
4178 }
Willy Tarreau21d2af32008-02-14 20:25:24 +01004179
Willy Tarreau90deb182010-01-07 00:20:41 +01004180 buffer_auto_close(rep);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004181 rep->analysers = 0;
4182 txn->status = 504;
Willy Tarreauc88ea682009-12-29 14:56:36 +01004183 rep->prod->flags |= SI_FL_NOLINGER;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004184 stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_504));
Willy Tarreau4076a152009-04-02 15:18:36 +02004185
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004186 if (!(s->flags & SN_ERR_MASK))
4187 s->flags |= SN_ERR_SRVTO;
4188 if (!(s->flags & SN_FINST_MASK))
4189 s->flags |= SN_FINST_H;
4190 return 0;
4191 }
Willy Tarreaua7c52762008-08-16 18:40:18 +02004192
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004193 /* close from server */
4194 else if (rep->flags & BF_SHUTR) {
4195 if (msg->err_pos >= 0)
4196 http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, s->fe);
Willy Tarreau21d2af32008-02-14 20:25:24 +01004197
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004198 s->be->counters.failed_resp++;
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01004199 if (s->srv) {
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004200 s->srv->counters.failed_resp++;
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01004201 health_adjust(s->srv, HANA_STATUS_HTTP_BROKEN_PIPE);
4202 }
Willy Tarreau21d2af32008-02-14 20:25:24 +01004203
Willy Tarreau90deb182010-01-07 00:20:41 +01004204 buffer_auto_close(rep);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004205 rep->analysers = 0;
4206 txn->status = 502;
Willy Tarreauc88ea682009-12-29 14:56:36 +01004207 rep->prod->flags |= SI_FL_NOLINGER;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004208 stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_502));
Willy Tarreau21d2af32008-02-14 20:25:24 +01004209
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004210 if (!(s->flags & SN_ERR_MASK))
4211 s->flags |= SN_ERR_SRVCL;
4212 if (!(s->flags & SN_FINST_MASK))
4213 s->flags |= SN_FINST_H;
4214 return 0;
4215 }
Krzysztof Piotr Oledzki5fb18822009-10-13 21:14:09 +02004216
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004217 /* write error to client (we don't send any message then) */
4218 else if (rep->flags & BF_WRITE_ERROR) {
4219 if (msg->err_pos >= 0)
4220 http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, s->fe);
Krzysztof Piotr Oledzki5fb18822009-10-13 21:14:09 +02004221
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004222 s->be->counters.failed_resp++;
4223 rep->analysers = 0;
Willy Tarreau90deb182010-01-07 00:20:41 +01004224 buffer_auto_close(rep);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004225
4226 if (!(s->flags & SN_ERR_MASK))
4227 s->flags |= SN_ERR_CLICL;
4228 if (!(s->flags & SN_FINST_MASK))
4229 s->flags |= SN_FINST_H;
4230
4231 /* process_session() will take care of the error */
4232 return 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004233 }
Willy Tarreau21d2af32008-02-14 20:25:24 +01004234
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004235 buffer_dont_close(rep);
4236 return 0;
4237 }
4238
4239 /* More interesting part now : we know that we have a complete
4240 * response which at least looks like HTTP. We have an indicator
4241 * of each header's length, so we can parse them quickly.
4242 */
4243
4244 if (unlikely(msg->err_pos >= 0))
4245 http_capture_bad_message(&s->be->invalid_rep, s, rep, msg, s->fe);
4246
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004247 /*
4248 * 1: get the status code
4249 */
Willy Tarreau962c3f42010-01-10 00:15:35 +01004250 n = msg->sol[msg->sl.st.c] - '0';
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004251 if (n < 1 || n > 5)
4252 n = 0;
4253 s->srv->counters.p.http.rsp[n]++;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004254
Willy Tarreau5b154472009-12-21 20:11:07 +01004255 /* check if the response is HTTP/1.1 or above */
4256 if ((msg->sl.st.v_l == 8) &&
Willy Tarreau962c3f42010-01-10 00:15:35 +01004257 ((msg->sol[5] > '1') ||
4258 ((msg->sol[5] == '1') &&
4259 (msg->sol[7] >= '1'))))
Willy Tarreau5b154472009-12-21 20:11:07 +01004260 txn->flags |= TX_RES_VER_11;
4261
4262 /* "connection" has not been parsed yet */
Willy Tarreaubbf0b372010-01-18 16:54:40 +01004263 txn->flags &= ~(TX_HDR_CONN_PRS | TX_HDR_CONN_CLO | TX_HDR_CONN_KAL);
Willy Tarreau5b154472009-12-21 20:11:07 +01004264
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004265 /* transfer length unknown*/
4266 txn->flags &= ~TX_RES_XFER_LEN;
4267
Willy Tarreau962c3f42010-01-10 00:15:35 +01004268 txn->status = strl2ui(msg->sol + msg->sl.st.c, msg->sl.st.c_l);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004269
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01004270 if (txn->status >= 100 && txn->status < 500)
4271 health_adjust(s->srv, HANA_STATUS_HTTP_OK);
4272 else
4273 health_adjust(s->srv, HANA_STATUS_HTTP_STS);
4274
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004275 /*
4276 * 2: check for cacheability.
4277 */
4278
4279 switch (txn->status) {
4280 case 200:
4281 case 203:
4282 case 206:
4283 case 300:
4284 case 301:
4285 case 410:
4286 /* RFC2616 @13.4:
4287 * "A response received with a status code of
4288 * 200, 203, 206, 300, 301 or 410 MAY be stored
4289 * by a cache (...) unless a cache-control
4290 * directive prohibits caching."
4291 *
4292 * RFC2616 @9.5: POST method :
4293 * "Responses to this method are not cacheable,
4294 * unless the response includes appropriate
4295 * Cache-Control or Expires header fields."
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004296 */
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004297 if (likely(txn->meth != HTTP_METH_POST) &&
4298 (s->be->options & (PR_O_CHK_CACHE|PR_O_COOK_NOC)))
4299 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
4300 break;
4301 default:
4302 break;
4303 }
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004304
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004305 /*
4306 * 3: we may need to capture headers
4307 */
4308 s->logs.logwait &= ~LW_RESP;
4309 if (unlikely((s->logs.logwait & LW_RSPHDR) && s->fe->rsp_cap))
Willy Tarreau962c3f42010-01-10 00:15:35 +01004310 capture_headers(msg->sol, &txn->hdr_idx,
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004311 txn->rsp.cap, s->fe->rsp_cap);
4312
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004313 /* 4: determine the transfer-length.
4314 * According to RFC2616 #4.4, amended by the HTTPbis working group,
4315 * the presence of a message-body in a RESPONSE and its transfer length
4316 * must be determined that way :
Willy Tarreaub8c82c22009-10-18 23:45:12 +02004317 *
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004318 * All responses to the HEAD request method MUST NOT include a
4319 * message-body, even though the presence of entity-header fields
4320 * might lead one to believe they do. All 1xx (informational), 204
4321 * (No Content), and 304 (Not Modified) responses MUST NOT include a
4322 * message-body. All other responses do include a message-body,
4323 * although it MAY be of zero length.
Willy Tarreaub8c82c22009-10-18 23:45:12 +02004324 *
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004325 * 1. Any response which "MUST NOT" include a message-body (such as the
4326 * 1xx, 204 and 304 responses and any response to a HEAD request) is
4327 * always terminated by the first empty line after the header fields,
4328 * regardless of the entity-header fields present in the message.
4329 *
4330 * 2. If a Transfer-Encoding header field (Section 9.7) is present and
4331 * the "chunked" transfer-coding (Section 6.2) is used, the
4332 * transfer-length is defined by the use of this transfer-coding.
4333 * If a Transfer-Encoding header field is present and the "chunked"
4334 * transfer-coding is not present, the transfer-length is defined by
4335 * the sender closing the connection.
4336 *
4337 * 3. If a Content-Length header field is present, its decimal value in
4338 * OCTETs represents both the entity-length and the transfer-length.
4339 * If a message is received with both a Transfer-Encoding header
4340 * field and a Content-Length header field, the latter MUST be ignored.
4341 *
4342 * 4. If the message uses the media type "multipart/byteranges", and
4343 * the transfer-length is not otherwise specified, then this self-
4344 * delimiting media type defines the transfer-length. This media
4345 * type MUST NOT be used unless the sender knows that the recipient
4346 * can parse it; the presence in a request of a Range header with
4347 * multiple byte-range specifiers from a 1.1 client implies that the
4348 * client can parse multipart/byteranges responses.
4349 *
4350 * 5. By the server closing the connection.
Willy Tarreaub8c82c22009-10-18 23:45:12 +02004351 */
4352
4353 /* Skip parsing if no content length is possible. The response flags
4354 * remain 0 as well as the hdr_content_len, which may or may not mirror
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004355 * the real header value, and we note that we know the response's length.
Willy Tarreaub8c82c22009-10-18 23:45:12 +02004356 * FIXME: should we parse anyway and return an error on chunked encoding ?
4357 */
4358 if (txn->meth == HTTP_METH_HEAD ||
4359 (txn->status >= 100 && txn->status < 200) ||
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004360 txn->status == 204 || txn->status == 304) {
4361 txn->flags |= TX_RES_XFER_LEN;
4362 goto skip_content_length;
4363 }
4364
4365 if (txn->meth == HTTP_METH_CONNECT)
Willy Tarreaub8c82c22009-10-18 23:45:12 +02004366 goto skip_content_length;
4367
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004368 use_close_only = 0;
Willy Tarreaub8c82c22009-10-18 23:45:12 +02004369 ctx.idx = 0;
Willy Tarreau9e13c3c2009-12-22 09:59:58 +01004370 while ((txn->flags & TX_RES_VER_11) &&
4371 http_find_header2("Transfer-Encoding", 17, msg->sol, &txn->hdr_idx, &ctx)) {
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004372 if (ctx.vlen == 7 && strncasecmp(ctx.line + ctx.val, "chunked", 7) == 0)
4373 txn->flags |= (TX_RES_TE_CHNK | TX_RES_XFER_LEN);
4374 else if (txn->flags & TX_RES_TE_CHNK) {
4375 /* bad transfer-encoding (chunked followed by something else) */
4376 use_close_only = 1;
4377 txn->flags &= ~(TX_RES_TE_CHNK | TX_RES_XFER_LEN);
4378 break;
4379 }
Willy Tarreaub8c82c22009-10-18 23:45:12 +02004380 }
4381
4382 /* FIXME: below we should remove the content-length header(s) in case of chunked encoding */
4383 ctx.idx = 0;
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004384 while (!(txn->flags & TX_RES_TE_CHNK) && !use_close_only &&
Willy Tarreaub8c82c22009-10-18 23:45:12 +02004385 http_find_header2("Content-Length", 14, msg->sol, &txn->hdr_idx, &ctx)) {
4386 signed long long cl;
4387
4388 if (!ctx.vlen)
4389 goto hdr_response_bad;
4390
4391 if (strl2llrc(ctx.line + ctx.val, ctx.vlen, &cl))
4392 goto hdr_response_bad; /* parse failure */
4393
4394 if (cl < 0)
4395 goto hdr_response_bad;
4396
4397 if ((txn->flags & TX_RES_CNT_LEN) && (msg->hdr_content_len != cl))
4398 goto hdr_response_bad; /* already specified, was different */
4399
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004400 txn->flags |= TX_RES_CNT_LEN | TX_RES_XFER_LEN;
Willy Tarreaub8c82c22009-10-18 23:45:12 +02004401 msg->hdr_content_len = cl;
4402 }
4403
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004404 /* FIXME: we should also implement the multipart/byterange method.
4405 * For now on, we resort to close mode in this case (unknown length).
4406 */
Willy Tarreaub8c82c22009-10-18 23:45:12 +02004407skip_content_length:
Willy Tarreaub8c82c22009-10-18 23:45:12 +02004408
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004409 /* end of job, return OK */
4410 rep->analysers &= ~an_bit;
4411 rep->analyse_exp = TICK_ETERNITY;
Willy Tarreau90deb182010-01-07 00:20:41 +01004412 buffer_auto_close(rep);
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004413 return 1;
4414}
4415
4416/* This function performs all the processing enabled for the current response.
Willy Tarreaue3fa6e52010-01-04 22:57:43 +01004417 * It normally returns 1 unless it wants to break. It relies on buffers flags,
4418 * and updates t->rep->analysers. It might make sense to explode it into several
4419 * other functions. It works like process_request (see indications above).
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004420 */
4421int http_process_res_common(struct session *t, struct buffer *rep, int an_bit, struct proxy *px)
4422{
4423 struct http_txn *txn = &t->txn;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004424 struct http_msg *msg = &txn->rsp;
4425 struct proxy *cur_proxy;
Willy Tarreaudeb9ed82010-01-03 21:03:22 +01004426 struct wordlist *wl;
Willy Tarreau5b154472009-12-21 20:11:07 +01004427 int conn_ka = 0, conn_cl = 0;
4428 int must_close = 0;
Willy Tarreaub608feb2010-01-02 22:47:18 +01004429 int must_del_close = 0, must_keep = 0;
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004430
4431 DPRINTF(stderr,"[%u] %s: session=%p b=%p, exp(r,w)=%u,%u bf=%08x bl=%d analysers=%02x\n",
4432 now_ms, __FUNCTION__,
4433 t,
4434 rep,
4435 rep->rex, rep->wex,
4436 rep->flags,
4437 rep->l,
4438 rep->analysers);
4439
Willy Tarreau655dce92009-11-08 13:10:58 +01004440 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) /* we need more data */
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004441 return 0;
4442
4443 rep->analysers &= ~an_bit;
4444 rep->analyse_exp = TICK_ETERNITY;
4445
Willy Tarreau5b154472009-12-21 20:11:07 +01004446 /* Now we have to check if we need to modify the Connection header.
4447 * This is more difficult on the response than it is on the request,
4448 * because we can have two different HTTP versions and we don't know
4449 * how the client will interprete a response. For instance, let's say
4450 * that the client sends a keep-alive request in HTTP/1.0 and gets an
4451 * HTTP/1.1 response without any header. Maybe it will bound itself to
4452 * HTTP/1.0 because it only knows about it, and will consider the lack
4453 * of header as a close, or maybe it knows HTTP/1.1 and can consider
4454 * the lack of header as a keep-alive. Thus we will use two flags
4455 * indicating how a request MAY be understood by the client. In case
4456 * of multiple possibilities, we'll fix the header to be explicit. If
4457 * ambiguous cases such as both close and keepalive are seen, then we
4458 * will fall back to explicit close. Note that we won't take risks with
4459 * HTTP/1.0 clients which may not necessarily understand keep-alive.
4460 */
4461
4462 if ((txn->meth != HTTP_METH_CONNECT) &&
Willy Tarreaubbf0b372010-01-18 16:54:40 +01004463 (txn->status >= 200) && !(txn->flags & TX_HDR_CONN_PRS) &&
Willy Tarreau0dfdf192010-01-05 11:33:11 +01004464 ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN ||
4465 ((t->fe->options|t->be->options) & PR_O_HTTP_CLOSE))) {
Willy Tarreau5b154472009-12-21 20:11:07 +01004466 int may_keep = 0, may_close = 0; /* how it may be understood */
4467 struct hdr_ctx ctx;
4468
4469 ctx.idx = 0;
4470 while (http_find_header2("Connection", 10, msg->sol, &txn->hdr_idx, &ctx)) {
4471 if (ctx.vlen == 5 && strncasecmp(ctx.line + ctx.val, "close", 5) == 0)
4472 conn_cl = 1;
4473 else if (ctx.vlen == 10 && strncasecmp(ctx.line + ctx.val, "keep-alive", 10) == 0)
4474 conn_ka = 1;
4475 }
4476
4477 if (conn_cl) {
4478 /* close header present */
4479 may_close = 1;
4480 if (conn_ka) /* we have both close and keep-alive */
4481 may_keep = 1;
4482 }
4483 else if (conn_ka) {
4484 /* keep-alive alone */
4485 may_keep = 1;
4486 }
4487 else {
4488 /* no close nor keep-alive header */
4489 if (txn->flags & TX_RES_VER_11)
4490 may_keep = 1;
4491 else
4492 may_close = 1;
4493
4494 if (txn->flags & TX_REQ_VER_11)
4495 may_keep = 1;
4496 else
4497 may_close = 1;
4498 }
4499
4500 /* let's update the transaction status to reflect any close.
4501 * Note that ambiguous cases with keep & close will also be
Willy Tarreaue8e785b2009-12-26 15:34:26 +01004502 * handled. We also explicitly state that we will close in
4503 * case of an ambiguous response having no content-length.
Willy Tarreau5b154472009-12-21 20:11:07 +01004504 */
Willy Tarreau0dfdf192010-01-05 11:33:11 +01004505 if ((may_close && ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_TUN) &&
Willy Tarreaub608feb2010-01-02 22:47:18 +01004506 (may_keep || ((txn->flags & TX_CON_WANT_MSK) != TX_CON_WANT_SCL))) ||
4507 !(txn->flags & TX_RES_XFER_LEN))
Willy Tarreau5b154472009-12-21 20:11:07 +01004508 txn->flags = (txn->flags & ~TX_CON_WANT_MSK) | TX_CON_WANT_CLO;
4509
4510 /* Now we must adjust the response header :
Willy Tarreau0dfdf192010-01-05 11:33:11 +01004511 * - set "close" if may_keep and (WANT_CLO | httpclose)
Willy Tarreau5b154472009-12-21 20:11:07 +01004512 * - remove "close" if WANT_SCL and REQ_1.1 and may_close and (content-length or TE_CHNK)
4513 * - add "keep-alive" if WANT_SCL and REQ_1.0 and may_close and content-length
Willy Tarreau5b154472009-12-21 20:11:07 +01004514 */
Willy Tarreau0dfdf192010-01-05 11:33:11 +01004515 if (may_keep &&
4516 ((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_CLO ||
4517 ((t->fe->options|t->be->options) & PR_O_HTTP_CLOSE)))
Willy Tarreau5b154472009-12-21 20:11:07 +01004518 must_close = 1;
Willy Tarreaub608feb2010-01-02 22:47:18 +01004519 else if (((txn->flags & TX_CON_WANT_MSK) == TX_CON_WANT_SCL) &&
4520 may_close && (txn->flags & TX_RES_XFER_LEN)) {
4521 must_del_close = 1;
4522 if (!(txn->flags & TX_REQ_VER_11))
4523 must_keep = 1;
4524 }
Willy Tarreau5b154472009-12-21 20:11:07 +01004525
4526 txn->flags |= TX_CON_HDR_PARS;
4527 }
4528
4529 /* We might have to check for "Connection:" if the server
4530 * returns a connection status that is not compatible with
4531 * the client's or with the config.
4532 */
Willy Tarreaub608feb2010-01-02 22:47:18 +01004533 if ((txn->status >= 200) && (must_del_close|must_close) && (conn_cl|conn_ka)) {
Willy Tarreau5b154472009-12-21 20:11:07 +01004534 char *cur_ptr, *cur_end, *cur_next;
4535 int cur_idx, old_idx, delta, val;
4536 int must_delete;
4537 struct hdr_idx_elem *cur_hdr;
4538
4539 /* we just have to remove the headers if both sides are 1.0 */
4540 must_delete = !(txn->flags & TX_REQ_VER_11) && !(txn->flags & TX_RES_VER_11);
Willy Tarreaub608feb2010-01-02 22:47:18 +01004541
4542 /* same if we want to re-enable keep-alive on 1.1 */
4543 must_delete |= must_del_close;
4544
Willy Tarreau962c3f42010-01-10 00:15:35 +01004545 cur_next = txn->rsp.sol + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau5b154472009-12-21 20:11:07 +01004546
4547 for (old_idx = 0; (cur_idx = txn->hdr_idx.v[old_idx].next); old_idx = cur_idx) {
4548 cur_hdr = &txn->hdr_idx.v[cur_idx];
4549 cur_ptr = cur_next;
4550 cur_end = cur_ptr + cur_hdr->len;
4551 cur_next = cur_end + cur_hdr->cr + 1;
4552
4553 val = http_header_match2(cur_ptr, cur_end, "Connection", 10);
4554 if (!val)
4555 continue;
4556
4557 /* 3 possibilities :
4558 * - we have already set "Connection: close" or we're in
4559 * HTTP/1.0, so we remove this line.
4560 * - we have not yet set "Connection: close", but this line
4561 * indicates close. We leave it untouched and set the flag.
4562 * - we have not yet set "Connection: close", and this line
4563 * indicates non-close. We replace it and set the flag.
4564 */
4565 if (must_delete) {
4566 delta = buffer_replace2(rep, cur_ptr, cur_next, NULL, 0);
4567 http_msg_move_end(&txn->rsp, delta);
4568 cur_next += delta;
4569 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
4570 txn->hdr_idx.used--;
4571 cur_hdr->len = 0;
4572 must_close = 0;
Willy Tarreaub608feb2010-01-02 22:47:18 +01004573 must_del_close = 0;
Willy Tarreau5b154472009-12-21 20:11:07 +01004574 } else {
4575 if (cur_end - cur_ptr - val != 5 ||
4576 strncasecmp(cur_ptr + val, "close", 5) != 0) {
4577 delta = buffer_replace2(rep, cur_ptr + val, cur_end,
4578 "close", 5);
4579 cur_next += delta;
4580 cur_hdr->len += delta;
4581 http_msg_move_end(&txn->rsp, delta);
4582 }
4583 must_delete = 1;
4584 must_close = 0;
4585 }
4586 } /* for loop */
4587 } /* if must close keep-alive */
4588
Willy Tarreaub37c27e2009-10-18 22:53:08 +02004589 if (1) {
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004590 /*
4591 * 3: we will have to evaluate the filters.
4592 * As opposed to version 1.2, now they will be evaluated in the
4593 * filters order and not in the header order. This means that
4594 * each filter has to be validated among all headers.
4595 *
4596 * Filters are tried with ->be first, then with ->fe if it is
4597 * different from ->be.
4598 */
4599
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004600 cur_proxy = t->be;
4601 while (1) {
4602 struct proxy *rule_set = cur_proxy;
4603
4604 /* try headers filters */
4605 if (rule_set->rsp_exp != NULL) {
4606 if (apply_filters_to_response(t, rep, rule_set->rsp_exp) < 0) {
4607 return_bad_resp:
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01004608 if (t->srv) {
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02004609 t->srv->counters.failed_resp++;
Krzysztof Piotr Oledzki97f07b82009-12-15 22:31:24 +01004610 health_adjust(t->srv, HANA_STATUS_HTTP_RSP);
4611 }
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02004612 cur_proxy->counters.failed_resp++;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004613 return_srv_prx_502:
Willy Tarreau2df28e82008-08-17 15:20:19 +02004614 rep->analysers = 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004615 txn->status = 502;
Willy Tarreauc88ea682009-12-29 14:56:36 +01004616 rep->prod->flags |= SI_FL_NOLINGER;
Willy Tarreau8e89b842009-10-18 23:56:35 +02004617 stream_int_retnclose(rep->cons, error_message(t, HTTP_ERR_502));
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004618 if (!(t->flags & SN_ERR_MASK))
4619 t->flags |= SN_ERR_PRXCOND;
4620 if (!(t->flags & SN_FINST_MASK))
4621 t->flags |= SN_FINST_H;
Willy Tarreaudafde432008-08-17 01:00:46 +02004622 return 0;
Willy Tarreau21d2af32008-02-14 20:25:24 +01004623 }
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004624 }
Willy Tarreau21d2af32008-02-14 20:25:24 +01004625
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004626 /* has the response been denied ? */
4627 if (txn->flags & TX_SVDENY) {
Willy Tarreau8365f932009-03-15 23:11:49 +01004628 if (t->srv)
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02004629 t->srv->counters.failed_secu++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02004630
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02004631 cur_proxy->counters.denied_resp++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02004632 if (t->listener->counters)
4633 t->listener->counters->denied_resp++;
4634
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004635 goto return_srv_prx_502;
Willy Tarreau51406232008-03-10 22:04:20 +01004636 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02004637
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004638 /* add response headers from the rule sets in the same order */
Willy Tarreaudeb9ed82010-01-03 21:03:22 +01004639 list_for_each_entry(wl, &rule_set->rsp_add, list) {
Willy Tarreau816b9792009-09-15 21:25:21 +02004640 if (txn->status < 200)
4641 break;
Willy Tarreaudeb9ed82010-01-03 21:03:22 +01004642 if (unlikely(http_header_add_tail(rep, &txn->rsp, &txn->hdr_idx, wl->s) < 0))
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004643 goto return_bad_resp;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02004644 }
4645
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004646 /* check whether we're already working on the frontend */
4647 if (cur_proxy == t->fe)
4648 break;
4649 cur_proxy = t->fe;
Willy Tarreaubaaee002006-06-26 02:48:02 +02004650 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02004651
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004652 /*
Willy Tarreau63c9e5f2009-12-22 16:01:27 +01004653 * We may be facing a 1xx response (100 continue, 101 switching protocols),
4654 * in which case this is not the right response, and we're waiting for the
4655 * next one. Let's allow this response to go to the client and wait for the
4656 * next one.
4657 */
4658 if (txn->status < 200) {
4659 hdr_idx_init(&txn->hdr_idx);
Willy Tarreau962c3f42010-01-10 00:15:35 +01004660 buffer_forward(rep, rep->lr - msg->sol);
Willy Tarreau63c9e5f2009-12-22 16:01:27 +01004661 msg->msg_state = HTTP_MSG_RPBEFORE;
4662 txn->status = 0;
4663 rep->analysers |= AN_RES_WAIT_HTTP | an_bit;
4664 return 1;
4665 }
4666
4667 /* we don't have any 1xx status code now */
4668
4669 /*
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004670 * 4: check for server cookie.
4671 */
Willy Tarreau63c9e5f2009-12-22 16:01:27 +01004672 if (t->be->cookie_name || t->be->appsession_name || t->fe->capture_name ||
4673 (t->be->options & PR_O_CHK_CACHE))
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004674 manage_server_side_cookies(t, rep);
Willy Tarreaubaaee002006-06-26 02:48:02 +02004675
Willy Tarreaubaaee002006-06-26 02:48:02 +02004676
Willy Tarreaua15645d2007-03-18 16:22:39 +01004677 /*
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004678 * 5: check for cache-control or pragma headers if required.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004679 */
Willy Tarreau63c9e5f2009-12-22 16:01:27 +01004680 if ((t->be->options & (PR_O_COOK_NOC | PR_O_CHK_CACHE)) != 0)
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004681 check_response_for_cacheability(t, rep);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004682
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004683 /*
4684 * 6: add server cookie in the response if needed
4685 */
4686 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
Willy Tarreau63c9e5f2009-12-22 16:01:27 +01004687 (!(t->be->options & PR_O_COOK_POST) || (txn->meth == HTTP_METH_POST))) {
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004688 int len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02004689
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004690 /* the server is known, it's not the one the client requested, we have to
4691 * insert a set-cookie here, except if we want to insert only on POST
4692 * requests and this one isn't. Note that servers which don't have cookies
4693 * (eg: some backup servers) will return a full cookie removal request.
4694 */
4695 len = sprintf(trash, "Set-Cookie: %s=%s; path=/",
4696 t->be->cookie_name,
4697 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
Willy Tarreaubaaee002006-06-26 02:48:02 +02004698
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004699 if (t->be->cookie_domain)
4700 len += sprintf(trash+len, "; domain=%s", t->be->cookie_domain);
Willy Tarreaubaaee002006-06-26 02:48:02 +02004701
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004702 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
Willy Tarreau58cc8722009-12-28 06:57:33 +01004703 trash, len) < 0))
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004704 goto return_bad_resp;
4705 txn->flags |= TX_SCK_INSERTED;
Willy Tarreaubaaee002006-06-26 02:48:02 +02004706
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004707 /* Here, we will tell an eventual cache on the client side that we don't
4708 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
4709 * Some caches understand the correct form: 'no-cache="set-cookie"', but
4710 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
4711 */
4712 if ((t->be->options & PR_O_COOK_NOC) && (txn->flags & TX_CACHEABLE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02004713
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004714 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
4715
4716 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
Willy Tarreau58cc8722009-12-28 06:57:33 +01004717 "Cache-control: private", 22) < 0))
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004718 goto return_bad_resp;
Willy Tarreaua15645d2007-03-18 16:22:39 +01004719 }
4720 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02004721
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004722 /*
4723 * 7: check if result will be cacheable with a cookie.
4724 * We'll block the response if security checks have caught
4725 * nasty things such as a cacheable cookie.
4726 */
4727 if (((txn->flags & (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) ==
4728 (TX_CACHEABLE | TX_CACHE_COOK | TX_SCK_ANY)) &&
Willy Tarreau63c9e5f2009-12-22 16:01:27 +01004729 (t->be->options & PR_O_CHK_CACHE)) {
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004730
4731 /* we're in presence of a cacheable response containing
4732 * a set-cookie header. We'll block it as requested by
4733 * the 'checkcache' option, and send an alert.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004734 */
Willy Tarreau8365f932009-03-15 23:11:49 +01004735 if (t->srv)
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02004736 t->srv->counters.failed_secu++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02004737
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02004738 cur_proxy->counters.denied_resp++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02004739 if (t->listener->counters)
4740 t->listener->counters->denied_resp++;
4741
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004742 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n",
4743 t->be->id, t->srv?t->srv->id:"<dispatch>");
4744 send_log(t->be, LOG_ALERT,
4745 "Blocking cacheable cookie in response from instance %s, server %s.\n",
4746 t->be->id, t->srv?t->srv->id:"<dispatch>");
4747 goto return_srv_prx_502;
4748 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01004749
4750 /*
Willy Tarreau5b154472009-12-21 20:11:07 +01004751 * 8: add "Connection: close" if needed and not yet set. This is
4752 * only needed for 1.1 responses since we know there is no other
4753 * Connection header.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004754 */
Willy Tarreau63c9e5f2009-12-22 16:01:27 +01004755 if (must_close && (txn->flags & TX_RES_VER_11)) {
Willy Tarreau5b154472009-12-21 20:11:07 +01004756 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
Willy Tarreau58cc8722009-12-28 06:57:33 +01004757 "Connection: close", 17) < 0))
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004758 goto return_bad_resp;
Willy Tarreau5b154472009-12-21 20:11:07 +01004759 must_close = 0;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004760 }
Willy Tarreaub608feb2010-01-02 22:47:18 +01004761 else if (must_keep && !(txn->flags & TX_REQ_VER_11)) {
4762 if (unlikely(http_header_add_tail2(rep, &txn->rsp, &txn->hdr_idx,
4763 "Connection: keep-alive", 22) < 0))
4764 goto return_bad_resp;
4765 must_keep = 0;
4766 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01004767
Willy Tarreaud98cf932009-12-27 22:54:55 +01004768 if (txn->flags & TX_RES_XFER_LEN)
4769 rep->analysers |= AN_RES_HTTP_XFER_BODY;
Willy Tarreau03945942009-12-22 16:50:27 +01004770
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004771 /*************************************************************
4772 * OK, that's finished for the headers. We have done what we *
4773 * could. Let's switch to the DATA state. *
4774 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02004775
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004776 t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
Willy Tarreaua15645d2007-03-18 16:22:39 +01004777
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004778 /* if the user wants to log as soon as possible, without counting
4779 * bytes from the server, then this is the right moment. We have
4780 * to temporarily assign bytes_out to log what we currently have.
4781 */
4782 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
4783 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
4784 t->logs.bytes_out = txn->rsp.eoh;
Willy Tarreaua5555ec2008-11-30 19:02:32 +01004785 t->do_log(t);
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004786 t->logs.bytes_out = 0;
4787 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01004788
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004789 /* Note: we must not try to cheat by jumping directly to DATA,
4790 * otherwise we would not let the client side wake up.
4791 */
Willy Tarreaua15645d2007-03-18 16:22:39 +01004792
Willy Tarreaue3fa6e52010-01-04 22:57:43 +01004793 return 1;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004794 }
Willy Tarreaue3fa6e52010-01-04 22:57:43 +01004795 return 1;
Willy Tarreauf5483bf2008-08-14 18:35:40 +02004796}
Willy Tarreaua15645d2007-03-18 16:22:39 +01004797
Willy Tarreaud98cf932009-12-27 22:54:55 +01004798/* This function is an analyser which forwards response body (including chunk
4799 * sizes if any). It is called as soon as we must forward, even if we forward
4800 * zero byte. The only situation where it must not be called is when we're in
4801 * tunnel mode and we want to forward till the close. It's used both to forward
4802 * remaining data and to resync after end of body. It expects the msg_state to
4803 * be between MSG_BODY and MSG_DONE (inclusive). It returns zero if it needs to
4804 * read more data, or 1 once we can go on with next request or end the session.
4805 * When in MSG_DATA or MSG_TRAILERS, it will automatically forward hdr_content_len
4806 * bytes of pending data + the headers if not already done (between som and sov).
4807 * It eventually adjusts som to match sov after the data in between have been sent.
4808 */
4809int http_response_forward_body(struct session *s, struct buffer *res, int an_bit)
4810{
4811 struct http_txn *txn = &s->txn;
4812 struct http_msg *msg = &s->txn.rsp;
4813
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01004814 if (unlikely(msg->msg_state < HTTP_MSG_BODY))
4815 return 0;
4816
Willy Tarreau6c2cbe12010-01-03 17:07:49 +01004817 if ((res->flags & (BF_READ_ERROR|BF_READ_TIMEOUT|BF_WRITE_ERROR|BF_WRITE_TIMEOUT)) ||
Willy Tarreau2fa144c2010-01-04 23:13:26 +01004818 ((res->flags & BF_SHUTW) && (res->to_forward || res->send_max)) ||
Willy Tarreau6c2cbe12010-01-03 17:07:49 +01004819 !s->req->analysers) {
4820 /* in case of error or if the other analyser went away, we can't analyse HTTP anymore */
4821 buffer_ignore(res, res->l - res->send_max);
Willy Tarreau90deb182010-01-07 00:20:41 +01004822 buffer_auto_read(res);
4823 buffer_auto_close(res);
Willy Tarreau082b01c2010-01-02 23:58:04 +01004824 res->analysers &= ~an_bit;
4825 return 1;
4826 }
4827
Willy Tarreaud3347ee2010-01-04 02:02:25 +01004828 buffer_dont_close(res);
Willy Tarreaub608feb2010-01-02 22:47:18 +01004829
Willy Tarreaud98cf932009-12-27 22:54:55 +01004830 if (msg->msg_state < HTTP_MSG_CHUNK_SIZE) {
4831 /* we have msg->col and msg->sov which both point to the first
4832 * byte of message body. msg->som still points to the beginning
4833 * of the message. We must save the body in req->lr because it
4834 * survives buffer re-alignments.
4835 */
4836 res->lr = res->data + msg->sov;
4837 if (txn->flags & TX_RES_TE_CHNK)
4838 msg->msg_state = HTTP_MSG_CHUNK_SIZE;
4839 else {
4840 msg->msg_state = HTTP_MSG_DATA;
4841 }
4842 }
4843
Willy Tarreaud98cf932009-12-27 22:54:55 +01004844 while (1) {
Willy Tarreau610ecce2010-01-04 21:15:02 +01004845 http_silent_debug(__LINE__, s);
Willy Tarreau638cd022010-01-03 07:42:04 +01004846 /* we may have some data pending */
4847 if (msg->hdr_content_len || msg->som != msg->sov) {
4848 int bytes = msg->sov - msg->som;
4849 if (bytes < 0) /* sov may have wrapped at the end */
4850 bytes += res->size;
4851 buffer_forward(res, bytes + msg->hdr_content_len);
4852 msg->hdr_content_len = 0; /* don't forward that again */
4853 msg->som = msg->sov;
4854 }
4855
Willy Tarreaucaabe412010-01-03 23:08:28 +01004856 if (msg->msg_state == HTTP_MSG_DATA) {
4857 /* must still forward */
4858 if (res->to_forward)
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01004859 goto missing_data;
Willy Tarreaucaabe412010-01-03 23:08:28 +01004860
4861 /* nothing left to forward */
4862 if (txn->flags & TX_RES_TE_CHNK)
4863 msg->msg_state = HTTP_MSG_DATA_CRLF;
4864 else
4865 msg->msg_state = HTTP_MSG_DONE;
4866 }
4867 else if (msg->msg_state == HTTP_MSG_CHUNK_SIZE) {
Willy Tarreaud98cf932009-12-27 22:54:55 +01004868 /* read the chunk size and assign it to ->hdr_content_len, then
4869 * set ->sov to point to the body and switch to DATA or TRAILERS state.
4870 */
4871 int ret = http_parse_chunk_size(res, msg);
4872
4873 if (!ret)
4874 goto missing_data;
4875 else if (ret < 0)
4876 goto return_bad_res;
4877 /* otherwise we're in HTTP_MSG_DATA or HTTP_MSG_TRAILERS state */
Willy Tarreaud98cf932009-12-27 22:54:55 +01004878 }
Willy Tarreaud98cf932009-12-27 22:54:55 +01004879 else if (msg->msg_state == HTTP_MSG_DATA_CRLF) {
4880 /* we want the CRLF after the data */
4881 int ret;
4882
Willy Tarreaud3347ee2010-01-04 02:02:25 +01004883 res->lr = res->w + res->send_max;
4884 if (res->lr >= res->data + res->size)
4885 res->lr -= res->size;
4886
Willy Tarreaud98cf932009-12-27 22:54:55 +01004887 ret = http_skip_chunk_crlf(res, msg);
4888
4889 if (!ret)
4890 goto missing_data;
4891 else if (ret < 0)
4892 goto return_bad_res;
4893 /* we're in MSG_CHUNK_SIZE now */
4894 }
4895 else if (msg->msg_state == HTTP_MSG_TRAILERS) {
4896 int ret = http_forward_trailers(res, msg);
Willy Tarreau5523b322009-12-29 12:05:52 +01004897
Willy Tarreaud98cf932009-12-27 22:54:55 +01004898 if (ret == 0)
4899 goto missing_data;
4900 else if (ret < 0)
4901 goto return_bad_res;
4902 /* we're in HTTP_MSG_DONE now */
4903 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01004904 else {
4905 /* other states, DONE...TUNNEL */
4906 if (http_resync_states(s)) {
4907 http_silent_debug(__LINE__, s);
4908 /* some state changes occurred, maybe the analyser
4909 * was disabled too.
Willy Tarreau5523b322009-12-29 12:05:52 +01004910 */
Willy Tarreau610ecce2010-01-04 21:15:02 +01004911 if (unlikely(msg->msg_state == HTTP_MSG_ERROR))
4912 goto return_bad_res;
4913 return 1;
Willy Tarreau5523b322009-12-29 12:05:52 +01004914 }
Willy Tarreau610ecce2010-01-04 21:15:02 +01004915 return 0;
Willy Tarreaud98cf932009-12-27 22:54:55 +01004916 }
4917 }
4918
Willy Tarreaud98cf932009-12-27 22:54:55 +01004919 missing_data:
Willy Tarreauf5c8bd62010-01-04 07:10:34 +01004920 /* stop waiting for data if the input is closed before the end */
4921 if (res->flags & BF_SHUTR)
4922 goto return_bad_res;
4923
Willy Tarreau610ecce2010-01-04 21:15:02 +01004924 if (!s->req->analysers)
4925 goto return_bad_res;
4926
Willy Tarreaud98cf932009-12-27 22:54:55 +01004927 /* forward the chunk size as well as any pending data */
4928 if (msg->hdr_content_len || msg->som != msg->sov) {
4929 buffer_forward(res, msg->sov - msg->som + msg->hdr_content_len);
4930 msg->hdr_content_len = 0; /* don't forward that again */
4931 msg->som = msg->sov;
4932 }
4933
Willy Tarreaud98cf932009-12-27 22:54:55 +01004934 /* the session handler will take care of timeouts and errors */
Willy Tarreau610ecce2010-01-04 21:15:02 +01004935 http_silent_debug(__LINE__, s);
Willy Tarreaud98cf932009-12-27 22:54:55 +01004936 return 0;
4937
4938 return_bad_res: /* let's centralize all bad resuests */
4939 txn->rsp.msg_state = HTTP_MSG_ERROR;
4940 txn->status = 502;
Willy Tarreau148d0992010-01-10 10:21:21 +01004941 /* don't send any error message as we're in the body */
4942 stream_int_retnclose(res->cons, NULL);
Willy Tarreaud98cf932009-12-27 22:54:55 +01004943 res->analysers = 0;
4944 s->be->counters.failed_resp++;
4945 if (s->srv) {
4946 s->srv->counters.failed_resp++;
4947 health_adjust(s->srv, HANA_STATUS_HTTP_HDRRSP);
4948 }
4949
4950 if (!(s->flags & SN_ERR_MASK))
4951 s->flags |= SN_ERR_PRXCOND;
4952 if (!(s->flags & SN_FINST_MASK))
4953 s->flags |= SN_FINST_R;
Willy Tarreau610ecce2010-01-04 21:15:02 +01004954 http_silent_debug(__LINE__, s);
Willy Tarreaud98cf932009-12-27 22:54:55 +01004955 return 0;
4956}
4957
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004958/* Iterate the same filter through all request headers.
4959 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreaua15645d2007-03-18 16:22:39 +01004960 * Since it can manage the switch to another backend, it updates the per-proxy
4961 * DENY stats.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004962 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004963int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004964{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004965 char term;
4966 char *cur_ptr, *cur_end, *cur_next;
4967 int cur_idx, old_idx, last_hdr;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004968 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004969 struct hdr_idx_elem *cur_hdr;
4970 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004971
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004972 last_hdr = 0;
4973
Willy Tarreau962c3f42010-01-10 00:15:35 +01004974 cur_next = txn->req.sol + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004975 old_idx = 0;
4976
4977 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01004978 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004979 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01004980 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004981 (exp->action == ACT_ALLOW ||
4982 exp->action == ACT_DENY ||
4983 exp->action == ACT_TARPIT))
4984 return 0;
4985
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004986 cur_idx = txn->hdr_idx.v[old_idx].next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004987 if (!cur_idx)
4988 break;
4989
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01004990 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004991 cur_ptr = cur_next;
4992 cur_end = cur_ptr + cur_hdr->len;
4993 cur_next = cur_end + cur_hdr->cr + 1;
4994
4995 /* Now we have one header between cur_ptr and cur_end,
4996 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01004997 */
4998
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004999 /* The annoying part is that pattern matching needs
5000 * that we modify the contents to null-terminate all
5001 * strings before testing them.
5002 */
5003
5004 term = *cur_end;
5005 *cur_end = '\0';
5006
5007 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
5008 switch (exp->action) {
5009 case ACT_SETBE:
5010 /* It is not possible to jump a second time.
5011 * FIXME: should we return an HTTP/500 here so that
5012 * the admin knows there's a problem ?
5013 */
5014 if (t->be != t->fe)
5015 break;
5016
5017 /* Swithing Proxy */
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02005018 session_set_backend(t, (struct proxy *)exp->replace);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005019 last_hdr = 1;
5020 break;
5021
5022 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01005023 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005024 last_hdr = 1;
5025 break;
5026
5027 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01005028 txn->flags |= TX_CLDENY;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005029 last_hdr = 1;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02005030
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02005031 t->be->counters.denied_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02005032 if (t->listener->counters)
5033 t->listener->counters->denied_resp++;
5034
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005035 break;
5036
5037 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01005038 txn->flags |= TX_CLTARPIT;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005039 last_hdr = 1;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02005040
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02005041 t->be->counters.denied_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02005042 if (t->listener->counters)
5043 t->listener->counters->denied_resp++;
5044
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005045 break;
5046
5047 case ACT_REPLACE:
5048 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
5049 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
5050 /* FIXME: if the user adds a newline in the replacement, the
5051 * index will not be recalculated for now, and the new line
5052 * will not be counted as a new header.
5053 */
5054
5055 cur_end += delta;
5056 cur_next += delta;
5057 cur_hdr->len += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01005058 http_msg_move_end(&txn->req, delta);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005059 break;
5060
5061 case ACT_REMOVE:
5062 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
5063 cur_next += delta;
5064
Willy Tarreaufa355d42009-11-29 18:12:29 +01005065 http_msg_move_end(&txn->req, delta);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005066 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
5067 txn->hdr_idx.used--;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005068 cur_hdr->len = 0;
5069 cur_end = NULL; /* null-term has been rewritten */
5070 break;
5071
5072 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01005073 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005074 if (cur_end)
5075 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01005076
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005077 /* keep the link from this header to next one in case of later
5078 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01005079 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005080 old_idx = cur_idx;
5081 }
5082 return 0;
5083}
5084
5085
5086/* Apply the filter to the request line.
5087 * Returns 0 if nothing has been done, 1 if the filter has been applied,
5088 * or -1 if a replacement resulted in an invalid request line.
Willy Tarreaua15645d2007-03-18 16:22:39 +01005089 * Since it can manage the switch to another backend, it updates the per-proxy
5090 * DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005091 */
5092int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
5093{
5094 char term;
5095 char *cur_ptr, *cur_end;
5096 int done;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005097 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005098 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005099
Willy Tarreau58f10d72006-12-04 02:26:12 +01005100
Willy Tarreau3d300592007-03-18 18:34:41 +01005101 if (unlikely(txn->flags & (TX_CLDENY | TX_CLTARPIT)))
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005102 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01005103 else if (unlikely(txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005104 (exp->action == ACT_ALLOW ||
5105 exp->action == ACT_DENY ||
5106 exp->action == ACT_TARPIT))
5107 return 0;
5108 else if (exp->action == ACT_REMOVE)
5109 return 0;
5110
5111 done = 0;
5112
Willy Tarreau962c3f42010-01-10 00:15:35 +01005113 cur_ptr = txn->req.sol;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005114 cur_end = cur_ptr + txn->req.sl.rq.l;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005115
5116 /* Now we have the request line between cur_ptr and cur_end */
5117
5118 /* The annoying part is that pattern matching needs
5119 * that we modify the contents to null-terminate all
5120 * strings before testing them.
5121 */
5122
5123 term = *cur_end;
5124 *cur_end = '\0';
5125
5126 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
5127 switch (exp->action) {
5128 case ACT_SETBE:
5129 /* It is not possible to jump a second time.
5130 * FIXME: should we return an HTTP/500 here so that
5131 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01005132 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005133 if (t->be != t->fe)
5134 break;
5135
5136 /* Swithing Proxy */
Willy Tarreau1d0dfb12009-07-07 15:10:31 +02005137 session_set_backend(t, (struct proxy *)exp->replace);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005138 done = 1;
5139 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005140
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005141 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01005142 txn->flags |= TX_CLALLOW;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005143 done = 1;
5144 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01005145
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005146 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01005147 txn->flags |= TX_CLDENY;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02005148
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02005149 t->be->counters.denied_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02005150 if (t->listener->counters)
5151 t->listener->counters->denied_resp++;
5152
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005153 done = 1;
5154 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01005155
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005156 case ACT_TARPIT:
Willy Tarreau3d300592007-03-18 18:34:41 +01005157 txn->flags |= TX_CLTARPIT;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02005158
Krzysztof Piotr Oledzki052d4fd2009-10-04 14:52:57 +02005159 t->be->counters.denied_req++;
Krzysztof Piotr Oledzkiaeebf9b2009-10-04 15:43:17 +02005160 if (t->listener->counters)
5161 t->listener->counters->denied_resp++;
5162
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005163 done = 1;
5164 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01005165
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005166 case ACT_REPLACE:
5167 *cur_end = term; /* restore the string terminator */
5168 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
5169 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
5170 /* FIXME: if the user adds a newline in the replacement, the
5171 * index will not be recalculated for now, and the new line
5172 * will not be counted as a new header.
5173 */
Willy Tarreaua496b602006-12-17 23:15:24 +01005174
Willy Tarreaufa355d42009-11-29 18:12:29 +01005175 http_msg_move_end(&txn->req, delta);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005176 cur_end += delta;
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005177 cur_end = (char *)http_parse_reqline(&txn->req, req->data,
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005178 HTTP_MSG_RQMETH,
5179 cur_ptr, cur_end + 1,
5180 NULL, NULL);
5181 if (unlikely(!cur_end))
5182 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01005183
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005184 /* we have a full request and we know that we have either a CR
5185 * or an LF at <ptr>.
5186 */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005187 txn->meth = find_http_meth(cur_ptr, txn->req.sl.rq.m_l);
5188 hdr_idx_set_start(&txn->hdr_idx, txn->req.sl.rq.l, *cur_end == '\r');
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005189 /* there is no point trying this regex on headers */
5190 return 1;
5191 }
5192 }
5193 *cur_end = term; /* restore the string terminator */
5194 return done;
5195}
Willy Tarreau97de6242006-12-27 17:18:38 +01005196
Willy Tarreau58f10d72006-12-04 02:26:12 +01005197
Willy Tarreau58f10d72006-12-04 02:26:12 +01005198
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005199/*
5200 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
5201 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
Willy Tarreaua15645d2007-03-18 16:22:39 +01005202 * unparsable request. Since it can manage the switch to another backend, it
5203 * updates the per-proxy DENY stats.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005204 */
5205int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
5206{
Willy Tarreau3d300592007-03-18 18:34:41 +01005207 struct http_txn *txn = &t->txn;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005208 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01005209 while (exp && !(txn->flags & (TX_CLDENY|TX_CLTARPIT))) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005210 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005211
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005212 /*
5213 * The interleaving of transformations and verdicts
5214 * makes it difficult to decide to continue or stop
5215 * the evaluation.
5216 */
5217
Willy Tarreau3d300592007-03-18 18:34:41 +01005218 if ((txn->flags & TX_CLALLOW) &&
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005219 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
5220 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
5221 exp = exp->next;
5222 continue;
5223 }
5224
5225 /* Apply the filter to the request line. */
5226 ret = apply_filter_to_req_line(t, req, exp);
5227 if (unlikely(ret < 0))
5228 return -1;
5229
5230 if (likely(ret == 0)) {
5231 /* The filter did not match the request, it can be
5232 * iterated through all headers.
5233 */
5234 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005235 }
5236 exp = exp->next;
5237 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005238 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005239}
5240
5241
Willy Tarreaua15645d2007-03-18 16:22:39 +01005242
Willy Tarreau58f10d72006-12-04 02:26:12 +01005243/*
Cyril Bontébf47aeb2009-10-15 00:15:40 +02005244 * Try to retrieve the server associated to the appsession.
5245 * If the server is found, it's assigned to the session.
5246 */
Cyril Bontéb21570a2009-11-29 20:04:48 +01005247void manage_client_side_appsession(struct session *t, const char *buf, int len) {
Cyril Bontébf47aeb2009-10-15 00:15:40 +02005248 struct http_txn *txn = &t->txn;
5249 appsess *asession = NULL;
5250 char *sessid_temp = NULL;
5251
Cyril Bontéb21570a2009-11-29 20:04:48 +01005252 if (len > t->be->appsession_len) {
5253 len = t->be->appsession_len;
5254 }
5255
Cyril Bontébf47aeb2009-10-15 00:15:40 +02005256 if (t->be->options2 & PR_O2_AS_REQL) {
5257 /* request-learn option is enabled : store the sessid in the session for future use */
Willy Tarreaua3377ee2010-01-10 10:49:11 +01005258 if (txn->sessid != NULL) {
Cyril Bontébf47aeb2009-10-15 00:15:40 +02005259 /* free previously allocated memory as we don't need the session id found in the URL anymore */
Willy Tarreaua3377ee2010-01-10 10:49:11 +01005260 pool_free2(apools.sessid, txn->sessid);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02005261 }
5262
Willy Tarreaua3377ee2010-01-10 10:49:11 +01005263 if ((txn->sessid = pool_alloc2(apools.sessid)) == NULL) {
Cyril Bontébf47aeb2009-10-15 00:15:40 +02005264 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
5265 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
5266 return;
5267 }
5268
Willy Tarreaua3377ee2010-01-10 10:49:11 +01005269 memcpy(txn->sessid, buf, len);
5270 txn->sessid[len] = 0;
Cyril Bontébf47aeb2009-10-15 00:15:40 +02005271 }
5272
5273 if ((sessid_temp = pool_alloc2(apools.sessid)) == NULL) {
5274 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
5275 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
5276 return;
5277 }
5278
Cyril Bontéb21570a2009-11-29 20:04:48 +01005279 memcpy(sessid_temp, buf, len);
5280 sessid_temp[len] = 0;
Cyril Bontébf47aeb2009-10-15 00:15:40 +02005281
5282 asession = appsession_hash_lookup(&(t->be->htbl_proxy), sessid_temp);
5283 /* free previously allocated memory */
5284 pool_free2(apools.sessid, sessid_temp);
5285
5286 if (asession != NULL) {
5287 asession->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
5288 if (!(t->be->options2 & PR_O2_AS_REQL))
5289 asession->request_count++;
5290
5291 if (asession->serverid != NULL) {
5292 struct server *srv = t->be->srv;
5293 while (srv) {
5294 if (strcmp(srv->id, asession->serverid) == 0) {
5295 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
5296 /* we found the server and it's usable */
5297 txn->flags &= ~TX_CK_MASK;
5298 txn->flags |= TX_CK_VALID;
5299 t->flags |= SN_DIRECT | SN_ASSIGNED;
5300 t->srv = srv;
5301 break;
5302 } else {
5303 txn->flags &= ~TX_CK_MASK;
5304 txn->flags |= TX_CK_DOWN;
5305 }
5306 }
5307 srv = srv->next;
5308 }
5309 }
5310 }
5311}
5312
5313/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01005314 * Manage client-side cookie. It can impact performance by about 2% so it is
5315 * desirable to call it only when needed.
Willy Tarreau58f10d72006-12-04 02:26:12 +01005316 */
5317void manage_client_side_cookies(struct session *t, struct buffer *req)
5318{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005319 struct http_txn *txn = &t->txn;
Willy Tarreau305ae852010-01-03 19:45:54 +01005320 char *p1, *p2, *p3, *p4, *p5;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005321 char *del_colon, *del_cookie, *colon;
5322 int app_cookies;
5323
Willy Tarreau58f10d72006-12-04 02:26:12 +01005324 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01005325 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005326
Willy Tarreau2a324282006-12-05 00:05:46 +01005327 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01005328 * we start with the start line.
5329 */
Willy Tarreau83969f42007-01-22 08:55:47 +01005330 old_idx = 0;
Willy Tarreau962c3f42010-01-10 00:15:35 +01005331 cur_next = txn->req.sol + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005332
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005333 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005334 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005335 int val;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005336
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005337 cur_hdr = &txn->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01005338 cur_ptr = cur_next;
5339 cur_end = cur_ptr + cur_hdr->len;
5340 cur_next = cur_end + cur_hdr->cr + 1;
5341
5342 /* We have one full header between cur_ptr and cur_end, and the
5343 * next header starts at cur_next. We're only interested in
5344 * "Cookie:" headers.
5345 */
5346
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005347 val = http_header_match2(cur_ptr, cur_end, "Cookie", 6);
5348 if (!val) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005349 old_idx = cur_idx;
5350 continue;
5351 }
5352
5353 /* Now look for cookies. Conforming to RFC2109, we have to support
5354 * attributes whose name begin with a '$', and associate them with
5355 * the right cookie, if we want to delete this cookie.
5356 * So there are 3 cases for each cookie read :
5357 * 1) it's a special attribute, beginning with a '$' : ignore it.
5358 * 2) it's a server id cookie that we *MAY* want to delete : save
5359 * some pointers on it (last semi-colon, beginning of cookie...)
5360 * 3) it's an application cookie : we *MAY* have to delete a previous
5361 * "special" cookie.
5362 * At the end of loop, if a "special" cookie remains, we may have to
5363 * remove it. If no application cookie persists in the header, we
5364 * *MUST* delete it
5365 */
5366
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005367 colon = p1 = cur_ptr + val; /* first non-space char after 'Cookie:' */
Willy Tarreau58f10d72006-12-04 02:26:12 +01005368
Willy Tarreau58f10d72006-12-04 02:26:12 +01005369 /* del_cookie == NULL => nothing to be deleted */
5370 del_colon = del_cookie = NULL;
5371 app_cookies = 0;
5372
5373 while (p1 < cur_end) {
5374 /* skip spaces and colons, but keep an eye on these ones */
Willy Tarreau305ae852010-01-03 19:45:54 +01005375 resync_name:
Willy Tarreau58f10d72006-12-04 02:26:12 +01005376 while (p1 < cur_end) {
5377 if (*p1 == ';' || *p1 == ',')
5378 colon = p1;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02005379 else if (!isspace((unsigned char)*p1))
Willy Tarreau58f10d72006-12-04 02:26:12 +01005380 break;
5381 p1++;
5382 }
5383
5384 if (p1 == cur_end)
5385 break;
5386
5387 /* p1 is at the beginning of the cookie name */
5388 p2 = p1;
Willy Tarreau305ae852010-01-03 19:45:54 +01005389 while (p2 < cur_end && *p2 != '=') {
5390 if (*p2 == ',' || *p2 == ';' || isspace((unsigned char)*p2)) {
5391 /* oops, the cookie name was truncated, resync */
5392 p1 = p2;
5393 goto resync_name;
5394 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01005395 p2++;
Willy Tarreau305ae852010-01-03 19:45:54 +01005396 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01005397
5398 if (p2 == cur_end)
5399 break;
5400
5401 p3 = p2 + 1; /* skips the '=' sign */
5402 if (p3 == cur_end)
5403 break;
5404
Willy Tarreau305ae852010-01-03 19:45:54 +01005405 /* parse the value, stripping leading and trailing spaces but keeping insiders. */
5406 p5 = p4 = p3;
5407 while (p5 < cur_end && *p5 != ';' && *p5 != ',') {
5408 if (!isspace((unsigned char)*p5))
5409 p4 = p5 + 1;
5410 p5++;
5411 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01005412
5413 /* here, we have the cookie name between p1 and p2,
5414 * and its value between p3 and p4.
5415 * we can process it :
5416 *
Willy Tarreau305ae852010-01-03 19:45:54 +01005417 * Cookie: NAME=VALUE ;
5418 * | || || |+-> p5
Willy Tarreau58f10d72006-12-04 02:26:12 +01005419 * | || || +--> p4
5420 * | || |+-------> p3
5421 * | || +--------> p2
5422 * | |+------------> p1
5423 * | +-------------> colon
5424 * +--------------------> cur_ptr
5425 */
5426
5427 if (*p1 == '$') {
5428 /* skip this one */
5429 }
5430 else {
5431 /* first, let's see if we want to capture it */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005432 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005433 txn->cli_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005434 (p4 - p1 >= t->fe->capture_namelen) &&
5435 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005436 int log_len = p4 - p1;
5437
Willy Tarreau086b3b42007-05-13 21:45:51 +02005438 if ((txn->cli_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005439 Alert("HTTP logging : out of memory.\n");
5440 } else {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005441 if (log_len > t->fe->capture_len)
5442 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005443 memcpy(txn->cli_cookie, p1, log_len);
5444 txn->cli_cookie[log_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005445 }
5446 }
5447
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005448 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
5449 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005450 /* Cool... it's the right one */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005451 struct server *srv = t->be->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005452 char *delim;
5453
5454 /* if we're in cookie prefix mode, we'll search the delimitor so that we
5455 * have the server ID betweek p3 and delim, and the original cookie between
5456 * delim+1 and p4. Otherwise, delim==p4 :
5457 *
Willy Tarreau305ae852010-01-03 19:45:54 +01005458 * Cookie: NAME=SRV~VALUE ;
5459 * | || || | |+-> p5
Willy Tarreau58f10d72006-12-04 02:26:12 +01005460 * | || || | +--> p4
5461 * | || || +--------> delim
5462 * | || |+-----------> p3
5463 * | || +------------> p2
5464 * | |+----------------> p1
5465 * | +-----------------> colon
5466 * +------------------------> cur_ptr
5467 */
5468
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005469 if (t->be->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005470 for (delim = p3; delim < p4; delim++)
5471 if (*delim == COOKIE_DELIM)
5472 break;
5473 }
5474 else
5475 delim = p4;
5476
5477
5478 /* Here, we'll look for the first running server which supports the cookie.
5479 * This allows to share a same cookie between several servers, for example
5480 * to dedicate backup servers to specific servers only.
5481 * However, to prevent clients from sticking to cookie-less backup server
5482 * when they have incidentely learned an empty cookie, we simply ignore
5483 * empty cookies and mark them as invalid.
5484 */
5485 if (delim == p3)
5486 srv = NULL;
5487
5488 while (srv) {
Willy Tarreau92f2ab12007-02-02 22:14:47 +01005489 if (srv->cookie && (srv->cklen == delim - p3) &&
5490 !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005491 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005492 /* we found the server and it's usable */
Willy Tarreau3d300592007-03-18 18:34:41 +01005493 txn->flags &= ~TX_CK_MASK;
5494 txn->flags |= TX_CK_VALID;
5495 t->flags |= SN_DIRECT | SN_ASSIGNED;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005496 t->srv = srv;
5497 break;
5498 } else {
5499 /* we found a server, but it's down */
Willy Tarreau3d300592007-03-18 18:34:41 +01005500 txn->flags &= ~TX_CK_MASK;
5501 txn->flags |= TX_CK_DOWN;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005502 }
5503 }
5504 srv = srv->next;
5505 }
5506
Willy Tarreau3d300592007-03-18 18:34:41 +01005507 if (!srv && !(txn->flags & TX_CK_DOWN)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005508 /* no server matched this cookie */
Willy Tarreau3d300592007-03-18 18:34:41 +01005509 txn->flags &= ~TX_CK_MASK;
5510 txn->flags |= TX_CK_INVALID;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005511 }
5512
5513 /* depending on the cookie mode, we may have to either :
5514 * - delete the complete cookie if we're in insert+indirect mode, so that
5515 * the server never sees it ;
5516 * - remove the server id from the cookie value, and tag the cookie as an
5517 * application cookie so that it does not get accidentely removed later,
5518 * if we're in cookie prefix mode
5519 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005520 if ((t->be->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01005521 int delta; /* negative */
5522
5523 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
5524 p4 += delta;
Willy Tarreau305ae852010-01-03 19:45:54 +01005525 p5 += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005526 cur_end += delta;
5527 cur_next += delta;
5528 cur_hdr->len += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01005529 http_msg_move_end(&txn->req, delta);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005530
5531 del_cookie = del_colon = NULL;
5532 app_cookies++; /* protect the header from deletion */
5533 }
5534 else if (del_cookie == NULL &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005535 (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 +01005536 del_cookie = p1;
5537 del_colon = colon;
5538 }
5539 } else {
5540 /* now we know that we must keep this cookie since it's
5541 * not ours. But if we wanted to delete our cookie
5542 * earlier, we cannot remove the complete header, but we
5543 * can remove the previous block itself.
5544 */
5545 app_cookies++;
5546
5547 if (del_cookie != NULL) {
5548 int delta; /* negative */
5549
5550 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
5551 p4 += delta;
Willy Tarreau305ae852010-01-03 19:45:54 +01005552 p5 += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005553 cur_end += delta;
5554 cur_next += delta;
5555 cur_hdr->len += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01005556 http_msg_move_end(&txn->req, delta);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005557 del_cookie = del_colon = NULL;
5558 }
5559 }
5560
Cyril Bontéb21570a2009-11-29 20:04:48 +01005561 if (t->be->appsession_name != NULL) {
5562 int cmp_len, value_len;
5563 char *value_begin;
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02005564
Cyril Bontéb21570a2009-11-29 20:04:48 +01005565 if (t->be->options2 & PR_O2_AS_PFX) {
5566 cmp_len = MIN(p4 - p1, t->be->appsession_name_len);
5567 value_begin = p1 + t->be->appsession_name_len;
5568 value_len = p4 - p1 - t->be->appsession_name_len;
5569 } else {
5570 cmp_len = p2 - p1;
5571 value_begin = p3;
5572 value_len = p4 - p3;
5573 }
5574
5575 /* let's see if the cookie is our appcookie */
5576 if (memcmp(p1, t->be->appsession_name, cmp_len) == 0) {
5577 /* Cool... it's the right one */
5578 manage_client_side_appsession(t, value_begin, value_len);
5579 }
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02005580#if defined(DEBUG_HASH)
5581 Alert("manage_client_side_cookies\n");
5582 appsession_hash_dump(&(t->be->htbl_proxy));
5583#endif
Willy Tarreau58f10d72006-12-04 02:26:12 +01005584 }/* end if ((t->proxy->appsession_name != NULL) ... */
5585 }
5586
5587 /* we'll have to look for another cookie ... */
Willy Tarreau305ae852010-01-03 19:45:54 +01005588 p1 = p5;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005589 } /* while (p1 < cur_end) */
5590
5591 /* There's no more cookie on this line.
5592 * We may have marked the last one(s) for deletion.
5593 * We must do this now in two ways :
5594 * - if there is no app cookie, we simply delete the header ;
5595 * - if there are app cookies, we must delete the end of the
5596 * string properly, including the colon/semi-colon before
5597 * the cookie name.
5598 */
5599 if (del_cookie != NULL) {
5600 int delta;
5601 if (app_cookies) {
5602 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
5603 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005604 cur_hdr->len += delta;
5605 } else {
5606 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005607
5608 /* FIXME: this should be a separate function */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01005609 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
5610 txn->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01005611 cur_hdr->len = 0;
5612 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01005613 cur_next += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01005614 http_msg_move_end(&txn->req, delta);
Willy Tarreau58f10d72006-12-04 02:26:12 +01005615 }
5616
5617 /* keep the link from this header to next one */
5618 old_idx = cur_idx;
5619 } /* end of cookie processing on this header */
5620}
5621
5622
Willy Tarreaua15645d2007-03-18 16:22:39 +01005623/* Iterate the same filter through all response headers contained in <rtr>.
5624 * Returns 1 if this filter can be stopped upon return, otherwise 0.
5625 */
5626int apply_filter_to_resp_headers(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
5627{
5628 char term;
5629 char *cur_ptr, *cur_end, *cur_next;
5630 int cur_idx, old_idx, last_hdr;
5631 struct http_txn *txn = &t->txn;
5632 struct hdr_idx_elem *cur_hdr;
5633 int len, delta;
5634
5635 last_hdr = 0;
5636
Willy Tarreau962c3f42010-01-10 00:15:35 +01005637 cur_next = txn->rsp.sol + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreaua15645d2007-03-18 16:22:39 +01005638 old_idx = 0;
5639
5640 while (!last_hdr) {
Willy Tarreau3d300592007-03-18 18:34:41 +01005641 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01005642 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01005643 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01005644 (exp->action == ACT_ALLOW ||
5645 exp->action == ACT_DENY))
5646 return 0;
5647
5648 cur_idx = txn->hdr_idx.v[old_idx].next;
5649 if (!cur_idx)
5650 break;
5651
5652 cur_hdr = &txn->hdr_idx.v[cur_idx];
5653 cur_ptr = cur_next;
5654 cur_end = cur_ptr + cur_hdr->len;
5655 cur_next = cur_end + cur_hdr->cr + 1;
5656
5657 /* Now we have one header between cur_ptr and cur_end,
5658 * and the next header starts at cur_next.
5659 */
5660
5661 /* The annoying part is that pattern matching needs
5662 * that we modify the contents to null-terminate all
5663 * strings before testing them.
5664 */
5665
5666 term = *cur_end;
5667 *cur_end = '\0';
5668
5669 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
5670 switch (exp->action) {
5671 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01005672 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005673 last_hdr = 1;
5674 break;
5675
5676 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01005677 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005678 last_hdr = 1;
5679 break;
5680
5681 case ACT_REPLACE:
5682 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
5683 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
5684 /* FIXME: if the user adds a newline in the replacement, the
5685 * index will not be recalculated for now, and the new line
5686 * will not be counted as a new header.
5687 */
5688
5689 cur_end += delta;
5690 cur_next += delta;
5691 cur_hdr->len += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01005692 http_msg_move_end(&txn->rsp, delta);
Willy Tarreaua15645d2007-03-18 16:22:39 +01005693 break;
5694
5695 case ACT_REMOVE:
5696 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
5697 cur_next += delta;
5698
Willy Tarreaufa355d42009-11-29 18:12:29 +01005699 http_msg_move_end(&txn->rsp, delta);
Willy Tarreaua15645d2007-03-18 16:22:39 +01005700 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
5701 txn->hdr_idx.used--;
5702 cur_hdr->len = 0;
5703 cur_end = NULL; /* null-term has been rewritten */
5704 break;
5705
5706 }
5707 }
5708 if (cur_end)
5709 *cur_end = term; /* restore the string terminator */
5710
5711 /* keep the link from this header to next one in case of later
5712 * removal of next header.
5713 */
5714 old_idx = cur_idx;
5715 }
5716 return 0;
5717}
5718
5719
5720/* Apply the filter to the status line in the response buffer <rtr>.
5721 * Returns 0 if nothing has been done, 1 if the filter has been applied,
5722 * or -1 if a replacement resulted in an invalid status line.
5723 */
5724int apply_filter_to_sts_line(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
5725{
5726 char term;
5727 char *cur_ptr, *cur_end;
5728 int done;
5729 struct http_txn *txn = &t->txn;
5730 int len, delta;
5731
5732
Willy Tarreau3d300592007-03-18 18:34:41 +01005733 if (unlikely(txn->flags & TX_SVDENY))
Willy Tarreaua15645d2007-03-18 16:22:39 +01005734 return 1;
Willy Tarreau3d300592007-03-18 18:34:41 +01005735 else if (unlikely(txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01005736 (exp->action == ACT_ALLOW ||
5737 exp->action == ACT_DENY))
5738 return 0;
5739 else if (exp->action == ACT_REMOVE)
5740 return 0;
5741
5742 done = 0;
5743
Willy Tarreau962c3f42010-01-10 00:15:35 +01005744 cur_ptr = txn->rsp.sol;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005745 cur_end = cur_ptr + txn->rsp.sl.rq.l;
5746
5747 /* Now we have the status line between cur_ptr and cur_end */
5748
5749 /* The annoying part is that pattern matching needs
5750 * that we modify the contents to null-terminate all
5751 * strings before testing them.
5752 */
5753
5754 term = *cur_end;
5755 *cur_end = '\0';
5756
5757 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
5758 switch (exp->action) {
5759 case ACT_ALLOW:
Willy Tarreau3d300592007-03-18 18:34:41 +01005760 txn->flags |= TX_SVALLOW;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005761 done = 1;
5762 break;
5763
5764 case ACT_DENY:
Willy Tarreau3d300592007-03-18 18:34:41 +01005765 txn->flags |= TX_SVDENY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005766 done = 1;
5767 break;
5768
5769 case ACT_REPLACE:
5770 *cur_end = term; /* restore the string terminator */
5771 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
5772 delta = buffer_replace2(rtr, cur_ptr, cur_end, trash, len);
5773 /* FIXME: if the user adds a newline in the replacement, the
5774 * index will not be recalculated for now, and the new line
5775 * will not be counted as a new header.
5776 */
5777
Willy Tarreaufa355d42009-11-29 18:12:29 +01005778 http_msg_move_end(&txn->rsp, delta);
Willy Tarreaua15645d2007-03-18 16:22:39 +01005779 cur_end += delta;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005780 cur_end = (char *)http_parse_stsline(&txn->rsp, rtr->data,
Willy Tarreau02785762007-04-03 14:45:44 +02005781 HTTP_MSG_RPVER,
Willy Tarreaua15645d2007-03-18 16:22:39 +01005782 cur_ptr, cur_end + 1,
5783 NULL, NULL);
5784 if (unlikely(!cur_end))
5785 return -1;
5786
5787 /* we have a full respnse and we know that we have either a CR
5788 * or an LF at <ptr>.
5789 */
Willy Tarreau962c3f42010-01-10 00:15:35 +01005790 txn->status = strl2ui(txn->rsp.sol + txn->rsp.sl.st.c, txn->rsp.sl.st.c_l);
Willy Tarreaua15645d2007-03-18 16:22:39 +01005791 hdr_idx_set_start(&txn->hdr_idx, txn->rsp.sl.rq.l, *cur_end == '\r');
5792 /* there is no point trying this regex on headers */
5793 return 1;
5794 }
5795 }
5796 *cur_end = term; /* restore the string terminator */
5797 return done;
5798}
5799
5800
5801
5802/*
5803 * Apply all the resp filters <exp> to all headers in buffer <rtr> of session <t>.
5804 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
5805 * unparsable response.
5806 */
5807int apply_filters_to_response(struct session *t, struct buffer *rtr, struct hdr_exp *exp)
5808{
Willy Tarreau3d300592007-03-18 18:34:41 +01005809 struct http_txn *txn = &t->txn;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005810 /* iterate through the filters in the outer loop */
Willy Tarreau3d300592007-03-18 18:34:41 +01005811 while (exp && !(txn->flags & TX_SVDENY)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01005812 int ret;
5813
5814 /*
5815 * The interleaving of transformations and verdicts
5816 * makes it difficult to decide to continue or stop
5817 * the evaluation.
5818 */
5819
Willy Tarreau3d300592007-03-18 18:34:41 +01005820 if ((txn->flags & TX_SVALLOW) &&
Willy Tarreaua15645d2007-03-18 16:22:39 +01005821 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
5822 exp->action == ACT_PASS)) {
5823 exp = exp->next;
5824 continue;
5825 }
5826
5827 /* Apply the filter to the status line. */
5828 ret = apply_filter_to_sts_line(t, rtr, exp);
5829 if (unlikely(ret < 0))
5830 return -1;
5831
5832 if (likely(ret == 0)) {
5833 /* The filter did not match the response, it can be
5834 * iterated through all headers.
5835 */
5836 apply_filter_to_resp_headers(t, rtr, exp);
5837 }
5838 exp = exp->next;
5839 }
5840 return 0;
5841}
5842
5843
5844
5845/*
Willy Tarreau396d2c62007-11-04 19:30:00 +01005846 * Manage server-side cookies. It can impact performance by about 2% so it is
5847 * desirable to call it only when needed.
Willy Tarreaua15645d2007-03-18 16:22:39 +01005848 */
5849void manage_server_side_cookies(struct session *t, struct buffer *rtr)
5850{
5851 struct http_txn *txn = &t->txn;
5852 char *p1, *p2, *p3, *p4;
5853
Willy Tarreaua15645d2007-03-18 16:22:39 +01005854 char *cur_ptr, *cur_end, *cur_next;
5855 int cur_idx, old_idx, delta;
5856
Willy Tarreaua15645d2007-03-18 16:22:39 +01005857 /* Iterate through the headers.
5858 * we start with the start line.
5859 */
5860 old_idx = 0;
Willy Tarreau962c3f42010-01-10 00:15:35 +01005861 cur_next = txn->rsp.sol + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreaua15645d2007-03-18 16:22:39 +01005862
5863 while ((cur_idx = txn->hdr_idx.v[old_idx].next)) {
5864 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005865 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005866
5867 cur_hdr = &txn->hdr_idx.v[cur_idx];
5868 cur_ptr = cur_next;
5869 cur_end = cur_ptr + cur_hdr->len;
5870 cur_next = cur_end + cur_hdr->cr + 1;
5871
5872 /* We have one full header between cur_ptr and cur_end, and the
5873 * next header starts at cur_next. We're only interested in
5874 * "Cookie:" headers.
5875 */
5876
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005877 val = http_header_match2(cur_ptr, cur_end, "Set-Cookie", 10);
5878 if (!val) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01005879 old_idx = cur_idx;
5880 continue;
5881 }
5882
5883 /* OK, right now we know we have a set-cookie at cur_ptr */
Willy Tarreau3d300592007-03-18 18:34:41 +01005884 txn->flags |= TX_SCK_ANY;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005885
5886
Willy Tarreaufd39dda2008-10-17 12:01:58 +02005887 /* maybe we only wanted to see if there was a set-cookie. Note that
5888 * the cookie capture is declared in the fronend.
5889 */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005890 if (t->be->cookie_name == NULL &&
5891 t->be->appsession_name == NULL &&
Willy Tarreaufd39dda2008-10-17 12:01:58 +02005892 t->fe->capture_name == NULL)
Willy Tarreaua15645d2007-03-18 16:22:39 +01005893 return;
5894
Willy Tarreauaa9dce32007-03-18 23:50:16 +01005895 p1 = cur_ptr + val; /* first non-space char after 'Set-Cookie:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01005896
5897 while (p1 < cur_end) { /* in fact, we'll break after the first cookie */
Willy Tarreaua15645d2007-03-18 16:22:39 +01005898 if (p1 == cur_end || *p1 == ';') /* end of cookie */
5899 break;
5900
5901 /* p1 is at the beginning of the cookie name */
5902 p2 = p1;
5903
5904 while (p2 < cur_end && *p2 != '=' && *p2 != ';')
5905 p2++;
5906
5907 if (p2 == cur_end || *p2 == ';') /* next cookie */
5908 break;
5909
5910 p3 = p2 + 1; /* skip the '=' sign */
5911 if (p3 == cur_end)
5912 break;
5913
5914 p4 = p3;
Willy Tarreau8f8e6452007-06-17 21:51:38 +02005915 while (p4 < cur_end && !isspace((unsigned char)*p4) && *p4 != ';')
Willy Tarreaua15645d2007-03-18 16:22:39 +01005916 p4++;
5917
5918 /* here, we have the cookie name between p1 and p2,
5919 * and its value between p3 and p4.
5920 * we can process it.
5921 */
5922
5923 /* first, let's see if we want to capture it */
Willy Tarreaufd39dda2008-10-17 12:01:58 +02005924 if (t->fe->capture_name != NULL &&
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005925 txn->srv_cookie == NULL &&
Willy Tarreaufd39dda2008-10-17 12:01:58 +02005926 (p4 - p1 >= t->fe->capture_namelen) &&
5927 memcmp(p1, t->fe->capture_name, t->fe->capture_namelen) == 0) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01005928 int log_len = p4 - p1;
5929
Willy Tarreau086b3b42007-05-13 21:45:51 +02005930 if ((txn->srv_cookie = pool_alloc2(pool2_capture)) == NULL) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01005931 Alert("HTTP logging : out of memory.\n");
5932 }
5933
Willy Tarreaufd39dda2008-10-17 12:01:58 +02005934 if (log_len > t->fe->capture_len)
5935 log_len = t->fe->capture_len;
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01005936 memcpy(txn->srv_cookie, p1, log_len);
5937 txn->srv_cookie[log_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005938 }
5939
5940 /* now check if we need to process it for persistence */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005941 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
5942 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01005943 /* Cool... it's the right one */
Willy Tarreau3d300592007-03-18 18:34:41 +01005944 txn->flags |= TX_SCK_SEEN;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005945
5946 /* If the cookie is in insert mode on a known server, we'll delete
5947 * this occurrence because we'll insert another one later.
5948 * We'll delete it too if the "indirect" option is set and we're in
5949 * a direct access. */
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005950 if (((t->srv) && (t->be->options & PR_O_COOK_INS)) ||
5951 ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01005952 /* this header must be deleted */
5953 delta = buffer_replace2(rtr, cur_ptr, cur_next, NULL, 0);
5954 txn->hdr_idx.v[old_idx].next = cur_hdr->next;
5955 txn->hdr_idx.used--;
5956 cur_hdr->len = 0;
5957 cur_next += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01005958 http_msg_move_end(&txn->rsp, delta);
Willy Tarreaua15645d2007-03-18 16:22:39 +01005959
Willy Tarreau3d300592007-03-18 18:34:41 +01005960 txn->flags |= TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005961 }
5962 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005963 (t->be->options & PR_O_COOK_RW)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01005964 /* replace bytes p3->p4 with the cookie name associated
5965 * with this server since we know it.
5966 */
5967 delta = buffer_replace2(rtr, p3, p4, t->srv->cookie, t->srv->cklen);
5968 cur_hdr->len += delta;
5969 cur_next += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01005970 http_msg_move_end(&txn->rsp, delta);
Willy Tarreaua15645d2007-03-18 16:22:39 +01005971
Willy Tarreau3d300592007-03-18 18:34:41 +01005972 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005973 }
5974 else if ((t->srv) && (t->srv->cookie) &&
Willy Tarreaue2e27a52007-04-01 00:01:37 +02005975 (t->be->options & PR_O_COOK_PFX)) {
Willy Tarreaua15645d2007-03-18 16:22:39 +01005976 /* insert the cookie name associated with this server
5977 * before existing cookie, and insert a delimitor between them..
5978 */
5979 delta = buffer_replace2(rtr, p3, p3, t->srv->cookie, t->srv->cklen + 1);
5980 cur_hdr->len += delta;
5981 cur_next += delta;
Willy Tarreaufa355d42009-11-29 18:12:29 +01005982 http_msg_move_end(&txn->rsp, delta);
Willy Tarreaua15645d2007-03-18 16:22:39 +01005983
5984 p3[t->srv->cklen] = COOKIE_DELIM;
Willy Tarreau3d300592007-03-18 18:34:41 +01005985 txn->flags |= TX_SCK_INSERTED | TX_SCK_DELETED;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005986 }
5987 }
5988 /* next, let's see if the cookie is our appcookie */
Cyril Bontéb21570a2009-11-29 20:04:48 +01005989 else if (t->be->appsession_name != NULL) {
5990 int cmp_len, value_len;
5991 char *value_begin;
Willy Tarreaua15645d2007-03-18 16:22:39 +01005992
Cyril Bontéb21570a2009-11-29 20:04:48 +01005993 if (t->be->options2 & PR_O2_AS_PFX) {
5994 cmp_len = MIN(p4 - p1, t->be->appsession_name_len);
5995 value_begin = p1 + t->be->appsession_name_len;
5996 value_len = MIN(t->be->appsession_len, p4 - p1 - t->be->appsession_name_len);
5997 } else {
5998 cmp_len = p2 - p1;
5999 value_begin = p3;
6000 value_len = MIN(t->be->appsession_len, p4 - p3);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02006001 }
Cyril Bontéb21570a2009-11-29 20:04:48 +01006002
6003 if (memcmp(p1, t->be->appsession_name, cmp_len) == 0) {
6004 /* Cool... it's the right one */
Willy Tarreaua3377ee2010-01-10 10:49:11 +01006005 if (txn->sessid != NULL) {
Cyril Bontéb21570a2009-11-29 20:04:48 +01006006 /* free previously allocated memory as we don't need it anymore */
Willy Tarreaua3377ee2010-01-10 10:49:11 +01006007 pool_free2(apools.sessid, txn->sessid);
Cyril Bontéb21570a2009-11-29 20:04:48 +01006008 }
6009 /* Store the sessid in the session for future use */
Willy Tarreaua3377ee2010-01-10 10:49:11 +01006010 if ((txn->sessid = pool_alloc2(apools.sessid)) == NULL) {
Cyril Bontéb21570a2009-11-29 20:04:48 +01006011 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
6012 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
6013 return;
6014 }
Willy Tarreaua3377ee2010-01-10 10:49:11 +01006015 memcpy(txn->sessid, value_begin, value_len);
6016 txn->sessid[value_len] = 0;
Willy Tarreaua15645d2007-03-18 16:22:39 +01006017 }
Cyril Bontéb21570a2009-11-29 20:04:48 +01006018 } /* end if ((t->be->appsession_name != NULL) ... */
Willy Tarreaua15645d2007-03-18 16:22:39 +01006019 break; /* we don't want to loop again since there cannot be another cookie on the same line */
6020 } /* we're now at the end of the cookie value */
Willy Tarreaua15645d2007-03-18 16:22:39 +01006021 /* keep the link from this header to next one */
6022 old_idx = cur_idx;
6023 } /* end of cookie processing on this header */
Cyril Bontébf47aeb2009-10-15 00:15:40 +02006024
Willy Tarreaua3377ee2010-01-10 10:49:11 +01006025 if (txn->sessid != NULL) {
Cyril Bontébf47aeb2009-10-15 00:15:40 +02006026 appsess *asession = NULL;
6027 /* only do insert, if lookup fails */
Willy Tarreaua3377ee2010-01-10 10:49:11 +01006028 asession = appsession_hash_lookup(&(t->be->htbl_proxy), txn->sessid);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02006029 if (asession == NULL) {
Willy Tarreau1fac7532010-01-09 19:23:06 +01006030 size_t server_id_len;
Cyril Bontébf47aeb2009-10-15 00:15:40 +02006031 if ((asession = pool_alloc2(pool2_appsess)) == NULL) {
6032 Alert("Not enough Memory process_srv():asession:calloc().\n");
6033 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession:calloc().\n");
6034 return;
6035 }
6036 if ((asession->sessid = pool_alloc2(apools.sessid)) == NULL) {
6037 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
6038 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
Cyril Bonté41689c22010-01-10 00:30:14 +01006039 t->be->htbl_proxy.destroy(asession);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02006040 return;
6041 }
Willy Tarreaua3377ee2010-01-10 10:49:11 +01006042 memcpy(asession->sessid, txn->sessid, t->be->appsession_len);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02006043 asession->sessid[t->be->appsession_len] = 0;
6044
Willy Tarreau1fac7532010-01-09 19:23:06 +01006045 server_id_len = strlen(t->srv->id) + 1;
Cyril Bontébf47aeb2009-10-15 00:15:40 +02006046 if ((asession->serverid = pool_alloc2(apools.serverid)) == NULL) {
6047 Alert("Not enough Memory process_srv():asession->sessid:malloc().\n");
6048 send_log(t->be, LOG_ALERT, "Not enough Memory process_srv():asession->sessid:malloc().\n");
Cyril Bonté41689c22010-01-10 00:30:14 +01006049 t->be->htbl_proxy.destroy(asession);
Cyril Bontébf47aeb2009-10-15 00:15:40 +02006050 return;
6051 }
6052 asession->serverid[0] = '\0';
6053 memcpy(asession->serverid, t->srv->id, server_id_len);
6054
6055 asession->request_count = 0;
6056 appsession_hash_insert(&(t->be->htbl_proxy), asession);
6057 }
6058
6059 asession->expire = tick_add_ifset(now_ms, t->be->timeout.appsession);
6060 asession->request_count++;
6061 }
6062
6063#if defined(DEBUG_HASH)
6064 Alert("manage_server_side_cookies\n");
6065 appsession_hash_dump(&(t->be->htbl_proxy));
6066#endif
Willy Tarreaua15645d2007-03-18 16:22:39 +01006067}
6068
6069
6070
6071/*
6072 * Check if response is cacheable or not. Updates t->flags.
6073 */
6074void check_response_for_cacheability(struct session *t, struct buffer *rtr)
6075{
6076 struct http_txn *txn = &t->txn;
6077 char *p1, *p2;
6078
6079 char *cur_ptr, *cur_end, *cur_next;
6080 int cur_idx;
6081
Willy Tarreau5df51872007-11-25 16:20:08 +01006082 if (!(txn->flags & TX_CACHEABLE))
Willy Tarreaua15645d2007-03-18 16:22:39 +01006083 return;
6084
6085 /* Iterate through the headers.
6086 * we start with the start line.
6087 */
6088 cur_idx = 0;
Willy Tarreau962c3f42010-01-10 00:15:35 +01006089 cur_next = txn->rsp.sol + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreaua15645d2007-03-18 16:22:39 +01006090
6091 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
6092 struct hdr_idx_elem *cur_hdr;
Willy Tarreauaa9dce32007-03-18 23:50:16 +01006093 int val;
Willy Tarreaua15645d2007-03-18 16:22:39 +01006094
6095 cur_hdr = &txn->hdr_idx.v[cur_idx];
6096 cur_ptr = cur_next;
6097 cur_end = cur_ptr + cur_hdr->len;
6098 cur_next = cur_end + cur_hdr->cr + 1;
6099
6100 /* We have one full header between cur_ptr and cur_end, and the
6101 * next header starts at cur_next. We're only interested in
6102 * "Cookie:" headers.
6103 */
6104
Willy Tarreauaa9dce32007-03-18 23:50:16 +01006105 val = http_header_match2(cur_ptr, cur_end, "Pragma", 6);
6106 if (val) {
6107 if ((cur_end - (cur_ptr + val) >= 8) &&
6108 strncasecmp(cur_ptr + val, "no-cache", 8) == 0) {
6109 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
6110 return;
6111 }
Willy Tarreaua15645d2007-03-18 16:22:39 +01006112 }
6113
Willy Tarreauaa9dce32007-03-18 23:50:16 +01006114 val = http_header_match2(cur_ptr, cur_end, "Cache-control", 13);
6115 if (!val)
Willy Tarreaua15645d2007-03-18 16:22:39 +01006116 continue;
6117
6118 /* OK, right now we know we have a cache-control header at cur_ptr */
6119
Willy Tarreauaa9dce32007-03-18 23:50:16 +01006120 p1 = cur_ptr + val; /* first non-space char after 'cache-control:' */
Willy Tarreaua15645d2007-03-18 16:22:39 +01006121
6122 if (p1 >= cur_end) /* no more info */
6123 continue;
6124
6125 /* p1 is at the beginning of the value */
6126 p2 = p1;
6127
Willy Tarreau8f8e6452007-06-17 21:51:38 +02006128 while (p2 < cur_end && *p2 != '=' && *p2 != ',' && !isspace((unsigned char)*p2))
Willy Tarreaua15645d2007-03-18 16:22:39 +01006129 p2++;
6130
6131 /* we have a complete value between p1 and p2 */
6132 if (p2 < cur_end && *p2 == '=') {
6133 /* we have something of the form no-cache="set-cookie" */
6134 if ((cur_end - p1 >= 21) &&
6135 strncasecmp(p1, "no-cache=\"set-cookie", 20) == 0
6136 && (p1[20] == '"' || p1[20] == ','))
Willy Tarreau3d300592007-03-18 18:34:41 +01006137 txn->flags &= ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01006138 continue;
6139 }
6140
6141 /* OK, so we know that either p2 points to the end of string or to a comma */
6142 if (((p2 - p1 == 7) && strncasecmp(p1, "private", 7) == 0) ||
6143 ((p2 - p1 == 8) && strncasecmp(p1, "no-store", 8) == 0) ||
6144 ((p2 - p1 == 9) && strncasecmp(p1, "max-age=0", 9) == 0) ||
6145 ((p2 - p1 == 10) && strncasecmp(p1, "s-maxage=0", 10) == 0)) {
Willy Tarreau3d300592007-03-18 18:34:41 +01006146 txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01006147 return;
6148 }
6149
6150 if ((p2 - p1 == 6) && strncasecmp(p1, "public", 6) == 0) {
Willy Tarreau3d300592007-03-18 18:34:41 +01006151 txn->flags |= TX_CACHEABLE | TX_CACHE_COOK;
Willy Tarreaua15645d2007-03-18 16:22:39 +01006152 continue;
6153 }
6154 }
6155}
6156
6157
Willy Tarreau58f10d72006-12-04 02:26:12 +01006158/*
6159 * Try to retrieve a known appsession in the URI, then the associated server.
6160 * If the server is found, it's assigned to the session.
6161 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006162void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01006163{
Cyril Bontéb21570a2009-11-29 20:04:48 +01006164 char *end_params, *first_param, *cur_param, *next_param;
6165 char separator;
6166 int value_len;
6167
6168 int mode = t->be->options2 & PR_O2_AS_M_ANY;
Willy Tarreau58f10d72006-12-04 02:26:12 +01006169
Willy Tarreaue2e27a52007-04-01 00:01:37 +02006170 if (t->be->appsession_name == NULL ||
Cyril Bontéb21570a2009-11-29 20:04:48 +01006171 (t->txn.meth != HTTP_METH_GET && t->txn.meth != HTTP_METH_POST)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01006172 return;
Cyril Bontéb21570a2009-11-29 20:04:48 +01006173 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01006174
Cyril Bontéb21570a2009-11-29 20:04:48 +01006175 first_param = NULL;
6176 switch (mode) {
6177 case PR_O2_AS_M_PP:
6178 first_param = memchr(begin, ';', len);
6179 break;
6180 case PR_O2_AS_M_QS:
6181 first_param = memchr(begin, '?', len);
6182 break;
6183 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01006184
Cyril Bontéb21570a2009-11-29 20:04:48 +01006185 if (first_param == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01006186 return;
Cyril Bontéb21570a2009-11-29 20:04:48 +01006187 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01006188
Cyril Bontéb21570a2009-11-29 20:04:48 +01006189 switch (mode) {
6190 case PR_O2_AS_M_PP:
6191 if ((end_params = memchr(first_param, '?', len - (begin - first_param))) == NULL) {
6192 end_params = (char *) begin + len;
6193 }
6194 separator = ';';
6195 break;
6196 case PR_O2_AS_M_QS:
6197 end_params = (char *) begin + len;
6198 separator = '&';
6199 break;
6200 default:
6201 /* unknown mode, shouldn't happen */
6202 return;
6203 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01006204
Cyril Bontéb21570a2009-11-29 20:04:48 +01006205 cur_param = next_param = end_params;
6206 while (cur_param > first_param) {
6207 cur_param--;
6208 if ((cur_param[0] == separator) || (cur_param == first_param)) {
6209 /* let's see if this is the appsession parameter */
6210 if ((cur_param + t->be->appsession_name_len + 1 < next_param) &&
6211 ((t->be->options2 & PR_O2_AS_PFX) || cur_param[t->be->appsession_name_len + 1] == '=') &&
6212 (strncasecmp(cur_param + 1, t->be->appsession_name, t->be->appsession_name_len) == 0)) {
6213 /* Cool... it's the right one */
6214 cur_param += t->be->appsession_name_len + (t->be->options2 & PR_O2_AS_PFX ? 1 : 2);
6215 value_len = MIN(t->be->appsession_len, next_param - cur_param);
6216 if (value_len > 0) {
6217 manage_client_side_appsession(t, cur_param, value_len);
6218 }
6219 break;
6220 }
6221 next_param = cur_param;
6222 }
6223 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01006224#if defined(DEBUG_HASH)
Aleksandar Lazic697bbb02008-08-13 19:57:02 +02006225 Alert("get_srv_from_appsession\n");
Willy Tarreau51041c72007-09-09 21:56:53 +02006226 appsession_hash_dump(&(t->be->htbl_proxy));
Willy Tarreau58f10d72006-12-04 02:26:12 +01006227#endif
Willy Tarreau58f10d72006-12-04 02:26:12 +01006228}
6229
6230
Willy Tarreaub2513902006-12-17 14:52:38 +01006231/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01006232 * In a GET or HEAD request, check if the requested URI matches the stats uri
6233 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01006234 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01006235 * It is assumed that the request is either a HEAD or GET and that the
Willy Tarreaue2e27a52007-04-01 00:01:37 +02006236 * t->be->uri_auth field is valid. An HTTP/401 response may be sent, or
Willy Tarreaub0c9bc42009-10-04 15:56:38 +02006237 * the stats I/O handler will be registered to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01006238 *
6239 * Returns 1 if the session's state changes, otherwise 0.
6240 */
6241int stats_check_uri_auth(struct session *t, struct proxy *backend)
6242{
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01006243 struct http_txn *txn = &t->txn;
Willy Tarreaub2513902006-12-17 14:52:38 +01006244 struct uri_auth *uri_auth = backend->uri_auth;
6245 struct user_auth *user;
6246 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006247 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01006248
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01006249 memset(&t->data_ctx.stats, 0, sizeof(t->data_ctx.stats));
6250
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006251 /* check URI size */
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01006252 if (uri_auth->uri_len > txn->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01006253 return 0;
6254
Willy Tarreau962c3f42010-01-10 00:15:35 +01006255 h = txn->req.sol + txn->req.sl.rq.u;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01006256
Willy Tarreau0214c3a2007-01-07 13:47:30 +01006257 /* the URI is in h */
6258 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01006259 return 0;
6260
Willy Tarreaue7150cd2007-07-25 14:43:32 +02006261 h += uri_auth->uri_len;
Willy Tarreau962c3f42010-01-10 00:15:35 +01006262 while (h <= txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 3) {
Willy Tarreaue7150cd2007-07-25 14:43:32 +02006263 if (memcmp(h, ";up", 3) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01006264 t->data_ctx.stats.flags |= STAT_HIDE_DOWN;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02006265 break;
6266 }
6267 h++;
6268 }
6269
6270 if (uri_auth->refresh) {
Willy Tarreau962c3f42010-01-10 00:15:35 +01006271 h = txn->req.sol + txn->req.sl.rq.u + uri_auth->uri_len;
6272 while (h <= txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 10) {
Willy Tarreaue7150cd2007-07-25 14:43:32 +02006273 if (memcmp(h, ";norefresh", 10) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01006274 t->data_ctx.stats.flags |= STAT_NO_REFRESH;
Willy Tarreaue7150cd2007-07-25 14:43:32 +02006275 break;
6276 }
6277 h++;
6278 }
6279 }
6280
Willy Tarreau962c3f42010-01-10 00:15:35 +01006281 h = txn->req.sol + txn->req.sl.rq.u + uri_auth->uri_len;
6282 while (h <= txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l - 4) {
Willy Tarreau55bb8452007-10-17 18:44:57 +02006283 if (memcmp(h, ";csv", 4) == 0) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01006284 t->data_ctx.stats.flags |= STAT_FMT_CSV;
Willy Tarreau55bb8452007-10-17 18:44:57 +02006285 break;
6286 }
6287 h++;
6288 }
6289
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01006290 t->data_ctx.stats.flags |= STAT_SHOW_STAT | STAT_SHOW_INFO;
6291
Willy Tarreaub2513902006-12-17 14:52:38 +01006292 /* we are in front of a interceptable URI. Let's check
6293 * if there's an authentication and if it's valid.
6294 */
6295 user = uri_auth->users;
6296 if (!user) {
6297 /* no user auth required, it's OK */
6298 authenticated = 1;
6299 } else {
6300 authenticated = 0;
6301
6302 /* a user list is defined, we have to check.
6303 * skip 21 chars for "Authorization: Basic ".
6304 */
6305
6306 /* FIXME: this should move to an earlier place */
6307 cur_idx = 0;
Willy Tarreau962c3f42010-01-10 00:15:35 +01006308 h = txn->req.sol + hdr_idx_first_pos(&txn->hdr_idx);
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01006309 while ((cur_idx = txn->hdr_idx.v[cur_idx].next)) {
6310 int len = txn->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01006311 if (len > 14 &&
6312 !strncasecmp("Authorization:", h, 14)) {
Krzysztof Piotr Oledzki6f61b212009-10-04 23:34:15 +02006313 chunk_initlen(&txn->auth_hdr, h, 0, len);
Willy Tarreaub2513902006-12-17 14:52:38 +01006314 break;
6315 }
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01006316 h += len + txn->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01006317 }
6318
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01006319 if (txn->auth_hdr.len < 21 ||
6320 memcmp(txn->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01006321 user = NULL;
6322
6323 while (user) {
Willy Tarreau4dbc4a22007-03-03 16:23:22 +01006324 if ((txn->auth_hdr.len == user->user_len + 14 + 7)
6325 && !memcmp(txn->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01006326 user->user_pwd, user->user_len)) {
6327 authenticated = 1;
6328 break;
6329 }
6330 user = user->next;
6331 }
6332 }
6333
6334 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01006335 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01006336
6337 /* no need to go further */
Krzysztof Piotr Oledzki78abe612009-09-27 13:23:20 +02006338 sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
6339 chunk_initlen(&msg, trash, sizeof(trash), strlen(trash));
Willy Tarreau3bac9ff2007-03-18 17:31:28 +01006340 txn->status = 401;
Willy Tarreaudded32d2008-11-30 19:48:07 +01006341 stream_int_retnclose(t->req->prod, &msg);
Willy Tarreau2df28e82008-08-17 15:20:19 +02006342 t->req->analysers = 0;
Willy Tarreaub2513902006-12-17 14:52:38 +01006343 if (!(t->flags & SN_ERR_MASK))
6344 t->flags |= SN_ERR_PRXCOND;
6345 if (!(t->flags & SN_FINST_MASK))
6346 t->flags |= SN_FINST_R;
6347 return 1;
6348 }
6349
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01006350 /* The request is valid, the user is authenticated. Let's start sending
Willy Tarreaub2513902006-12-17 14:52:38 +01006351 * data.
6352 */
Willy Tarreau70089872008-06-13 21:12:51 +02006353 t->logs.tv_request = now;
Willy Tarreaub2513902006-12-17 14:52:38 +01006354 t->data_source = DATA_SRC_STATS;
6355 t->data_state = DATA_ST_INIT;
Willy Tarreau91e99932008-06-30 07:51:00 +02006356 t->task->nice = -32; /* small boost for HTTP statistics */
Willy Tarreaub0c9bc42009-10-04 15:56:38 +02006357 stream_int_register_handler(t->rep->prod, http_stats_io_handler);
6358 t->rep->prod->private = t;
6359 t->rep->prod->st0 = t->rep->prod->st1 = 0;
Willy Tarreaub2513902006-12-17 14:52:38 +01006360 return 1;
6361}
6362
Willy Tarreau4076a152009-04-02 15:18:36 +02006363/*
6364 * Capture a bad request or response and archive it in the proxy's structure.
Willy Tarreau962c3f42010-01-10 00:15:35 +01006365 * WARNING: it's unlikely that we've reached HTTP_MSG_BODY here so we must not
6366 * assume that msg->sol = buf->data + msg->som.
Willy Tarreau4076a152009-04-02 15:18:36 +02006367 */
6368void http_capture_bad_message(struct error_snapshot *es, struct session *s,
6369 struct buffer *buf, struct http_msg *msg,
6370 struct proxy *other_end)
6371{
Willy Tarreau2df8d712009-05-01 11:33:17 +02006372 es->len = buf->r - (buf->data + msg->som);
6373 memcpy(es->buf, buf->data + msg->som, MIN(es->len, sizeof(es->buf)));
Willy Tarreau4076a152009-04-02 15:18:36 +02006374 if (msg->err_pos >= 0)
Willy Tarreau2df8d712009-05-01 11:33:17 +02006375 es->pos = msg->err_pos - msg->som;
Willy Tarreau4076a152009-04-02 15:18:36 +02006376 else
Willy Tarreau2df8d712009-05-01 11:33:17 +02006377 es->pos = buf->lr - (buf->data + msg->som);
Willy Tarreau4076a152009-04-02 15:18:36 +02006378 es->when = date; // user-visible date
6379 es->sid = s->uniq_id;
6380 es->srv = s->srv;
6381 es->oe = other_end;
6382 es->src = s->cli_addr;
6383}
Willy Tarreaub2513902006-12-17 14:52:38 +01006384
Willy Tarreaubaaee002006-06-26 02:48:02 +02006385/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01006386 * Print a debug line with a header
6387 */
6388void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
6389{
6390 int len, max;
6391 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
Willy Tarreau3a16b2c2008-08-28 08:54:27 +02006392 dir, (unsigned short)t->req->prod->fd, (unsigned short)t->req->cons->fd);
Willy Tarreau58f10d72006-12-04 02:26:12 +01006393 max = end - start;
6394 UBOUND(max, sizeof(trash) - len - 1);
6395 len += strlcpy2(trash + len, start, max + 1);
6396 trash[len++] = '\n';
6397 write(1, trash, len);
6398}
6399
Willy Tarreau0937bc42009-12-22 15:03:09 +01006400/*
6401 * Initialize a new HTTP transaction for session <s>. It is assumed that all
6402 * the required fields are properly allocated and that we only need to (re)init
6403 * them. This should be used before processing any new request.
6404 */
6405void http_init_txn(struct session *s)
6406{
6407 struct http_txn *txn = &s->txn;
6408 struct proxy *fe = s->fe;
6409
6410 txn->flags = 0;
6411 txn->status = -1;
6412
6413 txn->req.sol = txn->req.eol = NULL;
6414 txn->req.som = txn->req.eoh = 0; /* relative to the buffer */
6415 txn->rsp.sol = txn->rsp.eol = NULL;
6416 txn->rsp.som = txn->rsp.eoh = 0; /* relative to the buffer */
6417 txn->req.hdr_content_len = 0LL;
6418 txn->rsp.hdr_content_len = 0LL;
6419 txn->req.msg_state = HTTP_MSG_RQBEFORE; /* at the very beginning of the request */
6420 txn->rsp.msg_state = HTTP_MSG_RPBEFORE; /* at the very beginning of the response */
6421 chunk_reset(&txn->auth_hdr);
6422
6423 txn->req.err_pos = txn->rsp.err_pos = -2; /* block buggy requests/responses */
6424 if (fe->options2 & PR_O2_REQBUG_OK)
6425 txn->req.err_pos = -1; /* let buggy requests pass */
6426
Willy Tarreau46023632010-01-07 22:51:47 +01006427 if (txn->req.cap)
Willy Tarreau0937bc42009-12-22 15:03:09 +01006428 memset(txn->req.cap, 0, fe->nb_req_cap * sizeof(void *));
6429
Willy Tarreau46023632010-01-07 22:51:47 +01006430 if (txn->rsp.cap)
Willy Tarreau0937bc42009-12-22 15:03:09 +01006431 memset(txn->rsp.cap, 0, fe->nb_rsp_cap * sizeof(void *));
6432
6433 if (txn->hdr_idx.v)
6434 hdr_idx_init(&txn->hdr_idx);
6435}
6436
6437/* to be used at the end of a transaction */
6438void http_end_txn(struct session *s)
6439{
6440 struct http_txn *txn = &s->txn;
6441
6442 /* these ones will have been dynamically allocated */
6443 pool_free2(pool2_requri, txn->uri);
6444 pool_free2(pool2_capture, txn->cli_cookie);
6445 pool_free2(pool2_capture, txn->srv_cookie);
Willy Tarreaua3377ee2010-01-10 10:49:11 +01006446 pool_free2(apools.sessid, txn->sessid);
6447 txn->sessid = NULL;
Willy Tarreau0937bc42009-12-22 15:03:09 +01006448 txn->uri = NULL;
6449 txn->srv_cookie = NULL;
6450 txn->cli_cookie = NULL;
Willy Tarreau46023632010-01-07 22:51:47 +01006451
6452 if (txn->req.cap) {
6453 struct cap_hdr *h;
6454 for (h = s->fe->req_cap; h; h = h->next)
6455 pool_free2(h->pool, txn->req.cap[h->index]);
6456 memset(txn->req.cap, 0, s->fe->nb_req_cap * sizeof(void *));
6457 }
6458
6459 if (txn->rsp.cap) {
6460 struct cap_hdr *h;
6461 for (h = s->fe->rsp_cap; h; h = h->next)
6462 pool_free2(h->pool, txn->rsp.cap[h->index]);
6463 memset(txn->rsp.cap, 0, s->fe->nb_rsp_cap * sizeof(void *));
6464 }
6465
Willy Tarreau0937bc42009-12-22 15:03:09 +01006466}
6467
6468/* to be used at the end of a transaction to prepare a new one */
6469void http_reset_txn(struct session *s)
6470{
6471 http_end_txn(s);
6472 http_init_txn(s);
6473
6474 s->be = s->fe;
6475 s->req->analysers = s->listener->analysers;
6476 s->logs.logwait = s->fe->to_log;
6477 s->srv = s->prev_srv = s->srv_conn = NULL;
Emeric Brunb982a3d2010-01-04 15:45:53 +01006478 /* re-init store persistence */
6479 s->store_count = 0;
6480
Willy Tarreau0937bc42009-12-22 15:03:09 +01006481 s->pend_pos = NULL;
6482 s->conn_retries = s->be->conn_retries;
6483
6484 s->req->flags |= BF_READ_DONTWAIT; /* one read is usually enough */
6485
6486 s->req->rto = s->fe->timeout.client;
6487 s->req->wto = s->be->timeout.server;
6488 s->req->cto = s->be->timeout.connect;
6489
6490 s->rep->rto = s->be->timeout.server;
6491 s->rep->wto = s->fe->timeout.client;
6492 s->rep->cto = TICK_ETERNITY;
6493
6494 s->req->rex = TICK_ETERNITY;
6495 s->req->wex = TICK_ETERNITY;
6496 s->req->analyse_exp = TICK_ETERNITY;
6497 s->rep->rex = TICK_ETERNITY;
6498 s->rep->wex = TICK_ETERNITY;
6499 s->rep->analyse_exp = TICK_ETERNITY;
6500}
Willy Tarreau58f10d72006-12-04 02:26:12 +01006501
Willy Tarreau8797c062007-05-07 00:55:35 +02006502/************************************************************************/
6503/* The code below is dedicated to ACL parsing and matching */
6504/************************************************************************/
6505
6506
6507
6508
6509/* 1. Check on METHOD
6510 * We use the pre-parsed method if it is known, and store its number as an
6511 * integer. If it is unknown, we use the pointer and the length.
6512 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02006513static int acl_parse_meth(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02006514{
6515 int len, meth;
6516
Willy Tarreauae8b7962007-06-09 23:10:04 +02006517 len = strlen(*text);
6518 meth = find_http_meth(*text, len);
Willy Tarreau8797c062007-05-07 00:55:35 +02006519
6520 pattern->val.i = meth;
6521 if (meth == HTTP_METH_OTHER) {
Willy Tarreauae8b7962007-06-09 23:10:04 +02006522 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02006523 if (!pattern->ptr.str)
6524 return 0;
6525 pattern->len = len;
6526 }
6527 return 1;
6528}
6529
Willy Tarreaud41f8d82007-06-10 10:06:18 +02006530static int
Willy Tarreau97be1452007-06-10 11:47:14 +02006531acl_fetch_meth(struct proxy *px, struct session *l4, void *l7, int dir,
6532 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02006533{
6534 int meth;
6535 struct http_txn *txn = l7;
6536
Willy Tarreaub6866442008-07-14 23:54:42 +02006537 if (!txn)
6538 return 0;
6539
Willy Tarreau655dce92009-11-08 13:10:58 +01006540 if (txn->req.msg_state < HTTP_MSG_BODY)
Willy Tarreauc11416f2007-06-17 16:58:38 +02006541 return 0;
6542
Willy Tarreau8797c062007-05-07 00:55:35 +02006543 meth = txn->meth;
6544 test->i = meth;
6545 if (meth == HTTP_METH_OTHER) {
Willy Tarreauc11416f2007-06-17 16:58:38 +02006546 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
6547 /* ensure the indexes are not affected */
6548 return 0;
Willy Tarreau8797c062007-05-07 00:55:35 +02006549 test->len = txn->req.sl.rq.m_l;
6550 test->ptr = txn->req.sol;
6551 }
6552 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
6553 return 1;
6554}
6555
6556static int acl_match_meth(struct acl_test *test, struct acl_pattern *pattern)
6557{
Willy Tarreauc8d7c962007-06-17 08:20:33 +02006558 int icase;
6559
Willy Tarreau8797c062007-05-07 00:55:35 +02006560 if (test->i != pattern->val.i)
Willy Tarreau11382812008-07-09 16:18:21 +02006561 return ACL_PAT_FAIL;
Willy Tarreau8797c062007-05-07 00:55:35 +02006562
6563 if (test->i != HTTP_METH_OTHER)
Willy Tarreau11382812008-07-09 16:18:21 +02006564 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02006565
6566 /* Other method, we must compare the strings */
6567 if (pattern->len != test->len)
Willy Tarreau11382812008-07-09 16:18:21 +02006568 return ACL_PAT_FAIL;
Willy Tarreauc8d7c962007-06-17 08:20:33 +02006569
6570 icase = pattern->flags & ACL_PAT_F_IGNORE_CASE;
6571 if ((icase && strncasecmp(pattern->ptr.str, test->ptr, test->len) != 0) ||
6572 (!icase && strncmp(pattern->ptr.str, test->ptr, test->len) != 0))
Willy Tarreau11382812008-07-09 16:18:21 +02006573 return ACL_PAT_FAIL;
6574 return ACL_PAT_PASS;
Willy Tarreau8797c062007-05-07 00:55:35 +02006575}
6576
6577/* 2. Check on Request/Status Version
6578 * We simply compare strings here.
6579 */
Willy Tarreauae8b7962007-06-09 23:10:04 +02006580static int acl_parse_ver(const char **text, struct acl_pattern *pattern, int *opaque)
Willy Tarreau8797c062007-05-07 00:55:35 +02006581{
Willy Tarreauae8b7962007-06-09 23:10:04 +02006582 pattern->ptr.str = strdup(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02006583 if (!pattern->ptr.str)
6584 return 0;
Willy Tarreauae8b7962007-06-09 23:10:04 +02006585 pattern->len = strlen(*text);
Willy Tarreau8797c062007-05-07 00:55:35 +02006586 return 1;
6587}
6588
Willy Tarreaud41f8d82007-06-10 10:06:18 +02006589static int
Willy Tarreau97be1452007-06-10 11:47:14 +02006590acl_fetch_rqver(struct proxy *px, struct session *l4, void *l7, int dir,
6591 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02006592{
6593 struct http_txn *txn = l7;
6594 char *ptr;
6595 int len;
6596
Willy Tarreaub6866442008-07-14 23:54:42 +02006597 if (!txn)
6598 return 0;
6599
Willy Tarreau655dce92009-11-08 13:10:58 +01006600 if (txn->req.msg_state < HTTP_MSG_BODY)
Willy Tarreauc11416f2007-06-17 16:58:38 +02006601 return 0;
6602
Willy Tarreau8797c062007-05-07 00:55:35 +02006603 len = txn->req.sl.rq.v_l;
Willy Tarreau962c3f42010-01-10 00:15:35 +01006604 ptr = txn->req.sol + txn->req.sl.rq.v;
Willy Tarreau8797c062007-05-07 00:55:35 +02006605
6606 while ((len-- > 0) && (*ptr++ != '/'));
6607 if (len <= 0)
6608 return 0;
6609
6610 test->ptr = ptr;
6611 test->len = len;
6612
6613 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
6614 return 1;
6615}
6616
Willy Tarreaud41f8d82007-06-10 10:06:18 +02006617static int
Willy Tarreau97be1452007-06-10 11:47:14 +02006618acl_fetch_stver(struct proxy *px, struct session *l4, void *l7, int dir,
6619 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02006620{
6621 struct http_txn *txn = l7;
6622 char *ptr;
6623 int len;
6624
Willy Tarreaub6866442008-07-14 23:54:42 +02006625 if (!txn)
6626 return 0;
6627
Willy Tarreau655dce92009-11-08 13:10:58 +01006628 if (txn->rsp.msg_state < HTTP_MSG_BODY)
Willy Tarreauc11416f2007-06-17 16:58:38 +02006629 return 0;
6630
Willy Tarreau8797c062007-05-07 00:55:35 +02006631 len = txn->rsp.sl.st.v_l;
6632 ptr = txn->rsp.sol;
6633
6634 while ((len-- > 0) && (*ptr++ != '/'));
6635 if (len <= 0)
6636 return 0;
6637
6638 test->ptr = ptr;
6639 test->len = len;
6640
6641 test->flags = ACL_TEST_F_READ_ONLY | ACL_TEST_F_VOL_1ST;
6642 return 1;
6643}
6644
6645/* 3. Check on Status Code. We manipulate integers here. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02006646static int
Willy Tarreau97be1452007-06-10 11:47:14 +02006647acl_fetch_stcode(struct proxy *px, struct session *l4, void *l7, int dir,
6648 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02006649{
6650 struct http_txn *txn = l7;
6651 char *ptr;
6652 int len;
6653
Willy Tarreaub6866442008-07-14 23:54:42 +02006654 if (!txn)
6655 return 0;
6656
Willy Tarreau655dce92009-11-08 13:10:58 +01006657 if (txn->rsp.msg_state < HTTP_MSG_BODY)
Willy Tarreauc11416f2007-06-17 16:58:38 +02006658 return 0;
6659
Willy Tarreau8797c062007-05-07 00:55:35 +02006660 len = txn->rsp.sl.st.c_l;
Willy Tarreau962c3f42010-01-10 00:15:35 +01006661 ptr = txn->rsp.sol + txn->rsp.sl.st.c;
Willy Tarreau8797c062007-05-07 00:55:35 +02006662
6663 test->i = __strl2ui(ptr, len);
6664 test->flags = ACL_TEST_F_VOL_1ST;
6665 return 1;
6666}
6667
6668/* 4. Check on URL/URI. A pointer to the URI is stored. */
Willy Tarreaud41f8d82007-06-10 10:06:18 +02006669static int
Willy Tarreau97be1452007-06-10 11:47:14 +02006670acl_fetch_url(struct proxy *px, struct session *l4, void *l7, int dir,
6671 struct acl_expr *expr, struct acl_test *test)
Willy Tarreau8797c062007-05-07 00:55:35 +02006672{
6673 struct http_txn *txn = l7;
6674
Willy Tarreaub6866442008-07-14 23:54:42 +02006675 if (!txn)
6676 return 0;
6677
Willy Tarreau655dce92009-11-08 13:10:58 +01006678 if (txn->req.msg_state < HTTP_MSG_BODY)
Willy Tarreauc11416f2007-06-17 16:58:38 +02006679 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02006680
Willy Tarreauc11416f2007-06-17 16:58:38 +02006681 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
6682 /* ensure the indexes are not affected */
6683 return 0;
6684
Willy Tarreau8797c062007-05-07 00:55:35 +02006685 test->len = txn->req.sl.rq.u_l;
Willy Tarreau962c3f42010-01-10 00:15:35 +01006686 test->ptr = txn->req.sol + txn->req.sl.rq.u;
Willy Tarreau8797c062007-05-07 00:55:35 +02006687
Willy Tarreauf3d25982007-05-08 22:45:09 +02006688 /* we do not need to set READ_ONLY because the data is in a buffer */
6689 test->flags = ACL_TEST_F_VOL_1ST;
Willy Tarreau8797c062007-05-07 00:55:35 +02006690 return 1;
6691}
6692
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01006693static int
6694acl_fetch_url_ip(struct proxy *px, struct session *l4, void *l7, int dir,
6695 struct acl_expr *expr, struct acl_test *test)
6696{
6697 struct http_txn *txn = l7;
6698
Willy Tarreaub6866442008-07-14 23:54:42 +02006699 if (!txn)
6700 return 0;
6701
Willy Tarreau655dce92009-11-08 13:10:58 +01006702 if (txn->req.msg_state < HTTP_MSG_BODY)
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01006703 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02006704
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01006705 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
6706 /* ensure the indexes are not affected */
6707 return 0;
6708
6709 /* Parse HTTP request */
Willy Tarreau962c3f42010-01-10 00:15:35 +01006710 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01006711 test->ptr = (void *)&((struct sockaddr_in *)&l4->srv_addr)->sin_addr;
6712 test->i = AF_INET;
6713
6714 /*
6715 * If we are parsing url in frontend space, we prepare backend stage
6716 * to not parse again the same url ! optimization lazyness...
6717 */
6718 if (px->options & PR_O_HTTP_PROXY)
6719 l4->flags |= SN_ADDR_SET;
6720
6721 test->flags = ACL_TEST_F_READ_ONLY;
6722 return 1;
6723}
6724
6725static int
6726acl_fetch_url_port(struct proxy *px, struct session *l4, void *l7, int dir,
6727 struct acl_expr *expr, struct acl_test *test)
6728{
6729 struct http_txn *txn = l7;
6730
Willy Tarreaub6866442008-07-14 23:54:42 +02006731 if (!txn)
6732 return 0;
6733
Willy Tarreau655dce92009-11-08 13:10:58 +01006734 if (txn->req.msg_state < HTTP_MSG_BODY)
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01006735 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02006736
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01006737 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
6738 /* ensure the indexes are not affected */
6739 return 0;
6740
6741 /* Same optimization as url_ip */
Willy Tarreau962c3f42010-01-10 00:15:35 +01006742 url2sa(txn->req.sol + txn->req.sl.rq.u, txn->req.sl.rq.u_l, &l4->srv_addr);
Alexandre Cassen5eb1a902007-11-29 15:43:32 +01006743 test->i = ntohs(((struct sockaddr_in *)&l4->srv_addr)->sin_port);
6744
6745 if (px->options & PR_O_HTTP_PROXY)
6746 l4->flags |= SN_ADDR_SET;
6747
6748 test->flags = ACL_TEST_F_READ_ONLY;
6749 return 1;
6750}
6751
Willy Tarreauc11416f2007-06-17 16:58:38 +02006752/* 5. Check on HTTP header. A pointer to the beginning of the value is returned.
6753 * This generic function is used by both acl_fetch_chdr() and acl_fetch_shdr().
6754 */
Willy Tarreau33a7e692007-06-10 19:45:56 +02006755static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02006756acl_fetch_hdr(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02006757 struct acl_expr *expr, struct acl_test *test)
6758{
6759 struct http_txn *txn = l7;
6760 struct hdr_idx *idx = &txn->hdr_idx;
6761 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02006762
Willy Tarreaub6866442008-07-14 23:54:42 +02006763 if (!txn)
6764 return 0;
6765
Willy Tarreau33a7e692007-06-10 19:45:56 +02006766 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
6767 /* search for header from the beginning */
6768 ctx->idx = 0;
6769
Willy Tarreau33a7e692007-06-10 19:45:56 +02006770 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
6771 test->flags |= ACL_TEST_F_FETCH_MORE;
6772 test->flags |= ACL_TEST_F_VOL_HDR;
6773 test->len = ctx->vlen;
6774 test->ptr = (char *)ctx->line + ctx->val;
6775 return 1;
6776 }
6777
6778 test->flags &= ~ACL_TEST_F_FETCH_MORE;
6779 test->flags |= ACL_TEST_F_VOL_HDR;
6780 return 0;
6781}
6782
Willy Tarreau33a7e692007-06-10 19:45:56 +02006783static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02006784acl_fetch_chdr(struct proxy *px, struct session *l4, void *l7, int dir,
6785 struct acl_expr *expr, struct acl_test *test)
6786{
6787 struct http_txn *txn = l7;
6788
Willy Tarreaub6866442008-07-14 23:54:42 +02006789 if (!txn)
6790 return 0;
6791
Willy Tarreau655dce92009-11-08 13:10:58 +01006792 if (txn->req.msg_state < HTTP_MSG_BODY)
Willy Tarreauc11416f2007-06-17 16:58:38 +02006793 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02006794
Willy Tarreauc11416f2007-06-17 16:58:38 +02006795 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
6796 /* ensure the indexes are not affected */
6797 return 0;
6798
6799 return acl_fetch_hdr(px, l4, txn, txn->req.sol, expr, test);
6800}
6801
6802static int
6803acl_fetch_shdr(struct proxy *px, struct session *l4, void *l7, int dir,
6804 struct acl_expr *expr, struct acl_test *test)
6805{
6806 struct http_txn *txn = l7;
6807
Willy Tarreaub6866442008-07-14 23:54:42 +02006808 if (!txn)
6809 return 0;
6810
Willy Tarreau655dce92009-11-08 13:10:58 +01006811 if (txn->rsp.msg_state < HTTP_MSG_BODY)
Willy Tarreauc11416f2007-06-17 16:58:38 +02006812 return 0;
6813
6814 return acl_fetch_hdr(px, l4, txn, txn->rsp.sol, expr, test);
6815}
6816
6817/* 6. Check on HTTP header count. The number of occurrences is returned.
6818 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
6819 */
6820static int
6821acl_fetch_hdr_cnt(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02006822 struct acl_expr *expr, struct acl_test *test)
6823{
6824 struct http_txn *txn = l7;
6825 struct hdr_idx *idx = &txn->hdr_idx;
6826 struct hdr_ctx ctx;
Willy Tarreau33a7e692007-06-10 19:45:56 +02006827 int cnt;
Willy Tarreau8797c062007-05-07 00:55:35 +02006828
Willy Tarreaub6866442008-07-14 23:54:42 +02006829 if (!txn)
6830 return 0;
6831
Willy Tarreau33a7e692007-06-10 19:45:56 +02006832 ctx.idx = 0;
6833 cnt = 0;
6834 while (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, &ctx))
6835 cnt++;
6836
6837 test->i = cnt;
6838 test->flags = ACL_TEST_F_VOL_HDR;
6839 return 1;
6840}
6841
Willy Tarreauc11416f2007-06-17 16:58:38 +02006842static int
6843acl_fetch_chdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
6844 struct acl_expr *expr, struct acl_test *test)
6845{
6846 struct http_txn *txn = l7;
6847
Willy Tarreaub6866442008-07-14 23:54:42 +02006848 if (!txn)
6849 return 0;
6850
Willy Tarreau655dce92009-11-08 13:10:58 +01006851 if (txn->req.msg_state < HTTP_MSG_BODY)
Willy Tarreauc11416f2007-06-17 16:58:38 +02006852 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02006853
Willy Tarreauc11416f2007-06-17 16:58:38 +02006854 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
6855 /* ensure the indexes are not affected */
6856 return 0;
6857
6858 return acl_fetch_hdr_cnt(px, l4, txn, txn->req.sol, expr, test);
6859}
6860
6861static int
6862acl_fetch_shdr_cnt(struct proxy *px, struct session *l4, void *l7, int dir,
6863 struct acl_expr *expr, struct acl_test *test)
6864{
6865 struct http_txn *txn = l7;
6866
Willy Tarreaub6866442008-07-14 23:54:42 +02006867 if (!txn)
6868 return 0;
6869
Willy Tarreau655dce92009-11-08 13:10:58 +01006870 if (txn->rsp.msg_state < HTTP_MSG_BODY)
Willy Tarreauc11416f2007-06-17 16:58:38 +02006871 return 0;
6872
6873 return acl_fetch_hdr_cnt(px, l4, txn, txn->rsp.sol, expr, test);
6874}
6875
Willy Tarreau33a7e692007-06-10 19:45:56 +02006876/* 7. Check on HTTP header's integer value. The integer value is returned.
6877 * FIXME: the type is 'int', it may not be appropriate for everything.
Willy Tarreauc11416f2007-06-17 16:58:38 +02006878 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
Willy Tarreau33a7e692007-06-10 19:45:56 +02006879 */
6880static int
Willy Tarreauc11416f2007-06-17 16:58:38 +02006881acl_fetch_hdr_val(struct proxy *px, struct session *l4, void *l7, char *sol,
Willy Tarreau33a7e692007-06-10 19:45:56 +02006882 struct acl_expr *expr, struct acl_test *test)
6883{
6884 struct http_txn *txn = l7;
6885 struct hdr_idx *idx = &txn->hdr_idx;
6886 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
Willy Tarreau33a7e692007-06-10 19:45:56 +02006887
Willy Tarreaub6866442008-07-14 23:54:42 +02006888 if (!txn)
6889 return 0;
6890
Willy Tarreau33a7e692007-06-10 19:45:56 +02006891 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
6892 /* search for header from the beginning */
6893 ctx->idx = 0;
6894
Willy Tarreau33a7e692007-06-10 19:45:56 +02006895 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
6896 test->flags |= ACL_TEST_F_FETCH_MORE;
6897 test->flags |= ACL_TEST_F_VOL_HDR;
6898 test->i = strl2ic((char *)ctx->line + ctx->val, ctx->vlen);
6899 return 1;
6900 }
6901
6902 test->flags &= ~ACL_TEST_F_FETCH_MORE;
6903 test->flags |= ACL_TEST_F_VOL_HDR;
6904 return 0;
6905}
6906
Willy Tarreauc11416f2007-06-17 16:58:38 +02006907static int
6908acl_fetch_chdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
6909 struct acl_expr *expr, struct acl_test *test)
6910{
6911 struct http_txn *txn = l7;
6912
Willy Tarreaub6866442008-07-14 23:54:42 +02006913 if (!txn)
6914 return 0;
6915
Willy Tarreau655dce92009-11-08 13:10:58 +01006916 if (txn->req.msg_state < HTTP_MSG_BODY)
Willy Tarreauc11416f2007-06-17 16:58:38 +02006917 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02006918
Willy Tarreauc11416f2007-06-17 16:58:38 +02006919 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
6920 /* ensure the indexes are not affected */
6921 return 0;
6922
6923 return acl_fetch_hdr_val(px, l4, txn, txn->req.sol, expr, test);
6924}
6925
6926static int
6927acl_fetch_shdr_val(struct proxy *px, struct session *l4, void *l7, int dir,
6928 struct acl_expr *expr, struct acl_test *test)
6929{
6930 struct http_txn *txn = l7;
6931
Willy Tarreaub6866442008-07-14 23:54:42 +02006932 if (!txn)
6933 return 0;
6934
Willy Tarreau655dce92009-11-08 13:10:58 +01006935 if (txn->rsp.msg_state < HTTP_MSG_BODY)
Willy Tarreauc11416f2007-06-17 16:58:38 +02006936 return 0;
6937
6938 return acl_fetch_hdr_val(px, l4, txn, txn->rsp.sol, expr, test);
6939}
6940
Willy Tarreau106f9792009-09-19 07:54:16 +02006941/* 7. Check on HTTP header's IPv4 address value. The IPv4 address is returned.
6942 * This generic function is used by both acl_fetch_chdr* and acl_fetch_shdr*.
6943 */
6944static int
6945acl_fetch_hdr_ip(struct proxy *px, struct session *l4, void *l7, char *sol,
6946 struct acl_expr *expr, struct acl_test *test)
6947{
6948 struct http_txn *txn = l7;
6949 struct hdr_idx *idx = &txn->hdr_idx;
6950 struct hdr_ctx *ctx = (struct hdr_ctx *)test->ctx.a;
6951
6952 if (!txn)
6953 return 0;
6954
6955 if (!(test->flags & ACL_TEST_F_FETCH_MORE))
6956 /* search for header from the beginning */
6957 ctx->idx = 0;
6958
6959 if (http_find_header2(expr->arg.str, expr->arg_len, sol, idx, ctx)) {
6960 test->flags |= ACL_TEST_F_FETCH_MORE;
6961 test->flags |= ACL_TEST_F_VOL_HDR;
6962 /* Same optimization as url_ip */
6963 memset(&l4->srv_addr.sin_addr, 0, sizeof(l4->srv_addr.sin_addr));
6964 url2ip((char *)ctx->line + ctx->val, &l4->srv_addr.sin_addr);
6965 test->ptr = (void *)&l4->srv_addr.sin_addr;
6966 test->i = AF_INET;
6967 return 1;
6968 }
6969
6970 test->flags &= ~ACL_TEST_F_FETCH_MORE;
6971 test->flags |= ACL_TEST_F_VOL_HDR;
6972 return 0;
6973}
6974
6975static int
6976acl_fetch_chdr_ip(struct proxy *px, struct session *l4, void *l7, int dir,
6977 struct acl_expr *expr, struct acl_test *test)
6978{
6979 struct http_txn *txn = l7;
6980
6981 if (!txn)
6982 return 0;
6983
Willy Tarreau655dce92009-11-08 13:10:58 +01006984 if (txn->req.msg_state < HTTP_MSG_BODY)
Willy Tarreau106f9792009-09-19 07:54:16 +02006985 return 0;
6986
6987 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
6988 /* ensure the indexes are not affected */
6989 return 0;
6990
6991 return acl_fetch_hdr_ip(px, l4, txn, txn->req.sol, expr, test);
6992}
6993
6994static int
6995acl_fetch_shdr_ip(struct proxy *px, struct session *l4, void *l7, int dir,
6996 struct acl_expr *expr, struct acl_test *test)
6997{
6998 struct http_txn *txn = l7;
6999
7000 if (!txn)
7001 return 0;
7002
Willy Tarreau655dce92009-11-08 13:10:58 +01007003 if (txn->rsp.msg_state < HTTP_MSG_BODY)
Willy Tarreau106f9792009-09-19 07:54:16 +02007004 return 0;
7005
7006 return acl_fetch_hdr_ip(px, l4, txn, txn->rsp.sol, expr, test);
7007}
7008
Willy Tarreau737b0c12007-06-10 21:28:46 +02007009/* 8. Check on URI PATH. A pointer to the PATH is stored. The path starts at
7010 * the first '/' after the possible hostname, and ends before the possible '?'.
7011 */
7012static int
7013acl_fetch_path(struct proxy *px, struct session *l4, void *l7, int dir,
7014 struct acl_expr *expr, struct acl_test *test)
7015{
7016 struct http_txn *txn = l7;
7017 char *ptr, *end;
Willy Tarreau33a7e692007-06-10 19:45:56 +02007018
Willy Tarreaub6866442008-07-14 23:54:42 +02007019 if (!txn)
7020 return 0;
7021
Willy Tarreau655dce92009-11-08 13:10:58 +01007022 if (txn->req.msg_state < HTTP_MSG_BODY)
Willy Tarreauc11416f2007-06-17 16:58:38 +02007023 return 0;
Willy Tarreaub6866442008-07-14 23:54:42 +02007024
Willy Tarreauc11416f2007-06-17 16:58:38 +02007025 if (txn->rsp.msg_state != HTTP_MSG_RPBEFORE)
7026 /* ensure the indexes are not affected */
7027 return 0;
7028
Willy Tarreau962c3f42010-01-10 00:15:35 +01007029 end = txn->req.sol + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
Willy Tarreau21d2af32008-02-14 20:25:24 +01007030 ptr = http_get_path(txn);
7031 if (!ptr)
Willy Tarreau737b0c12007-06-10 21:28:46 +02007032 return 0;
7033
7034 /* OK, we got the '/' ! */
7035 test->ptr = ptr;
7036
7037 while (ptr < end && *ptr != '?')
7038 ptr++;
7039
7040 test->len = ptr - test->ptr;
7041
7042 /* we do not need to set READ_ONLY because the data is in a buffer */
7043 test->flags = ACL_TEST_F_VOL_1ST;
7044 return 1;
7045}
7046
Willy Tarreau2492d5b2009-07-11 00:06:00 +02007047static int
7048acl_fetch_proto_http(struct proxy *px, struct session *s, void *l7, int dir,
7049 struct acl_expr *expr, struct acl_test *test)
7050{
7051 struct buffer *req = s->req;
7052 struct http_txn *txn = &s->txn;
7053 struct http_msg *msg = &txn->req;
Willy Tarreau737b0c12007-06-10 21:28:46 +02007054
Willy Tarreau2492d5b2009-07-11 00:06:00 +02007055 /* Note: hdr_idx.v cannot be NULL in this ACL because the ACL is tagged
7056 * as a layer7 ACL, which involves automatic allocation of hdr_idx.
7057 */
7058
7059 if (!s || !req)
7060 return 0;
7061
Willy Tarreau655dce92009-11-08 13:10:58 +01007062 if (unlikely(msg->msg_state >= HTTP_MSG_BODY)) {
Willy Tarreau2492d5b2009-07-11 00:06:00 +02007063 /* Already decoded as OK */
7064 test->flags |= ACL_TEST_F_SET_RES_PASS;
7065 return 1;
7066 }
7067
7068 /* Try to decode HTTP request */
7069 if (likely(req->lr < req->r))
7070 http_msg_analyzer(req, msg, &txn->hdr_idx);
7071
Willy Tarreau655dce92009-11-08 13:10:58 +01007072 if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
Willy Tarreau2492d5b2009-07-11 00:06:00 +02007073 if ((msg->msg_state == HTTP_MSG_ERROR) || (req->flags & BF_FULL)) {
7074 test->flags |= ACL_TEST_F_SET_RES_FAIL;
7075 return 1;
7076 }
7077 /* wait for final state */
7078 test->flags |= ACL_TEST_F_MAY_CHANGE;
7079 return 0;
7080 }
7081
7082 /* OK we got a valid HTTP request. We have some minor preparation to
7083 * perform so that further checks can rely on HTTP tests.
7084 */
Willy Tarreau962c3f42010-01-10 00:15:35 +01007085 txn->meth = find_http_meth(msg->sol, msg->sl.rq.m_l);
Willy Tarreau2492d5b2009-07-11 00:06:00 +02007086 if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
7087 s->flags |= SN_REDIRECTABLE;
7088
7089 if (unlikely(msg->sl.rq.v_l == 0) && !http_upgrade_v09_to_v10(req, msg, txn)) {
7090 test->flags |= ACL_TEST_F_SET_RES_FAIL;
7091 return 1;
7092 }
7093
7094 test->flags |= ACL_TEST_F_SET_RES_PASS;
7095 return 1;
7096}
7097
Willy Tarreau8797c062007-05-07 00:55:35 +02007098
7099/************************************************************************/
7100/* All supported keywords must be declared here. */
7101/************************************************************************/
7102
7103/* Note: must not be declared <const> as its list will be overwritten */
7104static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau2492d5b2009-07-11 00:06:00 +02007105 { "req_proto_http", acl_parse_nothing, acl_fetch_proto_http, acl_match_nothing, ACL_USE_L7REQ_PERMANENT },
7106
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02007107 { "method", acl_parse_meth, acl_fetch_meth, acl_match_meth, ACL_USE_L7REQ_PERMANENT },
7108 { "req_ver", acl_parse_ver, acl_fetch_rqver, acl_match_str, ACL_USE_L7REQ_VOLATILE },
7109 { "resp_ver", acl_parse_ver, acl_fetch_stver, acl_match_str, ACL_USE_L7RTR_VOLATILE },
7110 { "status", acl_parse_int, acl_fetch_stcode, acl_match_int, ACL_USE_L7RTR_PERMANENT },
Willy Tarreau8797c062007-05-07 00:55:35 +02007111
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02007112 { "url", acl_parse_str, acl_fetch_url, acl_match_str, ACL_USE_L7REQ_VOLATILE },
7113 { "url_beg", acl_parse_str, acl_fetch_url, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
7114 { "url_end", acl_parse_str, acl_fetch_url, acl_match_end, ACL_USE_L7REQ_VOLATILE },
7115 { "url_sub", acl_parse_str, acl_fetch_url, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
7116 { "url_dir", acl_parse_str, acl_fetch_url, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
7117 { "url_dom", acl_parse_str, acl_fetch_url, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
7118 { "url_reg", acl_parse_reg, acl_fetch_url, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
7119 { "url_ip", acl_parse_ip, acl_fetch_url_ip, acl_match_ip, ACL_USE_L7REQ_VOLATILE },
7120 { "url_port", acl_parse_int, acl_fetch_url_port, acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau8797c062007-05-07 00:55:35 +02007121
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02007122 /* note: we should set hdr* to use ACL_USE_HDR_VOLATILE, and chdr* to use L7REQ_VOLATILE */
7123 { "hdr", acl_parse_str, acl_fetch_chdr, acl_match_str, ACL_USE_L7REQ_VOLATILE },
7124 { "hdr_reg", acl_parse_reg, acl_fetch_chdr, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
7125 { "hdr_beg", acl_parse_str, acl_fetch_chdr, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
7126 { "hdr_end", acl_parse_str, acl_fetch_chdr, acl_match_end, ACL_USE_L7REQ_VOLATILE },
7127 { "hdr_sub", acl_parse_str, acl_fetch_chdr, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
7128 { "hdr_dir", acl_parse_str, acl_fetch_chdr, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
7129 { "hdr_dom", acl_parse_str, acl_fetch_chdr, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
7130 { "hdr_cnt", acl_parse_int, acl_fetch_chdr_cnt,acl_match_int, ACL_USE_L7REQ_VOLATILE },
7131 { "hdr_val", acl_parse_int, acl_fetch_chdr_val,acl_match_int, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau106f9792009-09-19 07:54:16 +02007132 { "hdr_ip", acl_parse_ip, acl_fetch_chdr_ip, acl_match_ip, ACL_USE_L7REQ_VOLATILE },
Willy Tarreauc11416f2007-06-17 16:58:38 +02007133
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02007134 { "shdr", acl_parse_str, acl_fetch_shdr, acl_match_str, ACL_USE_L7RTR_VOLATILE },
7135 { "shdr_reg", acl_parse_reg, acl_fetch_shdr, acl_match_reg, ACL_USE_L7RTR_VOLATILE },
7136 { "shdr_beg", acl_parse_str, acl_fetch_shdr, acl_match_beg, ACL_USE_L7RTR_VOLATILE },
7137 { "shdr_end", acl_parse_str, acl_fetch_shdr, acl_match_end, ACL_USE_L7RTR_VOLATILE },
7138 { "shdr_sub", acl_parse_str, acl_fetch_shdr, acl_match_sub, ACL_USE_L7RTR_VOLATILE },
7139 { "shdr_dir", acl_parse_str, acl_fetch_shdr, acl_match_dir, ACL_USE_L7RTR_VOLATILE },
7140 { "shdr_dom", acl_parse_str, acl_fetch_shdr, acl_match_dom, ACL_USE_L7RTR_VOLATILE },
7141 { "shdr_cnt", acl_parse_int, acl_fetch_shdr_cnt,acl_match_int, ACL_USE_L7RTR_VOLATILE },
7142 { "shdr_val", acl_parse_int, acl_fetch_shdr_val,acl_match_int, ACL_USE_L7RTR_VOLATILE },
Willy Tarreau106f9792009-09-19 07:54:16 +02007143 { "shdr_ip", acl_parse_ip, acl_fetch_shdr_ip, acl_match_ip, ACL_USE_L7RTR_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02007144
Willy Tarreau0ceba5a2008-07-25 19:31:03 +02007145 { "path", acl_parse_str, acl_fetch_path, acl_match_str, ACL_USE_L7REQ_VOLATILE },
7146 { "path_reg", acl_parse_reg, acl_fetch_path, acl_match_reg, ACL_USE_L7REQ_VOLATILE },
7147 { "path_beg", acl_parse_str, acl_fetch_path, acl_match_beg, ACL_USE_L7REQ_VOLATILE },
7148 { "path_end", acl_parse_str, acl_fetch_path, acl_match_end, ACL_USE_L7REQ_VOLATILE },
7149 { "path_sub", acl_parse_str, acl_fetch_path, acl_match_sub, ACL_USE_L7REQ_VOLATILE },
7150 { "path_dir", acl_parse_str, acl_fetch_path, acl_match_dir, ACL_USE_L7REQ_VOLATILE },
7151 { "path_dom", acl_parse_str, acl_fetch_path, acl_match_dom, ACL_USE_L7REQ_VOLATILE },
Willy Tarreau737b0c12007-06-10 21:28:46 +02007152
Willy Tarreauf3d25982007-05-08 22:45:09 +02007153 { NULL, NULL, NULL, NULL },
7154
7155#if 0
Willy Tarreau8797c062007-05-07 00:55:35 +02007156 { "line", acl_parse_str, acl_fetch_line, acl_match_str },
7157 { "line_reg", acl_parse_reg, acl_fetch_line, acl_match_reg },
7158 { "line_beg", acl_parse_str, acl_fetch_line, acl_match_beg },
7159 { "line_end", acl_parse_str, acl_fetch_line, acl_match_end },
7160 { "line_sub", acl_parse_str, acl_fetch_line, acl_match_sub },
7161 { "line_dir", acl_parse_str, acl_fetch_line, acl_match_dir },
7162 { "line_dom", acl_parse_str, acl_fetch_line, acl_match_dom },
7163
Willy Tarreau8797c062007-05-07 00:55:35 +02007164 { "cook", acl_parse_str, acl_fetch_cook, acl_match_str },
7165 { "cook_reg", acl_parse_reg, acl_fetch_cook, acl_match_reg },
7166 { "cook_beg", acl_parse_str, acl_fetch_cook, acl_match_beg },
7167 { "cook_end", acl_parse_str, acl_fetch_cook, acl_match_end },
7168 { "cook_sub", acl_parse_str, acl_fetch_cook, acl_match_sub },
7169 { "cook_dir", acl_parse_str, acl_fetch_cook, acl_match_dir },
7170 { "cook_dom", acl_parse_str, acl_fetch_cook, acl_match_dom },
7171 { "cook_pst", acl_parse_none, acl_fetch_cook, acl_match_pst },
7172
7173 { "auth_user", acl_parse_str, acl_fetch_user, acl_match_str },
7174 { "auth_regex", acl_parse_reg, acl_fetch_user, acl_match_reg },
7175 { "auth_clear", acl_parse_str, acl_fetch_auth, acl_match_str },
7176 { "auth_md5", acl_parse_str, acl_fetch_auth, acl_match_md5 },
7177 { NULL, NULL, NULL, NULL },
7178#endif
7179}};
7180
7181
7182__attribute__((constructor))
7183static void __http_protocol_init(void)
7184{
7185 acl_register_keywords(&acl_kws);
7186}
7187
7188
Willy Tarreau58f10d72006-12-04 02:26:12 +01007189/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02007190 * Local variables:
7191 * c-indent-level: 8
7192 * c-basic-offset: 8
7193 * End:
7194 */