blob: c7d91d3185338d7094b4b6e9db0780925e1b116b [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 Tarreau830ff452006-12-17 19:31:23 +01002587 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_RW)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002588 /* replace bytes p3->p4 with the cookie name associated
2589 * with this server since we know it.
2590 */
2591 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2592 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2593 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002594 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_PFX)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002595 /* insert the cookie name associated with this server
2596 * before existing cookie, and insert a delimitor between them..
2597 */
2598 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
2599 p3[t->srv->cklen] = COOKIE_DELIM;
2600 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2601 }
2602 break;
2603 }
2604
2605 /* first, let's see if the cookie is our appcookie*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002606 if ((t->be->beprm->appsession_name != NULL) &&
2607 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002608
2609 /* Cool... it's the right one */
2610
2611 size_t server_id_len = strlen(t->srv->id) + 1;
2612 asession_temp = &local_asession;
2613
2614 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
2615 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002616 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002617 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002618 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
2619 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002620 asession_temp->serverid = NULL;
2621
2622 /* only do insert, if lookup fails */
Willy Tarreau73de9892006-11-30 11:40:23 +01002623 if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002624 if ((asession_temp = pool_alloc(appsess)) == NULL) {
2625 Alert("Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002626 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002627 return 0;
2628 }
2629 asession_temp->sessid = local_asession.sessid;
2630 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01002631 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002632 }/* end if (chtbl_lookup()) */
2633 else {
2634 /* free wasted memory */
2635 pool_free_to(apools.sessid, local_asession.sessid);
2636 } /* end else from if (chtbl_lookup()) */
2637
2638 if (asession_temp->serverid == NULL) {
2639 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
2640 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002641 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002642 }
2643 asession_temp->serverid[0] = '\0';
2644 }
2645
2646 if (asession_temp->serverid[0] == '\0')
2647 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
2648
Willy Tarreau830ff452006-12-17 19:31:23 +01002649 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002650
2651#if defined(DEBUG_HASH)
Willy Tarreau830ff452006-12-17 19:31:23 +01002652 print_table(&(t->be->beprm->htbl_proxy));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002653#endif
2654 break;
2655 }/* end if ((t->proxy->appsession_name != NULL) ... */
2656 else {
2657 // fprintf(stderr,"Ignoring unknown cookie : ");
2658 // write(2, p1, p2-p1);
2659 // fprintf(stderr," = ");
2660 // write(2, p3, p4-p3);
2661 // fprintf(stderr,"\n");
2662 }
2663 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2664 } /* we're now at the end of the cookie value */
2665 } /* end of cookie processing */
2666
2667 /* check for any set-cookie in case we check for cacheability */
2668 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002669 (t->be->beprm->options & PR_O_CHK_CACHE) &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002670 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2671 t->flags |= SN_SCK_ANY;
2672 }
2673
2674 /* let's look if we have to delete this header */
2675 if (delete_header && !(t->flags & SN_SVDENY))
2676 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2677
2678 rep->h = rep->lr;
2679 } /* while (rep->lr < rep->r) */
2680
2681 /* end of header processing (even if incomplete) */
2682
Willy Tarreau2a429502006-10-15 14:52:29 +02002683 if ((rep->l < rep->rlim - rep->data) && ! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002684 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
Willy Tarreaud7971282006-07-29 18:36:34 +02002685 * full. We cannot loop here since stream_sock_read will disable it only if
Willy Tarreaubaaee002006-06-26 02:48:02 +02002686 * rep->l == rlim-data
2687 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002688 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002689 if (t->be->beprm->srvtimeout)
2690 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002691 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002692 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002693 }
2694
2695 /* read error, write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002696 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002697 tv_eternity(&rep->rex);
2698 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002699 fd_delete(t->srv_fd);
2700 if (t->srv) {
2701 t->srv->cur_sess--;
2702 t->srv->failed_resp++;
2703 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002704 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002705 t->srv_state = SV_STCLOSE;
2706 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01002707 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002708 if (!(t->flags & SN_ERR_MASK))
2709 t->flags |= SN_ERR_SRVCL;
2710 if (!(t->flags & SN_FINST_MASK))
2711 t->flags |= SN_FINST_H;
2712 /* We used to have a free connection slot. Since we'll never use it,
2713 * we have to inform the server that it may be used by another session.
2714 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002715 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002716 task_wakeup(&rq, t->srv->queue_mgt);
2717
2718 return 1;
2719 }
2720 /* end of client write or end of server read.
2721 * since we are in header mode, if there's no space left for headers, we
2722 * won't be able to free more later, so the session will never terminate.
2723 */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002724 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 +02002725 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002726 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002727 shutdown(t->srv_fd, SHUT_RD);
2728 t->srv_state = SV_STSHUTR;
2729 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2730 return 1;
2731 }
2732 /* read timeout : return a 504 to the client.
2733 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002734 else if (MY_FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002735 tv_eternity(&rep->rex);
2736 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002737 fd_delete(t->srv_fd);
2738 if (t->srv) {
2739 t->srv->cur_sess--;
2740 t->srv->failed_resp++;
2741 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002742 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002743 t->srv_state = SV_STCLOSE;
2744 t->logs.status = 504;
Willy Tarreau80587432006-12-24 17:47:20 +01002745 client_return(t, error_message(t, HTTP_ERR_504));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002746 if (!(t->flags & SN_ERR_MASK))
2747 t->flags |= SN_ERR_SRVTO;
2748 if (!(t->flags & SN_FINST_MASK))
2749 t->flags |= SN_FINST_H;
2750 /* We used to have a free connection slot. Since we'll never use it,
2751 * we have to inform the server that it may be used by another session.
2752 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002753 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002754 task_wakeup(&rq, t->srv->queue_mgt);
2755
2756 return 1;
2757 }
2758 /* last client read and buffer empty */
2759 /* FIXME!!! here, we don't want to switch to SHUTW if the
2760 * client shuts read too early, because we may still have
2761 * some work to do on the headers.
2762 * The side-effect is that if the client completely closes its
2763 * connection during SV_STHEADER, the connection to the server
2764 * is kept until a response comes back or the timeout is reached.
2765 */
2766 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002767 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002768 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002769
2770 /* We must ensure that the read part is still alive when switching
2771 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002772 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002773 if (t->be->beprm->srvtimeout)
2774 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002775
2776 shutdown(t->srv_fd, SHUT_WR);
2777 t->srv_state = SV_STSHUTW;
2778 return 1;
2779 }
2780 /* write timeout */
2781 /* FIXME!!! here, we don't want to switch to SHUTW if the
2782 * client shuts read too early, because we may still have
2783 * some work to do on the headers.
2784 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002785 else if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&req->wex, &now) <= 0) {
2786 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002787 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002788 shutdown(t->srv_fd, SHUT_WR);
2789 /* We must ensure that the read part is still alive when switching
2790 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002791 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002792 if (t->be->beprm->srvtimeout)
2793 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002794
2795 /* We must ensure that the read part is still alive when switching
2796 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002797 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002798 if (t->be->beprm->srvtimeout)
2799 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002800
2801 t->srv_state = SV_STSHUTW;
2802 if (!(t->flags & SN_ERR_MASK))
2803 t->flags |= SN_ERR_SRVTO;
2804 if (!(t->flags & SN_FINST_MASK))
2805 t->flags |= SN_FINST_H;
2806 return 1;
2807 }
2808
2809 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002810 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2811 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002812 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002813 }
2814 }
2815 else { /* client buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002816 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2817 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002818 if (t->be->beprm->srvtimeout) {
2819 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002820 /* FIXME: to prevent the server from expiring read timeouts during writes,
2821 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002822 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002823 }
2824 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002825 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002826 }
2827 }
2828
2829 /* be nice with the client side which would like to send a complete header
2830 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2831 * would read all remaining data at once ! The client should not write past rep->lr
2832 * when the server is in header state.
2833 */
2834 //return header_processed;
2835 return t->srv_state != SV_STHEADERS;
2836 }
2837 else if (s == SV_STDATA) {
2838 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002839 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002840 tv_eternity(&rep->rex);
2841 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002842 fd_delete(t->srv_fd);
2843 if (t->srv) {
2844 t->srv->cur_sess--;
2845 t->srv->failed_resp++;
2846 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002847 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002848 t->srv_state = SV_STCLOSE;
2849 if (!(t->flags & SN_ERR_MASK))
2850 t->flags |= SN_ERR_SRVCL;
2851 if (!(t->flags & SN_FINST_MASK))
2852 t->flags |= SN_FINST_D;
2853 /* We used to have a free connection slot. Since we'll never use it,
2854 * we have to inform the server that it may be used by another session.
2855 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002856 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002857 task_wakeup(&rq, t->srv->queue_mgt);
2858
2859 return 1;
2860 }
2861 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002862 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002863 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002864 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002865 shutdown(t->srv_fd, SHUT_RD);
2866 t->srv_state = SV_STSHUTR;
2867 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2868 return 1;
2869 }
2870 /* end of client read and no more data to send */
2871 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002872 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002873 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002874 shutdown(t->srv_fd, SHUT_WR);
2875 /* We must ensure that the read part is still alive when switching
2876 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002877 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002878 if (t->be->beprm->srvtimeout)
2879 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002880
2881 t->srv_state = SV_STSHUTW;
2882 return 1;
2883 }
2884 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002885 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002886 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002887 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002888 shutdown(t->srv_fd, SHUT_RD);
2889 t->srv_state = SV_STSHUTR;
2890 if (!(t->flags & SN_ERR_MASK))
2891 t->flags |= SN_ERR_SRVTO;
2892 if (!(t->flags & SN_FINST_MASK))
2893 t->flags |= SN_FINST_D;
2894 return 1;
2895 }
2896 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002897 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002898 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002899 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002900 shutdown(t->srv_fd, SHUT_WR);
2901 /* We must ensure that the read part is still alive when switching
2902 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002903 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002904 if (t->be->beprm->srvtimeout)
2905 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002906 t->srv_state = SV_STSHUTW;
2907 if (!(t->flags & SN_ERR_MASK))
2908 t->flags |= SN_ERR_SRVTO;
2909 if (!(t->flags & SN_FINST_MASK))
2910 t->flags |= SN_FINST_D;
2911 return 1;
2912 }
2913
2914 /* recompute request time-outs */
2915 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002916 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2917 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002918 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002919 }
2920 }
2921 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau2a429502006-10-15 14:52:29 +02002922 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2923 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002924 if (t->be->beprm->srvtimeout) {
2925 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002926 /* FIXME: to prevent the server from expiring read timeouts during writes,
2927 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002928 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002929 }
2930 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002931 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002932 }
2933 }
2934
2935 /* recompute response time-outs */
2936 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002937 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2938 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002939 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002940 }
2941 }
2942 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002943 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2944 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002945 if (t->be->beprm->srvtimeout)
2946 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002947 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002948 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002949 }
2950 }
2951
2952 return 0; /* other cases change nothing */
2953 }
2954 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002955 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002956 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002957 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002958 fd_delete(t->srv_fd);
2959 if (t->srv) {
2960 t->srv->cur_sess--;
2961 t->srv->failed_resp++;
2962 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002963 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002964 //close(t->srv_fd);
2965 t->srv_state = SV_STCLOSE;
2966 if (!(t->flags & SN_ERR_MASK))
2967 t->flags |= SN_ERR_SRVCL;
2968 if (!(t->flags & SN_FINST_MASK))
2969 t->flags |= SN_FINST_D;
2970 /* We used to have a free connection slot. Since we'll never use it,
2971 * we have to inform the server that it may be used by another session.
2972 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002973 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002974 task_wakeup(&rq, t->srv->queue_mgt);
2975
2976 return 1;
2977 }
2978 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002979 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002980 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002981 fd_delete(t->srv_fd);
2982 if (t->srv)
2983 t->srv->cur_sess--;
2984 //close(t->srv_fd);
2985 t->srv_state = SV_STCLOSE;
2986 /* We used to have a free connection slot. Since we'll never use it,
2987 * we have to inform the server that it may be used by another session.
2988 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002989 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002990 task_wakeup(&rq, t->srv->queue_mgt);
2991
2992 return 1;
2993 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002994 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002995 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002996 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002997 fd_delete(t->srv_fd);
2998 if (t->srv)
2999 t->srv->cur_sess--;
3000 //close(t->srv_fd);
3001 t->srv_state = SV_STCLOSE;
3002 if (!(t->flags & SN_ERR_MASK))
3003 t->flags |= SN_ERR_SRVTO;
3004 if (!(t->flags & SN_FINST_MASK))
3005 t->flags |= SN_FINST_D;
3006 /* We used to have a free connection slot. Since we'll never use it,
3007 * we have to inform the server that it may be used by another session.
3008 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003009 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02003010 task_wakeup(&rq, t->srv->queue_mgt);
3011
3012 return 1;
3013 }
3014 else if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02003015 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3016 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02003017 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003018 }
3019 }
3020 else { /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02003021 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3022 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01003023 if (t->be->beprm->srvtimeout) {
3024 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003025 /* FIXME: to prevent the server from expiring read timeouts during writes,
3026 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02003027 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003028 }
3029 else
Willy Tarreaud7971282006-07-29 18:36:34 +02003030 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003031 }
3032 }
3033 return 0;
3034 }
3035 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003036 if (rep->flags & BF_READ_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02003037 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02003038 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003039 fd_delete(t->srv_fd);
3040 if (t->srv) {
3041 t->srv->cur_sess--;
3042 t->srv->failed_resp++;
3043 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003044 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003045 //close(t->srv_fd);
3046 t->srv_state = SV_STCLOSE;
3047 if (!(t->flags & SN_ERR_MASK))
3048 t->flags |= SN_ERR_SRVCL;
3049 if (!(t->flags & SN_FINST_MASK))
3050 t->flags |= SN_FINST_D;
3051 /* We used to have a free connection slot. Since we'll never use it,
3052 * we have to inform the server that it may be used by another session.
3053 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003054 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02003055 task_wakeup(&rq, t->srv->queue_mgt);
3056
3057 return 1;
3058 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003059 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02003060 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02003061 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003062 fd_delete(t->srv_fd);
3063 if (t->srv)
3064 t->srv->cur_sess--;
3065 //close(t->srv_fd);
3066 t->srv_state = SV_STCLOSE;
3067 /* We used to have a free connection slot. Since we'll never use it,
3068 * we have to inform the server that it may be used by another session.
3069 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003070 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02003071 task_wakeup(&rq, t->srv->queue_mgt);
3072
3073 return 1;
3074 }
Willy Tarreaud7971282006-07-29 18:36:34 +02003075 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02003076 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02003077 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003078 fd_delete(t->srv_fd);
3079 if (t->srv)
3080 t->srv->cur_sess--;
3081 //close(t->srv_fd);
3082 t->srv_state = SV_STCLOSE;
3083 if (!(t->flags & SN_ERR_MASK))
3084 t->flags |= SN_ERR_SRVTO;
3085 if (!(t->flags & SN_FINST_MASK))
3086 t->flags |= SN_FINST_D;
3087 /* We used to have a free connection slot. Since we'll never use it,
3088 * we have to inform the server that it may be used by another session.
3089 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003090 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02003091 task_wakeup(&rq, t->srv->queue_mgt);
3092
3093 return 1;
3094 }
3095 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02003096 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
3097 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02003098 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003099 }
3100 }
3101 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02003102 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
3103 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01003104 if (t->be->beprm->srvtimeout)
3105 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003106 else
Willy Tarreaud7971282006-07-29 18:36:34 +02003107 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003108 }
3109 }
3110 return 0;
3111 }
3112 else { /* SV_STCLOSE : nothing to do */
3113 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
3114 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01003115 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 +02003116 write(1, trash, len);
3117 }
3118 return 0;
3119 }
3120 return 0;
3121}
3122
3123
3124/*
3125 * Produces data for the session <s> depending on its source. Expects to be
3126 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3127 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3128 * session, which it uses to keep on being called when there is free space in
3129 * the buffer, of simply by letting an empty buffer upon return. It returns 1
3130 * if it changes the session state from CL_STSHUTR, otherwise 0.
3131 */
3132int produce_content(struct session *s)
3133{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003134 if (s->data_source == DATA_SRC_NONE) {
3135 s->flags &= ~SN_SELF_GEN;
3136 return 1;
3137 }
3138 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003139 /* dump server statistics */
3140 return produce_content_stats(s);
3141 }
3142 else {
3143 /* unknown data source */
3144 s->logs.status = 500;
3145 client_retnclose(s, error_message(s, HTTP_ERR_500));
3146 if (!(s->flags & SN_ERR_MASK))
3147 s->flags |= SN_ERR_PRXCOND;
3148 if (!(s->flags & SN_FINST_MASK))
3149 s->flags |= SN_FINST_R;
3150 s->flags &= ~SN_SELF_GEN;
3151 return 1;
3152 }
3153}
3154
3155
3156/*
3157 * Produces statistics data for the session <s>. Expects to be called with
3158 * s->cli_state == CL_STSHUTR. It stops by itself by unsetting the SN_SELF_GEN
3159 * flag from the session, which it uses to keep on being called when there is
3160 * free space in the buffer, of simply by letting an empty buffer upon return.
3161 * It returns 1 if it changes the session state from CL_STSHUTR, otherwise 0.
3162 */
3163int produce_content_stats(struct session *s)
3164{
3165 struct buffer *rep = s->rep;
3166 struct proxy *px;
3167 struct chunk msg;
3168 unsigned int up;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003169
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003170 msg.len = 0;
3171 msg.str = trash;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003172
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003173 switch (s->data_state) {
3174 case DATA_ST_INIT:
3175 /* the function had not been called yet */
3176 s->flags |= SN_SELF_GEN; // more data will follow
Willy Tarreaubaaee002006-06-26 02:48:02 +02003177
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003178 chunk_printf(&msg, sizeof(trash),
3179 "HTTP/1.0 200 OK\r\n"
3180 "Cache-Control: no-cache\r\n"
3181 "Connection: close\r\n"
3182 "Content-Type: text/html\r\n"
3183 "\r\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003184
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003185 s->logs.status = 200;
3186 client_retnclose(s, &msg); // send the start of the response.
3187 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003188
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003189 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
3190 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
3191 if (!(s->flags & SN_FINST_MASK))
3192 s->flags |= SN_FINST_R;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003193
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003194 if (s->hreq.meth == HTTP_METH_HEAD) {
3195 /* that's all we return in case of HEAD request */
3196 s->data_state = DATA_ST_FIN;
3197 s->flags &= ~SN_SELF_GEN;
3198 return 1;
3199 }
3200
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003201 s->data_state = DATA_ST_HEAD; /* let's start producing data */
3202 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003203
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003204 case DATA_ST_HEAD:
3205 /* WARNING! This must fit in the first buffer !!! */
3206 chunk_printf(&msg, sizeof(trash),
3207 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
3208 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
3209 "<style type=\"text/css\"><!--\n"
3210 "body {"
3211 " font-family: helvetica, arial;"
3212 " font-size: 12px;"
3213 " font-weight: normal;"
3214 " color: black;"
3215 " background: white;"
3216 "}\n"
3217 "th,td {"
3218 " font-size: 0.8em;"
3219 " align: center;"
3220 "}"
3221 "h1 {"
3222 " font-size: xx-large;"
3223 " margin-bottom: 0.5em;"
3224 "}\n"
3225 "h2 {"
3226 " font-family: helvetica, arial;"
3227 " font-size: x-large;"
3228 " font-weight: bold;"
3229 " font-style: italic;"
3230 " color: #6020a0;"
3231 " margin-top: 0em;"
3232 " margin-bottom: 0em;"
3233 "}\n"
3234 "h3 {"
3235 " font-family: helvetica, arial;"
3236 " font-size: 16px;"
3237 " font-weight: bold;"
3238 " color: #b00040;"
3239 " background: #e8e8d0;"
3240 " margin-top: 0em;"
3241 " margin-bottom: 0em;"
3242 "}\n"
3243 "li {"
3244 " margin-top: 0.25em;"
3245 " margin-right: 2em;"
3246 "}\n"
3247 ".hr {margin-top: 0.25em;"
3248 " border-color: black;"
3249 " border-bottom-style: solid;"
3250 "}\n"
3251 ".pxname {background: #b00040;color: #ffff40;font-weight: bold;}\n"
3252 ".titre {background: #20D0D0;color: #000000;font-weight: bold;}\n"
3253 ".total {background: #20D0D0;color: #ffff80;}\n"
3254 ".frontend {background: #e8e8d0;}\n"
3255 ".backend {background: #e8e8d0;}\n"
3256 ".active0 {background: #ff9090;}\n"
3257 ".active1 {background: #ffd020;}\n"
3258 ".active2 {background: #ffffa0;}\n"
3259 ".active3 {background: #c0ffc0;}\n"
3260 ".active4 {background: #e0e0e0;}\n"
3261 ".backup0 {background: #ff9090;}\n"
3262 ".backup1 {background: #ff80ff;}\n"
3263 ".backup2 {background: #c060ff;}\n"
3264 ".backup3 {background: #b0d0ff;}\n"
3265 ".backup4 {background: #e0e0e0;}\n"
3266 "table.tbl { border-collapse: collapse; border-style: none;}\n"
Willy Tarreau35d66b02007-01-02 00:28:21 +01003267 "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 +01003268 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}\n"
3269 "table.tbl th.empty { border-style: none; empty-cells: hide;}\n"
3270 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
3271 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
3272 "table.lgd td.noborder { border-style: none; padding: 2px; white-space: nowrap;}\n"
3273 "-->"
3274 "</style></head>");
3275
3276 if (buffer_write_chunk(rep, &msg) != 0)
3277 return 0;
3278
3279 s->data_state = DATA_ST_INFO;
3280 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003281
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003282 case DATA_ST_INFO:
3283 up = (now.tv_sec - start_date.tv_sec);
3284
3285 /* WARNING! this has to fit the first packet too.
3286 * We are around 3.5 kB, add adding entries will
3287 * become tricky if we want to support 4kB buffers !
3288 */
3289 chunk_printf(&msg, sizeof(trash),
3290 "<body><h1><a href=\"" PRODUCT_URL "\" style=\"text-decoration: none;\">"
3291 PRODUCT_NAME "</a></h1>\n"
3292 "<h2>Statistics Report for pid %d</h2>\n"
3293 "<hr width=\"100%%\" class=\"hr\">\n"
3294 "<h3>&gt; General process information</h3>\n"
3295 "<table border=0 cols=3><tr><td align=\"left\" nowrap width=\"1%%\">\n"
3296 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
3297 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
3298 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
3299 "<b>maxsock = </b> %d<br>\n"
3300 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
3301 "</td><td align=\"center\" nowrap>\n"
3302 "<table class=\"lgd\"><tr>"
3303 "<td class=\"active3\">&nbsp;</td><td class=\"noborder\">active UP </td>"
3304 "<td class=\"backup3\">&nbsp;</td><td class=\"noborder\">backup UP </td>"
3305 "</tr><tr>"
3306 "<td class=\"active2\"></td><td class=\"noborder\">active UP, going down </td>"
3307 "<td class=\"backup2\"></td><td class=\"noborder\">backup UP, going down </td>"
3308 "</tr><tr>"
3309 "<td class=\"active1\"></td><td class=\"noborder\">active DOWN, going up </td>"
3310 "<td class=\"backup1\"></td><td class=\"noborder\">backup DOWN, going up </td>"
3311 "</tr><tr>"
3312 "<td class=\"active0\"></td><td class=\"noborder\">active or backup DOWN &nbsp;</td>"
3313 "<td class=\"active4\"></td><td class=\"noborder\">not checked </td>"
3314 "</tr></table>\n"
3315 "</td>"
3316 "<td align=\"left\" nowrap width=\"1%%\">"
3317 "<b>External ressources:</b><ul style=\"margin-top: 0.25em;\">"
3318 "<li><a href=\"" PRODUCT_URL "\">Primary site</a><br>"
3319 "<li><a href=\"" PRODUCT_URL_UPD "\">Updates (v" PRODUCT_BRANCH ")</a><br>"
3320 "<li><a href=\"" PRODUCT_URL_DOC "\">Online manual</a><br>"
3321 "</ul>"
3322 "</td>"
3323 "</tr></table>\n"
3324 "",
3325 pid, pid, global.nbproc,
3326 up / 86400, (up % 86400) / 3600,
3327 (up % 3600) / 60, (up % 60),
3328 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
3329 global.rlimit_memmax ? " MB" : "",
3330 global.rlimit_nofile,
3331 global.maxsock,
3332 global.maxconn,
3333 actconn
3334 );
Willy Tarreaubaaee002006-06-26 02:48:02 +02003335
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003336 if (buffer_write_chunk(rep, &msg) != 0)
3337 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003338
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003339 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003340
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003341 s->data_ctx.stats.px = proxy;
3342 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
3343 s->data_state = DATA_ST_LIST;
3344 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003345
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003346 case DATA_ST_LIST:
3347 /* dump proxies */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003348 while (s->data_ctx.stats.px) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003349 px = s->data_ctx.stats.px;
3350 /* skip the disabled proxies and non-networked ones */
3351 if (px->state != PR_STSTOPPED && (px->cap & (PR_CAP_FE | PR_CAP_BE)))
3352 if (produce_content_stats_proxy(s, px) == 0)
3353 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003354
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003355 s->data_ctx.stats.px = px->next;
3356 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
3357 }
3358 /* here, we just have reached the last proxy */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003359
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003360 s->data_state = DATA_ST_END;
3361 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003362
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003363 case DATA_ST_END:
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003364 chunk_printf(&msg, sizeof(trash), "</body></html>\n");
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003365 if (buffer_write_chunk(rep, &msg) != 0)
3366 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003367
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003368 s->data_state = DATA_ST_FIN;
3369 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003370
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003371 case DATA_ST_FIN:
3372 s->flags &= ~SN_SELF_GEN;
3373 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003374
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003375 default:
3376 /* unknown state ! */
3377 s->logs.status = 500;
3378 client_retnclose(s, error_message(s, HTTP_ERR_500));
3379 if (!(s->flags & SN_ERR_MASK))
3380 s->flags |= SN_ERR_PRXCOND;
3381 if (!(s->flags & SN_FINST_MASK))
3382 s->flags |= SN_FINST_R;
3383 s->flags &= ~SN_SELF_GEN;
3384 return 1;
3385 }
3386}
Willy Tarreaubaaee002006-06-26 02:48:02 +02003387
Willy Tarreaubaaee002006-06-26 02:48:02 +02003388
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003389/*
3390 * Dumps statistics for a proxy.
3391 * Returns 0 if it had to stop dumping data because of lack of buffer space,
3392 * ot non-zero if everything completed.
3393 */
3394int produce_content_stats_proxy(struct session *s, struct proxy *px)
3395{
3396 struct buffer *rep = s->rep;
3397 struct server *sv;
3398 struct chunk msg;
3399
3400 msg.len = 0;
3401 msg.str = trash;
3402
3403 switch (s->data_ctx.stats.px_st) {
3404 case DATA_ST_PX_INIT:
3405 /* we are on a new proxy */
3406
3407 if (s->be->fiprm->uri_auth && s->be->fiprm->uri_auth->scope) {
3408 /* we have a limited scope, we have to check the proxy name */
3409 struct stat_scope *scope;
3410 int len;
3411
3412 len = strlen(px->id);
3413 scope = s->be->fiprm->uri_auth->scope;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003414
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003415 while (scope) {
3416 /* match exact proxy name */
3417 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3418 break;
3419
3420 /* match '.' which means 'self' proxy */
3421 if (!strcmp(scope->px_id, ".") && px == s->fe)
3422 break;
3423 scope = scope->next;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003424 }
3425
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003426 /* proxy name not found : don't dump anything */
3427 if (scope == NULL)
3428 return 1;
3429 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003430
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003431 s->data_ctx.stats.px_st = DATA_ST_PX_TH;
3432 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003433
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003434 case DATA_ST_PX_TH:
3435 /* print a new table */
3436 chunk_printf(&msg, sizeof(trash),
3437 "<table cols=\"20\" class=\"tbl\" width=\"100%%\">\n"
3438 "<tr align=\"center\" class=\"titre\">"
3439 "<th colspan=2 class=\"pxname\">%s</th>"
3440 "<th colspan=18 class=\"empty\"></th>"
3441 "</tr>\n"
3442 "<tr align=\"center\" class=\"titre\">"
3443 "<th rowspan=2></th>"
3444 "<th colspan=2>Queue</th><th colspan=4>Sessions</th>"
3445 "<th colspan=2>Bytes</th><th colspan=2>Denied</th>"
3446 "<th colspan=3>Errors</th><th colspan=6>Server</th>"
3447 "</tr>\n"
3448 "<tr align=\"center\" class=\"titre\">"
Willy Tarreau35d66b02007-01-02 00:28:21 +01003449 "<th>Cur</th><th>Max</th><th>Cur</th><th>Max</th>"
3450 "<th>Limit</th><th>Cumul</th><th>In</th><th>Out</th>"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003451 "<th>Req</th><th>Resp</th><th>Req</th><th>Conn</th>"
3452 "<th>Resp</th><th>Status</th><th>Weight</th><th>Act</th>"
3453 "<th>Bck</th><th>Check</th><th>Down</th></tr>\n"
3454 "",
3455 px->id);
3456
3457 if (buffer_write_chunk(rep, &msg) != 0)
3458 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003459
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003460 s->data_ctx.stats.px_st = DATA_ST_PX_FE;
3461 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003462
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003463 case DATA_ST_PX_FE:
3464 /* print the frontend */
3465 if (px->cap & PR_CAP_FE) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003466 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003467 /* name, queue */
3468 "<tr align=center class=\"frontend\"><td>Frontend</td><td colspan=2></td>"
3469 /* sessions : current, max, limit, cumul. */
3470 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
3471 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003472 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003473 /* denied: req, resp */
3474 "<td align=right>%d</td><td align=right>%d</td>"
3475 /* errors : request, connect, response */
3476 "<td align=right>%d</td><td align=right></td><td align=right></td>"
3477 /* server status : reflect backend status */
3478 "<td align=center>%s</td>"
3479 /* rest of server: nothing */
3480 "<td align=center colspan=5></td></tr>"
3481 "",
3482 px->feconn, px->feconn_max, px->maxconn, px->cum_feconn,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003483 px->bytes_in, px->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003484 px->denied_req, px->denied_resp,
3485 px->failed_req,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003486 px->state == PR_STRUN ? "OPEN" :
3487 px->state == PR_STIDLE ? "FULL" : "STOP");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003488
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003489 if (buffer_write_chunk(rep, &msg) != 0)
3490 return 0;
3491 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003492
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003493 s->data_ctx.stats.sv = px->srv; /* may be NULL */
3494 s->data_ctx.stats.px_st = DATA_ST_PX_SV;
3495 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003496
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003497 case DATA_ST_PX_SV:
3498 /* stats.sv has been initialized above */
3499 while (s->data_ctx.stats.sv != NULL) {
3500 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3501 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP, 4=unchecked */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003502
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003503 sv = s->data_ctx.stats.sv;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003504
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003505 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3506 if (!(sv->state & SRV_CHECKED))
3507 sv_state = 4;
3508 else if (sv->state & SRV_RUNNING)
3509 if (sv->health == sv->rise + sv->fall - 1)
3510 sv_state = 3; /* UP */
3511 else
3512 sv_state = 2; /* going down */
3513 else
3514 if (sv->health)
3515 sv_state = 1; /* going up */
3516 else
3517 sv_state = 0; /* DOWN */
3518
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003519 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003520 /* name */
3521 "<tr align=\"center\" class=\"%s%d\"><td>%s</td>"
3522 /* queue : current, max */
3523 "<td align=right>%d</td><td align=right>%d</td>"
3524 /* sessions : current, max, limit, cumul */
3525 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>"
3526 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003527 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003528 /* denied: req, resp */
3529 "<td align=right></td><td align=right>%d</td>"
3530 /* errors : request, connect, response */
3531 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
3532 "",
Willy Tarreau368e96a2007-01-07 00:16:15 +01003533 (sv->state & SRV_BACKUP) ? "backup" : "active",
Willy Tarreau128e9542007-01-01 22:01:43 +01003534 sv_state, sv->id,
3535 sv->nbpend, sv->nbpend_max,
3536 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003537 sv->bytes_in, sv->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003538 sv->failed_secu,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003539 sv->failed_conns, sv->failed_resp);
Willy Tarreau128e9542007-01-01 22:01:43 +01003540
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003541 /* status */
3542 chunk_printf(&msg, sizeof(trash), "<td nowrap>");
3543 chunk_printf(&msg, sizeof(trash),
3544 srv_hlt_st[sv_state],
3545 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3546 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3547
Willy Tarreau128e9542007-01-01 22:01:43 +01003548 chunk_printf(&msg, sizeof(trash),
3549 /* weight */
3550 "</td><td>%d</td>"
3551 /* act, bck */
3552 "<td>%s</td><td>%s</td>"
3553 "",
3554 sv->uweight+1,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003555 (sv->state & SRV_BACKUP) ? "-" : "Y",
3556 (sv->state & SRV_BACKUP) ? "Y" : "-");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003557
3558 /* check failures : unique, fatal */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003559 if (sv->state & SRV_CHECKED)
3560 chunk_printf(&msg, sizeof(trash),
3561 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3562 sv->failed_checks, sv->down_trans);
3563 else
3564 chunk_printf(&msg, sizeof(trash),
3565 "<td colspan=2></td></tr>\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003566
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003567 if (buffer_write_chunk(rep, &msg) != 0)
3568 return 0;
3569
3570 s->data_ctx.stats.sv = sv->next;
3571 } /* while sv */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003572
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003573 s->data_ctx.stats.px_st = DATA_ST_PX_BE;
3574 /* fall through */
3575
3576 case DATA_ST_PX_BE:
3577 /* print the backend */
3578 if (px->cap & PR_CAP_BE) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003579 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003580 /* name */
3581 "<tr align=center class=\"backend\"><td>Backend</td>"
3582 /* queue : current, max */
3583 "<td align=right>%d</td><td align=right>%d</td>"
3584 /* sessions : current, max, limit, cumul. */
3585 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
3586 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003587 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003588 /* denied: req, resp */
3589 "<td align=right>%d</td><td align=right>%d</td>"
3590 /* errors : request, connect, response */
3591 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
3592 /* server status : reflect backend status (up/down) : we display UP
3593 * if the backend has known working servers or if it has no server at
3594 * all (eg: for stats). Tthen we display the total weight, number of
3595 * active and backups. */
3596 "<td align=center>%s</td><td align=center>%d</td>"
3597 "<td align=center>%d</td><td align=center>%d</td>"
3598 /* rest of server: nothing */
3599 "<td align=center colspan=2></td></tr>"
3600 "",
3601 px->nbpend /* or px->totpend ? */, px->nbpend_max,
3602 px->beconn, px->beconn_max, px->fullconn, px->cum_beconn,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003603 px->bytes_in, px->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003604 px->denied_req, px->denied_resp,
3605 px->failed_conns, px->failed_resp,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003606 (px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN",
3607 px->srv_map_sz, px->srv_act, px->srv_bck);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003608
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003609 if (buffer_write_chunk(rep, &msg) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003610 return 0;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003611 }
3612
3613 s->data_ctx.stats.px_st = DATA_ST_PX_END;
3614 /* fall through */
3615
3616 case DATA_ST_PX_END:
3617 chunk_printf(&msg, sizeof(trash), "</table><p>\n");
3618
3619 if (buffer_write_chunk(rep, &msg) != 0)
3620 return 0;
3621
3622 s->data_ctx.stats.px_st = DATA_ST_PX_FIN;
3623 /* fall through */
3624
3625 case DATA_ST_PX_FIN:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003626 return 1;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003627
3628 default:
3629 /* unknown state, we should put an abort() here ! */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003630 return 1;
3631 }
3632}
3633
3634
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003635/* Iterate the same filter through all request headers.
3636 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003637 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003638int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003639{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003640 char term;
3641 char *cur_ptr, *cur_end, *cur_next;
3642 int cur_idx, old_idx, last_hdr;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003643 struct http_req *hreq = &t->hreq;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003644 struct hdr_idx_elem *cur_hdr;
3645 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003646
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003647 last_hdr = 0;
3648
3649 cur_next = req->data + hreq->req.sor + hdr_idx_first_pos(&hreq->hdr_idx);
3650 old_idx = 0;
3651
3652 while (!last_hdr) {
3653 if (unlikely(t->flags & (SN_CLDENY | SN_CLTARPIT)))
3654 return 1;
3655 else if (unlikely(t->flags & SN_CLALLOW) &&
3656 (exp->action == ACT_ALLOW ||
3657 exp->action == ACT_DENY ||
3658 exp->action == ACT_TARPIT))
3659 return 0;
3660
3661 cur_idx = hreq->hdr_idx.v[old_idx].next;
3662 if (!cur_idx)
3663 break;
3664
3665 cur_hdr = &hreq->hdr_idx.v[cur_idx];
3666 cur_ptr = cur_next;
3667 cur_end = cur_ptr + cur_hdr->len;
3668 cur_next = cur_end + cur_hdr->cr + 1;
3669
3670 /* Now we have one header between cur_ptr and cur_end,
3671 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003672 */
3673
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003674 /* The annoying part is that pattern matching needs
3675 * that we modify the contents to null-terminate all
3676 * strings before testing them.
3677 */
3678
3679 term = *cur_end;
3680 *cur_end = '\0';
3681
3682 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3683 switch (exp->action) {
3684 case ACT_SETBE:
3685 /* It is not possible to jump a second time.
3686 * FIXME: should we return an HTTP/500 here so that
3687 * the admin knows there's a problem ?
3688 */
3689 if (t->be != t->fe)
3690 break;
3691
3692 /* Swithing Proxy */
3693 t->be = (struct proxy *) exp->replace;
3694
3695 /* right now, the backend switch is not too much complicated
3696 * because we have associated req_cap and rsp_cap to the
3697 * frontend, and the beconn will be updated later.
3698 */
3699
3700 t->rep->rto = t->req->wto = t->be->beprm->srvtimeout;
3701 t->req->cto = t->be->beprm->contimeout;
3702 last_hdr = 1;
3703 break;
3704
3705 case ACT_ALLOW:
3706 t->flags |= SN_CLALLOW;
3707 last_hdr = 1;
3708 break;
3709
3710 case ACT_DENY:
3711 t->flags |= SN_CLDENY;
3712 last_hdr = 1;
3713 t->be->beprm->denied_req++;
3714 break;
3715
3716 case ACT_TARPIT:
3717 t->flags |= SN_CLTARPIT;
3718 last_hdr = 1;
3719 t->be->beprm->denied_req++;
3720 break;
3721
3722 case ACT_REPLACE:
3723 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3724 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3725 /* FIXME: if the user adds a newline in the replacement, the
3726 * index will not be recalculated for now, and the new line
3727 * will not be counted as a new header.
3728 */
3729
3730 cur_end += delta;
3731 cur_next += delta;
3732 cur_hdr->len += delta;
3733 hreq->req.eoh += delta;
3734 break;
3735
3736 case ACT_REMOVE:
3737 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3738 cur_next += delta;
3739
3740 /* FIXME: this should be a separate function */
3741 hreq->req.eoh += delta;
3742 hreq->hdr_idx.v[old_idx].next = cur_hdr->next;
3743 hreq->hdr_idx.used--;
3744 cur_hdr->len = 0;
3745 cur_end = NULL; /* null-term has been rewritten */
3746 break;
3747
3748 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01003749 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003750 if (cur_end)
3751 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003752
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003753 /* keep the link from this header to next one in case of later
3754 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003755 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003756 old_idx = cur_idx;
3757 }
3758 return 0;
3759}
3760
3761
3762/* Apply the filter to the request line.
3763 * Returns 0 if nothing has been done, 1 if the filter has been applied,
3764 * or -1 if a replacement resulted in an invalid request line.
3765 */
3766int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
3767{
3768 char term;
3769 char *cur_ptr, *cur_end;
3770 int done;
3771 struct http_req *hreq = &t->hreq;
3772 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003773
Willy Tarreau58f10d72006-12-04 02:26:12 +01003774
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003775 if (unlikely(t->flags & (SN_CLDENY | SN_CLTARPIT)))
3776 return 1;
3777 else if (unlikely(t->flags & SN_CLALLOW) &&
3778 (exp->action == ACT_ALLOW ||
3779 exp->action == ACT_DENY ||
3780 exp->action == ACT_TARPIT))
3781 return 0;
3782 else if (exp->action == ACT_REMOVE)
3783 return 0;
3784
3785 done = 0;
3786
3787 cur_ptr = req->data + hreq->req.sor;
3788 cur_end = cur_ptr + hreq->req.sl.rq.l;
3789
3790 /* Now we have the request line between cur_ptr and cur_end */
3791
3792 /* The annoying part is that pattern matching needs
3793 * that we modify the contents to null-terminate all
3794 * strings before testing them.
3795 */
3796
3797 term = *cur_end;
3798 *cur_end = '\0';
3799
3800 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3801 switch (exp->action) {
3802 case ACT_SETBE:
3803 /* It is not possible to jump a second time.
3804 * FIXME: should we return an HTTP/500 here so that
3805 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01003806 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003807 if (t->be != t->fe)
3808 break;
3809
3810 /* Swithing Proxy */
3811 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003812
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003813 /* right now, the backend switch is not too much complicated
3814 * because we have associated req_cap and rsp_cap to the
3815 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003816 */
3817
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003818 t->rep->rto = t->req->wto = t->be->beprm->srvtimeout;
3819 t->req->cto = t->be->beprm->contimeout;
3820 done = 1;
3821 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003822
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003823 case ACT_ALLOW:
3824 t->flags |= SN_CLALLOW;
3825 done = 1;
3826 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003827
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003828 case ACT_DENY:
3829 t->flags |= SN_CLDENY;
3830 t->be->beprm->denied_req++;
3831 done = 1;
3832 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003833
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003834 case ACT_TARPIT:
3835 t->flags |= SN_CLTARPIT;
3836 t->be->beprm->denied_req++;
3837 done = 1;
3838 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003839
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003840 case ACT_REPLACE:
3841 *cur_end = term; /* restore the string terminator */
3842 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3843 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3844 /* FIXME: if the user adds a newline in the replacement, the
3845 * index will not be recalculated for now, and the new line
3846 * will not be counted as a new header.
3847 */
Willy Tarreaua496b602006-12-17 23:15:24 +01003848
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003849 hreq->req.eoh += delta;
3850 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01003851
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003852 cur_end = (char *)http_parse_reqline(&hreq->req, req->data,
3853 HTTP_MSG_RQMETH,
3854 cur_ptr, cur_end + 1,
3855 NULL, NULL);
3856 if (unlikely(!cur_end))
3857 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01003858
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003859 /* we have a full request and we know that we have either a CR
3860 * or an LF at <ptr>.
3861 */
3862 hreq->meth = find_http_meth(cur_ptr, hreq->req.sl.rq.m_l);
3863 hdr_idx_set_start(&hreq->hdr_idx, hreq->req.sl.rq.l, *cur_end == '\r');
3864 /* there is no point trying this regex on headers */
3865 return 1;
3866 }
3867 }
3868 *cur_end = term; /* restore the string terminator */
3869 return done;
3870}
Willy Tarreau97de6242006-12-27 17:18:38 +01003871
Willy Tarreau58f10d72006-12-04 02:26:12 +01003872
Willy Tarreau58f10d72006-12-04 02:26:12 +01003873
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003874/*
3875 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
3876 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
3877 * unparsable request.
3878 */
3879int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
3880{
3881 /* iterate through the filters in the outer loop */
3882 while (exp && !(t->flags & (SN_CLDENY|SN_CLTARPIT))) {
3883 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003884
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003885 /*
3886 * The interleaving of transformations and verdicts
3887 * makes it difficult to decide to continue or stop
3888 * the evaluation.
3889 */
3890
3891 if ((t->flags & SN_CLALLOW) &&
3892 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
3893 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
3894 exp = exp->next;
3895 continue;
3896 }
3897
3898 /* Apply the filter to the request line. */
3899 ret = apply_filter_to_req_line(t, req, exp);
3900 if (unlikely(ret < 0))
3901 return -1;
3902
3903 if (likely(ret == 0)) {
3904 /* The filter did not match the request, it can be
3905 * iterated through all headers.
3906 */
3907 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003908 }
3909 exp = exp->next;
3910 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003911 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003912}
3913
3914
Willy Tarreau58f10d72006-12-04 02:26:12 +01003915/*
3916 * Manager client-side cookie
3917 */
3918void manage_client_side_cookies(struct session *t, struct buffer *req)
3919{
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003920 struct http_req *hreq = &t->hreq;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003921 char *p1, *p2, *p3, *p4;
3922 char *del_colon, *del_cookie, *colon;
3923 int app_cookies;
3924
3925 appsess *asession_temp = NULL;
3926 appsess local_asession;
3927
3928 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003929 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003930
Willy Tarreau830ff452006-12-17 19:31:23 +01003931 if (t->be->beprm->cookie_name == NULL &&
3932 t->be->beprm->appsession_name ==NULL &&
3933 t->be->fiprm->capture_name != NULL)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003934 return;
3935
Willy Tarreau2a324282006-12-05 00:05:46 +01003936 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003937 * we start with the start line.
3938 */
Willy Tarreau83969f42007-01-22 08:55:47 +01003939 old_idx = 0;
3940 cur_next = req->data + hreq->req.sor + hdr_idx_first_pos(&hreq->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003941
Willy Tarreau83969f42007-01-22 08:55:47 +01003942 while ((cur_idx = hreq->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003943 struct hdr_idx_elem *cur_hdr;
3944
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003945 cur_hdr = &hreq->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003946 cur_ptr = cur_next;
3947 cur_end = cur_ptr + cur_hdr->len;
3948 cur_next = cur_end + cur_hdr->cr + 1;
3949
3950 /* We have one full header between cur_ptr and cur_end, and the
3951 * next header starts at cur_next. We're only interested in
3952 * "Cookie:" headers.
3953 */
3954
3955 if ((cur_end - cur_ptr <= 7) ||
3956 (strncasecmp(cur_ptr, "Cookie:", 7) != 0)) {
3957 old_idx = cur_idx;
3958 continue;
3959 }
3960
3961 /* Now look for cookies. Conforming to RFC2109, we have to support
3962 * attributes whose name begin with a '$', and associate them with
3963 * the right cookie, if we want to delete this cookie.
3964 * So there are 3 cases for each cookie read :
3965 * 1) it's a special attribute, beginning with a '$' : ignore it.
3966 * 2) it's a server id cookie that we *MAY* want to delete : save
3967 * some pointers on it (last semi-colon, beginning of cookie...)
3968 * 3) it's an application cookie : we *MAY* have to delete a previous
3969 * "special" cookie.
3970 * At the end of loop, if a "special" cookie remains, we may have to
3971 * remove it. If no application cookie persists in the header, we
3972 * *MUST* delete it
3973 */
3974
3975
3976 p1 = cur_ptr + 7; /* first char after 'Cookie:' */
3977 if (isspace((int)*p1)) /* try to get the first space with it */
3978 p1++;
3979
3980 colon = p1;
3981 /* del_cookie == NULL => nothing to be deleted */
3982 del_colon = del_cookie = NULL;
3983 app_cookies = 0;
3984
3985 while (p1 < cur_end) {
3986 /* skip spaces and colons, but keep an eye on these ones */
3987 while (p1 < cur_end) {
3988 if (*p1 == ';' || *p1 == ',')
3989 colon = p1;
3990 else if (!isspace((int)*p1))
3991 break;
3992 p1++;
3993 }
3994
3995 if (p1 == cur_end)
3996 break;
3997
3998 /* p1 is at the beginning of the cookie name */
3999 p2 = p1;
4000 while (p2 < cur_end && *p2 != '=')
4001 p2++;
4002
4003 if (p2 == cur_end)
4004 break;
4005
4006 p3 = p2 + 1; /* skips the '=' sign */
4007 if (p3 == cur_end)
4008 break;
4009
4010 p4 = p3;
4011 while (p4 < cur_end && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
4012 p4++;
4013
4014 /* here, we have the cookie name between p1 and p2,
4015 * and its value between p3 and p4.
4016 * we can process it :
4017 *
4018 * Cookie: NAME=VALUE;
4019 * | || || |
4020 * | || || +--> p4
4021 * | || |+-------> p3
4022 * | || +--------> p2
4023 * | |+------------> p1
4024 * | +-------------> colon
4025 * +--------------------> cur_ptr
4026 */
4027
4028 if (*p1 == '$') {
4029 /* skip this one */
4030 }
4031 else {
4032 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01004033 if (t->fe->fiprm->capture_name != NULL &&
Willy Tarreau58f10d72006-12-04 02:26:12 +01004034 t->logs.cli_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01004035 (p4 - p1 >= t->fe->fiprm->capture_namelen) &&
4036 memcmp(p1, t->fe->fiprm->capture_name, t->fe->fiprm->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004037 int log_len = p4 - p1;
4038
4039 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4040 Alert("HTTP logging : out of memory.\n");
4041 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01004042 if (log_len > t->fe->fiprm->capture_len)
4043 log_len = t->fe->fiprm->capture_len;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004044 memcpy(t->logs.cli_cookie, p1, log_len);
4045 t->logs.cli_cookie[log_len] = 0;
4046 }
4047 }
4048
Willy Tarreau830ff452006-12-17 19:31:23 +01004049 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
4050 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004051 /* Cool... it's the right one */
Willy Tarreau830ff452006-12-17 19:31:23 +01004052 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004053 char *delim;
4054
4055 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4056 * have the server ID betweek p3 and delim, and the original cookie between
4057 * delim+1 and p4. Otherwise, delim==p4 :
4058 *
4059 * Cookie: NAME=SRV~VALUE;
4060 * | || || | |
4061 * | || || | +--> p4
4062 * | || || +--------> delim
4063 * | || |+-----------> p3
4064 * | || +------------> p2
4065 * | |+----------------> p1
4066 * | +-----------------> colon
4067 * +------------------------> cur_ptr
4068 */
4069
Willy Tarreau830ff452006-12-17 19:31:23 +01004070 if (t->be->beprm->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004071 for (delim = p3; delim < p4; delim++)
4072 if (*delim == COOKIE_DELIM)
4073 break;
4074 }
4075 else
4076 delim = p4;
4077
4078
4079 /* Here, we'll look for the first running server which supports the cookie.
4080 * This allows to share a same cookie between several servers, for example
4081 * to dedicate backup servers to specific servers only.
4082 * However, to prevent clients from sticking to cookie-less backup server
4083 * when they have incidentely learned an empty cookie, we simply ignore
4084 * empty cookies and mark them as invalid.
4085 */
4086 if (delim == p3)
4087 srv = NULL;
4088
4089 while (srv) {
4090 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreau830ff452006-12-17 19:31:23 +01004091 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004092 /* we found the server and it's usable */
4093 t->flags &= ~SN_CK_MASK;
4094 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
4095 t->srv = srv;
4096 break;
4097 } else {
4098 /* we found a server, but it's down */
4099 t->flags &= ~SN_CK_MASK;
4100 t->flags |= SN_CK_DOWN;
4101 }
4102 }
4103 srv = srv->next;
4104 }
4105
4106 if (!srv && !(t->flags & SN_CK_DOWN)) {
4107 /* no server matched this cookie */
4108 t->flags &= ~SN_CK_MASK;
4109 t->flags |= SN_CK_INVALID;
4110 }
4111
4112 /* depending on the cookie mode, we may have to either :
4113 * - delete the complete cookie if we're in insert+indirect mode, so that
4114 * the server never sees it ;
4115 * - remove the server id from the cookie value, and tag the cookie as an
4116 * application cookie so that it does not get accidentely removed later,
4117 * if we're in cookie prefix mode
4118 */
Willy Tarreau830ff452006-12-17 19:31:23 +01004119 if ((t->be->beprm->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004120 int delta; /* negative */
4121
4122 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
4123 p4 += delta;
4124 cur_end += delta;
4125 cur_next += delta;
4126 cur_hdr->len += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004127 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004128
4129 del_cookie = del_colon = NULL;
4130 app_cookies++; /* protect the header from deletion */
4131 }
4132 else if (del_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01004133 (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 +01004134 del_cookie = p1;
4135 del_colon = colon;
4136 }
4137 } else {
4138 /* now we know that we must keep this cookie since it's
4139 * not ours. But if we wanted to delete our cookie
4140 * earlier, we cannot remove the complete header, but we
4141 * can remove the previous block itself.
4142 */
4143 app_cookies++;
4144
4145 if (del_cookie != NULL) {
4146 int delta; /* negative */
4147
4148 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
4149 p4 += delta;
4150 cur_end += delta;
4151 cur_next += delta;
4152 cur_hdr->len += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004153 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004154 del_cookie = del_colon = NULL;
4155 }
4156 }
4157
Willy Tarreau830ff452006-12-17 19:31:23 +01004158 if ((t->be->beprm->appsession_name != NULL) &&
4159 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004160 /* first, let's see if the cookie is our appcookie*/
4161
4162 /* Cool... it's the right one */
4163
4164 asession_temp = &local_asession;
4165
4166 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4167 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4168 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4169 return;
4170 }
4171
Willy Tarreau830ff452006-12-17 19:31:23 +01004172 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
4173 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004174 asession_temp->serverid = NULL;
4175
4176 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01004177 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004178 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4179 /* free previously allocated memory */
4180 pool_free_to(apools.sessid, local_asession.sessid);
4181 Alert("Not enough memory process_cli():asession:calloc().\n");
4182 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4183 return;
4184 }
4185
4186 asession_temp->sessid = local_asession.sessid;
4187 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01004188 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004189 } else {
4190 /* free previously allocated memory */
4191 pool_free_to(apools.sessid, local_asession.sessid);
4192 }
4193
4194 if (asession_temp->serverid == NULL) {
4195 Alert("Found Application Session without matching server.\n");
4196 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01004197 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004198 while (srv) {
4199 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01004200 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004201 /* we found the server and it's usable */
4202 t->flags &= ~SN_CK_MASK;
4203 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
4204 t->srv = srv;
4205 break;
4206 } else {
4207 t->flags &= ~SN_CK_MASK;
4208 t->flags |= SN_CK_DOWN;
4209 }
4210 }
4211 srv = srv->next;
4212 }/* end while(srv) */
4213 }/* end else if server == NULL */
4214
Willy Tarreau830ff452006-12-17 19:31:23 +01004215 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004216 }/* end if ((t->proxy->appsession_name != NULL) ... */
4217 }
4218
4219 /* we'll have to look for another cookie ... */
4220 p1 = p4;
4221 } /* while (p1 < cur_end) */
4222
4223 /* There's no more cookie on this line.
4224 * We may have marked the last one(s) for deletion.
4225 * We must do this now in two ways :
4226 * - if there is no app cookie, we simply delete the header ;
4227 * - if there are app cookies, we must delete the end of the
4228 * string properly, including the colon/semi-colon before
4229 * the cookie name.
4230 */
4231 if (del_cookie != NULL) {
4232 int delta;
4233 if (app_cookies) {
4234 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
4235 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004236 cur_hdr->len += delta;
4237 } else {
4238 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004239
4240 /* FIXME: this should be a separate function */
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004241 hreq->hdr_idx.v[old_idx].next = cur_hdr->next;
4242 hreq->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004243 cur_hdr->len = 0;
4244 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01004245 cur_next += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004246 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004247 }
4248
4249 /* keep the link from this header to next one */
4250 old_idx = cur_idx;
4251 } /* end of cookie processing on this header */
4252}
4253
4254
Willy Tarreau58f10d72006-12-04 02:26:12 +01004255/*
4256 * Try to retrieve a known appsession in the URI, then the associated server.
4257 * If the server is found, it's assigned to the session.
4258 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004259void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004260{
4261 appsess *asession_temp = NULL;
4262 appsess local_asession;
4263 char *request_line;
4264
Willy Tarreau830ff452006-12-17 19:31:23 +01004265 if (t->be->beprm->appsession_name == NULL ||
Willy Tarreau921d7c02006-12-17 13:50:27 +01004266 (t->hreq.meth != HTTP_METH_GET && t->hreq.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004267 (request_line = memchr(begin, ';', len)) == NULL ||
4268 ((1 + t->be->beprm->appsession_name_len + 1 + t->be->beprm->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004269 return;
4270
4271 /* skip ';' */
4272 request_line++;
4273
4274 /* look if we have a jsessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01004275 if (strncasecmp(request_line, t->be->beprm->appsession_name, t->be->beprm->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004276 return;
4277
4278 /* skip jsessionid= */
Willy Tarreau830ff452006-12-17 19:31:23 +01004279 request_line += t->be->beprm->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004280
4281 /* First try if we already have an appsession */
4282 asession_temp = &local_asession;
4283
4284 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4285 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4286 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4287 return;
4288 }
4289
4290 /* Copy the sessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01004291 memcpy(asession_temp->sessid, request_line, t->be->beprm->appsession_len);
4292 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004293 asession_temp->serverid = NULL;
4294
4295 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01004296 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *)&asession_temp)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004297 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4298 /* free previously allocated memory */
4299 pool_free_to(apools.sessid, local_asession.sessid);
4300 Alert("Not enough memory process_cli():asession:calloc().\n");
4301 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4302 return;
4303 }
4304 asession_temp->sessid = local_asession.sessid;
4305 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01004306 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004307 }
4308 else {
4309 /* free previously allocated memory */
4310 pool_free_to(apools.sessid, local_asession.sessid);
4311 }
4312
Willy Tarreau830ff452006-12-17 19:31:23 +01004313 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004314 asession_temp->request_count++;
4315
4316#if defined(DEBUG_HASH)
4317 print_table(&(t->proxy->htbl_proxy));
4318#endif
4319 if (asession_temp->serverid == NULL) {
4320 Alert("Found Application Session without matching server.\n");
4321 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01004322 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004323 while (srv) {
4324 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01004325 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004326 /* we found the server and it's usable */
4327 t->flags &= ~SN_CK_MASK;
4328 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
4329 t->srv = srv;
4330 break;
4331 } else {
4332 t->flags &= ~SN_CK_MASK;
4333 t->flags |= SN_CK_DOWN;
4334 }
4335 }
4336 srv = srv->next;
4337 }
4338 }
4339}
4340
4341
Willy Tarreaub2513902006-12-17 14:52:38 +01004342/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004343 * In a GET or HEAD request, check if the requested URI matches the stats uri
4344 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01004345 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004346 * It is assumed that the request is either a HEAD or GET and that the
4347 * t->be->fiprm->uri_auth field is valid. An HTTP/401 response may be sent, or
4348 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01004349 *
4350 * Returns 1 if the session's state changes, otherwise 0.
4351 */
4352int stats_check_uri_auth(struct session *t, struct proxy *backend)
4353{
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004354 struct http_req *hreq = &t->hreq;
Willy Tarreaub2513902006-12-17 14:52:38 +01004355 struct uri_auth *uri_auth = backend->uri_auth;
4356 struct user_auth *user;
4357 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004358 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01004359
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004360 /* check URI size */
4361 if (uri_auth->uri_len > hreq->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01004362 return 0;
4363
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004364 h = t->req->data + hreq->req.sl.rq.u;
4365
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004366 /* the URI is in h */
4367 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01004368 return 0;
4369
4370 /* we are in front of a interceptable URI. Let's check
4371 * if there's an authentication and if it's valid.
4372 */
4373 user = uri_auth->users;
4374 if (!user) {
4375 /* no user auth required, it's OK */
4376 authenticated = 1;
4377 } else {
4378 authenticated = 0;
4379
4380 /* a user list is defined, we have to check.
4381 * skip 21 chars for "Authorization: Basic ".
4382 */
4383
4384 /* FIXME: this should move to an earlier place */
4385 cur_idx = 0;
Willy Tarreau83969f42007-01-22 08:55:47 +01004386 h = t->req->data + hreq->req.sor + hdr_idx_first_pos(&hreq->hdr_idx);
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004387 while ((cur_idx = hreq->hdr_idx.v[cur_idx].next)) {
4388 int len = hreq->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01004389 if (len > 14 &&
4390 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004391 hreq->auth_hdr.str = h;
4392 hreq->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01004393 break;
4394 }
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004395 h += len + hreq->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01004396 }
4397
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004398 if (hreq->auth_hdr.len < 21 ||
4399 memcmp(hreq->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01004400 user = NULL;
4401
4402 while (user) {
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004403 if ((hreq->auth_hdr.len == user->user_len + 14 + 7)
4404 && !memcmp(hreq->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01004405 user->user_pwd, user->user_len)) {
4406 authenticated = 1;
4407 break;
4408 }
4409 user = user->next;
4410 }
4411 }
4412
4413 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01004414 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01004415
4416 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01004417 msg.str = trash;
4418 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreaub2513902006-12-17 14:52:38 +01004419 t->logs.status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01004420 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01004421 if (!(t->flags & SN_ERR_MASK))
4422 t->flags |= SN_ERR_PRXCOND;
4423 if (!(t->flags & SN_FINST_MASK))
4424 t->flags |= SN_FINST_R;
4425 return 1;
4426 }
4427
4428 /* The request is valid, the user is authenticate. Let's start sending
4429 * data.
4430 */
4431 t->cli_state = CL_STSHUTR;
4432 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
4433 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
4434 t->data_source = DATA_SRC_STATS;
4435 t->data_state = DATA_ST_INIT;
4436 produce_content(t);
4437 return 1;
4438}
4439
4440
Willy Tarreaubaaee002006-06-26 02:48:02 +02004441/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01004442 * Print a debug line with a header
4443 */
4444void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
4445{
4446 int len, max;
4447 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
4448 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
4449 max = end - start;
4450 UBOUND(max, sizeof(trash) - len - 1);
4451 len += strlcpy2(trash + len, start, max + 1);
4452 trash[len++] = '\n';
4453 write(1, trash, len);
4454}
4455
4456
4457/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02004458 * Local variables:
4459 * c-indent-level: 8
4460 * c-basic-offset: 8
4461 * End:
4462 */