blob: 6399673591a5c876c94c64dcf24a8b62f30d1782 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * HTTP protocol analyzer
3 *
4 * Copyright 2000-2006 Willy Tarreau <w@1wt.eu>
5 *
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>
20
21#include <sys/socket.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24
Willy Tarreau2dd0d472006-06-29 17:53:05 +020025#include <common/appsession.h>
26#include <common/compat.h>
27#include <common/config.h>
Willy Tarreaua4cd1f52006-12-16 19:57:26 +010028#include <common/debug.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020029#include <common/memory.h>
30#include <common/mini-clist.h>
31#include <common/standard.h>
32#include <common/time.h>
33#include <common/uri_auth.h>
34#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020035
36#include <types/capture.h>
37#include <types/client.h>
38#include <types/global.h>
39#include <types/httperr.h>
40#include <types/polling.h>
41#include <types/proxy.h>
42#include <types/server.h>
43
44#include <proto/backend.h>
45#include <proto/buffers.h>
46#include <proto/fd.h>
47#include <proto/log.h>
Willy Tarreau58f10d72006-12-04 02:26:12 +010048#include <proto/hdr_idx.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020049#include <proto/proto_http.h>
50#include <proto/queue.h>
51#include <proto/session.h>
52#include <proto/task.h>
53
Willy Tarreau6d1a9882007-01-07 02:03:04 +010054#ifdef CONFIG_HAP_TCPSPLICE
55#include <libtcpsplice.h>
56#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020057
Willy Tarreau58f10d72006-12-04 02:26:12 +010058#define DEBUG_PARSE_NO_SPEEDUP
59#undef DEBUG_PARSE_NO_SPEEDUP
60
Willy Tarreau976f1ee2006-12-17 10:06:03 +010061/* This is used to perform a quick jump as an alternative to a break/continue
62 * instruction. The first argument is the label for normal operation, and the
63 * second one is the break/continue instruction in the no_speedup mode.
64 */
65
66#ifdef DEBUG_PARSE_NO_SPEEDUP
67#define QUICK_JUMP(x,y) y
68#else
69#define QUICK_JUMP(x,y) goto x
70#endif
71
Willy Tarreau1c47f852006-07-09 08:22:27 +020072/* This is used by remote monitoring */
Willy Tarreau0f772532006-12-23 20:51:41 +010073const char HTTP_200[] =
Willy Tarreau1c47f852006-07-09 08:22:27 +020074 "HTTP/1.0 200 OK\r\n"
75 "Cache-Control: no-cache\r\n"
76 "Connection: close\r\n"
77 "Content-Type: text/html\r\n"
78 "\r\n"
79 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
80
Willy Tarreau0f772532006-12-23 20:51:41 +010081const struct chunk http_200_chunk = {
82 .str = (char *)&HTTP_200,
83 .len = sizeof(HTTP_200)-1
84};
85
86const char *HTTP_302 =
87 "HTTP/1.0 302 Found\r\n"
88 "Cache-Control: no-cache\r\n"
89 "Connection: close\r\n"
90 "Location: "; /* not terminated since it will be concatenated with the URL */
91
92/* same as 302 except that the browser MUST retry with the GET method */
93const char *HTTP_303 =
94 "HTTP/1.0 303 See Other\r\n"
95 "Cache-Control: no-cache\r\n"
96 "Connection: close\r\n"
97 "Location: "; /* not terminated since it will be concatenated with the URL */
98
Willy Tarreaubaaee002006-06-26 02:48:02 +020099/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
100const char *HTTP_401_fmt =
101 "HTTP/1.0 401 Unauthorized\r\n"
102 "Cache-Control: no-cache\r\n"
103 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +0200104 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200105 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
106 "\r\n"
107 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
108
Willy Tarreau0f772532006-12-23 20:51:41 +0100109
110const int http_err_codes[HTTP_ERR_SIZE] = {
111 [HTTP_ERR_400] = 400,
112 [HTTP_ERR_403] = 403,
113 [HTTP_ERR_408] = 408,
114 [HTTP_ERR_500] = 500,
115 [HTTP_ERR_502] = 502,
116 [HTTP_ERR_503] = 503,
117 [HTTP_ERR_504] = 504,
118};
119
Willy Tarreau80587432006-12-24 17:47:20 +0100120static const char *http_err_msgs[HTTP_ERR_SIZE] = {
Willy Tarreau0f772532006-12-23 20:51:41 +0100121 [HTTP_ERR_400] =
Willy Tarreau80587432006-12-24 17:47:20 +0100122 "HTTP/1.0 400 Bad request\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +0100123 "Cache-Control: no-cache\r\n"
124 "Connection: close\r\n"
125 "Content-Type: text/html\r\n"
126 "\r\n"
127 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
128
129 [HTTP_ERR_403] =
130 "HTTP/1.0 403 Forbidden\r\n"
131 "Cache-Control: no-cache\r\n"
132 "Connection: close\r\n"
133 "Content-Type: text/html\r\n"
134 "\r\n"
135 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
136
137 [HTTP_ERR_408] =
138 "HTTP/1.0 408 Request Time-out\r\n"
139 "Cache-Control: no-cache\r\n"
140 "Connection: close\r\n"
141 "Content-Type: text/html\r\n"
142 "\r\n"
143 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
144
145 [HTTP_ERR_500] =
146 "HTTP/1.0 500 Server Error\r\n"
147 "Cache-Control: no-cache\r\n"
148 "Connection: close\r\n"
149 "Content-Type: text/html\r\n"
150 "\r\n"
151 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n",
152
153 [HTTP_ERR_502] =
154 "HTTP/1.0 502 Bad Gateway\r\n"
155 "Cache-Control: no-cache\r\n"
156 "Connection: close\r\n"
157 "Content-Type: text/html\r\n"
158 "\r\n"
159 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n",
160
161 [HTTP_ERR_503] =
162 "HTTP/1.0 503 Service Unavailable\r\n"
163 "Cache-Control: no-cache\r\n"
164 "Connection: close\r\n"
165 "Content-Type: text/html\r\n"
166 "\r\n"
167 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n",
168
169 [HTTP_ERR_504] =
170 "HTTP/1.0 504 Gateway Time-out\r\n"
171 "Cache-Control: no-cache\r\n"
172 "Connection: close\r\n"
173 "Content-Type: text/html\r\n"
174 "\r\n"
175 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n",
176
177};
178
Willy Tarreau80587432006-12-24 17:47:20 +0100179/* We must put the messages here since GCC cannot initialize consts depending
180 * on strlen().
181 */
182struct chunk http_err_chunks[HTTP_ERR_SIZE];
183
184void init_proto_http()
185{
186 int msg;
187 for (msg = 0; msg < HTTP_ERR_SIZE; msg++) {
188 if (!http_err_msgs[msg]) {
189 Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n", msg);
190 abort();
191 }
192
193 http_err_chunks[msg].str = (char *)http_err_msgs[msg];
194 http_err_chunks[msg].len = strlen(http_err_msgs[msg]);
195 }
196}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200197
Willy Tarreau53b6c742006-12-17 13:37:46 +0100198/*
199 * We have 26 list of methods (1 per first letter), each of which can have
200 * up to 3 entries (2 valid, 1 null).
201 */
202struct http_method_desc {
203 http_meth_t meth;
204 int len;
205 const char text[8];
206};
207
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100208const struct http_method_desc http_methods[26][3] = {
Willy Tarreau53b6c742006-12-17 13:37:46 +0100209 ['C' - 'A'] = {
210 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
211 },
212 ['D' - 'A'] = {
213 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
214 },
215 ['G' - 'A'] = {
216 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
217 },
218 ['H' - 'A'] = {
219 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
220 },
221 ['P' - 'A'] = {
222 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
223 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
224 },
225 ['T' - 'A'] = {
226 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
227 },
228 /* rest is empty like this :
229 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
230 */
231};
232
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100233/* It is about twice as fast on recent architectures to lookup a byte in a
234 * table than two perform a boolean AND or OR between two tests. Refer to
235 * RFC2616 for those chars.
236 */
237
238const char http_is_spht[256] = {
239 [' '] = 1, ['\t'] = 1,
240};
241
242const char http_is_crlf[256] = {
243 ['\r'] = 1, ['\n'] = 1,
244};
245
246const char http_is_lws[256] = {
247 [' '] = 1, ['\t'] = 1,
248 ['\r'] = 1, ['\n'] = 1,
249};
250
251const char http_is_sep[256] = {
252 ['('] = 1, [')'] = 1, ['<'] = 1, ['>'] = 1,
253 ['@'] = 1, [','] = 1, [';'] = 1, [':'] = 1,
254 ['"'] = 1, ['/'] = 1, ['['] = 1, [']'] = 1,
255 ['{'] = 1, ['}'] = 1, ['?'] = 1, ['='] = 1,
256 [' '] = 1, ['\t'] = 1, ['\\'] = 1,
257};
258
259const char http_is_ctl[256] = {
260 [0 ... 31] = 1,
261 [127] = 1,
262};
263
264/*
265 * A token is any ASCII char that is neither a separator nor a CTL char.
266 * Do not overwrite values in assignment since gcc-2.95 will not handle
267 * them correctly. Instead, define every non-CTL char's status.
268 */
269const char http_is_token[256] = {
270 [' '] = 0, ['!'] = 1, ['"'] = 0, ['#'] = 1,
271 ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1,
272 ['('] = 0, [')'] = 0, ['*'] = 1, ['+'] = 1,
273 [','] = 0, ['-'] = 1, ['.'] = 1, ['/'] = 0,
274 ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1,
275 ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1,
276 ['8'] = 1, ['9'] = 1, [':'] = 0, [';'] = 0,
277 ['<'] = 0, ['='] = 0, ['>'] = 0, ['?'] = 0,
278 ['@'] = 0, ['A'] = 1, ['B'] = 1, ['C'] = 1,
279 ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1,
280 ['H'] = 1, ['I'] = 1, ['J'] = 1, ['K'] = 1,
281 ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1,
282 ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1,
283 ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1,
284 ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 0,
285 ['\\'] = 0, [']'] = 0, ['^'] = 1, ['_'] = 1,
286 ['`'] = 1, ['a'] = 1, ['b'] = 1, ['c'] = 1,
287 ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1,
288 ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1,
289 ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1,
290 ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1,
291 ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1,
292 ['x'] = 1, ['y'] = 1, ['z'] = 1, ['{'] = 0,
293 ['|'] = 1, ['}'] = 0, ['~'] = 1,
294};
295
296
Willy Tarreaubaaee002006-06-26 02:48:02 +0200297#ifdef DEBUG_FULL
298static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
299static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
300#endif
301
302
303/*
304 * returns a message to the client ; the connection is shut down for read,
305 * and the request is cleared so that no server connection can be initiated.
306 * The client must be in a valid state for this (HEADER, DATA ...).
Willy Tarreau0f772532006-12-23 20:51:41 +0100307 * Nothing is performed on the server side. The message is contained in a
308 * "chunk". If it is null, then an empty message is used.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200309 * The reply buffer doesn't need to be empty before this.
310 */
Willy Tarreau0f772532006-12-23 20:51:41 +0100311void client_retnclose(struct session *s, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200312{
Willy Tarreau2a429502006-10-15 14:52:29 +0200313 MY_FD_CLR(s->cli_fd, StaticReadEvent);
314 MY_FD_SET(s->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +0200315 tv_eternity(&s->req->rex);
Willy Tarreau73de9892006-11-30 11:40:23 +0100316 if (s->fe->clitimeout)
317 tv_delayfrom(&s->rep->wex, &now, s->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200318 else
Willy Tarreaud7971282006-07-29 18:36:34 +0200319 tv_eternity(&s->rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200320 shutdown(s->cli_fd, SHUT_RD);
321 s->cli_state = CL_STSHUTR;
322 buffer_flush(s->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100323 if (msg->len)
324 buffer_write(s->rep, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200325 s->req->l = 0;
326}
327
328
329/*
330 * returns a message into the rep buffer, and flushes the req buffer.
Willy Tarreau0f772532006-12-23 20:51:41 +0100331 * The reply buffer doesn't need to be empty before this. The message
332 * is contained in a "chunk". If it is null, then an empty message is
333 * used.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200334 */
Willy Tarreau0f772532006-12-23 20:51:41 +0100335void client_return(struct session *s, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200336{
337 buffer_flush(s->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100338 if (msg->len)
339 buffer_write(s->rep, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200340 s->req->l = 0;
341}
342
343
344/* This function turns the server state into the SV_STCLOSE, and sets
Willy Tarreau0f772532006-12-23 20:51:41 +0100345 * indicators accordingly. Note that if <status> is 0, or if the message
346 * pointer is NULL, then no message is returned.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200347 */
348void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreau0f772532006-12-23 20:51:41 +0100349 int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200350{
351 t->srv_state = SV_STCLOSE;
Willy Tarreau0f772532006-12-23 20:51:41 +0100352 if (status > 0 && msg) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200353 t->logs.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100354 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100355 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200356 }
357 if (!(t->flags & SN_ERR_MASK))
358 t->flags |= err;
359 if (!(t->flags & SN_FINST_MASK))
360 t->flags |= finst;
361}
362
Willy Tarreau80587432006-12-24 17:47:20 +0100363/* This function returns the appropriate error location for the given session
364 * and message.
365 */
366
367struct chunk *error_message(struct session *s, int msgnum)
368{
369 if (s->be->beprm->errmsg[msgnum].str)
370 return &s->be->beprm->errmsg[msgnum];
371 else if (s->fe->errmsg[msgnum].str)
372 return &s->fe->errmsg[msgnum];
373 else
374 return &http_err_chunks[msgnum];
375}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200376
Willy Tarreau53b6c742006-12-17 13:37:46 +0100377/*
378 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
379 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
380 */
381static http_meth_t find_http_meth(const char *str, const int len)
382{
383 unsigned char m;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100384 const struct http_method_desc *h;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100385
386 m = ((unsigned)*str - 'A');
387
388 if (m < 26) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100389 for (h = http_methods[m]; h->len > 0; h++) {
390 if (unlikely(h->len != len))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100391 continue;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100392 if (likely(memcmp(str, h->text, h->len) == 0))
Willy Tarreau53b6c742006-12-17 13:37:46 +0100393 return h->meth;
Willy Tarreau53b6c742006-12-17 13:37:46 +0100394 };
395 return HTTP_METH_OTHER;
396 }
397 return HTTP_METH_NONE;
398
399}
400
401
Willy Tarreaubaaee002006-06-26 02:48:02 +0200402/* Processes the client and server jobs of a session task, then
403 * puts it back to the wait queue in a clean state, or
404 * cleans up its resources if it must be deleted. Returns
405 * the time the task accepts to wait, or TIME_ETERNITY for
406 * infinity.
407 */
408int process_session(struct task *t)
409{
410 struct session *s = t->context;
411 int fsm_resync = 0;
412
413 do {
414 fsm_resync = 0;
415 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
416 fsm_resync |= process_cli(s);
417 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
418 fsm_resync |= process_srv(s);
419 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
420 } while (fsm_resync);
421
422 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
423 struct timeval min1, min2;
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200424 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
425 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200426
Willy Tarreaud7971282006-07-29 18:36:34 +0200427 tv_min(&min1, &s->req->rex, &s->req->wex);
428 tv_min(&min2, &s->rep->rex, &s->rep->wex);
429 tv_min(&min1, &min1, &s->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200430 tv_min(&t->expire, &min1, &min2);
431
432 /* restore t to its place in the task list */
433 task_queue(t);
434
435#ifdef DEBUG_FULL
436 /* DEBUG code : this should never ever happen, otherwise it indicates
437 * that a task still has something to do and will provoke a quick loop.
438 */
439 if (tv_remain2(&now, &t->expire) <= 0)
440 exit(100);
441#endif
442
443 return tv_remain2(&now, &t->expire); /* nothing more to do */
444 }
445
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100446 s->fe->feconn--;
447 if (s->flags & SN_BE_ASSIGNED)
448 s->be->beprm->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200449 actconn--;
450
451 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
452 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100453 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreau830ff452006-12-17 19:31:23 +0100454 s->uniq_id, s->be->beprm->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100455 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200456 write(1, trash, len);
457 }
458
459 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
Willy Tarreau35d66b02007-01-02 00:28:21 +0100460 if (s->req != NULL)
461 s->logs.bytes_in = s->req->total;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200462 if (s->rep != NULL)
Willy Tarreau35d66b02007-01-02 00:28:21 +0100463 s->logs.bytes_out = s->rep->total;
464
465 s->fe->bytes_in += s->logs.bytes_in;
466 s->fe->bytes_out += s->logs.bytes_out;
467 if (s->be->beprm != s->fe) {
468 s->be->beprm->bytes_in += s->logs.bytes_in;
469 s->be->beprm->bytes_out += s->logs.bytes_out;
470 }
471 if (s->srv) {
472 s->srv->bytes_in += s->logs.bytes_in;
473 s->srv->bytes_out += s->logs.bytes_out;
474 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200475
476 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200477 if (s->logs.logwait &&
478 !(s->flags & SN_MONITOR) &&
Willy Tarreau73de9892006-11-30 11:40:23 +0100479 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total))
Willy Tarreaubaaee002006-06-26 02:48:02 +0200480 sess_log(s);
481
482 /* the task MUST not be in the run queue anymore */
483 task_delete(t);
484 session_free(s);
485 task_free(t);
486 return TIME_ETERNITY; /* rest in peace for eternity */
487}
488
489
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100490/* either we find an LF at <ptr> or we jump to <bad>.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200491 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100492#define EXPECT_LF_HERE(ptr, bad) do { if (unlikely(*(ptr) != '\n')) goto bad; } while (0)
493
494/* plays with variables <ptr>, <end> and <state>. Jumps to <good> if OK,
495 * otherwise to <http_msg_ood> with <state> set to <st>.
496 */
497#define EAT_AND_JUMP_OR_RETURN(good, st) do { \
498 ptr++; \
499 if (likely(ptr < end)) \
500 goto good; \
501 else { \
502 state = (st); \
503 goto http_msg_ood; \
504 } \
505 } while (0)
506
Willy Tarreaubaaee002006-06-26 02:48:02 +0200507/*
Willy Tarreau8973c702007-01-21 23:58:29 +0100508 * This function parses a response line between <ptr> and <end>, starting with
509 * parser state <state>. Only states HTTP_MSG_RPVER, HTTP_MSG_RPVER_SP,
510 * HTTP_MSG_RPCODE, HTTP_MSG_RPCODE_SP and HTTP_MSG_RPREASON are handled. Others
511 * will give undefined results.
512 * Note that it is upon the caller's responsibility to ensure that ptr < end,
513 * and that msg->sol points to the beginning of the response.
514 * If a complete line is found (which implies that at least one CR or LF is
515 * found before <end>, the updated <ptr> is returned, otherwise NULL is
516 * returned indicating an incomplete line (which does not mean that parts have
517 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
518 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
519 * upon next call.
520 *
521 * This function was intentionnally designed to be called from
522 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
523 * within its state machine and use the same macros, hence the need for same
524 * labels and variable names.
525 */
526const char *http_parse_rspline(struct http_msg *msg, const char *msg_buf, int state,
527 const char *ptr, const char *end,
528 char **ret_ptr, int *ret_state)
529{
530 __label__
531 http_msg_rpver,
532 http_msg_rpver_sp,
533 http_msg_rpcode,
534 http_msg_rpcode_sp,
535 http_msg_rpreason,
536 http_msg_rpline_eol,
537 http_msg_ood, /* out of data */
538 http_msg_invalid;
539
540 switch (state) {
541 http_msg_rpver:
542 case HTTP_MSG_RPVER:
543 if (likely(HTTP_IS_TOKEN(*ptr)))
544 EAT_AND_JUMP_OR_RETURN(http_msg_rpver, HTTP_MSG_RPVER);
545
546 if (likely(HTTP_IS_SPHT(*ptr))) {
547 msg->sl.st.v_l = (ptr - msg_buf) - msg->sor;
548 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
549 }
550 goto http_msg_invalid;
551
552 http_msg_rpver_sp:
553 case HTTP_MSG_RPVER_SP:
554 if (likely(!HTTP_IS_LWS(*ptr))) {
555 msg->sl.st.c = ptr - msg_buf;
556 goto http_msg_rpcode;
557 }
558 if (likely(HTTP_IS_SPHT(*ptr)))
559 EAT_AND_JUMP_OR_RETURN(http_msg_rpver_sp, HTTP_MSG_RPVER_SP);
560 /* so it's a CR/LF, this is invalid */
561 goto http_msg_invalid;
562
563 http_msg_rpcode:
564 case HTTP_MSG_RPCODE:
565 if (likely(!HTTP_IS_LWS(*ptr)))
566 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode, HTTP_MSG_RPCODE);
567
568 if (likely(HTTP_IS_SPHT(*ptr))) {
569 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
570 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
571 }
572
573 /* so it's a CR/LF, so there is no reason phrase */
574 msg->sl.st.c_l = (ptr - msg_buf) - msg->sl.st.c;
575 http_msg_rsp_reason:
576 /* FIXME: should we support HTTP responses without any reason phrase ? */
577 msg->sl.st.r = ptr - msg_buf;
578 msg->sl.st.r_l = 0;
579 goto http_msg_rpline_eol;
580
581 http_msg_rpcode_sp:
582 case HTTP_MSG_RPCODE_SP:
583 if (likely(!HTTP_IS_LWS(*ptr))) {
584 msg->sl.st.r = ptr - msg_buf;
585 goto http_msg_rpreason;
586 }
587 if (likely(HTTP_IS_SPHT(*ptr)))
588 EAT_AND_JUMP_OR_RETURN(http_msg_rpcode_sp, HTTP_MSG_RPCODE_SP);
589 /* so it's a CR/LF, so there is no reason phrase */
590 goto http_msg_rsp_reason;
591
592 http_msg_rpreason:
593 case HTTP_MSG_RPREASON:
594 if (likely(!HTTP_IS_CRLF(*ptr)))
595 EAT_AND_JUMP_OR_RETURN(http_msg_rpreason, HTTP_MSG_RPREASON);
596 msg->sl.st.r_l = (ptr - msg_buf) - msg->sl.st.r;
597 http_msg_rpline_eol:
598 /* We have seen the end of line. Note that we do not
599 * necessarily have the \n yet, but at least we know that we
600 * have EITHER \r OR \n, otherwise the response would not be
601 * complete. We can then record the response length and return
602 * to the caller which will be able to register it.
603 */
604 msg->sl.st.l = ptr - msg->sol;
605 return ptr;
606
607#ifdef DEBUG_FULL
608 default:
609 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
610 exit(1);
611#endif
612 }
613
614 http_msg_ood:
615 /* out of data */
616 if (ret_state)
617 *ret_state = state;
618 if (ret_ptr)
619 *ret_ptr = (char *)ptr;
620 return NULL;
621
622 http_msg_invalid:
623 /* invalid message */
624 if (ret_state)
625 *ret_state = HTTP_MSG_ERROR;
626 return NULL;
627}
628
629
630/*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100631 * This function parses a request line between <ptr> and <end>, starting with
632 * parser state <state>. Only states HTTP_MSG_RQMETH, HTTP_MSG_RQMETH_SP,
633 * HTTP_MSG_RQURI, HTTP_MSG_RQURI_SP and HTTP_MSG_RQVER are handled. Others
634 * will give undefined results.
635 * Note that it is upon the caller's responsibility to ensure that ptr < end,
636 * and that msg->sol points to the beginning of the request.
637 * If a complete line is found (which implies that at least one CR or LF is
638 * found before <end>, the updated <ptr> is returned, otherwise NULL is
639 * returned indicating an incomplete line (which does not mean that parts have
640 * not been updated). In the incomplete case, if <ret_ptr> or <ret_state> are
641 * non-NULL, they are fed with the new <ptr> and <state> values to be passed
642 * upon next call.
643 *
644 * This function was intentionnally designed to be called from
645 * http_msg_analyzer() with the lowest overhead. It should integrate perfectly
646 * within its state machine and use the same macros, hence the need for same
647 * labels and variable names.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200648 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100649const char *http_parse_reqline(struct http_msg *msg, const char *msg_buf, int state,
Willy Tarreau8973c702007-01-21 23:58:29 +0100650 const char *ptr, const char *end,
651 char **ret_ptr, int *ret_state)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200652{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100653 __label__
654 http_msg_rqmeth,
655 http_msg_rqmeth_sp,
656 http_msg_rquri,
657 http_msg_rquri_sp,
658 http_msg_rqver,
659 http_msg_rqline_eol,
660 http_msg_ood, /* out of data */
661 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100662
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100663 switch (state) {
664 http_msg_rqmeth:
665 case HTTP_MSG_RQMETH:
666 if (likely(HTTP_IS_TOKEN(*ptr)))
667 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth, HTTP_MSG_RQMETH);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100668
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100669 if (likely(HTTP_IS_SPHT(*ptr))) {
670 msg->sl.rq.m_l = (ptr - msg_buf) - msg->sor;
671 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
672 }
Willy Tarreau58f10d72006-12-04 02:26:12 +0100673
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100674 if (likely(HTTP_IS_CRLF(*ptr))) {
675 /* HTTP 0.9 request */
676 msg->sl.rq.m_l = (ptr - msg_buf) - msg->sor;
677 http_msg_req09_uri:
678 msg->sl.rq.u = ptr - msg_buf;
679 http_msg_req09_uri_e:
680 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
681 http_msg_req09_ver:
682 msg->sl.rq.v = ptr - msg_buf;
683 msg->sl.rq.v_l = 0;
684 goto http_msg_rqline_eol;
685 }
686 goto http_msg_invalid;
687
688 http_msg_rqmeth_sp:
689 case HTTP_MSG_RQMETH_SP:
690 if (likely(!HTTP_IS_LWS(*ptr))) {
691 msg->sl.rq.u = ptr - msg_buf;
692 goto http_msg_rquri;
693 }
694 if (likely(HTTP_IS_SPHT(*ptr)))
695 EAT_AND_JUMP_OR_RETURN(http_msg_rqmeth_sp, HTTP_MSG_RQMETH_SP);
696 /* so it's a CR/LF, meaning an HTTP 0.9 request */
697 goto http_msg_req09_uri;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100698
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100699 http_msg_rquri:
700 case HTTP_MSG_RQURI:
701 if (likely(!HTTP_IS_LWS(*ptr)))
702 EAT_AND_JUMP_OR_RETURN(http_msg_rquri, HTTP_MSG_RQURI);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100703
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100704 if (likely(HTTP_IS_SPHT(*ptr))) {
705 msg->sl.rq.u_l = (ptr - msg_buf) - msg->sl.rq.u;
706 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
707 }
Willy Tarreau58f10d72006-12-04 02:26:12 +0100708
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100709 /* so it's a CR/LF, meaning an HTTP 0.9 request */
710 goto http_msg_req09_uri_e;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100711
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100712 http_msg_rquri_sp:
713 case HTTP_MSG_RQURI_SP:
714 if (likely(!HTTP_IS_LWS(*ptr))) {
715 msg->sl.rq.v = ptr - msg_buf;
716 goto http_msg_rqver;
717 }
718 if (likely(HTTP_IS_SPHT(*ptr)))
719 EAT_AND_JUMP_OR_RETURN(http_msg_rquri_sp, HTTP_MSG_RQURI_SP);
720 /* so it's a CR/LF, meaning an HTTP 0.9 request */
721 goto http_msg_req09_ver;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100722
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100723 http_msg_rqver:
724 case HTTP_MSG_RQVER:
725 if (likely(!HTTP_IS_CRLF(*ptr)))
726 EAT_AND_JUMP_OR_RETURN(http_msg_rqver, HTTP_MSG_RQVER);
727 msg->sl.rq.v_l = (ptr - msg_buf) - msg->sl.rq.v;
728 http_msg_rqline_eol:
729 /* We have seen the end of line. Note that we do not
730 * necessarily have the \n yet, but at least we know that we
731 * have EITHER \r OR \n, otherwise the request would not be
732 * complete. We can then record the request length and return
733 * to the caller which will be able to register it.
734 */
735 msg->sl.rq.l = ptr - msg->sol;
736 return ptr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100737
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100738#ifdef DEBUG_FULL
739 default:
740 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
741 exit(1);
742#endif
743 }
Willy Tarreau58f10d72006-12-04 02:26:12 +0100744
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100745 http_msg_ood:
746 /* out of data */
747 if (ret_state)
748 *ret_state = state;
749 if (ret_ptr)
750 *ret_ptr = (char *)ptr;
751 return NULL;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100752
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100753 http_msg_invalid:
754 /* invalid message */
755 if (ret_state)
756 *ret_state = HTTP_MSG_ERROR;
757 return NULL;
758}
Willy Tarreau58f10d72006-12-04 02:26:12 +0100759
760
Willy Tarreau8973c702007-01-21 23:58:29 +0100761/*
762 * This function parses an HTTP message, either a request or a response,
763 * depending on the initial msg->hdr_state. It can be preempted everywhere
764 * when data are missing and recalled at the exact same location with no
765 * information loss. The header index is re-initialized when switching from
766 * MSG_R[PQ]BEFORE to MSG_RPVER|MSG_RQMETH.
767 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100768void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx *idx)
769{
770 __label__
771 http_msg_rqbefore,
772 http_msg_rqbefore_cr,
773 http_msg_rqmeth,
774 http_msg_rqline_end,
775 http_msg_hdr_first,
776 http_msg_hdr_name,
777 http_msg_hdr_l1_sp,
778 http_msg_hdr_l1_lf,
779 http_msg_hdr_l1_lws,
780 http_msg_hdr_val,
781 http_msg_hdr_l2_lf,
782 http_msg_hdr_l2_lws,
783 http_msg_complete_header,
784 http_msg_last_lf,
785 http_msg_ood, /* out of data */
786 http_msg_invalid;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100787
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100788 int state; /* updated only when leaving the FSM */
789 register char *ptr, *end; /* request pointers, to avoid dereferences */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100790
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100791 state = msg->hdr_state;
792 ptr = buf->lr;
793 end = buf->r;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100794
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100795 if (unlikely(ptr >= end))
796 goto http_msg_ood;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100797
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100798 switch (state) {
Willy Tarreau8973c702007-01-21 23:58:29 +0100799 /*
800 * First, states that are specific to the response only.
801 * We check them first so that request and headers are
802 * closer to each other (accessed more often).
803 */
804 http_msg_rpbefore:
805 case HTTP_MSG_RPBEFORE:
806 if (likely(HTTP_IS_TOKEN(*ptr))) {
807 if (likely(ptr == buf->data)) {
808 msg->sol = ptr;
809 msg->sor = 0;
810 } else {
811#if PARSE_PRESERVE_EMPTY_LINES
812 /* only skip empty leading lines, don't remove them */
813 msg->sol = ptr;
814 msg->sor = ptr - buf->data;
815#else
816 /* Remove empty leading lines, as recommended by
817 * RFC2616. This takes a lot of time because we
818 * must move all the buffer backwards, but this
819 * is rarely needed. The method above will be
820 * cleaner when we'll be able to start sending
821 * the request from any place in the buffer.
822 */
823 buf->lr = ptr;
824 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
825 msg->sor = 0;
826 msg->sol = buf->data;
827 ptr = buf->data;
828 end = buf->r;
829#endif
830 }
831 hdr_idx_init(idx);
832 state = HTTP_MSG_RPVER;
833 goto http_msg_rpver;
834 }
835
836 if (unlikely(!HTTP_IS_CRLF(*ptr)))
837 goto http_msg_invalid;
838
839 if (unlikely(*ptr == '\n'))
840 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
841 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore_cr, HTTP_MSG_RPBEFORE_CR);
842 /* stop here */
843
844 http_msg_rpbefore_cr:
845 case HTTP_MSG_RPBEFORE_CR:
846 EXPECT_LF_HERE(ptr, http_msg_invalid);
847 EAT_AND_JUMP_OR_RETURN(http_msg_rpbefore, HTTP_MSG_RPBEFORE);
848 /* stop here */
849
850 http_msg_rpver:
851 case HTTP_MSG_RPVER:
852 case HTTP_MSG_RPVER_SP:
853 case HTTP_MSG_RPCODE:
854 case HTTP_MSG_RPCODE_SP:
855 case HTTP_MSG_RPREASON:
856 ptr = (char *)http_parse_rspline(msg, buf->data, state, ptr, end,
857 &buf->lr, &msg->hdr_state);
858 if (unlikely(!ptr))
859 return;
860
861 /* we have a full response and we know that we have either a CR
862 * or an LF at <ptr>.
863 */
864 //fprintf(stderr,"sor=%d rq.l=%d *ptr=0x%02x\n", msg->sor, msg->sl.st.l, *ptr);
865 hdr_idx_set_start(idx, msg->sl.st.l, *ptr == '\r');
866
867 msg->sol = ptr;
868 if (likely(*ptr == '\r'))
869 EAT_AND_JUMP_OR_RETURN(http_msg_rpline_end, HTTP_MSG_RPLINE_END);
870 goto http_msg_rpline_end;
871
872 http_msg_rpline_end:
873 case HTTP_MSG_RPLINE_END:
874 /* msg->sol must point to the first of CR or LF. */
875 EXPECT_LF_HERE(ptr, http_msg_invalid);
876 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
877 /* stop here */
878
879 /*
880 * Second, states that are specific to the request only
881 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100882 http_msg_rqbefore:
883 case HTTP_MSG_RQBEFORE:
884 if (likely(HTTP_IS_TOKEN(*ptr))) {
885 if (likely(ptr == buf->data)) {
886 msg->sol = ptr;
887 msg->sor = 0;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100888 } else {
889#if PARSE_PRESERVE_EMPTY_LINES
890 /* only skip empty leading lines, don't remove them */
891 msg->sol = ptr;
892 msg->sor = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100893#else
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100894 /* Remove empty leading lines, as recommended by
895 * RFC2616. This takes a lot of time because we
896 * must move all the buffer backwards, but this
897 * is rarely needed. The method above will be
898 * cleaner when we'll be able to start sending
899 * the request from any place in the buffer.
Willy Tarreau58f10d72006-12-04 02:26:12 +0100900 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100901 buf->lr = ptr;
902 buffer_replace2(buf, buf->data, buf->lr, NULL, 0);
903 msg->sor = 0;
904 msg->sol = buf->data;
905 ptr = buf->data;
906 end = buf->r;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100907#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100908 }
Willy Tarreauf0d058e2007-01-25 12:03:42 +0100909 /* we will need this when keep-alive will be supported
910 hdr_idx_init(idx);
911 */
Willy Tarreau8973c702007-01-21 23:58:29 +0100912 state = HTTP_MSG_RQMETH;
913 goto http_msg_rqmeth;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100914 }
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100915
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100916 if (unlikely(!HTTP_IS_CRLF(*ptr)))
917 goto http_msg_invalid;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100918
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100919 if (unlikely(*ptr == '\n'))
920 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
921 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore_cr, HTTP_MSG_RQBEFORE_CR);
Willy Tarreau8973c702007-01-21 23:58:29 +0100922 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100923
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100924 http_msg_rqbefore_cr:
925 case HTTP_MSG_RQBEFORE_CR:
926 EXPECT_LF_HERE(ptr, http_msg_invalid);
927 EAT_AND_JUMP_OR_RETURN(http_msg_rqbefore, HTTP_MSG_RQBEFORE);
Willy Tarreau8973c702007-01-21 23:58:29 +0100928 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100929
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100930 http_msg_rqmeth:
931 case HTTP_MSG_RQMETH:
932 case HTTP_MSG_RQMETH_SP:
933 case HTTP_MSG_RQURI:
934 case HTTP_MSG_RQURI_SP:
935 case HTTP_MSG_RQVER:
936 ptr = (char *)http_parse_reqline(msg, buf->data, state, ptr, end,
937 &buf->lr, &msg->hdr_state);
938 if (unlikely(!ptr))
939 return;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100940
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100941 /* we have a full request and we know that we have either a CR
942 * or an LF at <ptr>.
943 */
944 //fprintf(stderr,"sor=%d rq.l=%d *ptr=0x%02x\n", msg->sor, msg->sl.rq.l, *ptr);
945 hdr_idx_set_start(idx, msg->sl.rq.l, *ptr == '\r');
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100946
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100947 msg->sol = ptr;
948 if (likely(*ptr == '\r'))
949 EAT_AND_JUMP_OR_RETURN(http_msg_rqline_end, HTTP_MSG_RQLINE_END);
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100950 goto http_msg_rqline_end;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100951
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100952 http_msg_rqline_end:
953 case HTTP_MSG_RQLINE_END:
954 /* check for HTTP/0.9 request : no version information available.
955 * msg->sol must point to the first of CR or LF.
956 */
957 if (unlikely(msg->sl.rq.v_l == 0))
958 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100959
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100960 EXPECT_LF_HERE(ptr, http_msg_invalid);
961 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_first, HTTP_MSG_HDR_FIRST);
Willy Tarreau8973c702007-01-21 23:58:29 +0100962 /* stop here */
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100963
Willy Tarreau8973c702007-01-21 23:58:29 +0100964 /*
965 * Common states below
966 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100967 http_msg_hdr_first:
968 case HTTP_MSG_HDR_FIRST:
969 msg->sol = ptr;
970 if (likely(!HTTP_IS_CRLF(*ptr))) {
971 goto http_msg_hdr_name;
972 }
973
974 if (likely(*ptr == '\r'))
975 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
976 goto http_msg_last_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100977
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100978 http_msg_hdr_name:
979 case HTTP_MSG_HDR_NAME:
980 /* assumes msg->sol points to the first char */
981 if (likely(HTTP_IS_TOKEN(*ptr)))
982 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_name, HTTP_MSG_HDR_NAME);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100983
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100984 if (likely(*ptr == ':')) {
985 msg->col = ptr - buf->data;
986 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
987 }
Willy Tarreau58f10d72006-12-04 02:26:12 +0100988
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100989 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100990
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100991 http_msg_hdr_l1_sp:
992 case HTTP_MSG_HDR_L1_SP:
993 /* assumes msg->sol points to the first char and msg->col to the colon */
994 if (likely(HTTP_IS_SPHT(*ptr)))
995 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_sp, HTTP_MSG_HDR_L1_SP);
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100996
Willy Tarreau8d5d7f22007-01-21 19:16:41 +0100997 /* header value can be basically anything except CR/LF */
998 msg->sov = ptr - buf->data;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100999
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001000 if (likely(!HTTP_IS_CRLF(*ptr))) {
1001 goto http_msg_hdr_val;
1002 }
1003
1004 if (likely(*ptr == '\r'))
1005 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lf, HTTP_MSG_HDR_L1_LF);
1006 goto http_msg_hdr_l1_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001007
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001008 http_msg_hdr_l1_lf:
1009 case HTTP_MSG_HDR_L1_LF:
1010 EXPECT_LF_HERE(ptr, http_msg_invalid);
1011 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l1_lws, HTTP_MSG_HDR_L1_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001012
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001013 http_msg_hdr_l1_lws:
1014 case HTTP_MSG_HDR_L1_LWS:
1015 if (likely(HTTP_IS_SPHT(*ptr))) {
1016 /* replace HT,CR,LF with spaces */
1017 for (; buf->data+msg->sov < ptr; msg->sov++)
1018 buf->data[msg->sov] = ' ';
1019 goto http_msg_hdr_l1_sp;
1020 }
Willy Tarreaub9ebf702007-01-26 23:39:38 +01001021 msg->eol = ptr;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001022 goto http_msg_complete_header;
1023
1024 http_msg_hdr_val:
1025 case HTTP_MSG_HDR_VAL:
1026 /* assumes msg->sol points to the first char, msg->col to the
1027 * colon, and msg->sov points to the first character of the
1028 * value.
1029 */
1030 if (likely(!HTTP_IS_CRLF(*ptr)))
1031 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001032
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001033 msg->eol = ptr;
1034 /* Note: we could also copy eol into ->eoh so that we have the
1035 * real header end in case it ends with lots of LWS, but is this
1036 * really needed ?
1037 */
1038 if (likely(*ptr == '\r'))
1039 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1040 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001041
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001042 http_msg_hdr_l2_lf:
1043 case HTTP_MSG_HDR_L2_LF:
1044 EXPECT_LF_HERE(ptr, http_msg_invalid);
1045 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001046
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001047 http_msg_hdr_l2_lws:
1048 case HTTP_MSG_HDR_L2_LWS:
1049 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1050 /* LWS: replace HT,CR,LF with spaces */
1051 for (; msg->eol < ptr; msg->eol++)
1052 *msg->eol = ' ';
1053 goto http_msg_hdr_val;
1054 }
1055 http_msg_complete_header:
1056 /*
1057 * It was a new header, so the last one is finished.
1058 * Assumes msg->sol points to the first char, msg->col to the
1059 * colon, msg->sov points to the first character of the value
1060 * and msg->eol to the first CR or LF so we know how the line
1061 * ends. We insert last header into the index.
1062 */
1063 /*
1064 fprintf(stderr,"registering %-2d bytes : ", msg->eol - msg->sol);
1065 write(2, msg->sol, msg->eol-msg->sol);
1066 fprintf(stderr,"\n");
1067 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001068
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001069 if (unlikely(hdr_idx_add(msg->eol - msg->sol, *msg->eol == '\r',
1070 idx, idx->tail) < 0))
1071 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001072
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001073 msg->sol = ptr;
1074 if (likely(!HTTP_IS_CRLF(*ptr))) {
1075 goto http_msg_hdr_name;
1076 }
1077
1078 if (likely(*ptr == '\r'))
1079 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1080 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001081
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001082 http_msg_last_lf:
1083 case HTTP_MSG_LAST_LF:
1084 /* Assumes msg->sol points to the first of either CR or LF */
1085 EXPECT_LF_HERE(ptr, http_msg_invalid);
1086 ptr++;
1087 buf->lr = ptr;
1088 msg->eoh = msg->sol - buf->data;
1089 msg->hdr_state = HTTP_MSG_BODY;
1090 return;
1091#ifdef DEBUG_FULL
1092 default:
1093 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1094 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001095#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001096 }
1097 http_msg_ood:
1098 /* out of data */
1099 msg->hdr_state = state;
1100 buf->lr = ptr;
1101 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001102
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001103 http_msg_invalid:
1104 /* invalid message */
1105 msg->hdr_state = HTTP_MSG_ERROR;
1106 return;
1107}
1108
1109/*
1110 * manages the client FSM and its socket. BTW, it also tries to handle the
1111 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1112 * 0 else.
1113 */
1114int process_cli(struct session *t)
1115{
1116 int s = t->srv_state;
1117 int c = t->cli_state;
1118 struct buffer *req = t->req;
1119 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001120
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001121 DPRINTF(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
1122 cli_stnames[c], srv_stnames[s],
1123 MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
1124 req->rex.tv_sec, req->rex.tv_usec,
1125 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001126
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001127 if (c == CL_STHEADERS) {
1128 /*
1129 * Now parse the partial (or complete) lines.
1130 * We will check the request syntax, and also join multi-line
1131 * headers. An index of all the lines will be elaborated while
1132 * parsing.
1133 *
Willy Tarreau8973c702007-01-21 23:58:29 +01001134 * For the parsing, we use a 28 states FSM.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001135 *
1136 * RFC2616 requires that both LF and CRLF are recognized as
1137 * line breaks, but that any other combination is an error.
1138 * To avoid duplicating all the states above to check for CR,
1139 * we use a special bit HTTP_PA_LF_EXP that we 'OR' with the
1140 * state we will switch to if the LF is seen, so that we know
1141 * whether there's a pending CR or not. We can check it
1142 * globally since all CR followed by anything but LF are
1143 * errors. Each state is entered with the first character is
1144 * has to process at req->lr.
1145 *
1146 * Here is the information we currently have :
1147 * req->data + req->sor = beginning of request
1148 * req->data + req->eoh = end of processed headers / start of current one
1149 * req->data + req->eol = end of current header or line (LF or CRLF)
1150 * req->lr = first non-visited byte
1151 * req->r = end of data
1152 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001153
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001154 int cur_idx;
1155 struct http_req *hreq = &t->hreq;
1156 struct http_msg *msg = &hreq->req;
1157 struct proxy *cur_proxy;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001158
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001159 if (likely(req->lr < req->r))
1160 http_msg_analyzer(req, msg, &hreq->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001161
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001162 /* 1: we might have to print this header in debug mode */
1163 if (unlikely((global.mode & MODE_DEBUG) &&
1164 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
1165 (msg->hdr_state == HTTP_MSG_BODY || msg->hdr_state == HTTP_MSG_ERROR))) {
1166 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001167
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001168 sol = req->data + msg->sor;
1169 eol = sol + msg->sl.rq.l;
1170 debug_hdr("clireq", t, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001171
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001172 sol += hdr_idx_first_pos(&hreq->hdr_idx);
1173 cur_idx = hdr_idx_first_idx(&hreq->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001174
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001175 while (cur_idx) {
1176 eol = sol + hreq->hdr_idx.v[cur_idx].len;
1177 debug_hdr("clihdr", t, sol, eol);
1178 sol = eol + hreq->hdr_idx.v[cur_idx].cr + 1;
1179 cur_idx = hreq->hdr_idx.v[cur_idx].next;
1180 }
1181 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001182
Willy Tarreau58f10d72006-12-04 02:26:12 +01001183
1184 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001185 * Now we quickly check if we have found a full valid request.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001186 * If not so, we check the FD and buffer states before leaving.
1187 * A full request is indicated by the fact that we have seen
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001188 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
1189 * requests are checked first.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001190 *
1191 */
1192
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001193 if (unlikely(msg->hdr_state != HTTP_MSG_BODY)) {
1194 /*
1195 * First, let's catch bad requests.
1196 */
1197 if (unlikely(msg->hdr_state == HTTP_MSG_ERROR))
1198 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001199
1200 /* 1: Since we are in header mode, if there's no space
1201 * left for headers, we won't be able to free more
1202 * later, so the session will never terminate. We
1203 * must terminate it now.
1204 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001205 if (unlikely(req->l >= req->rlim - req->data)) {
1206 /* FIXME: check if URI is set and return Status
1207 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001208 */
Willy Tarreau06619262006-12-17 08:37:22 +01001209 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001210 }
1211
1212 /* 2: have we encountered a read error or a close ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001213 else if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1214 /* read error, or last read : give up. */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001215 tv_eternity(&req->rex);
1216 fd_delete(t->cli_fd);
1217 t->cli_state = CL_STCLOSE;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001218 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001219 if (!(t->flags & SN_ERR_MASK))
1220 t->flags |= SN_ERR_CLICL;
1221 if (!(t->flags & SN_FINST_MASK))
1222 t->flags |= SN_FINST_R;
1223 return 1;
1224 }
1225
1226 /* 3: has the read timeout expired ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001227 else if (unlikely(tv_cmp2_ms(&req->rex, &now) <= 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001228 /* read timeout : give up with an error message. */
1229 t->logs.status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +01001230 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001231 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001232 if (!(t->flags & SN_ERR_MASK))
1233 t->flags |= SN_ERR_CLITO;
1234 if (!(t->flags & SN_FINST_MASK))
1235 t->flags |= SN_FINST_R;
1236 return 1;
1237 }
1238
1239 /* 4: do we need to re-enable the read socket ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001240 else if (unlikely(! MY_FD_ISSET(t->cli_fd, StaticReadEvent))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001241 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
1242 * full. We cannot loop here since stream_sock_read will disable it only if
1243 * req->l == rlim-data
1244 */
1245 MY_FD_SET(t->cli_fd, StaticReadEvent);
1246 if (t->fe->clitimeout)
1247 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
1248 else
1249 tv_eternity(&req->rex);
1250 }
1251 return t->cli_state != CL_STHEADERS;
1252 }
1253
1254
1255 /****************************************************************
1256 * More interesting part now : we know that we have a complete *
1257 * request which at least looks like HTTP. We have an indicator *
1258 * of each header's length, so we can parse them quickly. *
1259 ****************************************************************/
1260
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001261 /*
1262 * 1: identify the method
1263 */
1264 hreq->meth = find_http_meth(&req->data[msg->sor], msg->sl.rq.m_l);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001265
1266 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001267 * 2: check if the URI matches the monitor_uri.
Willy Tarreau06619262006-12-17 08:37:22 +01001268 * We have to do this for every request which gets in, because
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001269 * the monitor-uri is defined by the frontend.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001270 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001271 if (unlikely((t->fe->monitor_uri_len != 0) &&
1272 (t->fe->monitor_uri_len == msg->sl.rq.u_l) &&
1273 !memcmp(&req->data[msg->sl.rq.u],
1274 t->fe->monitor_uri,
1275 t->fe->monitor_uri_len))) {
1276 /*
1277 * We have found the monitor URI
1278 */
1279 t->flags |= SN_MONITOR;
1280 t->logs.status = 200;
1281 client_retnclose(t, &http_200_chunk);
1282 goto return_prx_cond;
1283 }
1284
1285 /*
1286 * 3: Maybe we have to copy the original REQURI for the logs ?
1287 * Note: we cannot log anymore if the request has been
1288 * classified as invalid.
1289 */
1290 if (unlikely(t->logs.logwait & LW_REQ)) {
1291 /* we have a complete HTTP request that we must log */
1292 if ((t->logs.uri = pool_alloc(requri)) != NULL) {
1293 int urilen = msg->sl.rq.l;
1294
1295 if (urilen >= REQURI_LEN)
1296 urilen = REQURI_LEN - 1;
1297 memcpy(t->logs.uri, &req->data[msg->sor], urilen);
1298 t->logs.uri[urilen] = 0;
1299
1300 if (!(t->logs.logwait &= ~LW_REQ))
1301 sess_log(t);
1302 } else {
1303 Alert("HTTP logging : out of memory.\n");
1304 }
1305 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001306
Willy Tarreau06619262006-12-17 08:37:22 +01001307
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001308 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
1309 if (unlikely(msg->sl.rq.v_l == 0)) {
1310 int delta;
1311 char *cur_end;
1312 msg->sol = req->data + msg->sor;
1313 cur_end = msg->sol + msg->sl.rq.l;
1314 delta = 0;
Willy Tarreau06619262006-12-17 08:37:22 +01001315
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001316 if (msg->sl.rq.u_l == 0) {
1317 /* if no URI was set, add "/" */
1318 delta = buffer_replace2(req, cur_end, cur_end, " /", 2);
1319 cur_end += delta;
1320 msg->eoh += delta;
Willy Tarreau06619262006-12-17 08:37:22 +01001321 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001322 /* add HTTP version */
1323 delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
1324 msg->eoh += delta;
1325 cur_end += delta;
1326 cur_end = (char *)http_parse_reqline(msg, req->data,
1327 HTTP_MSG_RQMETH,
1328 msg->sol, cur_end + 1,
1329 NULL, NULL);
1330 if (unlikely(!cur_end))
1331 goto return_bad_req;
1332
1333 /* we have a full HTTP/1.0 request now and we know that
1334 * we have either a CR or an LF at <ptr>.
1335 */
1336 hdr_idx_set_start(&hreq->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
Willy Tarreau58f10d72006-12-04 02:26:12 +01001337 }
1338
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001339
1340 /* 5: we may need to capture headers */
1341 if (unlikely((t->logs.logwait & LW_REQHDR) && t->fe->fiprm->req_cap)) {
1342 char *eol, *sol, *col, *sov;
1343 int cur_idx;
1344 struct cap_hdr *h;
1345 int len;
1346
1347 sol = req->data + msg->sor + hdr_idx_first_pos(&hreq->hdr_idx);
1348 cur_idx = hdr_idx_first_idx(&hreq->hdr_idx);
1349
1350 while (cur_idx) {
1351 eol = sol + hreq->hdr_idx.v[cur_idx].len;
1352
1353 col = sol;
1354 while (col < eol && *col != ':')
1355 col++;
1356
1357 sov = col + 1;
1358 while (sov < eol && http_is_lws[(unsigned char)*sov])
1359 sov++;
1360
1361 for (h = t->fe->fiprm->req_cap; h; h = h->next) {
1362 if ((h->namelen == col - sol) &&
1363 (strncasecmp(sol, h->name, h->namelen) == 0)) {
1364 if (hreq->req.cap[h->index] == NULL)
1365 hreq->req.cap[h->index] =
1366 pool_alloc_from(h->pool, h->len + 1);
1367
1368 if (hreq->req.cap[h->index] == NULL) {
1369 Alert("HTTP capture : out of memory.\n");
1370 continue;
1371 }
1372
1373 len = eol - sov;
1374 if (len > h->len)
1375 len = h->len;
1376
1377 memcpy(hreq->req.cap[h->index], sov, len);
1378 hreq->req.cap[h->index][len]=0;
1379 }
1380 }
1381 sol = eol + hreq->hdr_idx.v[cur_idx].cr + 1;
1382 cur_idx = hreq->hdr_idx.v[cur_idx].next;
1383 }
1384 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001385
1386 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001387 * 6: we will have to evaluate the filters.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001388 * As opposed to version 1.2, now they will be evaluated in the
1389 * filters order and not in the header order. This means that
1390 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001391 *
1392 * We can now check whether we want to switch to another
1393 * backend, in which case we will re-check the backend's
1394 * filters and various options. In order to support 3-level
1395 * switching, here's how we should proceed :
1396 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001397 * a) run be->fiprm.
1398 * if (switch) then switch ->be to the new backend.
1399 * b) run be->fiprm if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001400 * There cannot be any switch from there, so ->be cannot be
1401 * changed anymore.
1402 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001403 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001404 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001405 * The response path will be able to apply either ->be, or
1406 * ->be then ->fe filters in order to match the reverse of
1407 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001408 */
1409
Willy Tarreau06619262006-12-17 08:37:22 +01001410 do {
Willy Tarreau830ff452006-12-17 19:31:23 +01001411 struct proxy *rule_set = t->be->fiprm;
1412 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001413
Willy Tarreau06619262006-12-17 08:37:22 +01001414 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01001415 if (rule_set->req_exp != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001416 if (apply_filters_to_request(t, req, rule_set->req_exp) < 0)
1417 goto return_bad_req;
Willy Tarreau53b6c742006-12-17 13:37:46 +01001418 }
1419
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001420 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
1421 /* to ensure correct connection accounting on
1422 * the backend, we count the connection for the
1423 * one managing the queue.
1424 */
1425 t->be->beprm->beconn++;
1426 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1427 t->be->beprm->beconn_max = t->be->beprm->beconn;
1428 t->be->beprm->cum_beconn++;
1429 t->flags |= SN_BE_ASSIGNED;
1430 }
1431
Willy Tarreau06619262006-12-17 08:37:22 +01001432 /* has the request been denied ? */
1433 if (t->flags & SN_CLDENY) {
1434 /* no need to go further */
1435 t->logs.status = 403;
1436 /* let's log the request time */
1437 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreau80587432006-12-24 17:47:20 +01001438 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01001439 goto return_prx_cond;
1440 }
1441
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001442 /* We might have to check for "Connection:" */
1443 if (((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) &&
1444 !(t->flags & SN_CONN_CLOSED)) {
1445 char *cur_ptr, *cur_end, *cur_next;
1446 int cur_idx, old_idx, delta;
1447 struct hdr_idx_elem *cur_hdr;
Willy Tarreau06619262006-12-17 08:37:22 +01001448
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001449 cur_next = req->data + hreq->req.sor + hdr_idx_first_pos(&hreq->hdr_idx);
1450 old_idx = 0;
1451
1452 while ((cur_idx = hreq->hdr_idx.v[old_idx].next)) {
1453 cur_hdr = &hreq->hdr_idx.v[cur_idx];
1454 cur_ptr = cur_next;
1455 cur_end = cur_ptr + cur_hdr->len;
1456 cur_next = cur_end + cur_hdr->cr + 1;
1457
1458 if (strncasecmp(cur_ptr, "Connection:", 11) == 0) {
1459 /* 3 possibilities :
1460 * - we have already set Connection: close,
1461 * so we remove this line.
1462 * - we have not yet set Connection: close,
1463 * but this line indicates close. We leave
1464 * it untouched and set the flag.
1465 * - we have not yet set Connection: close,
1466 * and this line indicates non-close. We
1467 * replace it.
1468 */
1469 if (t->flags & SN_CONN_CLOSED) {
1470 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
1471 hreq->req.eoh += delta;
1472 cur_next += delta;
1473 hreq->hdr_idx.v[old_idx].next = cur_hdr->next;
1474 hreq->hdr_idx.used--;
1475 cur_hdr->len = 0;
1476 } else {
1477 if (cur_ptr + 17 > cur_end ||
1478 !http_is_lws[(unsigned char)*(cur_ptr+17)] ||
1479 strncasecmp(cur_ptr+11, " close", 6)) {
1480 delta = buffer_replace2(req, cur_ptr+11, cur_end,
1481 " close", 6);
1482 cur_next += delta;
1483 cur_hdr->len += delta;
1484 hreq->req.eoh += delta;
1485 }
1486 t->flags |= SN_CONN_CLOSED;
1487 }
1488 }
1489 old_idx = cur_idx;
1490 }
1491
1492 /* add request headers from the rule sets in the same order */
1493 for (cur_idx = 0; cur_idx < rule_set->nb_reqadd; cur_idx++) {
1494 int len;
1495
1496 len = sprintf(trash, "%s\r\n", rule_set->req_add[cur_idx]);
1497 len = buffer_replace2(req, req->data + hreq->req.eoh,
1498 req->data + hreq->req.eoh, trash, len);
1499 hreq->req.eoh += len;
Willy Tarreau06619262006-12-17 08:37:22 +01001500
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001501 if (unlikely(hdr_idx_add(len - 2, 1, &hreq->hdr_idx, hreq->hdr_idx.tail) < 0))
1502 goto return_bad_req;
1503 }
Willy Tarreau06619262006-12-17 08:37:22 +01001504 }
Willy Tarreaub2513902006-12-17 14:52:38 +01001505
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001506 /* check if stats URI was requested, and if an auth is needed */
Willy Tarreau0214c3a2007-01-07 13:47:30 +01001507 if (rule_set->uri_auth != NULL &&
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001508 (hreq->meth == HTTP_METH_GET || hreq->meth == HTTP_METH_HEAD)) {
Willy Tarreaub2513902006-12-17 14:52:38 +01001509 /* we have to check the URI and auth for this request */
1510 if (stats_check_uri_auth(t, rule_set))
1511 return 1;
1512 }
1513
Willy Tarreau5fdfb912007-01-01 23:11:07 +01001514 if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
1515 /* No backend was set, but there was a default
1516 * backend set in the frontend, so we use it and
1517 * loop again.
1518 */
1519 t->be = cur_proxy->defbe.be;
1520 t->be->beprm->beconn++;
1521 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1522 t->be->beprm->beconn_max = t->be->beprm->beconn;
1523 t->be->beprm->cum_beconn++;
1524 t->flags |= SN_BE_ASSIGNED;
1525 }
1526 } while (t->be != cur_proxy); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01001527
Willy Tarreau58f10d72006-12-04 02:26:12 +01001528
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001529 if (!(t->flags & SN_BE_ASSIGNED)) {
1530 /* To ensure correct connection accounting on
1531 * the backend, we count the connection for the
1532 * one managing the queue.
1533 */
1534 t->be->beprm->beconn++;
1535 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1536 t->be->beprm->beconn_max = t->be->beprm->beconn;
1537 t->be->beprm->cum_beconn++;
1538 t->flags |= SN_BE_ASSIGNED;
1539 }
1540
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001541 /*
1542 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01001543 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001544 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01001545 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01001546 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001547
Willy Tarreau58f10d72006-12-04 02:26:12 +01001548
Willy Tarreau58f10d72006-12-04 02:26:12 +01001549
Willy Tarreau58f10d72006-12-04 02:26:12 +01001550
Willy Tarreau2a324282006-12-05 00:05:46 +01001551 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001552 * 7: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01001553 * so let's do the same now.
1554 */
1555
1556 /* It needs to look into the URI */
Willy Tarreau830ff452006-12-17 19:31:23 +01001557 if (t->be->beprm->appsession_name) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001558 get_srv_from_appsession(t, &req->data[msg->sor], msg->sl.rq.l);
Willy Tarreau06619262006-12-17 08:37:22 +01001559 }
1560
1561
1562 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001563 * 8: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01001564 * Note that doing so might move headers in the request, but
1565 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01001566 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01001567 */
1568 if (!(t->flags & (SN_CLDENY|SN_CLTARPIT)))
1569 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001570
Willy Tarreau58f10d72006-12-04 02:26:12 +01001571
Willy Tarreau2a324282006-12-05 00:05:46 +01001572 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001573 * 9: add X-Forwarded-For : Should depend on the backend only.
Willy Tarreau2a324282006-12-05 00:05:46 +01001574 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001575 if (t->be->beprm->options & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001576 if (t->cli_addr.ss_family == AF_INET) {
1577 int len;
1578 unsigned char *pn;
1579 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
1580 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
1581 pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001582 len = buffer_replace2(req, req->data + hreq->req.eoh,
1583 req->data + hreq->req.eoh, trash, len);
1584 hreq->req.eoh += len;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001585
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001586 if (hdr_idx_add(len - 2, 1, &hreq->hdr_idx, hreq->hdr_idx.tail) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01001587 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001588 }
1589 else if (t->cli_addr.ss_family == AF_INET6) {
1590 int len;
1591 char pn[INET6_ADDRSTRLEN];
1592 inet_ntop(AF_INET6,
1593 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
1594 pn, sizeof(pn));
1595 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001596 len = buffer_replace2(req, req->data + hreq->req.eoh,
1597 req->data + hreq->req.eoh, trash, len);
1598 hreq->req.eoh += len;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001599
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001600 if (hdr_idx_add(len - 2, 1, &hreq->hdr_idx, hreq->hdr_idx.tail) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01001601 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001602 }
1603 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001604
Willy Tarreau2a324282006-12-05 00:05:46 +01001605 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001606 * 10: add "Connection: close" if needed and not yet set.
Willy Tarreaub2513902006-12-17 14:52:38 +01001607 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001608 if (((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) &&
1609 !(t->flags & SN_CONN_CLOSED)) {
Willy Tarreau45e73e32006-12-17 00:05:15 +01001610 int len;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001611 len = buffer_replace2(req, req->data + hreq->req.eoh,
1612 req->data + hreq->req.eoh, "Connection: close\r\n", 19);
1613 hreq->req.eoh += len;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001614
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001615 if (hdr_idx_add(17, 1, &hreq->hdr_idx, hreq->hdr_idx.tail) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01001616 goto return_bad_req;
Willy Tarreaue15d9132006-12-14 22:26:42 +01001617 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001618
Willy Tarreau2a324282006-12-05 00:05:46 +01001619 /*************************************************************
1620 * OK, that's finished for the headers. We have done what we *
1621 * could. Let's switch to the DATA state. *
1622 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02001623
Willy Tarreau2a324282006-12-05 00:05:46 +01001624 t->cli_state = CL_STDATA;
1625 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001626
Willy Tarreau2a324282006-12-05 00:05:46 +01001627 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001628
Willy Tarreau2a324282006-12-05 00:05:46 +01001629 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001630 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001631 /* If the client has no timeout, or if the server is not ready yet,
1632 * and we know for sure that it can expire, then it's cleaner to
1633 * disable the timeout on the client side so that too low values
1634 * cannot make the sessions abort too early.
1635 *
1636 * FIXME-20050705: the server needs a way to re-enable this time-out
1637 * when it switches its state, otherwise a client can stay connected
1638 * indefinitely. This now seems to be OK.
1639 */
1640 tv_eternity(&req->rex);
1641 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001642
Willy Tarreau2a324282006-12-05 00:05:46 +01001643 /* When a connection is tarpitted, we use the queue timeout for the
1644 * tarpit delay, which currently happens to be the server's connect
1645 * timeout. If unset, then set it to zero because we really want it
1646 * to expire at one moment.
1647 */
1648 if (t->flags & SN_CLTARPIT) {
1649 t->req->l = 0;
1650 /* flush the request so that we can drop the connection early
1651 * if the client closes first.
1652 */
1653 tv_delayfrom(&req->cex, &now,
Willy Tarreau830ff452006-12-17 19:31:23 +01001654 t->be->beprm->contimeout ? t->be->beprm->contimeout : 0);
Willy Tarreau2a324282006-12-05 00:05:46 +01001655 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001656
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001657 /* OK let's go on with the BODY now */
Willy Tarreau06619262006-12-17 08:37:22 +01001658 goto process_data;
1659
1660 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001661 hreq->req.hdr_state = HTTP_MSG_ERROR;
Willy Tarreau06619262006-12-17 08:37:22 +01001662 t->logs.status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01001663 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001664 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01001665 return_prx_cond:
1666 if (!(t->flags & SN_ERR_MASK))
1667 t->flags |= SN_ERR_PRXCOND;
1668 if (!(t->flags & SN_FINST_MASK))
1669 t->flags |= SN_FINST_R;
1670 return 1;
1671
Willy Tarreaubaaee002006-06-26 02:48:02 +02001672 }
1673 else if (c == CL_STDATA) {
1674 process_data:
1675 /* FIXME: this error handling is partly buggy because we always report
1676 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
1677 * or HEADER phase. BTW, it's not logical to expire the client while
1678 * we're waiting for the server to connect.
1679 */
1680 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001681 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001682 tv_eternity(&req->rex);
1683 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001684 fd_delete(t->cli_fd);
1685 t->cli_state = CL_STCLOSE;
1686 if (!(t->flags & SN_ERR_MASK))
1687 t->flags |= SN_ERR_CLICL;
1688 if (!(t->flags & SN_FINST_MASK)) {
1689 if (t->pend_pos)
1690 t->flags |= SN_FINST_Q;
1691 else if (s == SV_STCONN)
1692 t->flags |= SN_FINST_C;
1693 else
1694 t->flags |= SN_FINST_D;
1695 }
1696 return 1;
1697 }
1698 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001699 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001700 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001701 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001702 shutdown(t->cli_fd, SHUT_RD);
1703 t->cli_state = CL_STSHUTR;
1704 return 1;
1705 }
1706 /* last server read and buffer empty */
1707 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001708 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001709 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001710 shutdown(t->cli_fd, SHUT_WR);
1711 /* We must ensure that the read part is still alive when switching
1712 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001713 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001714 if (t->fe->clitimeout)
1715 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001716 t->cli_state = CL_STSHUTW;
1717 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1718 return 1;
1719 }
1720 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001721 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001722 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001723 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001724 shutdown(t->cli_fd, SHUT_RD);
1725 t->cli_state = CL_STSHUTR;
1726 if (!(t->flags & SN_ERR_MASK))
1727 t->flags |= SN_ERR_CLITO;
1728 if (!(t->flags & SN_FINST_MASK)) {
1729 if (t->pend_pos)
1730 t->flags |= SN_FINST_Q;
1731 else if (s == SV_STCONN)
1732 t->flags |= SN_FINST_C;
1733 else
1734 t->flags |= SN_FINST_D;
1735 }
1736 return 1;
1737 }
1738 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001739 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001740 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001741 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001742 shutdown(t->cli_fd, SHUT_WR);
1743 /* We must ensure that the read part is still alive when switching
1744 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001745 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001746 if (t->fe->clitimeout)
1747 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001748
1749 t->cli_state = CL_STSHUTW;
1750 if (!(t->flags & SN_ERR_MASK))
1751 t->flags |= SN_ERR_CLITO;
1752 if (!(t->flags & SN_FINST_MASK)) {
1753 if (t->pend_pos)
1754 t->flags |= SN_FINST_Q;
1755 else if (s == SV_STCONN)
1756 t->flags |= SN_FINST_C;
1757 else
1758 t->flags |= SN_FINST_D;
1759 }
1760 return 1;
1761 }
1762
1763 if (req->l >= req->rlim - req->data) {
1764 /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02001765 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001766 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001767 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001768 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001769 }
1770 } else {
1771 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001772 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1773 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001774 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001775 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001776 /* If the client has no timeout, or if the server not ready yet, and we
1777 * know for sure that it can expire, then it's cleaner to disable the
1778 * timeout on the client side so that too low values cannot make the
1779 * sessions abort too early.
1780 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001781 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001782 else
Willy Tarreau73de9892006-11-30 11:40:23 +01001783 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001784 }
1785 }
1786
1787 if ((rep->l == 0) ||
1788 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001789 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1790 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001791 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001792 }
1793 } else {
1794 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001795 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1796 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001797 if (t->fe->clitimeout) {
1798 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001799 /* FIXME: to prevent the client from expiring read timeouts during writes,
1800 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001801 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001802 }
1803 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001804 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001805 }
1806 }
1807 return 0; /* other cases change nothing */
1808 }
1809 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001810 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001811 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001812 fd_delete(t->cli_fd);
1813 t->cli_state = CL_STCLOSE;
1814 if (!(t->flags & SN_ERR_MASK))
1815 t->flags |= SN_ERR_CLICL;
1816 if (!(t->flags & SN_FINST_MASK)) {
1817 if (t->pend_pos)
1818 t->flags |= SN_FINST_Q;
1819 else if (s == SV_STCONN)
1820 t->flags |= SN_FINST_C;
1821 else
1822 t->flags |= SN_FINST_D;
1823 }
1824 return 1;
1825 }
1826 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
1827 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001828 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001829 fd_delete(t->cli_fd);
1830 t->cli_state = CL_STCLOSE;
1831 return 1;
1832 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001833 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
1834 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001835 fd_delete(t->cli_fd);
1836 t->cli_state = CL_STCLOSE;
1837 if (!(t->flags & SN_ERR_MASK))
1838 t->flags |= SN_ERR_CLITO;
1839 if (!(t->flags & SN_FINST_MASK)) {
1840 if (t->pend_pos)
1841 t->flags |= SN_FINST_Q;
1842 else if (s == SV_STCONN)
1843 t->flags |= SN_FINST_C;
1844 else
1845 t->flags |= SN_FINST_D;
1846 }
1847 return 1;
1848 }
1849
1850 if (t->flags & SN_SELF_GEN) {
1851 produce_content(t);
1852 if (rep->l == 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001853 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001854 fd_delete(t->cli_fd);
1855 t->cli_state = CL_STCLOSE;
1856 return 1;
1857 }
1858 }
1859
1860 if ((rep->l == 0)
1861 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001862 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1863 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001864 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001865 }
1866 } else {
1867 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001868 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1869 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001870 if (t->fe->clitimeout) {
1871 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001872 /* FIXME: to prevent the client from expiring read timeouts during writes,
1873 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001874 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001875 }
1876 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001877 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001878 }
1879 }
1880 return 0;
1881 }
1882 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001883 if (req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001884 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001885 fd_delete(t->cli_fd);
1886 t->cli_state = CL_STCLOSE;
1887 if (!(t->flags & SN_ERR_MASK))
1888 t->flags |= SN_ERR_CLICL;
1889 if (!(t->flags & SN_FINST_MASK)) {
1890 if (t->pend_pos)
1891 t->flags |= SN_FINST_Q;
1892 else if (s == SV_STCONN)
1893 t->flags |= SN_FINST_C;
1894 else
1895 t->flags |= SN_FINST_D;
1896 }
1897 return 1;
1898 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001899 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001900 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001901 fd_delete(t->cli_fd);
1902 t->cli_state = CL_STCLOSE;
1903 return 1;
1904 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001905 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
1906 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001907 fd_delete(t->cli_fd);
1908 t->cli_state = CL_STCLOSE;
1909 if (!(t->flags & SN_ERR_MASK))
1910 t->flags |= SN_ERR_CLITO;
1911 if (!(t->flags & SN_FINST_MASK)) {
1912 if (t->pend_pos)
1913 t->flags |= SN_FINST_Q;
1914 else if (s == SV_STCONN)
1915 t->flags |= SN_FINST_C;
1916 else
1917 t->flags |= SN_FINST_D;
1918 }
1919 return 1;
1920 }
1921 else if (req->l >= req->rlim - req->data) {
1922 /* no room to read more data */
1923
1924 /* FIXME-20050705: is it possible for a client to maintain a session
1925 * after the timeout by sending more data after it receives a close ?
1926 */
1927
Willy Tarreau2a429502006-10-15 14:52:29 +02001928 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001929 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001930 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001931 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001932 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1933 }
1934 } else {
1935 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001936 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1937 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001938 if (t->fe->clitimeout)
1939 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001940 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001941 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001942 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1943 }
1944 }
1945 return 0;
1946 }
1947 else { /* CL_STCLOSE: nothing to do */
1948 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1949 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01001950 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be->beprm->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001951 write(1, trash, len);
1952 }
1953 return 0;
1954 }
1955 return 0;
1956}
1957
1958
1959/*
1960 * manages the server FSM and its socket. It returns 1 if a state has changed
1961 * (and a resync may be needed), 0 else.
1962 */
1963int process_srv(struct session *t)
1964{
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001965 struct http_req *hreq = &t->hreq;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001966 int s = t->srv_state;
1967 int c = t->cli_state;
1968 struct buffer *req = t->req;
1969 struct buffer *rep = t->rep;
1970 appsess *asession_temp = NULL;
1971 appsess local_asession;
1972 int conn_err;
1973
1974#ifdef DEBUG_FULL
1975 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
1976#endif
1977 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
Willy Tarreau2a429502006-10-15 14:52:29 +02001978 //MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
1979 //MY_FD_ISSET(t->srv_fd, StaticReadEvent), MY_FD_ISSET(t->srv_fd, StaticWriteEvent)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001980 //);
1981 if (s == SV_STIDLE) {
1982 if (c == CL_STHEADERS)
1983 return 0; /* stay in idle, waiting for data to reach the client side */
1984 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
1985 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001986 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001987 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001988 if (t->pend_pos)
1989 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1990 /* note that this must not return any error because it would be able to
1991 * overwrite the client_retnclose() output.
1992 */
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001993 if (t->flags & SN_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01001994 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001995 else
Willy Tarreau0f772532006-12-23 20:51:41 +01001996 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001997
1998 return 1;
1999 }
2000 else {
Willy Tarreaub8750a82006-09-03 09:56:00 +02002001 if (t->flags & SN_CLTARPIT) {
2002 /* This connection is being tarpitted. The CLIENT side has
2003 * already set the connect expiration date to the right
2004 * timeout. We just have to check that it has not expired.
2005 */
2006 if (tv_cmp2_ms(&req->cex, &now) > 0)
2007 return 0;
2008
2009 /* We will set the queue timer to the time spent, just for
2010 * logging purposes. We fake a 500 server error, so that the
2011 * attacker will not suspect his connection has been tarpitted.
2012 * It will not cause trouble to the logs because we can exclude
2013 * the tarpitted connections by filtering on the 'PT' status flags.
2014 */
2015 tv_eternity(&req->cex);
2016 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
2017 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01002018 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02002019 return 1;
2020 }
2021
Willy Tarreaubaaee002006-06-26 02:48:02 +02002022 /* Right now, we will need to create a connection to the server.
2023 * We might already have tried, and got a connection pending, in
2024 * which case we will not do anything till it's pending. It's up
2025 * to any other session to release it and wake us up again.
2026 */
2027 if (t->pend_pos) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002028 if (tv_cmp2_ms(&req->cex, &now) > 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002029 return 0;
2030 else {
2031 /* we've been waiting too long here */
Willy Tarreaud7971282006-07-29 18:36:34 +02002032 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002033 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
2034 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01002035 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002036 if (t->srv)
2037 t->srv->failed_conns++;
Willy Tarreau73de9892006-11-30 11:40:23 +01002038 t->fe->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002039 return 1;
2040 }
2041 }
2042
2043 do {
2044 /* first, get a connection */
2045 if (srv_redispatch_connect(t))
2046 return t->srv_state != SV_STIDLE;
2047
2048 /* try to (re-)connect to the server, and fail if we expire the
2049 * number of retries.
2050 */
2051 if (srv_retryable_connect(t)) {
2052 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
2053 return t->srv_state != SV_STIDLE;
2054 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002055 } while (1);
2056 }
2057 }
2058 else if (s == SV_STCONN) { /* connection in progress */
2059 if (c == CL_STCLOSE || c == CL_STSHUTW ||
2060 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002061 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02002062 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002063 fd_delete(t->srv_fd);
2064 if (t->srv)
2065 t->srv->cur_sess--;
2066
2067 /* note that this must not return any error because it would be able to
2068 * overwrite the client_retnclose() output.
2069 */
Willy Tarreau0f772532006-12-23 20:51:41 +01002070 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002071 return 1;
2072 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002073 if (!(req->flags & BF_WRITE_STATUS) && tv_cmp2_ms(&req->cex, &now) > 0) {
2074 //fprintf(stderr,"1: c=%d, s=%d, now=%d.%06d, exp=%d.%06d\n", c, s, now.tv_sec, now.tv_usec, req->cex.tv_sec, req->cex.tv_usec);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002075 return 0; /* nothing changed */
2076 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002077 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002078 /* timeout, asynchronous connect error or first write error */
2079 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2080
2081 fd_delete(t->srv_fd);
2082 if (t->srv)
2083 t->srv->cur_sess--;
2084
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002085 if (!(req->flags & BF_WRITE_STATUS))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002086 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
2087 else
2088 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
2089
2090 /* ensure that we have enough retries left */
2091 if (srv_count_retry_down(t, conn_err))
2092 return 1;
2093
Willy Tarreau830ff452006-12-17 19:31:23 +01002094 if (t->srv && t->conn_retries == 0 && t->be->beprm->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002095 /* We're on our last chance, and the REDISP option was specified.
2096 * We will ignore cookie and force to balance or use the dispatcher.
2097 */
2098 /* let's try to offer this slot to anybody */
Willy Tarreau830ff452006-12-17 19:31:23 +01002099 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002100 task_wakeup(&rq, t->srv->queue_mgt);
2101
2102 if (t->srv)
2103 t->srv->failed_conns++;
Willy Tarreau830ff452006-12-17 19:31:23 +01002104 t->be->beprm->failed_conns++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002105
2106 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
2107 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2108 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
2109 t->flags &= ~SN_CK_MASK;
2110 t->flags |= SN_CK_DOWN;
2111 }
2112
2113 /* first, get a connection */
2114 if (srv_redispatch_connect(t))
2115 return t->srv_state != SV_STIDLE;
2116 }
2117
Willy Tarreaubaaee002006-06-26 02:48:02 +02002118 do {
2119 /* Now we will try to either reconnect to the same server or
2120 * connect to another server. If the connection gets queued
2121 * because all servers are saturated, then we will go back to
2122 * the SV_STIDLE state.
2123 */
2124 if (srv_retryable_connect(t)) {
2125 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
2126 return t->srv_state != SV_STCONN;
2127 }
2128
2129 /* we need to redispatch the connection to another server */
2130 if (srv_redispatch_connect(t))
2131 return t->srv_state != SV_STCONN;
2132 } while (1);
2133 }
2134 else { /* no error or write 0 */
2135 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
2136
2137 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2138 if (req->l == 0) /* nothing to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02002139 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002140 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002141 } else /* need the right to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02002142 MY_FD_SET(t->srv_fd, StaticWriteEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002143 if (t->be->beprm->srvtimeout) {
2144 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002145 /* FIXME: to prevent the server from expiring read timeouts during writes,
2146 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002147 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002148 }
2149 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002150 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002151 }
2152
Willy Tarreau830ff452006-12-17 19:31:23 +01002153 if (t->be->beprm->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreau2a429502006-10-15 14:52:29 +02002154 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002155 if (t->be->beprm->srvtimeout)
2156 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002157 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002158 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002159
2160 t->srv_state = SV_STDATA;
2161 if (t->srv)
2162 t->srv->cum_sess++;
2163 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
2164
2165 /* if the user wants to log as soon as possible, without counting
2166 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002167 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002168 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
2169 sess_log(t);
2170 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002171#ifdef CONFIG_HAP_TCPSPLICE
2172 if ((t->fe->options & t->be->beprm->options) & PR_O_TCPSPLICE) {
2173 /* TCP splicing supported by both FE and BE */
2174 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2175 }
2176#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002177 }
2178 else {
2179 t->srv_state = SV_STHEADERS;
2180 if (t->srv)
2181 t->srv->cum_sess++;
2182 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2183 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002184 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002185 return 1;
2186 }
2187 }
2188 else if (s == SV_STHEADERS) { /* receiving server headers */
2189 /* now parse the partial (or complete) headers */
2190 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2191 char *ptr;
2192 int delete_header;
2193
2194 ptr = rep->lr;
2195
2196 /* look for the end of the current header */
2197 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2198 ptr++;
2199
2200 if (ptr == rep->h) {
2201 int line, len;
2202
2203 /* we can only get here after an end of headers */
2204
2205 /* first, we'll block if security checks have caught nasty things */
2206 if (t->flags & SN_CACHEABLE) {
2207 if ((t->flags & SN_CACHE_COOK) &&
2208 (t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002209 (t->be->beprm->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002210
2211 /* we're in presence of a cacheable response containing
2212 * a set-cookie header. We'll block it as requested by
2213 * the 'checkcache' option, and send an alert.
2214 */
Willy Tarreaud7971282006-07-29 18:36:34 +02002215 tv_eternity(&rep->rex);
2216 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002217 fd_delete(t->srv_fd);
2218 if (t->srv) {
2219 t->srv->cur_sess--;
2220 t->srv->failed_secu++;
2221 }
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002222 t->be->beprm->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002223 t->srv_state = SV_STCLOSE;
2224 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01002225 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002226 if (!(t->flags & SN_ERR_MASK))
2227 t->flags |= SN_ERR_PRXCOND;
2228 if (!(t->flags & SN_FINST_MASK))
2229 t->flags |= SN_FINST_H;
2230
Willy Tarreau830ff452006-12-17 19:31:23 +01002231 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->be->beprm->id, t->srv->id);
2232 send_log(t->be, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->be->beprm->id, t->srv->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002233
2234 /* We used to have a free connection slot. Since we'll never use it,
2235 * we have to inform the server that it may be used by another session.
2236 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002237 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002238 task_wakeup(&rq, t->srv->queue_mgt);
2239
2240 return 1;
2241 }
2242 }
2243
2244 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
2245 if (t->flags & SN_SVDENY) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002246 tv_eternity(&rep->rex);
2247 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002248 fd_delete(t->srv_fd);
2249 if (t->srv) {
2250 t->srv->cur_sess--;
2251 t->srv->failed_secu++;
2252 }
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002253 t->be->beprm->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002254 t->srv_state = SV_STCLOSE;
2255 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01002256 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002257 if (!(t->flags & SN_ERR_MASK))
2258 t->flags |= SN_ERR_PRXCOND;
2259 if (!(t->flags & SN_FINST_MASK))
2260 t->flags |= SN_FINST_H;
2261 /* We used to have a free connection slot. Since we'll never use it,
2262 * we have to inform the server that it may be used by another session.
2263 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002264 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002265 task_wakeup(&rq, t->srv->queue_mgt);
2266
2267 return 1;
2268 }
2269
2270 /* we'll have something else to do here : add new headers ... */
2271
Willy Tarreau830ff452006-12-17 19:31:23 +01002272 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_INS) &&
Willy Tarreau0f7562b2007-01-07 15:46:13 +01002273 (!(t->be->beprm->options & PR_O_COOK_POST) || (hreq->meth == HTTP_METH_POST))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002274 /* the server is known, it's not the one the client requested, we have to
2275 * insert a set-cookie here, except if we want to insert only on POST
2276 * requests and this one isn't. Note that servers which don't have cookies
2277 * (eg: some backup servers) will return a full cookie removal request.
2278 */
2279 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
Willy Tarreau830ff452006-12-17 19:31:23 +01002280 t->be->beprm->cookie_name,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002281 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
2282
2283 t->flags |= SN_SCK_INSERTED;
2284
2285 /* Here, we will tell an eventual cache on the client side that we don't
2286 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
2287 * Some caches understand the correct form: 'no-cache="set-cookie"', but
2288 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
2289 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002290 if (t->be->beprm->options & PR_O_COOK_NOC)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002291 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
2292 len += sprintf(trash + len, "Cache-control: private\r\n");
2293
2294 if (rep->data + rep->l < rep->h)
2295 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
2296 *(int *)0 = 0;
2297 buffer_replace2(rep, rep->h, rep->h, trash, len);
2298 }
2299
2300 /* headers to be added */
Willy Tarreau830ff452006-12-17 19:31:23 +01002301 /* FIXME: we should add headers from BE then from FE */
2302 for (line = 0; line < t->be->fiprm->nb_rspadd; line++) {
2303 len = sprintf(trash, "%s\r\n", t->be->fiprm->rsp_add[line]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002304 buffer_replace2(rep, rep->h, rep->h, trash, len);
2305 }
2306
2307 /* add a "connection: close" line if needed */
Willy Tarreaue01954f2006-12-30 23:43:54 +01002308 if ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002309 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
2310
2311 t->srv_state = SV_STDATA;
2312 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
2313 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
2314
2315 /* client connection already closed or option 'httpclose' required :
2316 * we close the server's outgoing connection right now.
2317 */
2318 if ((req->l == 0) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002319 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->beprm->options & PR_O_FORCE_CLO)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002320 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002321 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002322
2323 /* We must ensure that the read part is still alive when switching
2324 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002325 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002326 if (t->be->beprm->srvtimeout)
2327 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002328
2329 shutdown(t->srv_fd, SHUT_WR);
2330 t->srv_state = SV_STSHUTW;
2331 }
2332
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002333#ifdef CONFIG_HAP_TCPSPLICE
2334 if ((t->fe->options & t->be->beprm->options) & PR_O_TCPSPLICE) {
2335 /* TCP splicing supported by both FE and BE */
2336 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2337 }
2338#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002339 /* if the user wants to log as soon as possible, without counting
2340 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002341 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002342 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreau35d66b02007-01-02 00:28:21 +01002343 t->logs.bytes_in = rep->h - rep->data;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002344 sess_log(t);
2345 }
2346 break;
2347 }
2348
2349 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2350 if (ptr > rep->r - 2) {
2351 /* this is a partial header, let's wait for more to come */
2352 rep->lr = ptr;
2353 break;
2354 }
2355
2356 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2357 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2358
2359 /* now we know that *ptr is either \r or \n,
2360 * and that there are at least 1 char after it.
2361 */
2362 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2363 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2364 else
2365 rep->lr = ptr + 2; /* \r\n or \n\r */
2366
2367 /*
2368 * now we know that we have a full header ; we can do whatever
2369 * we want with these pointers :
2370 * rep->h = beginning of header
2371 * ptr = end of header (first \r or \n)
2372 * rep->lr = beginning of next line (next rep->h)
2373 * rep->r = end of data (not used at this stage)
2374 */
2375
2376
2377 if (t->logs.status == -1) {
2378 t->logs.logwait &= ~LW_RESP;
2379 t->logs.status = atoi(rep->h + 9);
2380 switch (t->logs.status) {
2381 case 200:
2382 case 203:
2383 case 206:
2384 case 300:
2385 case 301:
2386 case 410:
2387 /* RFC2616 @13.4:
2388 * "A response received with a status code of
2389 * 200, 203, 206, 300, 301 or 410 MAY be stored
2390 * by a cache (...) unless a cache-control
2391 * directive prohibits caching."
2392 *
2393 * RFC2616 @9.5: POST method :
2394 * "Responses to this method are not cacheable,
2395 * unless the response includes appropriate
2396 * Cache-Control or Expires header fields."
2397 */
Willy Tarreau0f7562b2007-01-07 15:46:13 +01002398 if (!(hreq->meth == HTTP_METH_POST) && (t->be->beprm->options & PR_O_CHK_CACHE))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002399 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
2400 break;
2401 default:
2402 break;
2403 }
2404 }
2405 else if (t->logs.logwait & LW_RSPHDR) {
2406 struct cap_hdr *h;
2407 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01002408 for (h = t->fe->fiprm->rsp_cap; h; h = h->next) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002409 if ((h->namelen + 2 <= ptr - rep->h) &&
2410 (rep->h[h->namelen] == ':') &&
2411 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
Willy Tarreau362b34d2007-01-21 20:49:31 +01002412 if (hreq->rsp.cap[h->index] == NULL)
2413 hreq->rsp.cap[h->index] =
2414 pool_alloc_from(h->pool, h->len + 1);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002415
Willy Tarreau362b34d2007-01-21 20:49:31 +01002416 if (hreq->rsp.cap[h->index] == NULL) {
2417 Alert("HTTP capture : out of memory.\n");
2418 continue;
2419 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002420
2421 len = ptr - (rep->h + h->namelen + 2);
2422 if (len > h->len)
2423 len = h->len;
2424
Willy Tarreau362b34d2007-01-21 20:49:31 +01002425 memcpy(hreq->rsp.cap[h->index], rep->h + h->namelen + 2, len);
2426 hreq->rsp.cap[h->index][len]=0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002427 }
2428 }
2429
2430 }
2431
2432 delete_header = 0;
2433
Willy Tarreau58f10d72006-12-04 02:26:12 +01002434 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
2435 debug_hdr("srvhdr", t, rep->h, ptr);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002436
2437 /* remove "connection: " if needed */
Willy Tarreaue01954f2006-12-30 23:43:54 +01002438 if (!delete_header &&
2439 ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) &&
2440 (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002441 delete_header = 1;
2442 }
2443
2444 /* try headers regexps */
Willy Tarreau830ff452006-12-17 19:31:23 +01002445 if (!delete_header && t->be->fiprm->rsp_exp != NULL
Willy Tarreaubaaee002006-06-26 02:48:02 +02002446 && !(t->flags & SN_SVDENY)) {
2447 struct hdr_exp *exp;
2448 char term;
2449
2450 term = *ptr;
2451 *ptr = '\0';
Willy Tarreau830ff452006-12-17 19:31:23 +01002452 exp = t->be->fiprm->rsp_exp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002453 do {
2454 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2455 switch (exp->action) {
2456 case ACT_ALLOW:
2457 if (!(t->flags & SN_SVDENY))
2458 t->flags |= SN_SVALLOW;
2459 break;
2460 case ACT_REPLACE:
2461 if (!(t->flags & SN_SVDENY)) {
2462 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
2463 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2464 }
2465 break;
2466 case ACT_REMOVE:
2467 if (!(t->flags & SN_SVDENY))
2468 delete_header = 1;
2469 break;
2470 case ACT_DENY:
2471 if (!(t->flags & SN_SVALLOW))
2472 t->flags |= SN_SVDENY;
2473 break;
2474 case ACT_PASS: /* we simply don't deny this one */
2475 break;
2476 }
2477 break;
2478 }
2479 } while ((exp = exp->next) != NULL);
2480 *ptr = term; /* restore the string terminator */
2481 }
2482
2483 /* check for cache-control: or pragma: headers */
2484 if (!delete_header && (t->flags & SN_CACHEABLE)) {
2485 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
2486 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2487 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
2488 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
2489 if (rep->h + 23 == ptr || rep->h[23] == ',')
2490 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2491 else {
2492 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
2493 && (rep->h[35] == '"' || rep->h[35] == ','))
2494 t->flags &= ~SN_CACHE_COOK;
2495 }
2496 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
2497 (rep->h + 22 == ptr || rep->h[22] == ','))
2498 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
2499 (rep->h + 23 == ptr || rep->h[23] == ','))) {
2500 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2501 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
2502 (rep->h + 24 == ptr || rep->h[24] == ',')) {
2503 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2504 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
2505 (rep->h + 25 == ptr || rep->h[25] == ',')) {
2506 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2507 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
2508 (rep->h + 21 == ptr || rep->h[21] == ',')) {
2509 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
2510 }
2511 }
2512 }
2513
2514 /* check for server cookies */
2515 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002516 && (t->be->beprm->cookie_name != NULL ||
2517 t->be->fiprm->capture_name != NULL ||
2518 t->be->beprm->appsession_name !=NULL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002519 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2520 char *p1, *p2, *p3, *p4;
2521
2522 t->flags |= SN_SCK_ANY;
2523
2524 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2525
2526 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
2527 while (p1 < ptr && (isspace((int)*p1)))
2528 p1++;
2529
2530 if (p1 == ptr || *p1 == ';') /* end of cookie */
2531 break;
2532
2533 /* p1 is at the beginning of the cookie name */
2534 p2 = p1;
2535
2536 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2537 p2++;
2538
2539 if (p2 == ptr || *p2 == ';') /* next cookie */
2540 break;
2541
2542 p3 = p2 + 1; /* skips the '=' sign */
2543 if (p3 == ptr)
2544 break;
2545
2546 p4 = p3;
2547 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
2548 p4++;
2549
2550 /* here, we have the cookie name between p1 and p2,
2551 * and its value between p3 and p4.
2552 * we can process it.
2553 */
2554
2555 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01002556 if (t->be->fiprm->capture_name != NULL &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002557 t->logs.srv_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002558 (p4 - p1 >= t->be->fiprm->capture_namelen) &&
2559 memcmp(p1, t->be->fiprm->capture_name, t->be->fiprm->capture_namelen) == 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002560 int log_len = p4 - p1;
2561
2562 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
2563 Alert("HTTP logging : out of memory.\n");
2564 }
2565
Willy Tarreau830ff452006-12-17 19:31:23 +01002566 if (log_len > t->be->fiprm->capture_len)
2567 log_len = t->be->fiprm->capture_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002568 memcpy(t->logs.srv_cookie, p1, log_len);
2569 t->logs.srv_cookie[log_len] = 0;
2570 }
2571
Willy Tarreau830ff452006-12-17 19:31:23 +01002572 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
2573 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002574 /* Cool... it's the right one */
2575 t->flags |= SN_SCK_SEEN;
2576
2577 /* If the cookie is in insert mode on a known server, we'll delete
2578 * this occurrence because we'll insert another one later.
2579 * We'll delete it too if the "indirect" option is set and we're in
2580 * a direct access. */
Willy Tarreau830ff452006-12-17 19:31:23 +01002581 if (((t->srv) && (t->be->beprm->options & PR_O_COOK_INS)) ||
2582 ((t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_IND))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002583 /* this header must be deleted */
2584 delete_header = 1;
2585 t->flags |= SN_SCK_DELETED;
2586 }
Willy Tarreau92f2ab12007-02-02 22:14:47 +01002587 else if ((t->srv) && (t->srv->cookie) &&
2588 (t->be->beprm->options & PR_O_COOK_RW)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002589 /* replace bytes p3->p4 with the cookie name associated
2590 * with this server since we know it.
2591 */
2592 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2593 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2594 }
Willy Tarreau92f2ab12007-02-02 22:14:47 +01002595 else if ((t->srv) && (t->srv->cookie) &&
2596 (t->be->beprm->options & PR_O_COOK_PFX)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002597 /* insert the cookie name associated with this server
2598 * before existing cookie, and insert a delimitor between them..
2599 */
2600 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
2601 p3[t->srv->cklen] = COOKIE_DELIM;
2602 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2603 }
2604 break;
2605 }
2606
2607 /* first, let's see if the cookie is our appcookie*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002608 if ((t->be->beprm->appsession_name != NULL) &&
2609 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002610
2611 /* Cool... it's the right one */
2612
2613 size_t server_id_len = strlen(t->srv->id) + 1;
2614 asession_temp = &local_asession;
2615
2616 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
2617 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002618 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002619 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002620 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
2621 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002622 asession_temp->serverid = NULL;
2623
2624 /* only do insert, if lookup fails */
Willy Tarreau73de9892006-11-30 11:40:23 +01002625 if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002626 if ((asession_temp = pool_alloc(appsess)) == NULL) {
2627 Alert("Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002628 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002629 return 0;
2630 }
2631 asession_temp->sessid = local_asession.sessid;
2632 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01002633 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002634 }/* end if (chtbl_lookup()) */
2635 else {
2636 /* free wasted memory */
2637 pool_free_to(apools.sessid, local_asession.sessid);
2638 } /* end else from if (chtbl_lookup()) */
2639
2640 if (asession_temp->serverid == NULL) {
2641 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
2642 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002643 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002644 }
2645 asession_temp->serverid[0] = '\0';
2646 }
2647
2648 if (asession_temp->serverid[0] == '\0')
2649 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
2650
Willy Tarreau830ff452006-12-17 19:31:23 +01002651 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002652
2653#if defined(DEBUG_HASH)
Willy Tarreau830ff452006-12-17 19:31:23 +01002654 print_table(&(t->be->beprm->htbl_proxy));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002655#endif
2656 break;
2657 }/* end if ((t->proxy->appsession_name != NULL) ... */
2658 else {
2659 // fprintf(stderr,"Ignoring unknown cookie : ");
2660 // write(2, p1, p2-p1);
2661 // fprintf(stderr," = ");
2662 // write(2, p3, p4-p3);
2663 // fprintf(stderr,"\n");
2664 }
2665 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2666 } /* we're now at the end of the cookie value */
2667 } /* end of cookie processing */
2668
2669 /* check for any set-cookie in case we check for cacheability */
2670 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002671 (t->be->beprm->options & PR_O_CHK_CACHE) &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002672 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2673 t->flags |= SN_SCK_ANY;
2674 }
2675
2676 /* let's look if we have to delete this header */
2677 if (delete_header && !(t->flags & SN_SVDENY))
2678 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2679
2680 rep->h = rep->lr;
2681 } /* while (rep->lr < rep->r) */
2682
2683 /* end of header processing (even if incomplete) */
2684
Willy Tarreau2a429502006-10-15 14:52:29 +02002685 if ((rep->l < rep->rlim - rep->data) && ! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002686 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
Willy Tarreaud7971282006-07-29 18:36:34 +02002687 * full. We cannot loop here since stream_sock_read will disable it only if
Willy Tarreaubaaee002006-06-26 02:48:02 +02002688 * rep->l == rlim-data
2689 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002690 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002691 if (t->be->beprm->srvtimeout)
2692 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002693 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002694 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002695 }
2696
2697 /* read error, write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002698 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002699 tv_eternity(&rep->rex);
2700 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002701 fd_delete(t->srv_fd);
2702 if (t->srv) {
2703 t->srv->cur_sess--;
2704 t->srv->failed_resp++;
2705 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002706 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002707 t->srv_state = SV_STCLOSE;
2708 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01002709 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002710 if (!(t->flags & SN_ERR_MASK))
2711 t->flags |= SN_ERR_SRVCL;
2712 if (!(t->flags & SN_FINST_MASK))
2713 t->flags |= SN_FINST_H;
2714 /* We used to have a free connection slot. Since we'll never use it,
2715 * we have to inform the server that it may be used by another session.
2716 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002717 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002718 task_wakeup(&rq, t->srv->queue_mgt);
2719
2720 return 1;
2721 }
2722 /* end of client write or end of server read.
2723 * since we are in header mode, if there's no space left for headers, we
2724 * won't be able to free more later, so the session will never terminate.
2725 */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002726 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE || rep->l >= rep->rlim - rep->data) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002727 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002728 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002729 shutdown(t->srv_fd, SHUT_RD);
2730 t->srv_state = SV_STSHUTR;
2731 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2732 return 1;
2733 }
2734 /* read timeout : return a 504 to the client.
2735 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002736 else if (MY_FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002737 tv_eternity(&rep->rex);
2738 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002739 fd_delete(t->srv_fd);
2740 if (t->srv) {
2741 t->srv->cur_sess--;
2742 t->srv->failed_resp++;
2743 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002744 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002745 t->srv_state = SV_STCLOSE;
2746 t->logs.status = 504;
Willy Tarreau80587432006-12-24 17:47:20 +01002747 client_return(t, error_message(t, HTTP_ERR_504));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002748 if (!(t->flags & SN_ERR_MASK))
2749 t->flags |= SN_ERR_SRVTO;
2750 if (!(t->flags & SN_FINST_MASK))
2751 t->flags |= SN_FINST_H;
2752 /* We used to have a free connection slot. Since we'll never use it,
2753 * we have to inform the server that it may be used by another session.
2754 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002755 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002756 task_wakeup(&rq, t->srv->queue_mgt);
2757
2758 return 1;
2759 }
2760 /* last client read and buffer empty */
2761 /* FIXME!!! here, we don't want to switch to SHUTW if the
2762 * client shuts read too early, because we may still have
2763 * some work to do on the headers.
2764 * The side-effect is that if the client completely closes its
2765 * connection during SV_STHEADER, the connection to the server
2766 * is kept until a response comes back or the timeout is reached.
2767 */
2768 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002769 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002770 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002771
2772 /* We must ensure that the read part is still alive when switching
2773 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002774 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002775 if (t->be->beprm->srvtimeout)
2776 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002777
2778 shutdown(t->srv_fd, SHUT_WR);
2779 t->srv_state = SV_STSHUTW;
2780 return 1;
2781 }
2782 /* write timeout */
2783 /* FIXME!!! here, we don't want to switch to SHUTW if the
2784 * client shuts read too early, because we may still have
2785 * some work to do on the headers.
2786 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002787 else if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&req->wex, &now) <= 0) {
2788 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002789 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002790 shutdown(t->srv_fd, SHUT_WR);
2791 /* We must ensure that the read part is still alive when switching
2792 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002793 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002794 if (t->be->beprm->srvtimeout)
2795 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002796
2797 /* We must ensure that the read part is still alive when switching
2798 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002799 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002800 if (t->be->beprm->srvtimeout)
2801 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002802
2803 t->srv_state = SV_STSHUTW;
2804 if (!(t->flags & SN_ERR_MASK))
2805 t->flags |= SN_ERR_SRVTO;
2806 if (!(t->flags & SN_FINST_MASK))
2807 t->flags |= SN_FINST_H;
2808 return 1;
2809 }
2810
2811 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002812 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2813 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002814 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002815 }
2816 }
2817 else { /* client buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002818 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2819 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002820 if (t->be->beprm->srvtimeout) {
2821 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002822 /* FIXME: to prevent the server from expiring read timeouts during writes,
2823 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002824 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002825 }
2826 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002827 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002828 }
2829 }
2830
2831 /* be nice with the client side which would like to send a complete header
2832 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2833 * would read all remaining data at once ! The client should not write past rep->lr
2834 * when the server is in header state.
2835 */
2836 //return header_processed;
2837 return t->srv_state != SV_STHEADERS;
2838 }
2839 else if (s == SV_STDATA) {
2840 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002841 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002842 tv_eternity(&rep->rex);
2843 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002844 fd_delete(t->srv_fd);
2845 if (t->srv) {
2846 t->srv->cur_sess--;
2847 t->srv->failed_resp++;
2848 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002849 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002850 t->srv_state = SV_STCLOSE;
2851 if (!(t->flags & SN_ERR_MASK))
2852 t->flags |= SN_ERR_SRVCL;
2853 if (!(t->flags & SN_FINST_MASK))
2854 t->flags |= SN_FINST_D;
2855 /* We used to have a free connection slot. Since we'll never use it,
2856 * we have to inform the server that it may be used by another session.
2857 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002858 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002859 task_wakeup(&rq, t->srv->queue_mgt);
2860
2861 return 1;
2862 }
2863 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002864 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002865 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002866 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002867 shutdown(t->srv_fd, SHUT_RD);
2868 t->srv_state = SV_STSHUTR;
2869 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2870 return 1;
2871 }
2872 /* end of client read and no more data to send */
2873 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002874 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002875 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002876 shutdown(t->srv_fd, SHUT_WR);
2877 /* We must ensure that the read part is still alive when switching
2878 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002879 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002880 if (t->be->beprm->srvtimeout)
2881 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002882
2883 t->srv_state = SV_STSHUTW;
2884 return 1;
2885 }
2886 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002887 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002888 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002889 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002890 shutdown(t->srv_fd, SHUT_RD);
2891 t->srv_state = SV_STSHUTR;
2892 if (!(t->flags & SN_ERR_MASK))
2893 t->flags |= SN_ERR_SRVTO;
2894 if (!(t->flags & SN_FINST_MASK))
2895 t->flags |= SN_FINST_D;
2896 return 1;
2897 }
2898 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002899 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002900 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002901 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002902 shutdown(t->srv_fd, SHUT_WR);
2903 /* We must ensure that the read part is still alive when switching
2904 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002905 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002906 if (t->be->beprm->srvtimeout)
2907 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002908 t->srv_state = SV_STSHUTW;
2909 if (!(t->flags & SN_ERR_MASK))
2910 t->flags |= SN_ERR_SRVTO;
2911 if (!(t->flags & SN_FINST_MASK))
2912 t->flags |= SN_FINST_D;
2913 return 1;
2914 }
2915
2916 /* recompute request time-outs */
2917 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002918 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2919 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002920 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002921 }
2922 }
2923 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau2a429502006-10-15 14:52:29 +02002924 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2925 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002926 if (t->be->beprm->srvtimeout) {
2927 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002928 /* FIXME: to prevent the server from expiring read timeouts during writes,
2929 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002930 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002931 }
2932 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002933 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002934 }
2935 }
2936
2937 /* recompute response time-outs */
2938 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002939 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2940 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002941 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002942 }
2943 }
2944 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002945 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2946 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002947 if (t->be->beprm->srvtimeout)
2948 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002949 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002950 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002951 }
2952 }
2953
2954 return 0; /* other cases change nothing */
2955 }
2956 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002957 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002958 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002959 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002960 fd_delete(t->srv_fd);
2961 if (t->srv) {
2962 t->srv->cur_sess--;
2963 t->srv->failed_resp++;
2964 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002965 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002966 //close(t->srv_fd);
2967 t->srv_state = SV_STCLOSE;
2968 if (!(t->flags & SN_ERR_MASK))
2969 t->flags |= SN_ERR_SRVCL;
2970 if (!(t->flags & SN_FINST_MASK))
2971 t->flags |= SN_FINST_D;
2972 /* We used to have a free connection slot. Since we'll never use it,
2973 * we have to inform the server that it may be used by another session.
2974 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002975 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002976 task_wakeup(&rq, t->srv->queue_mgt);
2977
2978 return 1;
2979 }
2980 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002981 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002982 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002983 fd_delete(t->srv_fd);
2984 if (t->srv)
2985 t->srv->cur_sess--;
2986 //close(t->srv_fd);
2987 t->srv_state = SV_STCLOSE;
2988 /* We used to have a free connection slot. Since we'll never use it,
2989 * we have to inform the server that it may be used by another session.
2990 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002991 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002992 task_wakeup(&rq, t->srv->queue_mgt);
2993
2994 return 1;
2995 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002996 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002997 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002998 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002999 fd_delete(t->srv_fd);
3000 if (t->srv)
3001 t->srv->cur_sess--;
3002 //close(t->srv_fd);
3003 t->srv_state = SV_STCLOSE;
3004 if (!(t->flags & SN_ERR_MASK))
3005 t->flags |= SN_ERR_SRVTO;
3006 if (!(t->flags & SN_FINST_MASK))
3007 t->flags |= SN_FINST_D;
3008 /* We used to have a free connection slot. Since we'll never use it,
3009 * we have to inform the server that it may be used by another session.
3010 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003011 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02003012 task_wakeup(&rq, t->srv->queue_mgt);
3013
3014 return 1;
3015 }
3016 else if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02003017 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3018 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02003019 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003020 }
3021 }
3022 else { /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02003023 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3024 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01003025 if (t->be->beprm->srvtimeout) {
3026 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003027 /* FIXME: to prevent the server from expiring read timeouts during writes,
3028 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02003029 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003030 }
3031 else
Willy Tarreaud7971282006-07-29 18:36:34 +02003032 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003033 }
3034 }
3035 return 0;
3036 }
3037 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003038 if (rep->flags & BF_READ_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02003039 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02003040 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003041 fd_delete(t->srv_fd);
3042 if (t->srv) {
3043 t->srv->cur_sess--;
3044 t->srv->failed_resp++;
3045 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003046 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003047 //close(t->srv_fd);
3048 t->srv_state = SV_STCLOSE;
3049 if (!(t->flags & SN_ERR_MASK))
3050 t->flags |= SN_ERR_SRVCL;
3051 if (!(t->flags & SN_FINST_MASK))
3052 t->flags |= SN_FINST_D;
3053 /* We used to have a free connection slot. Since we'll never use it,
3054 * we have to inform the server that it may be used by another session.
3055 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003056 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02003057 task_wakeup(&rq, t->srv->queue_mgt);
3058
3059 return 1;
3060 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003061 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02003062 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02003063 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003064 fd_delete(t->srv_fd);
3065 if (t->srv)
3066 t->srv->cur_sess--;
3067 //close(t->srv_fd);
3068 t->srv_state = SV_STCLOSE;
3069 /* We used to have a free connection slot. Since we'll never use it,
3070 * we have to inform the server that it may be used by another session.
3071 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003072 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02003073 task_wakeup(&rq, t->srv->queue_mgt);
3074
3075 return 1;
3076 }
Willy Tarreaud7971282006-07-29 18:36:34 +02003077 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02003078 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02003079 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003080 fd_delete(t->srv_fd);
3081 if (t->srv)
3082 t->srv->cur_sess--;
3083 //close(t->srv_fd);
3084 t->srv_state = SV_STCLOSE;
3085 if (!(t->flags & SN_ERR_MASK))
3086 t->flags |= SN_ERR_SRVTO;
3087 if (!(t->flags & SN_FINST_MASK))
3088 t->flags |= SN_FINST_D;
3089 /* We used to have a free connection slot. Since we'll never use it,
3090 * we have to inform the server that it may be used by another session.
3091 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003092 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02003093 task_wakeup(&rq, t->srv->queue_mgt);
3094
3095 return 1;
3096 }
3097 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02003098 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
3099 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02003100 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003101 }
3102 }
3103 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02003104 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
3105 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01003106 if (t->be->beprm->srvtimeout)
3107 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003108 else
Willy Tarreaud7971282006-07-29 18:36:34 +02003109 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003110 }
3111 }
3112 return 0;
3113 }
3114 else { /* SV_STCLOSE : nothing to do */
3115 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
3116 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01003117 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n", t->uniq_id, t->be->beprm->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003118 write(1, trash, len);
3119 }
3120 return 0;
3121 }
3122 return 0;
3123}
3124
3125
3126/*
3127 * Produces data for the session <s> depending on its source. Expects to be
3128 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3129 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3130 * session, which it uses to keep on being called when there is free space in
3131 * the buffer, of simply by letting an empty buffer upon return. It returns 1
3132 * if it changes the session state from CL_STSHUTR, otherwise 0.
3133 */
3134int produce_content(struct session *s)
3135{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003136 if (s->data_source == DATA_SRC_NONE) {
3137 s->flags &= ~SN_SELF_GEN;
3138 return 1;
3139 }
3140 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003141 /* dump server statistics */
3142 return produce_content_stats(s);
3143 }
3144 else {
3145 /* unknown data source */
3146 s->logs.status = 500;
3147 client_retnclose(s, error_message(s, HTTP_ERR_500));
3148 if (!(s->flags & SN_ERR_MASK))
3149 s->flags |= SN_ERR_PRXCOND;
3150 if (!(s->flags & SN_FINST_MASK))
3151 s->flags |= SN_FINST_R;
3152 s->flags &= ~SN_SELF_GEN;
3153 return 1;
3154 }
3155}
3156
3157
3158/*
3159 * Produces statistics data for the session <s>. Expects to be called with
3160 * s->cli_state == CL_STSHUTR. It stops by itself by unsetting the SN_SELF_GEN
3161 * flag from the session, which it uses to keep on being called when there is
3162 * free space in the buffer, of simply by letting an empty buffer upon return.
3163 * It returns 1 if it changes the session state from CL_STSHUTR, otherwise 0.
3164 */
3165int produce_content_stats(struct session *s)
3166{
3167 struct buffer *rep = s->rep;
3168 struct proxy *px;
3169 struct chunk msg;
3170 unsigned int up;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003171
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003172 msg.len = 0;
3173 msg.str = trash;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003174
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003175 switch (s->data_state) {
3176 case DATA_ST_INIT:
3177 /* the function had not been called yet */
3178 s->flags |= SN_SELF_GEN; // more data will follow
Willy Tarreaubaaee002006-06-26 02:48:02 +02003179
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003180 chunk_printf(&msg, sizeof(trash),
3181 "HTTP/1.0 200 OK\r\n"
3182 "Cache-Control: no-cache\r\n"
3183 "Connection: close\r\n"
3184 "Content-Type: text/html\r\n"
3185 "\r\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003186
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003187 s->logs.status = 200;
3188 client_retnclose(s, &msg); // send the start of the response.
3189 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003190
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003191 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
3192 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
3193 if (!(s->flags & SN_FINST_MASK))
3194 s->flags |= SN_FINST_R;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003195
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003196 if (s->hreq.meth == HTTP_METH_HEAD) {
3197 /* that's all we return in case of HEAD request */
3198 s->data_state = DATA_ST_FIN;
3199 s->flags &= ~SN_SELF_GEN;
3200 return 1;
3201 }
3202
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003203 s->data_state = DATA_ST_HEAD; /* let's start producing data */
3204 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003205
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003206 case DATA_ST_HEAD:
3207 /* WARNING! This must fit in the first buffer !!! */
3208 chunk_printf(&msg, sizeof(trash),
3209 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
3210 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
3211 "<style type=\"text/css\"><!--\n"
3212 "body {"
3213 " font-family: helvetica, arial;"
3214 " font-size: 12px;"
3215 " font-weight: normal;"
3216 " color: black;"
3217 " background: white;"
3218 "}\n"
3219 "th,td {"
3220 " font-size: 0.8em;"
3221 " align: center;"
3222 "}"
3223 "h1 {"
3224 " font-size: xx-large;"
3225 " margin-bottom: 0.5em;"
3226 "}\n"
3227 "h2 {"
3228 " font-family: helvetica, arial;"
3229 " font-size: x-large;"
3230 " font-weight: bold;"
3231 " font-style: italic;"
3232 " color: #6020a0;"
3233 " margin-top: 0em;"
3234 " margin-bottom: 0em;"
3235 "}\n"
3236 "h3 {"
3237 " font-family: helvetica, arial;"
3238 " font-size: 16px;"
3239 " font-weight: bold;"
3240 " color: #b00040;"
3241 " background: #e8e8d0;"
3242 " margin-top: 0em;"
3243 " margin-bottom: 0em;"
3244 "}\n"
3245 "li {"
3246 " margin-top: 0.25em;"
3247 " margin-right: 2em;"
3248 "}\n"
3249 ".hr {margin-top: 0.25em;"
3250 " border-color: black;"
3251 " border-bottom-style: solid;"
3252 "}\n"
3253 ".pxname {background: #b00040;color: #ffff40;font-weight: bold;}\n"
3254 ".titre {background: #20D0D0;color: #000000;font-weight: bold;}\n"
3255 ".total {background: #20D0D0;color: #ffff80;}\n"
3256 ".frontend {background: #e8e8d0;}\n"
3257 ".backend {background: #e8e8d0;}\n"
3258 ".active0 {background: #ff9090;}\n"
3259 ".active1 {background: #ffd020;}\n"
3260 ".active2 {background: #ffffa0;}\n"
3261 ".active3 {background: #c0ffc0;}\n"
3262 ".active4 {background: #e0e0e0;}\n"
3263 ".backup0 {background: #ff9090;}\n"
3264 ".backup1 {background: #ff80ff;}\n"
3265 ".backup2 {background: #c060ff;}\n"
3266 ".backup3 {background: #b0d0ff;}\n"
3267 ".backup4 {background: #e0e0e0;}\n"
3268 "table.tbl { border-collapse: collapse; border-style: none;}\n"
Willy Tarreau35d66b02007-01-02 00:28:21 +01003269 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; padding: 2px 3px; border-color: gray;}\n"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003270 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}\n"
3271 "table.tbl th.empty { border-style: none; empty-cells: hide;}\n"
3272 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
3273 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
3274 "table.lgd td.noborder { border-style: none; padding: 2px; white-space: nowrap;}\n"
3275 "-->"
3276 "</style></head>");
3277
3278 if (buffer_write_chunk(rep, &msg) != 0)
3279 return 0;
3280
3281 s->data_state = DATA_ST_INFO;
3282 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003283
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003284 case DATA_ST_INFO:
3285 up = (now.tv_sec - start_date.tv_sec);
3286
3287 /* WARNING! this has to fit the first packet too.
3288 * We are around 3.5 kB, add adding entries will
3289 * become tricky if we want to support 4kB buffers !
3290 */
3291 chunk_printf(&msg, sizeof(trash),
3292 "<body><h1><a href=\"" PRODUCT_URL "\" style=\"text-decoration: none;\">"
3293 PRODUCT_NAME "</a></h1>\n"
3294 "<h2>Statistics Report for pid %d</h2>\n"
3295 "<hr width=\"100%%\" class=\"hr\">\n"
3296 "<h3>&gt; General process information</h3>\n"
3297 "<table border=0 cols=3><tr><td align=\"left\" nowrap width=\"1%%\">\n"
3298 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
3299 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
3300 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
3301 "<b>maxsock = </b> %d<br>\n"
3302 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
3303 "</td><td align=\"center\" nowrap>\n"
3304 "<table class=\"lgd\"><tr>"
3305 "<td class=\"active3\">&nbsp;</td><td class=\"noborder\">active UP </td>"
3306 "<td class=\"backup3\">&nbsp;</td><td class=\"noborder\">backup UP </td>"
3307 "</tr><tr>"
3308 "<td class=\"active2\"></td><td class=\"noborder\">active UP, going down </td>"
3309 "<td class=\"backup2\"></td><td class=\"noborder\">backup UP, going down </td>"
3310 "</tr><tr>"
3311 "<td class=\"active1\"></td><td class=\"noborder\">active DOWN, going up </td>"
3312 "<td class=\"backup1\"></td><td class=\"noborder\">backup DOWN, going up </td>"
3313 "</tr><tr>"
3314 "<td class=\"active0\"></td><td class=\"noborder\">active or backup DOWN &nbsp;</td>"
3315 "<td class=\"active4\"></td><td class=\"noborder\">not checked </td>"
3316 "</tr></table>\n"
3317 "</td>"
3318 "<td align=\"left\" nowrap width=\"1%%\">"
3319 "<b>External ressources:</b><ul style=\"margin-top: 0.25em;\">"
3320 "<li><a href=\"" PRODUCT_URL "\">Primary site</a><br>"
3321 "<li><a href=\"" PRODUCT_URL_UPD "\">Updates (v" PRODUCT_BRANCH ")</a><br>"
3322 "<li><a href=\"" PRODUCT_URL_DOC "\">Online manual</a><br>"
3323 "</ul>"
3324 "</td>"
3325 "</tr></table>\n"
3326 "",
3327 pid, pid, global.nbproc,
3328 up / 86400, (up % 86400) / 3600,
3329 (up % 3600) / 60, (up % 60),
3330 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
3331 global.rlimit_memmax ? " MB" : "",
3332 global.rlimit_nofile,
3333 global.maxsock,
3334 global.maxconn,
3335 actconn
3336 );
Willy Tarreaubaaee002006-06-26 02:48:02 +02003337
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003338 if (buffer_write_chunk(rep, &msg) != 0)
3339 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003340
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003341 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003342
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003343 s->data_ctx.stats.px = proxy;
3344 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
3345 s->data_state = DATA_ST_LIST;
3346 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003347
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003348 case DATA_ST_LIST:
3349 /* dump proxies */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003350 while (s->data_ctx.stats.px) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003351 px = s->data_ctx.stats.px;
3352 /* skip the disabled proxies and non-networked ones */
3353 if (px->state != PR_STSTOPPED && (px->cap & (PR_CAP_FE | PR_CAP_BE)))
3354 if (produce_content_stats_proxy(s, px) == 0)
3355 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003356
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003357 s->data_ctx.stats.px = px->next;
3358 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
3359 }
3360 /* here, we just have reached the last proxy */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003361
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003362 s->data_state = DATA_ST_END;
3363 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003364
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003365 case DATA_ST_END:
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003366 chunk_printf(&msg, sizeof(trash), "</body></html>\n");
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003367 if (buffer_write_chunk(rep, &msg) != 0)
3368 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003369
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003370 s->data_state = DATA_ST_FIN;
3371 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003372
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003373 case DATA_ST_FIN:
3374 s->flags &= ~SN_SELF_GEN;
3375 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003376
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003377 default:
3378 /* unknown state ! */
3379 s->logs.status = 500;
3380 client_retnclose(s, error_message(s, HTTP_ERR_500));
3381 if (!(s->flags & SN_ERR_MASK))
3382 s->flags |= SN_ERR_PRXCOND;
3383 if (!(s->flags & SN_FINST_MASK))
3384 s->flags |= SN_FINST_R;
3385 s->flags &= ~SN_SELF_GEN;
3386 return 1;
3387 }
3388}
Willy Tarreaubaaee002006-06-26 02:48:02 +02003389
Willy Tarreaubaaee002006-06-26 02:48:02 +02003390
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003391/*
3392 * Dumps statistics for a proxy.
3393 * Returns 0 if it had to stop dumping data because of lack of buffer space,
3394 * ot non-zero if everything completed.
3395 */
3396int produce_content_stats_proxy(struct session *s, struct proxy *px)
3397{
3398 struct buffer *rep = s->rep;
3399 struct server *sv;
3400 struct chunk msg;
3401
3402 msg.len = 0;
3403 msg.str = trash;
3404
3405 switch (s->data_ctx.stats.px_st) {
3406 case DATA_ST_PX_INIT:
3407 /* we are on a new proxy */
3408
3409 if (s->be->fiprm->uri_auth && s->be->fiprm->uri_auth->scope) {
3410 /* we have a limited scope, we have to check the proxy name */
3411 struct stat_scope *scope;
3412 int len;
3413
3414 len = strlen(px->id);
3415 scope = s->be->fiprm->uri_auth->scope;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003416
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003417 while (scope) {
3418 /* match exact proxy name */
3419 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3420 break;
3421
3422 /* match '.' which means 'self' proxy */
3423 if (!strcmp(scope->px_id, ".") && px == s->fe)
3424 break;
3425 scope = scope->next;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003426 }
3427
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003428 /* proxy name not found : don't dump anything */
3429 if (scope == NULL)
3430 return 1;
3431 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003432
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003433 s->data_ctx.stats.px_st = DATA_ST_PX_TH;
3434 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003435
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003436 case DATA_ST_PX_TH:
3437 /* print a new table */
3438 chunk_printf(&msg, sizeof(trash),
3439 "<table cols=\"20\" class=\"tbl\" width=\"100%%\">\n"
3440 "<tr align=\"center\" class=\"titre\">"
3441 "<th colspan=2 class=\"pxname\">%s</th>"
3442 "<th colspan=18 class=\"empty\"></th>"
3443 "</tr>\n"
3444 "<tr align=\"center\" class=\"titre\">"
3445 "<th rowspan=2></th>"
3446 "<th colspan=2>Queue</th><th colspan=4>Sessions</th>"
3447 "<th colspan=2>Bytes</th><th colspan=2>Denied</th>"
3448 "<th colspan=3>Errors</th><th colspan=6>Server</th>"
3449 "</tr>\n"
3450 "<tr align=\"center\" class=\"titre\">"
Willy Tarreau35d66b02007-01-02 00:28:21 +01003451 "<th>Cur</th><th>Max</th><th>Cur</th><th>Max</th>"
3452 "<th>Limit</th><th>Cumul</th><th>In</th><th>Out</th>"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003453 "<th>Req</th><th>Resp</th><th>Req</th><th>Conn</th>"
3454 "<th>Resp</th><th>Status</th><th>Weight</th><th>Act</th>"
3455 "<th>Bck</th><th>Check</th><th>Down</th></tr>\n"
3456 "",
3457 px->id);
3458
3459 if (buffer_write_chunk(rep, &msg) != 0)
3460 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003461
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003462 s->data_ctx.stats.px_st = DATA_ST_PX_FE;
3463 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003464
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003465 case DATA_ST_PX_FE:
3466 /* print the frontend */
3467 if (px->cap & PR_CAP_FE) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003468 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003469 /* name, queue */
3470 "<tr align=center class=\"frontend\"><td>Frontend</td><td colspan=2></td>"
3471 /* sessions : current, max, limit, cumul. */
3472 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
3473 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003474 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003475 /* denied: req, resp */
3476 "<td align=right>%d</td><td align=right>%d</td>"
3477 /* errors : request, connect, response */
3478 "<td align=right>%d</td><td align=right></td><td align=right></td>"
3479 /* server status : reflect backend status */
3480 "<td align=center>%s</td>"
3481 /* rest of server: nothing */
3482 "<td align=center colspan=5></td></tr>"
3483 "",
3484 px->feconn, px->feconn_max, px->maxconn, px->cum_feconn,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003485 px->bytes_in, px->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003486 px->denied_req, px->denied_resp,
3487 px->failed_req,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003488 px->state == PR_STRUN ? "OPEN" :
3489 px->state == PR_STIDLE ? "FULL" : "STOP");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003490
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003491 if (buffer_write_chunk(rep, &msg) != 0)
3492 return 0;
3493 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003494
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003495 s->data_ctx.stats.sv = px->srv; /* may be NULL */
3496 s->data_ctx.stats.px_st = DATA_ST_PX_SV;
3497 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003498
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003499 case DATA_ST_PX_SV:
3500 /* stats.sv has been initialized above */
3501 while (s->data_ctx.stats.sv != NULL) {
3502 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3503 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP, 4=unchecked */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003504
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003505 sv = s->data_ctx.stats.sv;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003506
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003507 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3508 if (!(sv->state & SRV_CHECKED))
3509 sv_state = 4;
3510 else if (sv->state & SRV_RUNNING)
3511 if (sv->health == sv->rise + sv->fall - 1)
3512 sv_state = 3; /* UP */
3513 else
3514 sv_state = 2; /* going down */
3515 else
3516 if (sv->health)
3517 sv_state = 1; /* going up */
3518 else
3519 sv_state = 0; /* DOWN */
3520
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003521 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003522 /* name */
3523 "<tr align=\"center\" class=\"%s%d\"><td>%s</td>"
3524 /* queue : current, max */
3525 "<td align=right>%d</td><td align=right>%d</td>"
3526 /* sessions : current, max, limit, cumul */
3527 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>"
3528 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003529 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003530 /* denied: req, resp */
3531 "<td align=right></td><td align=right>%d</td>"
3532 /* errors : request, connect, response */
3533 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
3534 "",
Willy Tarreau368e96a2007-01-07 00:16:15 +01003535 (sv->state & SRV_BACKUP) ? "backup" : "active",
Willy Tarreau128e9542007-01-01 22:01:43 +01003536 sv_state, sv->id,
3537 sv->nbpend, sv->nbpend_max,
3538 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003539 sv->bytes_in, sv->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003540 sv->failed_secu,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003541 sv->failed_conns, sv->failed_resp);
Willy Tarreau128e9542007-01-01 22:01:43 +01003542
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003543 /* status */
3544 chunk_printf(&msg, sizeof(trash), "<td nowrap>");
3545 chunk_printf(&msg, sizeof(trash),
3546 srv_hlt_st[sv_state],
3547 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3548 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3549
Willy Tarreau128e9542007-01-01 22:01:43 +01003550 chunk_printf(&msg, sizeof(trash),
3551 /* weight */
3552 "</td><td>%d</td>"
3553 /* act, bck */
3554 "<td>%s</td><td>%s</td>"
3555 "",
3556 sv->uweight+1,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003557 (sv->state & SRV_BACKUP) ? "-" : "Y",
3558 (sv->state & SRV_BACKUP) ? "Y" : "-");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003559
3560 /* check failures : unique, fatal */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003561 if (sv->state & SRV_CHECKED)
3562 chunk_printf(&msg, sizeof(trash),
3563 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3564 sv->failed_checks, sv->down_trans);
3565 else
3566 chunk_printf(&msg, sizeof(trash),
3567 "<td colspan=2></td></tr>\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003568
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003569 if (buffer_write_chunk(rep, &msg) != 0)
3570 return 0;
3571
3572 s->data_ctx.stats.sv = sv->next;
3573 } /* while sv */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003574
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003575 s->data_ctx.stats.px_st = DATA_ST_PX_BE;
3576 /* fall through */
3577
3578 case DATA_ST_PX_BE:
3579 /* print the backend */
3580 if (px->cap & PR_CAP_BE) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003581 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003582 /* name */
3583 "<tr align=center class=\"backend\"><td>Backend</td>"
3584 /* queue : current, max */
3585 "<td align=right>%d</td><td align=right>%d</td>"
3586 /* sessions : current, max, limit, cumul. */
3587 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
3588 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003589 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003590 /* denied: req, resp */
3591 "<td align=right>%d</td><td align=right>%d</td>"
3592 /* errors : request, connect, response */
3593 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
3594 /* server status : reflect backend status (up/down) : we display UP
3595 * if the backend has known working servers or if it has no server at
3596 * all (eg: for stats). Tthen we display the total weight, number of
3597 * active and backups. */
3598 "<td align=center>%s</td><td align=center>%d</td>"
3599 "<td align=center>%d</td><td align=center>%d</td>"
3600 /* rest of server: nothing */
3601 "<td align=center colspan=2></td></tr>"
3602 "",
3603 px->nbpend /* or px->totpend ? */, px->nbpend_max,
3604 px->beconn, px->beconn_max, px->fullconn, px->cum_beconn,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003605 px->bytes_in, px->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003606 px->denied_req, px->denied_resp,
3607 px->failed_conns, px->failed_resp,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003608 (px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN",
3609 px->srv_map_sz, px->srv_act, px->srv_bck);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003610
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003611 if (buffer_write_chunk(rep, &msg) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003612 return 0;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003613 }
3614
3615 s->data_ctx.stats.px_st = DATA_ST_PX_END;
3616 /* fall through */
3617
3618 case DATA_ST_PX_END:
3619 chunk_printf(&msg, sizeof(trash), "</table><p>\n");
3620
3621 if (buffer_write_chunk(rep, &msg) != 0)
3622 return 0;
3623
3624 s->data_ctx.stats.px_st = DATA_ST_PX_FIN;
3625 /* fall through */
3626
3627 case DATA_ST_PX_FIN:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003628 return 1;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003629
3630 default:
3631 /* unknown state, we should put an abort() here ! */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003632 return 1;
3633 }
3634}
3635
3636
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003637/* Iterate the same filter through all request headers.
3638 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003639 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003640int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003641{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003642 char term;
3643 char *cur_ptr, *cur_end, *cur_next;
3644 int cur_idx, old_idx, last_hdr;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003645 struct http_req *hreq = &t->hreq;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003646 struct hdr_idx_elem *cur_hdr;
3647 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003648
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003649 last_hdr = 0;
3650
3651 cur_next = req->data + hreq->req.sor + hdr_idx_first_pos(&hreq->hdr_idx);
3652 old_idx = 0;
3653
3654 while (!last_hdr) {
3655 if (unlikely(t->flags & (SN_CLDENY | SN_CLTARPIT)))
3656 return 1;
3657 else if (unlikely(t->flags & SN_CLALLOW) &&
3658 (exp->action == ACT_ALLOW ||
3659 exp->action == ACT_DENY ||
3660 exp->action == ACT_TARPIT))
3661 return 0;
3662
3663 cur_idx = hreq->hdr_idx.v[old_idx].next;
3664 if (!cur_idx)
3665 break;
3666
3667 cur_hdr = &hreq->hdr_idx.v[cur_idx];
3668 cur_ptr = cur_next;
3669 cur_end = cur_ptr + cur_hdr->len;
3670 cur_next = cur_end + cur_hdr->cr + 1;
3671
3672 /* Now we have one header between cur_ptr and cur_end,
3673 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003674 */
3675
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003676 /* The annoying part is that pattern matching needs
3677 * that we modify the contents to null-terminate all
3678 * strings before testing them.
3679 */
3680
3681 term = *cur_end;
3682 *cur_end = '\0';
3683
3684 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3685 switch (exp->action) {
3686 case ACT_SETBE:
3687 /* It is not possible to jump a second time.
3688 * FIXME: should we return an HTTP/500 here so that
3689 * the admin knows there's a problem ?
3690 */
3691 if (t->be != t->fe)
3692 break;
3693
3694 /* Swithing Proxy */
3695 t->be = (struct proxy *) exp->replace;
3696
3697 /* right now, the backend switch is not too much complicated
3698 * because we have associated req_cap and rsp_cap to the
3699 * frontend, and the beconn will be updated later.
3700 */
3701
3702 t->rep->rto = t->req->wto = t->be->beprm->srvtimeout;
3703 t->req->cto = t->be->beprm->contimeout;
3704 last_hdr = 1;
3705 break;
3706
3707 case ACT_ALLOW:
3708 t->flags |= SN_CLALLOW;
3709 last_hdr = 1;
3710 break;
3711
3712 case ACT_DENY:
3713 t->flags |= SN_CLDENY;
3714 last_hdr = 1;
3715 t->be->beprm->denied_req++;
3716 break;
3717
3718 case ACT_TARPIT:
3719 t->flags |= SN_CLTARPIT;
3720 last_hdr = 1;
3721 t->be->beprm->denied_req++;
3722 break;
3723
3724 case ACT_REPLACE:
3725 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3726 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3727 /* FIXME: if the user adds a newline in the replacement, the
3728 * index will not be recalculated for now, and the new line
3729 * will not be counted as a new header.
3730 */
3731
3732 cur_end += delta;
3733 cur_next += delta;
3734 cur_hdr->len += delta;
3735 hreq->req.eoh += delta;
3736 break;
3737
3738 case ACT_REMOVE:
3739 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3740 cur_next += delta;
3741
3742 /* FIXME: this should be a separate function */
3743 hreq->req.eoh += delta;
3744 hreq->hdr_idx.v[old_idx].next = cur_hdr->next;
3745 hreq->hdr_idx.used--;
3746 cur_hdr->len = 0;
3747 cur_end = NULL; /* null-term has been rewritten */
3748 break;
3749
3750 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01003751 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003752 if (cur_end)
3753 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003754
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003755 /* keep the link from this header to next one in case of later
3756 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003757 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003758 old_idx = cur_idx;
3759 }
3760 return 0;
3761}
3762
3763
3764/* Apply the filter to the request line.
3765 * Returns 0 if nothing has been done, 1 if the filter has been applied,
3766 * or -1 if a replacement resulted in an invalid request line.
3767 */
3768int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
3769{
3770 char term;
3771 char *cur_ptr, *cur_end;
3772 int done;
3773 struct http_req *hreq = &t->hreq;
3774 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003775
Willy Tarreau58f10d72006-12-04 02:26:12 +01003776
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003777 if (unlikely(t->flags & (SN_CLDENY | SN_CLTARPIT)))
3778 return 1;
3779 else if (unlikely(t->flags & SN_CLALLOW) &&
3780 (exp->action == ACT_ALLOW ||
3781 exp->action == ACT_DENY ||
3782 exp->action == ACT_TARPIT))
3783 return 0;
3784 else if (exp->action == ACT_REMOVE)
3785 return 0;
3786
3787 done = 0;
3788
3789 cur_ptr = req->data + hreq->req.sor;
3790 cur_end = cur_ptr + hreq->req.sl.rq.l;
3791
3792 /* Now we have the request line between cur_ptr and cur_end */
3793
3794 /* The annoying part is that pattern matching needs
3795 * that we modify the contents to null-terminate all
3796 * strings before testing them.
3797 */
3798
3799 term = *cur_end;
3800 *cur_end = '\0';
3801
3802 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3803 switch (exp->action) {
3804 case ACT_SETBE:
3805 /* It is not possible to jump a second time.
3806 * FIXME: should we return an HTTP/500 here so that
3807 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01003808 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003809 if (t->be != t->fe)
3810 break;
3811
3812 /* Swithing Proxy */
3813 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003814
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003815 /* right now, the backend switch is not too much complicated
3816 * because we have associated req_cap and rsp_cap to the
3817 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003818 */
3819
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003820 t->rep->rto = t->req->wto = t->be->beprm->srvtimeout;
3821 t->req->cto = t->be->beprm->contimeout;
3822 done = 1;
3823 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003824
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003825 case ACT_ALLOW:
3826 t->flags |= SN_CLALLOW;
3827 done = 1;
3828 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003829
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003830 case ACT_DENY:
3831 t->flags |= SN_CLDENY;
3832 t->be->beprm->denied_req++;
3833 done = 1;
3834 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003835
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003836 case ACT_TARPIT:
3837 t->flags |= SN_CLTARPIT;
3838 t->be->beprm->denied_req++;
3839 done = 1;
3840 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003841
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003842 case ACT_REPLACE:
3843 *cur_end = term; /* restore the string terminator */
3844 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3845 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3846 /* FIXME: if the user adds a newline in the replacement, the
3847 * index will not be recalculated for now, and the new line
3848 * will not be counted as a new header.
3849 */
Willy Tarreaua496b602006-12-17 23:15:24 +01003850
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003851 hreq->req.eoh += delta;
3852 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01003853
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003854 cur_end = (char *)http_parse_reqline(&hreq->req, req->data,
3855 HTTP_MSG_RQMETH,
3856 cur_ptr, cur_end + 1,
3857 NULL, NULL);
3858 if (unlikely(!cur_end))
3859 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01003860
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003861 /* we have a full request and we know that we have either a CR
3862 * or an LF at <ptr>.
3863 */
3864 hreq->meth = find_http_meth(cur_ptr, hreq->req.sl.rq.m_l);
3865 hdr_idx_set_start(&hreq->hdr_idx, hreq->req.sl.rq.l, *cur_end == '\r');
3866 /* there is no point trying this regex on headers */
3867 return 1;
3868 }
3869 }
3870 *cur_end = term; /* restore the string terminator */
3871 return done;
3872}
Willy Tarreau97de6242006-12-27 17:18:38 +01003873
Willy Tarreau58f10d72006-12-04 02:26:12 +01003874
Willy Tarreau58f10d72006-12-04 02:26:12 +01003875
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003876/*
3877 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
3878 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
3879 * unparsable request.
3880 */
3881int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
3882{
3883 /* iterate through the filters in the outer loop */
3884 while (exp && !(t->flags & (SN_CLDENY|SN_CLTARPIT))) {
3885 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003886
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003887 /*
3888 * The interleaving of transformations and verdicts
3889 * makes it difficult to decide to continue or stop
3890 * the evaluation.
3891 */
3892
3893 if ((t->flags & SN_CLALLOW) &&
3894 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
3895 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
3896 exp = exp->next;
3897 continue;
3898 }
3899
3900 /* Apply the filter to the request line. */
3901 ret = apply_filter_to_req_line(t, req, exp);
3902 if (unlikely(ret < 0))
3903 return -1;
3904
3905 if (likely(ret == 0)) {
3906 /* The filter did not match the request, it can be
3907 * iterated through all headers.
3908 */
3909 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003910 }
3911 exp = exp->next;
3912 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003913 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003914}
3915
3916
Willy Tarreau58f10d72006-12-04 02:26:12 +01003917/*
3918 * Manager client-side cookie
3919 */
3920void manage_client_side_cookies(struct session *t, struct buffer *req)
3921{
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003922 struct http_req *hreq = &t->hreq;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003923 char *p1, *p2, *p3, *p4;
3924 char *del_colon, *del_cookie, *colon;
3925 int app_cookies;
3926
3927 appsess *asession_temp = NULL;
3928 appsess local_asession;
3929
3930 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003931 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003932
Willy Tarreau830ff452006-12-17 19:31:23 +01003933 if (t->be->beprm->cookie_name == NULL &&
3934 t->be->beprm->appsession_name ==NULL &&
3935 t->be->fiprm->capture_name != NULL)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003936 return;
3937
Willy Tarreau2a324282006-12-05 00:05:46 +01003938 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003939 * we start with the start line.
3940 */
Willy Tarreau83969f42007-01-22 08:55:47 +01003941 old_idx = 0;
3942 cur_next = req->data + hreq->req.sor + hdr_idx_first_pos(&hreq->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003943
Willy Tarreau83969f42007-01-22 08:55:47 +01003944 while ((cur_idx = hreq->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003945 struct hdr_idx_elem *cur_hdr;
3946
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003947 cur_hdr = &hreq->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003948 cur_ptr = cur_next;
3949 cur_end = cur_ptr + cur_hdr->len;
3950 cur_next = cur_end + cur_hdr->cr + 1;
3951
3952 /* We have one full header between cur_ptr and cur_end, and the
3953 * next header starts at cur_next. We're only interested in
3954 * "Cookie:" headers.
3955 */
3956
3957 if ((cur_end - cur_ptr <= 7) ||
3958 (strncasecmp(cur_ptr, "Cookie:", 7) != 0)) {
3959 old_idx = cur_idx;
3960 continue;
3961 }
3962
3963 /* Now look for cookies. Conforming to RFC2109, we have to support
3964 * attributes whose name begin with a '$', and associate them with
3965 * the right cookie, if we want to delete this cookie.
3966 * So there are 3 cases for each cookie read :
3967 * 1) it's a special attribute, beginning with a '$' : ignore it.
3968 * 2) it's a server id cookie that we *MAY* want to delete : save
3969 * some pointers on it (last semi-colon, beginning of cookie...)
3970 * 3) it's an application cookie : we *MAY* have to delete a previous
3971 * "special" cookie.
3972 * At the end of loop, if a "special" cookie remains, we may have to
3973 * remove it. If no application cookie persists in the header, we
3974 * *MUST* delete it
3975 */
3976
3977
3978 p1 = cur_ptr + 7; /* first char after 'Cookie:' */
3979 if (isspace((int)*p1)) /* try to get the first space with it */
3980 p1++;
3981
3982 colon = p1;
3983 /* del_cookie == NULL => nothing to be deleted */
3984 del_colon = del_cookie = NULL;
3985 app_cookies = 0;
3986
3987 while (p1 < cur_end) {
3988 /* skip spaces and colons, but keep an eye on these ones */
3989 while (p1 < cur_end) {
3990 if (*p1 == ';' || *p1 == ',')
3991 colon = p1;
3992 else if (!isspace((int)*p1))
3993 break;
3994 p1++;
3995 }
3996
3997 if (p1 == cur_end)
3998 break;
3999
4000 /* p1 is at the beginning of the cookie name */
4001 p2 = p1;
4002 while (p2 < cur_end && *p2 != '=')
4003 p2++;
4004
4005 if (p2 == cur_end)
4006 break;
4007
4008 p3 = p2 + 1; /* skips the '=' sign */
4009 if (p3 == cur_end)
4010 break;
4011
4012 p4 = p3;
4013 while (p4 < cur_end && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
4014 p4++;
4015
4016 /* here, we have the cookie name between p1 and p2,
4017 * and its value between p3 and p4.
4018 * we can process it :
4019 *
4020 * Cookie: NAME=VALUE;
4021 * | || || |
4022 * | || || +--> p4
4023 * | || |+-------> p3
4024 * | || +--------> p2
4025 * | |+------------> p1
4026 * | +-------------> colon
4027 * +--------------------> cur_ptr
4028 */
4029
4030 if (*p1 == '$') {
4031 /* skip this one */
4032 }
4033 else {
4034 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01004035 if (t->fe->fiprm->capture_name != NULL &&
Willy Tarreau58f10d72006-12-04 02:26:12 +01004036 t->logs.cli_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01004037 (p4 - p1 >= t->fe->fiprm->capture_namelen) &&
4038 memcmp(p1, t->fe->fiprm->capture_name, t->fe->fiprm->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004039 int log_len = p4 - p1;
4040
4041 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4042 Alert("HTTP logging : out of memory.\n");
4043 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01004044 if (log_len > t->fe->fiprm->capture_len)
4045 log_len = t->fe->fiprm->capture_len;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004046 memcpy(t->logs.cli_cookie, p1, log_len);
4047 t->logs.cli_cookie[log_len] = 0;
4048 }
4049 }
4050
Willy Tarreau830ff452006-12-17 19:31:23 +01004051 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
4052 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004053 /* Cool... it's the right one */
Willy Tarreau830ff452006-12-17 19:31:23 +01004054 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004055 char *delim;
4056
4057 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4058 * have the server ID betweek p3 and delim, and the original cookie between
4059 * delim+1 and p4. Otherwise, delim==p4 :
4060 *
4061 * Cookie: NAME=SRV~VALUE;
4062 * | || || | |
4063 * | || || | +--> p4
4064 * | || || +--------> delim
4065 * | || |+-----------> p3
4066 * | || +------------> p2
4067 * | |+----------------> p1
4068 * | +-----------------> colon
4069 * +------------------------> cur_ptr
4070 */
4071
Willy Tarreau830ff452006-12-17 19:31:23 +01004072 if (t->be->beprm->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004073 for (delim = p3; delim < p4; delim++)
4074 if (*delim == COOKIE_DELIM)
4075 break;
4076 }
4077 else
4078 delim = p4;
4079
4080
4081 /* Here, we'll look for the first running server which supports the cookie.
4082 * This allows to share a same cookie between several servers, for example
4083 * to dedicate backup servers to specific servers only.
4084 * However, to prevent clients from sticking to cookie-less backup server
4085 * when they have incidentely learned an empty cookie, we simply ignore
4086 * empty cookies and mark them as invalid.
4087 */
4088 if (delim == p3)
4089 srv = NULL;
4090
4091 while (srv) {
Willy Tarreau92f2ab12007-02-02 22:14:47 +01004092 if (srv->cookie && (srv->cklen == delim - p3) &&
4093 !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreau830ff452006-12-17 19:31:23 +01004094 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004095 /* we found the server and it's usable */
4096 t->flags &= ~SN_CK_MASK;
4097 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
4098 t->srv = srv;
4099 break;
4100 } else {
4101 /* we found a server, but it's down */
4102 t->flags &= ~SN_CK_MASK;
4103 t->flags |= SN_CK_DOWN;
4104 }
4105 }
4106 srv = srv->next;
4107 }
4108
4109 if (!srv && !(t->flags & SN_CK_DOWN)) {
4110 /* no server matched this cookie */
4111 t->flags &= ~SN_CK_MASK;
4112 t->flags |= SN_CK_INVALID;
4113 }
4114
4115 /* depending on the cookie mode, we may have to either :
4116 * - delete the complete cookie if we're in insert+indirect mode, so that
4117 * the server never sees it ;
4118 * - remove the server id from the cookie value, and tag the cookie as an
4119 * application cookie so that it does not get accidentely removed later,
4120 * if we're in cookie prefix mode
4121 */
Willy Tarreau830ff452006-12-17 19:31:23 +01004122 if ((t->be->beprm->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004123 int delta; /* negative */
4124
4125 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
4126 p4 += delta;
4127 cur_end += delta;
4128 cur_next += delta;
4129 cur_hdr->len += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004130 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004131
4132 del_cookie = del_colon = NULL;
4133 app_cookies++; /* protect the header from deletion */
4134 }
4135 else if (del_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01004136 (t->be->beprm->options & (PR_O_COOK_INS | PR_O_COOK_IND)) == (PR_O_COOK_INS | PR_O_COOK_IND)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004137 del_cookie = p1;
4138 del_colon = colon;
4139 }
4140 } else {
4141 /* now we know that we must keep this cookie since it's
4142 * not ours. But if we wanted to delete our cookie
4143 * earlier, we cannot remove the complete header, but we
4144 * can remove the previous block itself.
4145 */
4146 app_cookies++;
4147
4148 if (del_cookie != NULL) {
4149 int delta; /* negative */
4150
4151 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
4152 p4 += delta;
4153 cur_end += delta;
4154 cur_next += delta;
4155 cur_hdr->len += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004156 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004157 del_cookie = del_colon = NULL;
4158 }
4159 }
4160
Willy Tarreau830ff452006-12-17 19:31:23 +01004161 if ((t->be->beprm->appsession_name != NULL) &&
4162 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004163 /* first, let's see if the cookie is our appcookie*/
4164
4165 /* Cool... it's the right one */
4166
4167 asession_temp = &local_asession;
4168
4169 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4170 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4171 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4172 return;
4173 }
4174
Willy Tarreau830ff452006-12-17 19:31:23 +01004175 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
4176 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004177 asession_temp->serverid = NULL;
4178
4179 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01004180 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004181 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4182 /* free previously allocated memory */
4183 pool_free_to(apools.sessid, local_asession.sessid);
4184 Alert("Not enough memory process_cli():asession:calloc().\n");
4185 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4186 return;
4187 }
4188
4189 asession_temp->sessid = local_asession.sessid;
4190 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01004191 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004192 } else {
4193 /* free previously allocated memory */
4194 pool_free_to(apools.sessid, local_asession.sessid);
4195 }
4196
4197 if (asession_temp->serverid == NULL) {
4198 Alert("Found Application Session without matching server.\n");
4199 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01004200 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004201 while (srv) {
4202 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01004203 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004204 /* we found the server and it's usable */
4205 t->flags &= ~SN_CK_MASK;
4206 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
4207 t->srv = srv;
4208 break;
4209 } else {
4210 t->flags &= ~SN_CK_MASK;
4211 t->flags |= SN_CK_DOWN;
4212 }
4213 }
4214 srv = srv->next;
4215 }/* end while(srv) */
4216 }/* end else if server == NULL */
4217
Willy Tarreau830ff452006-12-17 19:31:23 +01004218 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004219 }/* end if ((t->proxy->appsession_name != NULL) ... */
4220 }
4221
4222 /* we'll have to look for another cookie ... */
4223 p1 = p4;
4224 } /* while (p1 < cur_end) */
4225
4226 /* There's no more cookie on this line.
4227 * We may have marked the last one(s) for deletion.
4228 * We must do this now in two ways :
4229 * - if there is no app cookie, we simply delete the header ;
4230 * - if there are app cookies, we must delete the end of the
4231 * string properly, including the colon/semi-colon before
4232 * the cookie name.
4233 */
4234 if (del_cookie != NULL) {
4235 int delta;
4236 if (app_cookies) {
4237 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
4238 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004239 cur_hdr->len += delta;
4240 } else {
4241 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004242
4243 /* FIXME: this should be a separate function */
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004244 hreq->hdr_idx.v[old_idx].next = cur_hdr->next;
4245 hreq->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004246 cur_hdr->len = 0;
4247 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01004248 cur_next += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004249 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004250 }
4251
4252 /* keep the link from this header to next one */
4253 old_idx = cur_idx;
4254 } /* end of cookie processing on this header */
4255}
4256
4257
Willy Tarreau58f10d72006-12-04 02:26:12 +01004258/*
4259 * Try to retrieve a known appsession in the URI, then the associated server.
4260 * If the server is found, it's assigned to the session.
4261 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004262void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004263{
4264 appsess *asession_temp = NULL;
4265 appsess local_asession;
4266 char *request_line;
4267
Willy Tarreau830ff452006-12-17 19:31:23 +01004268 if (t->be->beprm->appsession_name == NULL ||
Willy Tarreau921d7c02006-12-17 13:50:27 +01004269 (t->hreq.meth != HTTP_METH_GET && t->hreq.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004270 (request_line = memchr(begin, ';', len)) == NULL ||
4271 ((1 + t->be->beprm->appsession_name_len + 1 + t->be->beprm->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004272 return;
4273
4274 /* skip ';' */
4275 request_line++;
4276
4277 /* look if we have a jsessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01004278 if (strncasecmp(request_line, t->be->beprm->appsession_name, t->be->beprm->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004279 return;
4280
4281 /* skip jsessionid= */
Willy Tarreau830ff452006-12-17 19:31:23 +01004282 request_line += t->be->beprm->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004283
4284 /* First try if we already have an appsession */
4285 asession_temp = &local_asession;
4286
4287 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4288 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4289 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4290 return;
4291 }
4292
4293 /* Copy the sessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01004294 memcpy(asession_temp->sessid, request_line, t->be->beprm->appsession_len);
4295 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004296 asession_temp->serverid = NULL;
4297
4298 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01004299 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *)&asession_temp)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004300 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4301 /* free previously allocated memory */
4302 pool_free_to(apools.sessid, local_asession.sessid);
4303 Alert("Not enough memory process_cli():asession:calloc().\n");
4304 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4305 return;
4306 }
4307 asession_temp->sessid = local_asession.sessid;
4308 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01004309 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004310 }
4311 else {
4312 /* free previously allocated memory */
4313 pool_free_to(apools.sessid, local_asession.sessid);
4314 }
4315
Willy Tarreau830ff452006-12-17 19:31:23 +01004316 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004317 asession_temp->request_count++;
4318
4319#if defined(DEBUG_HASH)
4320 print_table(&(t->proxy->htbl_proxy));
4321#endif
4322 if (asession_temp->serverid == NULL) {
4323 Alert("Found Application Session without matching server.\n");
4324 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01004325 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004326 while (srv) {
4327 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01004328 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004329 /* we found the server and it's usable */
4330 t->flags &= ~SN_CK_MASK;
4331 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
4332 t->srv = srv;
4333 break;
4334 } else {
4335 t->flags &= ~SN_CK_MASK;
4336 t->flags |= SN_CK_DOWN;
4337 }
4338 }
4339 srv = srv->next;
4340 }
4341 }
4342}
4343
4344
Willy Tarreaub2513902006-12-17 14:52:38 +01004345/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004346 * In a GET or HEAD request, check if the requested URI matches the stats uri
4347 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01004348 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004349 * It is assumed that the request is either a HEAD or GET and that the
4350 * t->be->fiprm->uri_auth field is valid. An HTTP/401 response may be sent, or
4351 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01004352 *
4353 * Returns 1 if the session's state changes, otherwise 0.
4354 */
4355int stats_check_uri_auth(struct session *t, struct proxy *backend)
4356{
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004357 struct http_req *hreq = &t->hreq;
Willy Tarreaub2513902006-12-17 14:52:38 +01004358 struct uri_auth *uri_auth = backend->uri_auth;
4359 struct user_auth *user;
4360 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004361 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01004362
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004363 /* check URI size */
4364 if (uri_auth->uri_len > hreq->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01004365 return 0;
4366
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004367 h = t->req->data + hreq->req.sl.rq.u;
4368
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004369 /* the URI is in h */
4370 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01004371 return 0;
4372
4373 /* we are in front of a interceptable URI. Let's check
4374 * if there's an authentication and if it's valid.
4375 */
4376 user = uri_auth->users;
4377 if (!user) {
4378 /* no user auth required, it's OK */
4379 authenticated = 1;
4380 } else {
4381 authenticated = 0;
4382
4383 /* a user list is defined, we have to check.
4384 * skip 21 chars for "Authorization: Basic ".
4385 */
4386
4387 /* FIXME: this should move to an earlier place */
4388 cur_idx = 0;
Willy Tarreau83969f42007-01-22 08:55:47 +01004389 h = t->req->data + hreq->req.sor + hdr_idx_first_pos(&hreq->hdr_idx);
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004390 while ((cur_idx = hreq->hdr_idx.v[cur_idx].next)) {
4391 int len = hreq->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01004392 if (len > 14 &&
4393 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004394 hreq->auth_hdr.str = h;
4395 hreq->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01004396 break;
4397 }
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004398 h += len + hreq->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01004399 }
4400
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004401 if (hreq->auth_hdr.len < 21 ||
4402 memcmp(hreq->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01004403 user = NULL;
4404
4405 while (user) {
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004406 if ((hreq->auth_hdr.len == user->user_len + 14 + 7)
4407 && !memcmp(hreq->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01004408 user->user_pwd, user->user_len)) {
4409 authenticated = 1;
4410 break;
4411 }
4412 user = user->next;
4413 }
4414 }
4415
4416 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01004417 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01004418
4419 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01004420 msg.str = trash;
4421 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreaub2513902006-12-17 14:52:38 +01004422 t->logs.status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01004423 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01004424 if (!(t->flags & SN_ERR_MASK))
4425 t->flags |= SN_ERR_PRXCOND;
4426 if (!(t->flags & SN_FINST_MASK))
4427 t->flags |= SN_FINST_R;
4428 return 1;
4429 }
4430
4431 /* The request is valid, the user is authenticate. Let's start sending
4432 * data.
4433 */
4434 t->cli_state = CL_STSHUTR;
4435 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
4436 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
4437 t->data_source = DATA_SRC_STATS;
4438 t->data_state = DATA_ST_INIT;
4439 produce_content(t);
4440 return 1;
4441}
4442
4443
Willy Tarreaubaaee002006-06-26 02:48:02 +02004444/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01004445 * Print a debug line with a header
4446 */
4447void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
4448{
4449 int len, max;
4450 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
4451 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
4452 max = end - start;
4453 UBOUND(max, sizeof(trash) - len - 1);
4454 len += strlcpy2(trash + len, start, max + 1);
4455 trash[len++] = '\n';
4456 write(1, trash, len);
4457}
4458
4459
4460/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02004461 * Local variables:
4462 * c-indent-level: 8
4463 * c-basic-offset: 8
4464 * End:
4465 */