blob: 5aad97d044e2a81b012abe0b2cd9e06f422c81de [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 }
1021 goto http_msg_complete_header;
1022
1023 http_msg_hdr_val:
1024 case HTTP_MSG_HDR_VAL:
1025 /* assumes msg->sol points to the first char, msg->col to the
1026 * colon, and msg->sov points to the first character of the
1027 * value.
1028 */
1029 if (likely(!HTTP_IS_CRLF(*ptr)))
1030 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_val, HTTP_MSG_HDR_VAL);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001031
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001032 msg->eol = ptr;
1033 /* Note: we could also copy eol into ->eoh so that we have the
1034 * real header end in case it ends with lots of LWS, but is this
1035 * really needed ?
1036 */
1037 if (likely(*ptr == '\r'))
1038 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lf, HTTP_MSG_HDR_L2_LF);
1039 goto http_msg_hdr_l2_lf;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001040
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001041 http_msg_hdr_l2_lf:
1042 case HTTP_MSG_HDR_L2_LF:
1043 EXPECT_LF_HERE(ptr, http_msg_invalid);
1044 EAT_AND_JUMP_OR_RETURN(http_msg_hdr_l2_lws, HTTP_MSG_HDR_L2_LWS);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001045
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001046 http_msg_hdr_l2_lws:
1047 case HTTP_MSG_HDR_L2_LWS:
1048 if (unlikely(HTTP_IS_SPHT(*ptr))) {
1049 /* LWS: replace HT,CR,LF with spaces */
1050 for (; msg->eol < ptr; msg->eol++)
1051 *msg->eol = ' ';
1052 goto http_msg_hdr_val;
1053 }
1054 http_msg_complete_header:
1055 /*
1056 * It was a new header, so the last one is finished.
1057 * Assumes msg->sol points to the first char, msg->col to the
1058 * colon, msg->sov points to the first character of the value
1059 * and msg->eol to the first CR or LF so we know how the line
1060 * ends. We insert last header into the index.
1061 */
1062 /*
1063 fprintf(stderr,"registering %-2d bytes : ", msg->eol - msg->sol);
1064 write(2, msg->sol, msg->eol-msg->sol);
1065 fprintf(stderr,"\n");
1066 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001067
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001068 if (unlikely(hdr_idx_add(msg->eol - msg->sol, *msg->eol == '\r',
1069 idx, idx->tail) < 0))
1070 goto http_msg_invalid;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001071
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001072 msg->sol = ptr;
1073 if (likely(!HTTP_IS_CRLF(*ptr))) {
1074 goto http_msg_hdr_name;
1075 }
1076
1077 if (likely(*ptr == '\r'))
1078 EAT_AND_JUMP_OR_RETURN(http_msg_last_lf, HTTP_MSG_LAST_LF);
1079 goto http_msg_last_lf;
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001080
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001081 http_msg_last_lf:
1082 case HTTP_MSG_LAST_LF:
1083 /* Assumes msg->sol points to the first of either CR or LF */
1084 EXPECT_LF_HERE(ptr, http_msg_invalid);
1085 ptr++;
1086 buf->lr = ptr;
1087 msg->eoh = msg->sol - buf->data;
1088 msg->hdr_state = HTTP_MSG_BODY;
1089 return;
1090#ifdef DEBUG_FULL
1091 default:
1092 fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, state);
1093 exit(1);
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001094#endif
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001095 }
1096 http_msg_ood:
1097 /* out of data */
1098 msg->hdr_state = state;
1099 buf->lr = ptr;
1100 return;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001101
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001102 http_msg_invalid:
1103 /* invalid message */
1104 msg->hdr_state = HTTP_MSG_ERROR;
1105 return;
1106}
1107
1108/*
1109 * manages the client FSM and its socket. BTW, it also tries to handle the
1110 * cookie. It returns 1 if a state has changed (and a resync may be needed),
1111 * 0 else.
1112 */
1113int process_cli(struct session *t)
1114{
1115 int s = t->srv_state;
1116 int c = t->cli_state;
1117 struct buffer *req = t->req;
1118 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001119
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001120 DPRINTF(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
1121 cli_stnames[c], srv_stnames[s],
1122 MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
1123 req->rex.tv_sec, req->rex.tv_usec,
1124 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001125
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001126 if (c == CL_STHEADERS) {
1127 /*
1128 * Now parse the partial (or complete) lines.
1129 * We will check the request syntax, and also join multi-line
1130 * headers. An index of all the lines will be elaborated while
1131 * parsing.
1132 *
Willy Tarreau8973c702007-01-21 23:58:29 +01001133 * For the parsing, we use a 28 states FSM.
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001134 *
1135 * RFC2616 requires that both LF and CRLF are recognized as
1136 * line breaks, but that any other combination is an error.
1137 * To avoid duplicating all the states above to check for CR,
1138 * we use a special bit HTTP_PA_LF_EXP that we 'OR' with the
1139 * state we will switch to if the LF is seen, so that we know
1140 * whether there's a pending CR or not. We can check it
1141 * globally since all CR followed by anything but LF are
1142 * errors. Each state is entered with the first character is
1143 * has to process at req->lr.
1144 *
1145 * Here is the information we currently have :
1146 * req->data + req->sor = beginning of request
1147 * req->data + req->eoh = end of processed headers / start of current one
1148 * req->data + req->eol = end of current header or line (LF or CRLF)
1149 * req->lr = first non-visited byte
1150 * req->r = end of data
1151 */
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001152
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001153 int cur_idx;
1154 struct http_req *hreq = &t->hreq;
1155 struct http_msg *msg = &hreq->req;
1156 struct proxy *cur_proxy;
Willy Tarreau976f1ee2006-12-17 10:06:03 +01001157
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001158 if (likely(req->lr < req->r))
1159 http_msg_analyzer(req, msg, &hreq->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001160
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001161 /* 1: we might have to print this header in debug mode */
1162 if (unlikely((global.mode & MODE_DEBUG) &&
1163 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) &&
1164 (msg->hdr_state == HTTP_MSG_BODY || msg->hdr_state == HTTP_MSG_ERROR))) {
1165 char *eol, *sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001166
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001167 sol = req->data + msg->sor;
1168 eol = sol + msg->sl.rq.l;
1169 debug_hdr("clireq", t, sol, eol);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001170
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001171 sol += hdr_idx_first_pos(&hreq->hdr_idx);
1172 cur_idx = hdr_idx_first_idx(&hreq->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001173
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001174 while (cur_idx) {
1175 eol = sol + hreq->hdr_idx.v[cur_idx].len;
1176 debug_hdr("clihdr", t, sol, eol);
1177 sol = eol + hreq->hdr_idx.v[cur_idx].cr + 1;
1178 cur_idx = hreq->hdr_idx.v[cur_idx].next;
1179 }
1180 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001181
Willy Tarreau58f10d72006-12-04 02:26:12 +01001182
1183 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001184 * Now we quickly check if we have found a full valid request.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001185 * If not so, we check the FD and buffer states before leaving.
1186 * A full request is indicated by the fact that we have seen
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001187 * the double LF/CRLF, so the state is HTTP_MSG_BODY. Invalid
1188 * requests are checked first.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001189 *
1190 */
1191
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001192 if (unlikely(msg->hdr_state != HTTP_MSG_BODY)) {
1193 /*
1194 * First, let's catch bad requests.
1195 */
1196 if (unlikely(msg->hdr_state == HTTP_MSG_ERROR))
1197 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001198
1199 /* 1: Since we are in header mode, if there's no space
1200 * left for headers, we won't be able to free more
1201 * later, so the session will never terminate. We
1202 * must terminate it now.
1203 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001204 if (unlikely(req->l >= req->rlim - req->data)) {
1205 /* FIXME: check if URI is set and return Status
1206 * 414 Request URI too long instead.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001207 */
Willy Tarreau06619262006-12-17 08:37:22 +01001208 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001209 }
1210
1211 /* 2: have we encountered a read error or a close ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001212 else if (unlikely(req->flags & (BF_READ_ERROR | BF_READ_NULL))) {
1213 /* read error, or last read : give up. */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001214 tv_eternity(&req->rex);
1215 fd_delete(t->cli_fd);
1216 t->cli_state = CL_STCLOSE;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001217 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001218 if (!(t->flags & SN_ERR_MASK))
1219 t->flags |= SN_ERR_CLICL;
1220 if (!(t->flags & SN_FINST_MASK))
1221 t->flags |= SN_FINST_R;
1222 return 1;
1223 }
1224
1225 /* 3: has the read timeout expired ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001226 else if (unlikely(tv_cmp2_ms(&req->rex, &now) <= 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001227 /* read timeout : give up with an error message. */
1228 t->logs.status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +01001229 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001230 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001231 if (!(t->flags & SN_ERR_MASK))
1232 t->flags |= SN_ERR_CLITO;
1233 if (!(t->flags & SN_FINST_MASK))
1234 t->flags |= SN_FINST_R;
1235 return 1;
1236 }
1237
1238 /* 4: do we need to re-enable the read socket ? */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001239 else if (unlikely(! MY_FD_ISSET(t->cli_fd, StaticReadEvent))) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01001240 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
1241 * full. We cannot loop here since stream_sock_read will disable it only if
1242 * req->l == rlim-data
1243 */
1244 MY_FD_SET(t->cli_fd, StaticReadEvent);
1245 if (t->fe->clitimeout)
1246 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
1247 else
1248 tv_eternity(&req->rex);
1249 }
1250 return t->cli_state != CL_STHEADERS;
1251 }
1252
1253
1254 /****************************************************************
1255 * More interesting part now : we know that we have a complete *
1256 * request which at least looks like HTTP. We have an indicator *
1257 * of each header's length, so we can parse them quickly. *
1258 ****************************************************************/
1259
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001260 /*
1261 * 1: identify the method
1262 */
1263 hreq->meth = find_http_meth(&req->data[msg->sor], msg->sl.rq.m_l);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001264
1265 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001266 * 2: check if the URI matches the monitor_uri.
Willy Tarreau06619262006-12-17 08:37:22 +01001267 * We have to do this for every request which gets in, because
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001268 * the monitor-uri is defined by the frontend.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001269 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001270 if (unlikely((t->fe->monitor_uri_len != 0) &&
1271 (t->fe->monitor_uri_len == msg->sl.rq.u_l) &&
1272 !memcmp(&req->data[msg->sl.rq.u],
1273 t->fe->monitor_uri,
1274 t->fe->monitor_uri_len))) {
1275 /*
1276 * We have found the monitor URI
1277 */
1278 t->flags |= SN_MONITOR;
1279 t->logs.status = 200;
1280 client_retnclose(t, &http_200_chunk);
1281 goto return_prx_cond;
1282 }
1283
1284 /*
1285 * 3: Maybe we have to copy the original REQURI for the logs ?
1286 * Note: we cannot log anymore if the request has been
1287 * classified as invalid.
1288 */
1289 if (unlikely(t->logs.logwait & LW_REQ)) {
1290 /* we have a complete HTTP request that we must log */
1291 if ((t->logs.uri = pool_alloc(requri)) != NULL) {
1292 int urilen = msg->sl.rq.l;
1293
1294 if (urilen >= REQURI_LEN)
1295 urilen = REQURI_LEN - 1;
1296 memcpy(t->logs.uri, &req->data[msg->sor], urilen);
1297 t->logs.uri[urilen] = 0;
1298
1299 if (!(t->logs.logwait &= ~LW_REQ))
1300 sess_log(t);
1301 } else {
1302 Alert("HTTP logging : out of memory.\n");
1303 }
1304 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001305
Willy Tarreau06619262006-12-17 08:37:22 +01001306
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001307 /* 4. We may have to convert HTTP/0.9 requests to HTTP/1.0 */
1308 if (unlikely(msg->sl.rq.v_l == 0)) {
1309 int delta;
1310 char *cur_end;
1311 msg->sol = req->data + msg->sor;
1312 cur_end = msg->sol + msg->sl.rq.l;
1313 delta = 0;
Willy Tarreau06619262006-12-17 08:37:22 +01001314
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001315 if (msg->sl.rq.u_l == 0) {
1316 /* if no URI was set, add "/" */
1317 delta = buffer_replace2(req, cur_end, cur_end, " /", 2);
1318 cur_end += delta;
1319 msg->eoh += delta;
Willy Tarreau06619262006-12-17 08:37:22 +01001320 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001321 /* add HTTP version */
1322 delta = buffer_replace2(req, cur_end, cur_end, " HTTP/1.0\r\n", 11);
1323 msg->eoh += delta;
1324 cur_end += delta;
1325 cur_end = (char *)http_parse_reqline(msg, req->data,
1326 HTTP_MSG_RQMETH,
1327 msg->sol, cur_end + 1,
1328 NULL, NULL);
1329 if (unlikely(!cur_end))
1330 goto return_bad_req;
1331
1332 /* we have a full HTTP/1.0 request now and we know that
1333 * we have either a CR or an LF at <ptr>.
1334 */
1335 hdr_idx_set_start(&hreq->hdr_idx, msg->sl.rq.l, *cur_end == '\r');
Willy Tarreau58f10d72006-12-04 02:26:12 +01001336 }
1337
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001338
1339 /* 5: we may need to capture headers */
1340 if (unlikely((t->logs.logwait & LW_REQHDR) && t->fe->fiprm->req_cap)) {
1341 char *eol, *sol, *col, *sov;
1342 int cur_idx;
1343 struct cap_hdr *h;
1344 int len;
1345
1346 sol = req->data + msg->sor + hdr_idx_first_pos(&hreq->hdr_idx);
1347 cur_idx = hdr_idx_first_idx(&hreq->hdr_idx);
1348
1349 while (cur_idx) {
1350 eol = sol + hreq->hdr_idx.v[cur_idx].len;
1351
1352 col = sol;
1353 while (col < eol && *col != ':')
1354 col++;
1355
1356 sov = col + 1;
1357 while (sov < eol && http_is_lws[(unsigned char)*sov])
1358 sov++;
1359
1360 for (h = t->fe->fiprm->req_cap; h; h = h->next) {
1361 if ((h->namelen == col - sol) &&
1362 (strncasecmp(sol, h->name, h->namelen) == 0)) {
1363 if (hreq->req.cap[h->index] == NULL)
1364 hreq->req.cap[h->index] =
1365 pool_alloc_from(h->pool, h->len + 1);
1366
1367 if (hreq->req.cap[h->index] == NULL) {
1368 Alert("HTTP capture : out of memory.\n");
1369 continue;
1370 }
1371
1372 len = eol - sov;
1373 if (len > h->len)
1374 len = h->len;
1375
1376 memcpy(hreq->req.cap[h->index], sov, len);
1377 hreq->req.cap[h->index][len]=0;
1378 }
1379 }
1380 sol = eol + hreq->hdr_idx.v[cur_idx].cr + 1;
1381 cur_idx = hreq->hdr_idx.v[cur_idx].next;
1382 }
1383 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001384
1385 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001386 * 6: we will have to evaluate the filters.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001387 * As opposed to version 1.2, now they will be evaluated in the
1388 * filters order and not in the header order. This means that
1389 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001390 *
1391 * We can now check whether we want to switch to another
1392 * backend, in which case we will re-check the backend's
1393 * filters and various options. In order to support 3-level
1394 * switching, here's how we should proceed :
1395 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001396 * a) run be->fiprm.
1397 * if (switch) then switch ->be to the new backend.
1398 * b) run be->fiprm if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001399 * There cannot be any switch from there, so ->be cannot be
1400 * changed anymore.
1401 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001402 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001403 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001404 * The response path will be able to apply either ->be, or
1405 * ->be then ->fe filters in order to match the reverse of
1406 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001407 */
1408
Willy Tarreau06619262006-12-17 08:37:22 +01001409 do {
Willy Tarreau830ff452006-12-17 19:31:23 +01001410 struct proxy *rule_set = t->be->fiprm;
1411 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001412
Willy Tarreau06619262006-12-17 08:37:22 +01001413 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01001414 if (rule_set->req_exp != NULL) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001415 if (apply_filters_to_request(t, req, rule_set->req_exp) < 0)
1416 goto return_bad_req;
Willy Tarreau53b6c742006-12-17 13:37:46 +01001417 }
1418
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001419 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
1420 /* to ensure correct connection accounting on
1421 * the backend, we count the connection for the
1422 * one managing the queue.
1423 */
1424 t->be->beprm->beconn++;
1425 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1426 t->be->beprm->beconn_max = t->be->beprm->beconn;
1427 t->be->beprm->cum_beconn++;
1428 t->flags |= SN_BE_ASSIGNED;
1429 }
1430
Willy Tarreau06619262006-12-17 08:37:22 +01001431 /* has the request been denied ? */
1432 if (t->flags & SN_CLDENY) {
1433 /* no need to go further */
1434 t->logs.status = 403;
1435 /* let's log the request time */
1436 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreau80587432006-12-24 17:47:20 +01001437 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01001438 goto return_prx_cond;
1439 }
1440
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001441 /* We might have to check for "Connection:" */
1442 if (((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) &&
1443 !(t->flags & SN_CONN_CLOSED)) {
1444 char *cur_ptr, *cur_end, *cur_next;
1445 int cur_idx, old_idx, delta;
1446 struct hdr_idx_elem *cur_hdr;
Willy Tarreau06619262006-12-17 08:37:22 +01001447
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001448 cur_next = req->data + hreq->req.sor + hdr_idx_first_pos(&hreq->hdr_idx);
1449 old_idx = 0;
1450
1451 while ((cur_idx = hreq->hdr_idx.v[old_idx].next)) {
1452 cur_hdr = &hreq->hdr_idx.v[cur_idx];
1453 cur_ptr = cur_next;
1454 cur_end = cur_ptr + cur_hdr->len;
1455 cur_next = cur_end + cur_hdr->cr + 1;
1456
1457 if (strncasecmp(cur_ptr, "Connection:", 11) == 0) {
1458 /* 3 possibilities :
1459 * - we have already set Connection: close,
1460 * so we remove this line.
1461 * - we have not yet set Connection: close,
1462 * but this line indicates close. We leave
1463 * it untouched and set the flag.
1464 * - we have not yet set Connection: close,
1465 * and this line indicates non-close. We
1466 * replace it.
1467 */
1468 if (t->flags & SN_CONN_CLOSED) {
1469 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
1470 hreq->req.eoh += delta;
1471 cur_next += delta;
1472 hreq->hdr_idx.v[old_idx].next = cur_hdr->next;
1473 hreq->hdr_idx.used--;
1474 cur_hdr->len = 0;
1475 } else {
1476 if (cur_ptr + 17 > cur_end ||
1477 !http_is_lws[(unsigned char)*(cur_ptr+17)] ||
1478 strncasecmp(cur_ptr+11, " close", 6)) {
1479 delta = buffer_replace2(req, cur_ptr+11, cur_end,
1480 " close", 6);
1481 cur_next += delta;
1482 cur_hdr->len += delta;
1483 hreq->req.eoh += delta;
1484 }
1485 t->flags |= SN_CONN_CLOSED;
1486 }
1487 }
1488 old_idx = cur_idx;
1489 }
1490
1491 /* add request headers from the rule sets in the same order */
1492 for (cur_idx = 0; cur_idx < rule_set->nb_reqadd; cur_idx++) {
1493 int len;
1494
1495 len = sprintf(trash, "%s\r\n", rule_set->req_add[cur_idx]);
1496 len = buffer_replace2(req, req->data + hreq->req.eoh,
1497 req->data + hreq->req.eoh, trash, len);
1498 hreq->req.eoh += len;
Willy Tarreau06619262006-12-17 08:37:22 +01001499
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001500 if (unlikely(hdr_idx_add(len - 2, 1, &hreq->hdr_idx, hreq->hdr_idx.tail) < 0))
1501 goto return_bad_req;
1502 }
Willy Tarreau06619262006-12-17 08:37:22 +01001503 }
Willy Tarreaub2513902006-12-17 14:52:38 +01001504
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001505 /* check if stats URI was requested, and if an auth is needed */
Willy Tarreau0214c3a2007-01-07 13:47:30 +01001506 if (rule_set->uri_auth != NULL &&
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001507 (hreq->meth == HTTP_METH_GET || hreq->meth == HTTP_METH_HEAD)) {
Willy Tarreaub2513902006-12-17 14:52:38 +01001508 /* we have to check the URI and auth for this request */
1509 if (stats_check_uri_auth(t, rule_set))
1510 return 1;
1511 }
1512
Willy Tarreau5fdfb912007-01-01 23:11:07 +01001513 if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
1514 /* No backend was set, but there was a default
1515 * backend set in the frontend, so we use it and
1516 * loop again.
1517 */
1518 t->be = cur_proxy->defbe.be;
1519 t->be->beprm->beconn++;
1520 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1521 t->be->beprm->beconn_max = t->be->beprm->beconn;
1522 t->be->beprm->cum_beconn++;
1523 t->flags |= SN_BE_ASSIGNED;
1524 }
1525 } while (t->be != cur_proxy); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01001526
Willy Tarreau58f10d72006-12-04 02:26:12 +01001527
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001528 if (!(t->flags & SN_BE_ASSIGNED)) {
1529 /* To ensure correct connection accounting on
1530 * the backend, we count the connection for the
1531 * one managing the queue.
1532 */
1533 t->be->beprm->beconn++;
1534 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1535 t->be->beprm->beconn_max = t->be->beprm->beconn;
1536 t->be->beprm->cum_beconn++;
1537 t->flags |= SN_BE_ASSIGNED;
1538 }
1539
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001540 /*
1541 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01001542 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001543 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01001544 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01001545 */
Willy Tarreau58f10d72006-12-04 02:26:12 +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 Tarreau2a324282006-12-05 00:05:46 +01001550 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001551 * 7: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01001552 * so let's do the same now.
1553 */
1554
1555 /* It needs to look into the URI */
Willy Tarreau830ff452006-12-17 19:31:23 +01001556 if (t->be->beprm->appsession_name) {
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001557 get_srv_from_appsession(t, &req->data[msg->sor], msg->sl.rq.l);
Willy Tarreau06619262006-12-17 08:37:22 +01001558 }
1559
1560
1561 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001562 * 8: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01001563 * Note that doing so might move headers in the request, but
1564 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01001565 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01001566 */
1567 if (!(t->flags & (SN_CLDENY|SN_CLTARPIT)))
1568 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001569
Willy Tarreau58f10d72006-12-04 02:26:12 +01001570
Willy Tarreau2a324282006-12-05 00:05:46 +01001571 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001572 * 9: add X-Forwarded-For : Should depend on the backend only.
Willy Tarreau2a324282006-12-05 00:05:46 +01001573 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001574 if (t->be->beprm->options & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001575 if (t->cli_addr.ss_family == AF_INET) {
1576 int len;
1577 unsigned char *pn;
1578 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
1579 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
1580 pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001581 len = buffer_replace2(req, req->data + hreq->req.eoh,
1582 req->data + hreq->req.eoh, trash, len);
1583 hreq->req.eoh += len;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001584
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001585 if (hdr_idx_add(len - 2, 1, &hreq->hdr_idx, hreq->hdr_idx.tail) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01001586 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001587 }
1588 else if (t->cli_addr.ss_family == AF_INET6) {
1589 int len;
1590 char pn[INET6_ADDRSTRLEN];
1591 inet_ntop(AF_INET6,
1592 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
1593 pn, sizeof(pn));
1594 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001595 len = buffer_replace2(req, req->data + hreq->req.eoh,
1596 req->data + hreq->req.eoh, trash, len);
1597 hreq->req.eoh += len;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001598
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001599 if (hdr_idx_add(len - 2, 1, &hreq->hdr_idx, hreq->hdr_idx.tail) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01001600 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001601 }
1602 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001603
Willy Tarreau2a324282006-12-05 00:05:46 +01001604 /*
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001605 * 10: add "Connection: close" if needed and not yet set.
Willy Tarreaub2513902006-12-17 14:52:38 +01001606 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001607 if (((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) &&
1608 !(t->flags & SN_CONN_CLOSED)) {
Willy Tarreau45e73e32006-12-17 00:05:15 +01001609 int len;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001610 len = buffer_replace2(req, req->data + hreq->req.eoh,
1611 req->data + hreq->req.eoh, "Connection: close\r\n", 19);
1612 hreq->req.eoh += len;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001613
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001614 if (hdr_idx_add(17, 1, &hreq->hdr_idx, hreq->hdr_idx.tail) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01001615 goto return_bad_req;
Willy Tarreaue15d9132006-12-14 22:26:42 +01001616 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001617
Willy Tarreau2a324282006-12-05 00:05:46 +01001618 /*************************************************************
1619 * OK, that's finished for the headers. We have done what we *
1620 * could. Let's switch to the DATA state. *
1621 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02001622
Willy Tarreau2a324282006-12-05 00:05:46 +01001623 t->cli_state = CL_STDATA;
1624 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001625
Willy Tarreau2a324282006-12-05 00:05:46 +01001626 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001627
Willy Tarreau2a324282006-12-05 00:05:46 +01001628 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001629 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001630 /* If the client has no timeout, or if the server is not ready yet,
1631 * and we know for sure that it can expire, then it's cleaner to
1632 * disable the timeout on the client side so that too low values
1633 * cannot make the sessions abort too early.
1634 *
1635 * FIXME-20050705: the server needs a way to re-enable this time-out
1636 * when it switches its state, otherwise a client can stay connected
1637 * indefinitely. This now seems to be OK.
1638 */
1639 tv_eternity(&req->rex);
1640 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001641
Willy Tarreau2a324282006-12-05 00:05:46 +01001642 /* When a connection is tarpitted, we use the queue timeout for the
1643 * tarpit delay, which currently happens to be the server's connect
1644 * timeout. If unset, then set it to zero because we really want it
1645 * to expire at one moment.
1646 */
1647 if (t->flags & SN_CLTARPIT) {
1648 t->req->l = 0;
1649 /* flush the request so that we can drop the connection early
1650 * if the client closes first.
1651 */
1652 tv_delayfrom(&req->cex, &now,
Willy Tarreau830ff452006-12-17 19:31:23 +01001653 t->be->beprm->contimeout ? t->be->beprm->contimeout : 0);
Willy Tarreau2a324282006-12-05 00:05:46 +01001654 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001655
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001656 /* OK let's go on with the BODY now */
Willy Tarreau06619262006-12-17 08:37:22 +01001657 goto process_data;
1658
1659 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01001660 hreq->req.hdr_state = HTTP_MSG_ERROR;
Willy Tarreau06619262006-12-17 08:37:22 +01001661 t->logs.status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01001662 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001663 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01001664 return_prx_cond:
1665 if (!(t->flags & SN_ERR_MASK))
1666 t->flags |= SN_ERR_PRXCOND;
1667 if (!(t->flags & SN_FINST_MASK))
1668 t->flags |= SN_FINST_R;
1669 return 1;
1670
Willy Tarreaubaaee002006-06-26 02:48:02 +02001671 }
1672 else if (c == CL_STDATA) {
1673 process_data:
1674 /* FIXME: this error handling is partly buggy because we always report
1675 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
1676 * or HEADER phase. BTW, it's not logical to expire the client while
1677 * we're waiting for the server to connect.
1678 */
1679 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001680 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001681 tv_eternity(&req->rex);
1682 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001683 fd_delete(t->cli_fd);
1684 t->cli_state = CL_STCLOSE;
1685 if (!(t->flags & SN_ERR_MASK))
1686 t->flags |= SN_ERR_CLICL;
1687 if (!(t->flags & SN_FINST_MASK)) {
1688 if (t->pend_pos)
1689 t->flags |= SN_FINST_Q;
1690 else if (s == SV_STCONN)
1691 t->flags |= SN_FINST_C;
1692 else
1693 t->flags |= SN_FINST_D;
1694 }
1695 return 1;
1696 }
1697 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001698 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001699 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001700 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001701 shutdown(t->cli_fd, SHUT_RD);
1702 t->cli_state = CL_STSHUTR;
1703 return 1;
1704 }
1705 /* last server read and buffer empty */
1706 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001707 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001708 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001709 shutdown(t->cli_fd, SHUT_WR);
1710 /* We must ensure that the read part is still alive when switching
1711 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001712 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001713 if (t->fe->clitimeout)
1714 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001715 t->cli_state = CL_STSHUTW;
1716 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1717 return 1;
1718 }
1719 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001720 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001721 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001722 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001723 shutdown(t->cli_fd, SHUT_RD);
1724 t->cli_state = CL_STSHUTR;
1725 if (!(t->flags & SN_ERR_MASK))
1726 t->flags |= SN_ERR_CLITO;
1727 if (!(t->flags & SN_FINST_MASK)) {
1728 if (t->pend_pos)
1729 t->flags |= SN_FINST_Q;
1730 else if (s == SV_STCONN)
1731 t->flags |= SN_FINST_C;
1732 else
1733 t->flags |= SN_FINST_D;
1734 }
1735 return 1;
1736 }
1737 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001738 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001739 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001740 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001741 shutdown(t->cli_fd, SHUT_WR);
1742 /* We must ensure that the read part is still alive when switching
1743 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001744 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001745 if (t->fe->clitimeout)
1746 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001747
1748 t->cli_state = CL_STSHUTW;
1749 if (!(t->flags & SN_ERR_MASK))
1750 t->flags |= SN_ERR_CLITO;
1751 if (!(t->flags & SN_FINST_MASK)) {
1752 if (t->pend_pos)
1753 t->flags |= SN_FINST_Q;
1754 else if (s == SV_STCONN)
1755 t->flags |= SN_FINST_C;
1756 else
1757 t->flags |= SN_FINST_D;
1758 }
1759 return 1;
1760 }
1761
1762 if (req->l >= req->rlim - req->data) {
1763 /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02001764 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001765 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001766 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001767 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001768 }
1769 } else {
1770 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001771 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1772 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001773 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001774 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001775 /* If the client has no timeout, or if the server not ready yet, and we
1776 * know for sure that it can expire, then it's cleaner to disable the
1777 * timeout on the client side so that too low values cannot make the
1778 * sessions abort too early.
1779 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001780 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001781 else
Willy Tarreau73de9892006-11-30 11:40:23 +01001782 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001783 }
1784 }
1785
1786 if ((rep->l == 0) ||
1787 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001788 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1789 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001790 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001791 }
1792 } else {
1793 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001794 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1795 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001796 if (t->fe->clitimeout) {
1797 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001798 /* FIXME: to prevent the client from expiring read timeouts during writes,
1799 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001800 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001801 }
1802 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001803 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001804 }
1805 }
1806 return 0; /* other cases change nothing */
1807 }
1808 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001809 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001810 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001811 fd_delete(t->cli_fd);
1812 t->cli_state = CL_STCLOSE;
1813 if (!(t->flags & SN_ERR_MASK))
1814 t->flags |= SN_ERR_CLICL;
1815 if (!(t->flags & SN_FINST_MASK)) {
1816 if (t->pend_pos)
1817 t->flags |= SN_FINST_Q;
1818 else if (s == SV_STCONN)
1819 t->flags |= SN_FINST_C;
1820 else
1821 t->flags |= SN_FINST_D;
1822 }
1823 return 1;
1824 }
1825 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
1826 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001827 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001828 fd_delete(t->cli_fd);
1829 t->cli_state = CL_STCLOSE;
1830 return 1;
1831 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001832 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
1833 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001834 fd_delete(t->cli_fd);
1835 t->cli_state = CL_STCLOSE;
1836 if (!(t->flags & SN_ERR_MASK))
1837 t->flags |= SN_ERR_CLITO;
1838 if (!(t->flags & SN_FINST_MASK)) {
1839 if (t->pend_pos)
1840 t->flags |= SN_FINST_Q;
1841 else if (s == SV_STCONN)
1842 t->flags |= SN_FINST_C;
1843 else
1844 t->flags |= SN_FINST_D;
1845 }
1846 return 1;
1847 }
1848
1849 if (t->flags & SN_SELF_GEN) {
1850 produce_content(t);
1851 if (rep->l == 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001852 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001853 fd_delete(t->cli_fd);
1854 t->cli_state = CL_STCLOSE;
1855 return 1;
1856 }
1857 }
1858
1859 if ((rep->l == 0)
1860 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001861 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1862 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001863 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001864 }
1865 } else {
1866 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001867 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1868 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001869 if (t->fe->clitimeout) {
1870 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001871 /* FIXME: to prevent the client from expiring read timeouts during writes,
1872 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001873 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001874 }
1875 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001876 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001877 }
1878 }
1879 return 0;
1880 }
1881 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001882 if (req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001883 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001884 fd_delete(t->cli_fd);
1885 t->cli_state = CL_STCLOSE;
1886 if (!(t->flags & SN_ERR_MASK))
1887 t->flags |= SN_ERR_CLICL;
1888 if (!(t->flags & SN_FINST_MASK)) {
1889 if (t->pend_pos)
1890 t->flags |= SN_FINST_Q;
1891 else if (s == SV_STCONN)
1892 t->flags |= SN_FINST_C;
1893 else
1894 t->flags |= SN_FINST_D;
1895 }
1896 return 1;
1897 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001898 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001899 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001900 fd_delete(t->cli_fd);
1901 t->cli_state = CL_STCLOSE;
1902 return 1;
1903 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001904 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
1905 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001906 fd_delete(t->cli_fd);
1907 t->cli_state = CL_STCLOSE;
1908 if (!(t->flags & SN_ERR_MASK))
1909 t->flags |= SN_ERR_CLITO;
1910 if (!(t->flags & SN_FINST_MASK)) {
1911 if (t->pend_pos)
1912 t->flags |= SN_FINST_Q;
1913 else if (s == SV_STCONN)
1914 t->flags |= SN_FINST_C;
1915 else
1916 t->flags |= SN_FINST_D;
1917 }
1918 return 1;
1919 }
1920 else if (req->l >= req->rlim - req->data) {
1921 /* no room to read more data */
1922
1923 /* FIXME-20050705: is it possible for a client to maintain a session
1924 * after the timeout by sending more data after it receives a close ?
1925 */
1926
Willy Tarreau2a429502006-10-15 14:52:29 +02001927 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001928 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001929 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001930 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001931 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1932 }
1933 } else {
1934 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001935 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1936 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001937 if (t->fe->clitimeout)
1938 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001939 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001940 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001941 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1942 }
1943 }
1944 return 0;
1945 }
1946 else { /* CL_STCLOSE: nothing to do */
1947 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1948 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01001949 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 +02001950 write(1, trash, len);
1951 }
1952 return 0;
1953 }
1954 return 0;
1955}
1956
1957
1958/*
1959 * manages the server FSM and its socket. It returns 1 if a state has changed
1960 * (and a resync may be needed), 0 else.
1961 */
1962int process_srv(struct session *t)
1963{
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001964 struct http_req *hreq = &t->hreq;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001965 int s = t->srv_state;
1966 int c = t->cli_state;
1967 struct buffer *req = t->req;
1968 struct buffer *rep = t->rep;
1969 appsess *asession_temp = NULL;
1970 appsess local_asession;
1971 int conn_err;
1972
1973#ifdef DEBUG_FULL
1974 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
1975#endif
1976 //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 +02001977 //MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
1978 //MY_FD_ISSET(t->srv_fd, StaticReadEvent), MY_FD_ISSET(t->srv_fd, StaticWriteEvent)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001979 //);
1980 if (s == SV_STIDLE) {
1981 if (c == CL_STHEADERS)
1982 return 0; /* stay in idle, waiting for data to reach the client side */
1983 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
1984 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001985 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001986 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001987 if (t->pend_pos)
1988 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1989 /* note that this must not return any error because it would be able to
1990 * overwrite the client_retnclose() output.
1991 */
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001992 if (t->flags & SN_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01001993 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001994 else
Willy Tarreau0f772532006-12-23 20:51:41 +01001995 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 +02001996
1997 return 1;
1998 }
1999 else {
Willy Tarreaub8750a82006-09-03 09:56:00 +02002000 if (t->flags & SN_CLTARPIT) {
2001 /* This connection is being tarpitted. The CLIENT side has
2002 * already set the connect expiration date to the right
2003 * timeout. We just have to check that it has not expired.
2004 */
2005 if (tv_cmp2_ms(&req->cex, &now) > 0)
2006 return 0;
2007
2008 /* We will set the queue timer to the time spent, just for
2009 * logging purposes. We fake a 500 server error, so that the
2010 * attacker will not suspect his connection has been tarpitted.
2011 * It will not cause trouble to the logs because we can exclude
2012 * the tarpitted connections by filtering on the 'PT' status flags.
2013 */
2014 tv_eternity(&req->cex);
2015 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
2016 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01002017 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02002018 return 1;
2019 }
2020
Willy Tarreaubaaee002006-06-26 02:48:02 +02002021 /* Right now, we will need to create a connection to the server.
2022 * We might already have tried, and got a connection pending, in
2023 * which case we will not do anything till it's pending. It's up
2024 * to any other session to release it and wake us up again.
2025 */
2026 if (t->pend_pos) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002027 if (tv_cmp2_ms(&req->cex, &now) > 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002028 return 0;
2029 else {
2030 /* we've been waiting too long here */
Willy Tarreaud7971282006-07-29 18:36:34 +02002031 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002032 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
2033 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01002034 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002035 if (t->srv)
2036 t->srv->failed_conns++;
Willy Tarreau73de9892006-11-30 11:40:23 +01002037 t->fe->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002038 return 1;
2039 }
2040 }
2041
2042 do {
2043 /* first, get a connection */
2044 if (srv_redispatch_connect(t))
2045 return t->srv_state != SV_STIDLE;
2046
2047 /* try to (re-)connect to the server, and fail if we expire the
2048 * number of retries.
2049 */
2050 if (srv_retryable_connect(t)) {
2051 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
2052 return t->srv_state != SV_STIDLE;
2053 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002054 } while (1);
2055 }
2056 }
2057 else if (s == SV_STCONN) { /* connection in progress */
2058 if (c == CL_STCLOSE || c == CL_STSHUTW ||
2059 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002060 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02002061 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002062 fd_delete(t->srv_fd);
2063 if (t->srv)
2064 t->srv->cur_sess--;
2065
2066 /* note that this must not return any error because it would be able to
2067 * overwrite the client_retnclose() output.
2068 */
Willy Tarreau0f772532006-12-23 20:51:41 +01002069 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002070 return 1;
2071 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002072 if (!(req->flags & BF_WRITE_STATUS) && tv_cmp2_ms(&req->cex, &now) > 0) {
2073 //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 +02002074 return 0; /* nothing changed */
2075 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002076 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002077 /* timeout, asynchronous connect error or first write error */
2078 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
2079
2080 fd_delete(t->srv_fd);
2081 if (t->srv)
2082 t->srv->cur_sess--;
2083
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002084 if (!(req->flags & BF_WRITE_STATUS))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002085 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
2086 else
2087 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
2088
2089 /* ensure that we have enough retries left */
2090 if (srv_count_retry_down(t, conn_err))
2091 return 1;
2092
Willy Tarreau830ff452006-12-17 19:31:23 +01002093 if (t->srv && t->conn_retries == 0 && t->be->beprm->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002094 /* We're on our last chance, and the REDISP option was specified.
2095 * We will ignore cookie and force to balance or use the dispatcher.
2096 */
2097 /* let's try to offer this slot to anybody */
Willy Tarreau830ff452006-12-17 19:31:23 +01002098 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002099 task_wakeup(&rq, t->srv->queue_mgt);
2100
2101 if (t->srv)
2102 t->srv->failed_conns++;
Willy Tarreau830ff452006-12-17 19:31:23 +01002103 t->be->beprm->failed_conns++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02002104
2105 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
2106 t->srv = NULL; /* it's left to the dispatcher to choose a server */
2107 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
2108 t->flags &= ~SN_CK_MASK;
2109 t->flags |= SN_CK_DOWN;
2110 }
2111
2112 /* first, get a connection */
2113 if (srv_redispatch_connect(t))
2114 return t->srv_state != SV_STIDLE;
2115 }
2116
Willy Tarreaubaaee002006-06-26 02:48:02 +02002117 do {
2118 /* Now we will try to either reconnect to the same server or
2119 * connect to another server. If the connection gets queued
2120 * because all servers are saturated, then we will go back to
2121 * the SV_STIDLE state.
2122 */
2123 if (srv_retryable_connect(t)) {
2124 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
2125 return t->srv_state != SV_STCONN;
2126 }
2127
2128 /* we need to redispatch the connection to another server */
2129 if (srv_redispatch_connect(t))
2130 return t->srv_state != SV_STCONN;
2131 } while (1);
2132 }
2133 else { /* no error or write 0 */
2134 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
2135
2136 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
2137 if (req->l == 0) /* nothing to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02002138 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002139 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002140 } else /* need the right to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02002141 MY_FD_SET(t->srv_fd, StaticWriteEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002142 if (t->be->beprm->srvtimeout) {
2143 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002144 /* FIXME: to prevent the server from expiring read timeouts during writes,
2145 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002146 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002147 }
2148 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002149 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002150 }
2151
Willy Tarreau830ff452006-12-17 19:31:23 +01002152 if (t->be->beprm->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreau2a429502006-10-15 14:52:29 +02002153 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002154 if (t->be->beprm->srvtimeout)
2155 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002156 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002157 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002158
2159 t->srv_state = SV_STDATA;
2160 if (t->srv)
2161 t->srv->cum_sess++;
2162 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
2163
2164 /* if the user wants to log as soon as possible, without counting
2165 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002166 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002167 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
2168 sess_log(t);
2169 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002170#ifdef CONFIG_HAP_TCPSPLICE
2171 if ((t->fe->options & t->be->beprm->options) & PR_O_TCPSPLICE) {
2172 /* TCP splicing supported by both FE and BE */
2173 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2174 }
2175#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002176 }
2177 else {
2178 t->srv_state = SV_STHEADERS;
2179 if (t->srv)
2180 t->srv->cum_sess++;
2181 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
2182 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002183 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002184 return 1;
2185 }
2186 }
2187 else if (s == SV_STHEADERS) { /* receiving server headers */
2188 /* now parse the partial (or complete) headers */
2189 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
2190 char *ptr;
2191 int delete_header;
2192
2193 ptr = rep->lr;
2194
2195 /* look for the end of the current header */
2196 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
2197 ptr++;
2198
2199 if (ptr == rep->h) {
2200 int line, len;
2201
2202 /* we can only get here after an end of headers */
2203
2204 /* first, we'll block if security checks have caught nasty things */
2205 if (t->flags & SN_CACHEABLE) {
2206 if ((t->flags & SN_CACHE_COOK) &&
2207 (t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002208 (t->be->beprm->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002209
2210 /* we're in presence of a cacheable response containing
2211 * a set-cookie header. We'll block it as requested by
2212 * the 'checkcache' option, and send an alert.
2213 */
Willy Tarreaud7971282006-07-29 18:36:34 +02002214 tv_eternity(&rep->rex);
2215 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002216 fd_delete(t->srv_fd);
2217 if (t->srv) {
2218 t->srv->cur_sess--;
2219 t->srv->failed_secu++;
2220 }
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002221 t->be->beprm->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002222 t->srv_state = SV_STCLOSE;
2223 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01002224 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002225 if (!(t->flags & SN_ERR_MASK))
2226 t->flags |= SN_ERR_PRXCOND;
2227 if (!(t->flags & SN_FINST_MASK))
2228 t->flags |= SN_FINST_H;
2229
Willy Tarreau830ff452006-12-17 19:31:23 +01002230 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->be->beprm->id, t->srv->id);
2231 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 +02002232
2233 /* We used to have a free connection slot. Since we'll never use it,
2234 * we have to inform the server that it may be used by another session.
2235 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002236 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002237 task_wakeup(&rq, t->srv->queue_mgt);
2238
2239 return 1;
2240 }
2241 }
2242
2243 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
2244 if (t->flags & SN_SVDENY) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002245 tv_eternity(&rep->rex);
2246 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002247 fd_delete(t->srv_fd);
2248 if (t->srv) {
2249 t->srv->cur_sess--;
2250 t->srv->failed_secu++;
2251 }
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002252 t->be->beprm->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002253 t->srv_state = SV_STCLOSE;
2254 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01002255 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002256 if (!(t->flags & SN_ERR_MASK))
2257 t->flags |= SN_ERR_PRXCOND;
2258 if (!(t->flags & SN_FINST_MASK))
2259 t->flags |= SN_FINST_H;
2260 /* We used to have a free connection slot. Since we'll never use it,
2261 * we have to inform the server that it may be used by another session.
2262 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002263 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002264 task_wakeup(&rq, t->srv->queue_mgt);
2265
2266 return 1;
2267 }
2268
2269 /* we'll have something else to do here : add new headers ... */
2270
Willy Tarreau830ff452006-12-17 19:31:23 +01002271 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_INS) &&
Willy Tarreau0f7562b2007-01-07 15:46:13 +01002272 (!(t->be->beprm->options & PR_O_COOK_POST) || (hreq->meth == HTTP_METH_POST))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002273 /* the server is known, it's not the one the client requested, we have to
2274 * insert a set-cookie here, except if we want to insert only on POST
2275 * requests and this one isn't. Note that servers which don't have cookies
2276 * (eg: some backup servers) will return a full cookie removal request.
2277 */
2278 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
Willy Tarreau830ff452006-12-17 19:31:23 +01002279 t->be->beprm->cookie_name,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002280 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
2281
2282 t->flags |= SN_SCK_INSERTED;
2283
2284 /* Here, we will tell an eventual cache on the client side that we don't
2285 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
2286 * Some caches understand the correct form: 'no-cache="set-cookie"', but
2287 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
2288 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002289 if (t->be->beprm->options & PR_O_COOK_NOC)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002290 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
2291 len += sprintf(trash + len, "Cache-control: private\r\n");
2292
2293 if (rep->data + rep->l < rep->h)
2294 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
2295 *(int *)0 = 0;
2296 buffer_replace2(rep, rep->h, rep->h, trash, len);
2297 }
2298
2299 /* headers to be added */
Willy Tarreau830ff452006-12-17 19:31:23 +01002300 /* FIXME: we should add headers from BE then from FE */
2301 for (line = 0; line < t->be->fiprm->nb_rspadd; line++) {
2302 len = sprintf(trash, "%s\r\n", t->be->fiprm->rsp_add[line]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002303 buffer_replace2(rep, rep->h, rep->h, trash, len);
2304 }
2305
2306 /* add a "connection: close" line if needed */
Willy Tarreaue01954f2006-12-30 23:43:54 +01002307 if ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002308 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
2309
2310 t->srv_state = SV_STDATA;
2311 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
2312 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
2313
2314 /* client connection already closed or option 'httpclose' required :
2315 * we close the server's outgoing connection right now.
2316 */
2317 if ((req->l == 0) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002318 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->beprm->options & PR_O_FORCE_CLO)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002319 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002320 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002321
2322 /* We must ensure that the read part is still alive when switching
2323 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002324 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002325 if (t->be->beprm->srvtimeout)
2326 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002327
2328 shutdown(t->srv_fd, SHUT_WR);
2329 t->srv_state = SV_STSHUTW;
2330 }
2331
Willy Tarreau6d1a9882007-01-07 02:03:04 +01002332#ifdef CONFIG_HAP_TCPSPLICE
2333 if ((t->fe->options & t->be->beprm->options) & PR_O_TCPSPLICE) {
2334 /* TCP splicing supported by both FE and BE */
2335 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
2336 }
2337#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02002338 /* if the user wants to log as soon as possible, without counting
2339 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01002340 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002341 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreau35d66b02007-01-02 00:28:21 +01002342 t->logs.bytes_in = rep->h - rep->data;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002343 sess_log(t);
2344 }
2345 break;
2346 }
2347
2348 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
2349 if (ptr > rep->r - 2) {
2350 /* this is a partial header, let's wait for more to come */
2351 rep->lr = ptr;
2352 break;
2353 }
2354
2355 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
2356 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
2357
2358 /* now we know that *ptr is either \r or \n,
2359 * and that there are at least 1 char after it.
2360 */
2361 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2362 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2363 else
2364 rep->lr = ptr + 2; /* \r\n or \n\r */
2365
2366 /*
2367 * now we know that we have a full header ; we can do whatever
2368 * we want with these pointers :
2369 * rep->h = beginning of header
2370 * ptr = end of header (first \r or \n)
2371 * rep->lr = beginning of next line (next rep->h)
2372 * rep->r = end of data (not used at this stage)
2373 */
2374
2375
2376 if (t->logs.status == -1) {
2377 t->logs.logwait &= ~LW_RESP;
2378 t->logs.status = atoi(rep->h + 9);
2379 switch (t->logs.status) {
2380 case 200:
2381 case 203:
2382 case 206:
2383 case 300:
2384 case 301:
2385 case 410:
2386 /* RFC2616 @13.4:
2387 * "A response received with a status code of
2388 * 200, 203, 206, 300, 301 or 410 MAY be stored
2389 * by a cache (...) unless a cache-control
2390 * directive prohibits caching."
2391 *
2392 * RFC2616 @9.5: POST method :
2393 * "Responses to this method are not cacheable,
2394 * unless the response includes appropriate
2395 * Cache-Control or Expires header fields."
2396 */
Willy Tarreau0f7562b2007-01-07 15:46:13 +01002397 if (!(hreq->meth == HTTP_METH_POST) && (t->be->beprm->options & PR_O_CHK_CACHE))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002398 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
2399 break;
2400 default:
2401 break;
2402 }
2403 }
2404 else if (t->logs.logwait & LW_RSPHDR) {
2405 struct cap_hdr *h;
2406 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01002407 for (h = t->fe->fiprm->rsp_cap; h; h = h->next) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002408 if ((h->namelen + 2 <= ptr - rep->h) &&
2409 (rep->h[h->namelen] == ':') &&
2410 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
Willy Tarreau362b34d2007-01-21 20:49:31 +01002411 if (hreq->rsp.cap[h->index] == NULL)
2412 hreq->rsp.cap[h->index] =
2413 pool_alloc_from(h->pool, h->len + 1);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002414
Willy Tarreau362b34d2007-01-21 20:49:31 +01002415 if (hreq->rsp.cap[h->index] == NULL) {
2416 Alert("HTTP capture : out of memory.\n");
2417 continue;
2418 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02002419
2420 len = ptr - (rep->h + h->namelen + 2);
2421 if (len > h->len)
2422 len = h->len;
2423
Willy Tarreau362b34d2007-01-21 20:49:31 +01002424 memcpy(hreq->rsp.cap[h->index], rep->h + h->namelen + 2, len);
2425 hreq->rsp.cap[h->index][len]=0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002426 }
2427 }
2428
2429 }
2430
2431 delete_header = 0;
2432
Willy Tarreau58f10d72006-12-04 02:26:12 +01002433 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
2434 debug_hdr("srvhdr", t, rep->h, ptr);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002435
2436 /* remove "connection: " if needed */
Willy Tarreaue01954f2006-12-30 23:43:54 +01002437 if (!delete_header &&
2438 ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) &&
2439 (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002440 delete_header = 1;
2441 }
2442
2443 /* try headers regexps */
Willy Tarreau830ff452006-12-17 19:31:23 +01002444 if (!delete_header && t->be->fiprm->rsp_exp != NULL
Willy Tarreaubaaee002006-06-26 02:48:02 +02002445 && !(t->flags & SN_SVDENY)) {
2446 struct hdr_exp *exp;
2447 char term;
2448
2449 term = *ptr;
2450 *ptr = '\0';
Willy Tarreau830ff452006-12-17 19:31:23 +01002451 exp = t->be->fiprm->rsp_exp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002452 do {
2453 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2454 switch (exp->action) {
2455 case ACT_ALLOW:
2456 if (!(t->flags & SN_SVDENY))
2457 t->flags |= SN_SVALLOW;
2458 break;
2459 case ACT_REPLACE:
2460 if (!(t->flags & SN_SVDENY)) {
2461 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
2462 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2463 }
2464 break;
2465 case ACT_REMOVE:
2466 if (!(t->flags & SN_SVDENY))
2467 delete_header = 1;
2468 break;
2469 case ACT_DENY:
2470 if (!(t->flags & SN_SVALLOW))
2471 t->flags |= SN_SVDENY;
2472 break;
2473 case ACT_PASS: /* we simply don't deny this one */
2474 break;
2475 }
2476 break;
2477 }
2478 } while ((exp = exp->next) != NULL);
2479 *ptr = term; /* restore the string terminator */
2480 }
2481
2482 /* check for cache-control: or pragma: headers */
2483 if (!delete_header && (t->flags & SN_CACHEABLE)) {
2484 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
2485 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2486 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
2487 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
2488 if (rep->h + 23 == ptr || rep->h[23] == ',')
2489 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2490 else {
2491 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
2492 && (rep->h[35] == '"' || rep->h[35] == ','))
2493 t->flags &= ~SN_CACHE_COOK;
2494 }
2495 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
2496 (rep->h + 22 == ptr || rep->h[22] == ','))
2497 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
2498 (rep->h + 23 == ptr || rep->h[23] == ','))) {
2499 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2500 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
2501 (rep->h + 24 == ptr || rep->h[24] == ',')) {
2502 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2503 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
2504 (rep->h + 25 == ptr || rep->h[25] == ',')) {
2505 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2506 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
2507 (rep->h + 21 == ptr || rep->h[21] == ',')) {
2508 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
2509 }
2510 }
2511 }
2512
2513 /* check for server cookies */
2514 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002515 && (t->be->beprm->cookie_name != NULL ||
2516 t->be->fiprm->capture_name != NULL ||
2517 t->be->beprm->appsession_name !=NULL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002518 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2519 char *p1, *p2, *p3, *p4;
2520
2521 t->flags |= SN_SCK_ANY;
2522
2523 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2524
2525 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
2526 while (p1 < ptr && (isspace((int)*p1)))
2527 p1++;
2528
2529 if (p1 == ptr || *p1 == ';') /* end of cookie */
2530 break;
2531
2532 /* p1 is at the beginning of the cookie name */
2533 p2 = p1;
2534
2535 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2536 p2++;
2537
2538 if (p2 == ptr || *p2 == ';') /* next cookie */
2539 break;
2540
2541 p3 = p2 + 1; /* skips the '=' sign */
2542 if (p3 == ptr)
2543 break;
2544
2545 p4 = p3;
2546 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
2547 p4++;
2548
2549 /* here, we have the cookie name between p1 and p2,
2550 * and its value between p3 and p4.
2551 * we can process it.
2552 */
2553
2554 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01002555 if (t->be->fiprm->capture_name != NULL &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002556 t->logs.srv_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002557 (p4 - p1 >= t->be->fiprm->capture_namelen) &&
2558 memcmp(p1, t->be->fiprm->capture_name, t->be->fiprm->capture_namelen) == 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002559 int log_len = p4 - p1;
2560
2561 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
2562 Alert("HTTP logging : out of memory.\n");
2563 }
2564
Willy Tarreau830ff452006-12-17 19:31:23 +01002565 if (log_len > t->be->fiprm->capture_len)
2566 log_len = t->be->fiprm->capture_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002567 memcpy(t->logs.srv_cookie, p1, log_len);
2568 t->logs.srv_cookie[log_len] = 0;
2569 }
2570
Willy Tarreau830ff452006-12-17 19:31:23 +01002571 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
2572 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002573 /* Cool... it's the right one */
2574 t->flags |= SN_SCK_SEEN;
2575
2576 /* If the cookie is in insert mode on a known server, we'll delete
2577 * this occurrence because we'll insert another one later.
2578 * We'll delete it too if the "indirect" option is set and we're in
2579 * a direct access. */
Willy Tarreau830ff452006-12-17 19:31:23 +01002580 if (((t->srv) && (t->be->beprm->options & PR_O_COOK_INS)) ||
2581 ((t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_IND))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002582 /* this header must be deleted */
2583 delete_header = 1;
2584 t->flags |= SN_SCK_DELETED;
2585 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002586 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_RW)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002587 /* replace bytes p3->p4 with the cookie name associated
2588 * with this server since we know it.
2589 */
2590 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2591 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2592 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002593 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_PFX)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002594 /* insert the cookie name associated with this server
2595 * before existing cookie, and insert a delimitor between them..
2596 */
2597 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
2598 p3[t->srv->cklen] = COOKIE_DELIM;
2599 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2600 }
2601 break;
2602 }
2603
2604 /* first, let's see if the cookie is our appcookie*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002605 if ((t->be->beprm->appsession_name != NULL) &&
2606 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002607
2608 /* Cool... it's the right one */
2609
2610 size_t server_id_len = strlen(t->srv->id) + 1;
2611 asession_temp = &local_asession;
2612
2613 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
2614 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002615 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002616 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002617 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
2618 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002619 asession_temp->serverid = NULL;
2620
2621 /* only do insert, if lookup fails */
Willy Tarreau73de9892006-11-30 11:40:23 +01002622 if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002623 if ((asession_temp = pool_alloc(appsess)) == NULL) {
2624 Alert("Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002625 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002626 return 0;
2627 }
2628 asession_temp->sessid = local_asession.sessid;
2629 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01002630 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002631 }/* end if (chtbl_lookup()) */
2632 else {
2633 /* free wasted memory */
2634 pool_free_to(apools.sessid, local_asession.sessid);
2635 } /* end else from if (chtbl_lookup()) */
2636
2637 if (asession_temp->serverid == NULL) {
2638 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
2639 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002640 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002641 }
2642 asession_temp->serverid[0] = '\0';
2643 }
2644
2645 if (asession_temp->serverid[0] == '\0')
2646 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
2647
Willy Tarreau830ff452006-12-17 19:31:23 +01002648 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002649
2650#if defined(DEBUG_HASH)
Willy Tarreau830ff452006-12-17 19:31:23 +01002651 print_table(&(t->be->beprm->htbl_proxy));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002652#endif
2653 break;
2654 }/* end if ((t->proxy->appsession_name != NULL) ... */
2655 else {
2656 // fprintf(stderr,"Ignoring unknown cookie : ");
2657 // write(2, p1, p2-p1);
2658 // fprintf(stderr," = ");
2659 // write(2, p3, p4-p3);
2660 // fprintf(stderr,"\n");
2661 }
2662 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2663 } /* we're now at the end of the cookie value */
2664 } /* end of cookie processing */
2665
2666 /* check for any set-cookie in case we check for cacheability */
2667 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002668 (t->be->beprm->options & PR_O_CHK_CACHE) &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002669 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2670 t->flags |= SN_SCK_ANY;
2671 }
2672
2673 /* let's look if we have to delete this header */
2674 if (delete_header && !(t->flags & SN_SVDENY))
2675 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2676
2677 rep->h = rep->lr;
2678 } /* while (rep->lr < rep->r) */
2679
2680 /* end of header processing (even if incomplete) */
2681
Willy Tarreau2a429502006-10-15 14:52:29 +02002682 if ((rep->l < rep->rlim - rep->data) && ! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002683 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
Willy Tarreaud7971282006-07-29 18:36:34 +02002684 * full. We cannot loop here since stream_sock_read will disable it only if
Willy Tarreaubaaee002006-06-26 02:48:02 +02002685 * rep->l == rlim-data
2686 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002687 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002688 if (t->be->beprm->srvtimeout)
2689 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002690 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002691 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002692 }
2693
2694 /* read error, write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002695 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002696 tv_eternity(&rep->rex);
2697 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002698 fd_delete(t->srv_fd);
2699 if (t->srv) {
2700 t->srv->cur_sess--;
2701 t->srv->failed_resp++;
2702 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002703 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002704 t->srv_state = SV_STCLOSE;
2705 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01002706 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002707 if (!(t->flags & SN_ERR_MASK))
2708 t->flags |= SN_ERR_SRVCL;
2709 if (!(t->flags & SN_FINST_MASK))
2710 t->flags |= SN_FINST_H;
2711 /* We used to have a free connection slot. Since we'll never use it,
2712 * we have to inform the server that it may be used by another session.
2713 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002714 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002715 task_wakeup(&rq, t->srv->queue_mgt);
2716
2717 return 1;
2718 }
2719 /* end of client write or end of server read.
2720 * since we are in header mode, if there's no space left for headers, we
2721 * won't be able to free more later, so the session will never terminate.
2722 */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002723 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 +02002724 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002725 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002726 shutdown(t->srv_fd, SHUT_RD);
2727 t->srv_state = SV_STSHUTR;
2728 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2729 return 1;
2730 }
2731 /* read timeout : return a 504 to the client.
2732 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002733 else if (MY_FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002734 tv_eternity(&rep->rex);
2735 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002736 fd_delete(t->srv_fd);
2737 if (t->srv) {
2738 t->srv->cur_sess--;
2739 t->srv->failed_resp++;
2740 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002741 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002742 t->srv_state = SV_STCLOSE;
2743 t->logs.status = 504;
Willy Tarreau80587432006-12-24 17:47:20 +01002744 client_return(t, error_message(t, HTTP_ERR_504));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002745 if (!(t->flags & SN_ERR_MASK))
2746 t->flags |= SN_ERR_SRVTO;
2747 if (!(t->flags & SN_FINST_MASK))
2748 t->flags |= SN_FINST_H;
2749 /* We used to have a free connection slot. Since we'll never use it,
2750 * we have to inform the server that it may be used by another session.
2751 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002752 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002753 task_wakeup(&rq, t->srv->queue_mgt);
2754
2755 return 1;
2756 }
2757 /* last client read and buffer empty */
2758 /* FIXME!!! here, we don't want to switch to SHUTW if the
2759 * client shuts read too early, because we may still have
2760 * some work to do on the headers.
2761 * The side-effect is that if the client completely closes its
2762 * connection during SV_STHEADER, the connection to the server
2763 * is kept until a response comes back or the timeout is reached.
2764 */
2765 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002766 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002767 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002768
2769 /* We must ensure that the read part is still alive when switching
2770 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002771 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002772 if (t->be->beprm->srvtimeout)
2773 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002774
2775 shutdown(t->srv_fd, SHUT_WR);
2776 t->srv_state = SV_STSHUTW;
2777 return 1;
2778 }
2779 /* write timeout */
2780 /* FIXME!!! here, we don't want to switch to SHUTW if the
2781 * client shuts read too early, because we may still have
2782 * some work to do on the headers.
2783 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002784 else if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&req->wex, &now) <= 0) {
2785 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002786 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002787 shutdown(t->srv_fd, SHUT_WR);
2788 /* We must ensure that the read part is still alive when switching
2789 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002790 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002791 if (t->be->beprm->srvtimeout)
2792 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002793
2794 /* We must ensure that the read part is still alive when switching
2795 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002796 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002797 if (t->be->beprm->srvtimeout)
2798 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002799
2800 t->srv_state = SV_STSHUTW;
2801 if (!(t->flags & SN_ERR_MASK))
2802 t->flags |= SN_ERR_SRVTO;
2803 if (!(t->flags & SN_FINST_MASK))
2804 t->flags |= SN_FINST_H;
2805 return 1;
2806 }
2807
2808 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002809 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2810 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002811 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002812 }
2813 }
2814 else { /* client buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002815 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2816 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002817 if (t->be->beprm->srvtimeout) {
2818 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002819 /* FIXME: to prevent the server from expiring read timeouts during writes,
2820 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002821 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002822 }
2823 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002824 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002825 }
2826 }
2827
2828 /* be nice with the client side which would like to send a complete header
2829 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2830 * would read all remaining data at once ! The client should not write past rep->lr
2831 * when the server is in header state.
2832 */
2833 //return header_processed;
2834 return t->srv_state != SV_STHEADERS;
2835 }
2836 else if (s == SV_STDATA) {
2837 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002838 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002839 tv_eternity(&rep->rex);
2840 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002841 fd_delete(t->srv_fd);
2842 if (t->srv) {
2843 t->srv->cur_sess--;
2844 t->srv->failed_resp++;
2845 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002846 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002847 t->srv_state = SV_STCLOSE;
2848 if (!(t->flags & SN_ERR_MASK))
2849 t->flags |= SN_ERR_SRVCL;
2850 if (!(t->flags & SN_FINST_MASK))
2851 t->flags |= SN_FINST_D;
2852 /* We used to have a free connection slot. Since we'll never use it,
2853 * we have to inform the server that it may be used by another session.
2854 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002855 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002856 task_wakeup(&rq, t->srv->queue_mgt);
2857
2858 return 1;
2859 }
2860 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002861 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002862 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002863 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002864 shutdown(t->srv_fd, SHUT_RD);
2865 t->srv_state = SV_STSHUTR;
2866 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2867 return 1;
2868 }
2869 /* end of client read and no more data to send */
2870 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002871 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002872 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002873 shutdown(t->srv_fd, SHUT_WR);
2874 /* We must ensure that the read part is still alive when switching
2875 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002876 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002877 if (t->be->beprm->srvtimeout)
2878 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002879
2880 t->srv_state = SV_STSHUTW;
2881 return 1;
2882 }
2883 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002884 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002885 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002886 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002887 shutdown(t->srv_fd, SHUT_RD);
2888 t->srv_state = SV_STSHUTR;
2889 if (!(t->flags & SN_ERR_MASK))
2890 t->flags |= SN_ERR_SRVTO;
2891 if (!(t->flags & SN_FINST_MASK))
2892 t->flags |= SN_FINST_D;
2893 return 1;
2894 }
2895 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002896 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002897 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002898 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002899 shutdown(t->srv_fd, SHUT_WR);
2900 /* We must ensure that the read part is still alive when switching
2901 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002902 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002903 if (t->be->beprm->srvtimeout)
2904 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002905 t->srv_state = SV_STSHUTW;
2906 if (!(t->flags & SN_ERR_MASK))
2907 t->flags |= SN_ERR_SRVTO;
2908 if (!(t->flags & SN_FINST_MASK))
2909 t->flags |= SN_FINST_D;
2910 return 1;
2911 }
2912
2913 /* recompute request time-outs */
2914 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002915 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2916 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002917 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002918 }
2919 }
2920 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau2a429502006-10-15 14:52:29 +02002921 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2922 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002923 if (t->be->beprm->srvtimeout) {
2924 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002925 /* FIXME: to prevent the server from expiring read timeouts during writes,
2926 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002927 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002928 }
2929 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002930 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002931 }
2932 }
2933
2934 /* recompute response time-outs */
2935 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002936 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2937 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002938 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002939 }
2940 }
2941 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002942 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2943 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002944 if (t->be->beprm->srvtimeout)
2945 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002946 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002947 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002948 }
2949 }
2950
2951 return 0; /* other cases change nothing */
2952 }
2953 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002954 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002955 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002956 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002957 fd_delete(t->srv_fd);
2958 if (t->srv) {
2959 t->srv->cur_sess--;
2960 t->srv->failed_resp++;
2961 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002962 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002963 //close(t->srv_fd);
2964 t->srv_state = SV_STCLOSE;
2965 if (!(t->flags & SN_ERR_MASK))
2966 t->flags |= SN_ERR_SRVCL;
2967 if (!(t->flags & SN_FINST_MASK))
2968 t->flags |= SN_FINST_D;
2969 /* We used to have a free connection slot. Since we'll never use it,
2970 * we have to inform the server that it may be used by another session.
2971 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002972 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002973 task_wakeup(&rq, t->srv->queue_mgt);
2974
2975 return 1;
2976 }
2977 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002978 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002979 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002980 fd_delete(t->srv_fd);
2981 if (t->srv)
2982 t->srv->cur_sess--;
2983 //close(t->srv_fd);
2984 t->srv_state = SV_STCLOSE;
2985 /* We used to have a free connection slot. Since we'll never use it,
2986 * we have to inform the server that it may be used by another session.
2987 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002988 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002989 task_wakeup(&rq, t->srv->queue_mgt);
2990
2991 return 1;
2992 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002993 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002994 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002995 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002996 fd_delete(t->srv_fd);
2997 if (t->srv)
2998 t->srv->cur_sess--;
2999 //close(t->srv_fd);
3000 t->srv_state = SV_STCLOSE;
3001 if (!(t->flags & SN_ERR_MASK))
3002 t->flags |= SN_ERR_SRVTO;
3003 if (!(t->flags & SN_FINST_MASK))
3004 t->flags |= SN_FINST_D;
3005 /* We used to have a free connection slot. Since we'll never use it,
3006 * we have to inform the server that it may be used by another session.
3007 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003008 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02003009 task_wakeup(&rq, t->srv->queue_mgt);
3010
3011 return 1;
3012 }
3013 else if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02003014 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3015 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02003016 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003017 }
3018 }
3019 else { /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02003020 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
3021 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01003022 if (t->be->beprm->srvtimeout) {
3023 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003024 /* FIXME: to prevent the server from expiring read timeouts during writes,
3025 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02003026 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003027 }
3028 else
Willy Tarreaud7971282006-07-29 18:36:34 +02003029 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003030 }
3031 }
3032 return 0;
3033 }
3034 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003035 if (rep->flags & BF_READ_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02003036 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02003037 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003038 fd_delete(t->srv_fd);
3039 if (t->srv) {
3040 t->srv->cur_sess--;
3041 t->srv->failed_resp++;
3042 }
Willy Tarreau73de9892006-11-30 11:40:23 +01003043 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003044 //close(t->srv_fd);
3045 t->srv_state = SV_STCLOSE;
3046 if (!(t->flags & SN_ERR_MASK))
3047 t->flags |= SN_ERR_SRVCL;
3048 if (!(t->flags & SN_FINST_MASK))
3049 t->flags |= SN_FINST_D;
3050 /* We used to have a free connection slot. Since we'll never use it,
3051 * we have to inform the server that it may be used by another session.
3052 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003053 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02003054 task_wakeup(&rq, t->srv->queue_mgt);
3055
3056 return 1;
3057 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02003058 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02003059 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02003060 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003061 fd_delete(t->srv_fd);
3062 if (t->srv)
3063 t->srv->cur_sess--;
3064 //close(t->srv_fd);
3065 t->srv_state = SV_STCLOSE;
3066 /* We used to have a free connection slot. Since we'll never use it,
3067 * we have to inform the server that it may be used by another session.
3068 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003069 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02003070 task_wakeup(&rq, t->srv->queue_mgt);
3071
3072 return 1;
3073 }
Willy Tarreaud7971282006-07-29 18:36:34 +02003074 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02003075 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02003076 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003077 fd_delete(t->srv_fd);
3078 if (t->srv)
3079 t->srv->cur_sess--;
3080 //close(t->srv_fd);
3081 t->srv_state = SV_STCLOSE;
3082 if (!(t->flags & SN_ERR_MASK))
3083 t->flags |= SN_ERR_SRVTO;
3084 if (!(t->flags & SN_FINST_MASK))
3085 t->flags |= SN_FINST_D;
3086 /* We used to have a free connection slot. Since we'll never use it,
3087 * we have to inform the server that it may be used by another session.
3088 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003089 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02003090 task_wakeup(&rq, t->srv->queue_mgt);
3091
3092 return 1;
3093 }
3094 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02003095 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
3096 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02003097 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003098 }
3099 }
3100 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02003101 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
3102 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01003103 if (t->be->beprm->srvtimeout)
3104 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003105 else
Willy Tarreaud7971282006-07-29 18:36:34 +02003106 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003107 }
3108 }
3109 return 0;
3110 }
3111 else { /* SV_STCLOSE : nothing to do */
3112 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
3113 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01003114 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 +02003115 write(1, trash, len);
3116 }
3117 return 0;
3118 }
3119 return 0;
3120}
3121
3122
3123/*
3124 * Produces data for the session <s> depending on its source. Expects to be
3125 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
3126 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
3127 * session, which it uses to keep on being called when there is free space in
3128 * the buffer, of simply by letting an empty buffer upon return. It returns 1
3129 * if it changes the session state from CL_STSHUTR, otherwise 0.
3130 */
3131int produce_content(struct session *s)
3132{
Willy Tarreaubaaee002006-06-26 02:48:02 +02003133 if (s->data_source == DATA_SRC_NONE) {
3134 s->flags &= ~SN_SELF_GEN;
3135 return 1;
3136 }
3137 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003138 /* dump server statistics */
3139 return produce_content_stats(s);
3140 }
3141 else {
3142 /* unknown data source */
3143 s->logs.status = 500;
3144 client_retnclose(s, error_message(s, HTTP_ERR_500));
3145 if (!(s->flags & SN_ERR_MASK))
3146 s->flags |= SN_ERR_PRXCOND;
3147 if (!(s->flags & SN_FINST_MASK))
3148 s->flags |= SN_FINST_R;
3149 s->flags &= ~SN_SELF_GEN;
3150 return 1;
3151 }
3152}
3153
3154
3155/*
3156 * Produces statistics data for the session <s>. Expects to be called with
3157 * s->cli_state == CL_STSHUTR. It stops by itself by unsetting the SN_SELF_GEN
3158 * flag from the session, which it uses to keep on being called when there is
3159 * free space in the buffer, of simply by letting an empty buffer upon return.
3160 * It returns 1 if it changes the session state from CL_STSHUTR, otherwise 0.
3161 */
3162int produce_content_stats(struct session *s)
3163{
3164 struct buffer *rep = s->rep;
3165 struct proxy *px;
3166 struct chunk msg;
3167 unsigned int up;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003168
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003169 msg.len = 0;
3170 msg.str = trash;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003171
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003172 switch (s->data_state) {
3173 case DATA_ST_INIT:
3174 /* the function had not been called yet */
3175 s->flags |= SN_SELF_GEN; // more data will follow
Willy Tarreaubaaee002006-06-26 02:48:02 +02003176
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003177 chunk_printf(&msg, sizeof(trash),
3178 "HTTP/1.0 200 OK\r\n"
3179 "Cache-Control: no-cache\r\n"
3180 "Connection: close\r\n"
3181 "Content-Type: text/html\r\n"
3182 "\r\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003183
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003184 s->logs.status = 200;
3185 client_retnclose(s, &msg); // send the start of the response.
3186 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003187
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003188 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
3189 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
3190 if (!(s->flags & SN_FINST_MASK))
3191 s->flags |= SN_FINST_R;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003192
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003193 if (s->hreq.meth == HTTP_METH_HEAD) {
3194 /* that's all we return in case of HEAD request */
3195 s->data_state = DATA_ST_FIN;
3196 s->flags &= ~SN_SELF_GEN;
3197 return 1;
3198 }
3199
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003200 s->data_state = DATA_ST_HEAD; /* let's start producing data */
3201 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003202
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003203 case DATA_ST_HEAD:
3204 /* WARNING! This must fit in the first buffer !!! */
3205 chunk_printf(&msg, sizeof(trash),
3206 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
3207 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
3208 "<style type=\"text/css\"><!--\n"
3209 "body {"
3210 " font-family: helvetica, arial;"
3211 " font-size: 12px;"
3212 " font-weight: normal;"
3213 " color: black;"
3214 " background: white;"
3215 "}\n"
3216 "th,td {"
3217 " font-size: 0.8em;"
3218 " align: center;"
3219 "}"
3220 "h1 {"
3221 " font-size: xx-large;"
3222 " margin-bottom: 0.5em;"
3223 "}\n"
3224 "h2 {"
3225 " font-family: helvetica, arial;"
3226 " font-size: x-large;"
3227 " font-weight: bold;"
3228 " font-style: italic;"
3229 " color: #6020a0;"
3230 " margin-top: 0em;"
3231 " margin-bottom: 0em;"
3232 "}\n"
3233 "h3 {"
3234 " font-family: helvetica, arial;"
3235 " font-size: 16px;"
3236 " font-weight: bold;"
3237 " color: #b00040;"
3238 " background: #e8e8d0;"
3239 " margin-top: 0em;"
3240 " margin-bottom: 0em;"
3241 "}\n"
3242 "li {"
3243 " margin-top: 0.25em;"
3244 " margin-right: 2em;"
3245 "}\n"
3246 ".hr {margin-top: 0.25em;"
3247 " border-color: black;"
3248 " border-bottom-style: solid;"
3249 "}\n"
3250 ".pxname {background: #b00040;color: #ffff40;font-weight: bold;}\n"
3251 ".titre {background: #20D0D0;color: #000000;font-weight: bold;}\n"
3252 ".total {background: #20D0D0;color: #ffff80;}\n"
3253 ".frontend {background: #e8e8d0;}\n"
3254 ".backend {background: #e8e8d0;}\n"
3255 ".active0 {background: #ff9090;}\n"
3256 ".active1 {background: #ffd020;}\n"
3257 ".active2 {background: #ffffa0;}\n"
3258 ".active3 {background: #c0ffc0;}\n"
3259 ".active4 {background: #e0e0e0;}\n"
3260 ".backup0 {background: #ff9090;}\n"
3261 ".backup1 {background: #ff80ff;}\n"
3262 ".backup2 {background: #c060ff;}\n"
3263 ".backup3 {background: #b0d0ff;}\n"
3264 ".backup4 {background: #e0e0e0;}\n"
3265 "table.tbl { border-collapse: collapse; border-style: none;}\n"
Willy Tarreau35d66b02007-01-02 00:28:21 +01003266 "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 +01003267 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}\n"
3268 "table.tbl th.empty { border-style: none; empty-cells: hide;}\n"
3269 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
3270 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
3271 "table.lgd td.noborder { border-style: none; padding: 2px; white-space: nowrap;}\n"
3272 "-->"
3273 "</style></head>");
3274
3275 if (buffer_write_chunk(rep, &msg) != 0)
3276 return 0;
3277
3278 s->data_state = DATA_ST_INFO;
3279 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003280
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003281 case DATA_ST_INFO:
3282 up = (now.tv_sec - start_date.tv_sec);
3283
3284 /* WARNING! this has to fit the first packet too.
3285 * We are around 3.5 kB, add adding entries will
3286 * become tricky if we want to support 4kB buffers !
3287 */
3288 chunk_printf(&msg, sizeof(trash),
3289 "<body><h1><a href=\"" PRODUCT_URL "\" style=\"text-decoration: none;\">"
3290 PRODUCT_NAME "</a></h1>\n"
3291 "<h2>Statistics Report for pid %d</h2>\n"
3292 "<hr width=\"100%%\" class=\"hr\">\n"
3293 "<h3>&gt; General process information</h3>\n"
3294 "<table border=0 cols=3><tr><td align=\"left\" nowrap width=\"1%%\">\n"
3295 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
3296 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
3297 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
3298 "<b>maxsock = </b> %d<br>\n"
3299 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
3300 "</td><td align=\"center\" nowrap>\n"
3301 "<table class=\"lgd\"><tr>"
3302 "<td class=\"active3\">&nbsp;</td><td class=\"noborder\">active UP </td>"
3303 "<td class=\"backup3\">&nbsp;</td><td class=\"noborder\">backup UP </td>"
3304 "</tr><tr>"
3305 "<td class=\"active2\"></td><td class=\"noborder\">active UP, going down </td>"
3306 "<td class=\"backup2\"></td><td class=\"noborder\">backup UP, going down </td>"
3307 "</tr><tr>"
3308 "<td class=\"active1\"></td><td class=\"noborder\">active DOWN, going up </td>"
3309 "<td class=\"backup1\"></td><td class=\"noborder\">backup DOWN, going up </td>"
3310 "</tr><tr>"
3311 "<td class=\"active0\"></td><td class=\"noborder\">active or backup DOWN &nbsp;</td>"
3312 "<td class=\"active4\"></td><td class=\"noborder\">not checked </td>"
3313 "</tr></table>\n"
3314 "</td>"
3315 "<td align=\"left\" nowrap width=\"1%%\">"
3316 "<b>External ressources:</b><ul style=\"margin-top: 0.25em;\">"
3317 "<li><a href=\"" PRODUCT_URL "\">Primary site</a><br>"
3318 "<li><a href=\"" PRODUCT_URL_UPD "\">Updates (v" PRODUCT_BRANCH ")</a><br>"
3319 "<li><a href=\"" PRODUCT_URL_DOC "\">Online manual</a><br>"
3320 "</ul>"
3321 "</td>"
3322 "</tr></table>\n"
3323 "",
3324 pid, pid, global.nbproc,
3325 up / 86400, (up % 86400) / 3600,
3326 (up % 3600) / 60, (up % 60),
3327 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
3328 global.rlimit_memmax ? " MB" : "",
3329 global.rlimit_nofile,
3330 global.maxsock,
3331 global.maxconn,
3332 actconn
3333 );
Willy Tarreaubaaee002006-06-26 02:48:02 +02003334
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003335 if (buffer_write_chunk(rep, &msg) != 0)
3336 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003337
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003338 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003339
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003340 s->data_ctx.stats.px = proxy;
3341 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
3342 s->data_state = DATA_ST_LIST;
3343 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003344
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003345 case DATA_ST_LIST:
3346 /* dump proxies */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003347 while (s->data_ctx.stats.px) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003348 px = s->data_ctx.stats.px;
3349 /* skip the disabled proxies and non-networked ones */
3350 if (px->state != PR_STSTOPPED && (px->cap & (PR_CAP_FE | PR_CAP_BE)))
3351 if (produce_content_stats_proxy(s, px) == 0)
3352 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003353
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003354 s->data_ctx.stats.px = px->next;
3355 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
3356 }
3357 /* here, we just have reached the last proxy */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003358
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003359 s->data_state = DATA_ST_END;
3360 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003361
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003362 case DATA_ST_END:
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003363 chunk_printf(&msg, sizeof(trash), "</body></html>\n");
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003364 if (buffer_write_chunk(rep, &msg) != 0)
3365 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003366
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003367 s->data_state = DATA_ST_FIN;
3368 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003369
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003370 case DATA_ST_FIN:
3371 s->flags &= ~SN_SELF_GEN;
3372 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003373
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003374 default:
3375 /* unknown state ! */
3376 s->logs.status = 500;
3377 client_retnclose(s, error_message(s, HTTP_ERR_500));
3378 if (!(s->flags & SN_ERR_MASK))
3379 s->flags |= SN_ERR_PRXCOND;
3380 if (!(s->flags & SN_FINST_MASK))
3381 s->flags |= SN_FINST_R;
3382 s->flags &= ~SN_SELF_GEN;
3383 return 1;
3384 }
3385}
Willy Tarreaubaaee002006-06-26 02:48:02 +02003386
Willy Tarreaubaaee002006-06-26 02:48:02 +02003387
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003388/*
3389 * Dumps statistics for a proxy.
3390 * Returns 0 if it had to stop dumping data because of lack of buffer space,
3391 * ot non-zero if everything completed.
3392 */
3393int produce_content_stats_proxy(struct session *s, struct proxy *px)
3394{
3395 struct buffer *rep = s->rep;
3396 struct server *sv;
3397 struct chunk msg;
3398
3399 msg.len = 0;
3400 msg.str = trash;
3401
3402 switch (s->data_ctx.stats.px_st) {
3403 case DATA_ST_PX_INIT:
3404 /* we are on a new proxy */
3405
3406 if (s->be->fiprm->uri_auth && s->be->fiprm->uri_auth->scope) {
3407 /* we have a limited scope, we have to check the proxy name */
3408 struct stat_scope *scope;
3409 int len;
3410
3411 len = strlen(px->id);
3412 scope = s->be->fiprm->uri_auth->scope;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003413
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003414 while (scope) {
3415 /* match exact proxy name */
3416 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3417 break;
3418
3419 /* match '.' which means 'self' proxy */
3420 if (!strcmp(scope->px_id, ".") && px == s->fe)
3421 break;
3422 scope = scope->next;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003423 }
3424
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003425 /* proxy name not found : don't dump anything */
3426 if (scope == NULL)
3427 return 1;
3428 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003429
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003430 s->data_ctx.stats.px_st = DATA_ST_PX_TH;
3431 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003432
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003433 case DATA_ST_PX_TH:
3434 /* print a new table */
3435 chunk_printf(&msg, sizeof(trash),
3436 "<table cols=\"20\" class=\"tbl\" width=\"100%%\">\n"
3437 "<tr align=\"center\" class=\"titre\">"
3438 "<th colspan=2 class=\"pxname\">%s</th>"
3439 "<th colspan=18 class=\"empty\"></th>"
3440 "</tr>\n"
3441 "<tr align=\"center\" class=\"titre\">"
3442 "<th rowspan=2></th>"
3443 "<th colspan=2>Queue</th><th colspan=4>Sessions</th>"
3444 "<th colspan=2>Bytes</th><th colspan=2>Denied</th>"
3445 "<th colspan=3>Errors</th><th colspan=6>Server</th>"
3446 "</tr>\n"
3447 "<tr align=\"center\" class=\"titre\">"
Willy Tarreau35d66b02007-01-02 00:28:21 +01003448 "<th>Cur</th><th>Max</th><th>Cur</th><th>Max</th>"
3449 "<th>Limit</th><th>Cumul</th><th>In</th><th>Out</th>"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003450 "<th>Req</th><th>Resp</th><th>Req</th><th>Conn</th>"
3451 "<th>Resp</th><th>Status</th><th>Weight</th><th>Act</th>"
3452 "<th>Bck</th><th>Check</th><th>Down</th></tr>\n"
3453 "",
3454 px->id);
3455
3456 if (buffer_write_chunk(rep, &msg) != 0)
3457 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003458
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003459 s->data_ctx.stats.px_st = DATA_ST_PX_FE;
3460 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003461
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003462 case DATA_ST_PX_FE:
3463 /* print the frontend */
3464 if (px->cap & PR_CAP_FE) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003465 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003466 /* name, queue */
3467 "<tr align=center class=\"frontend\"><td>Frontend</td><td colspan=2></td>"
3468 /* sessions : current, max, limit, cumul. */
3469 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
3470 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003471 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003472 /* denied: req, resp */
3473 "<td align=right>%d</td><td align=right>%d</td>"
3474 /* errors : request, connect, response */
3475 "<td align=right>%d</td><td align=right></td><td align=right></td>"
3476 /* server status : reflect backend status */
3477 "<td align=center>%s</td>"
3478 /* rest of server: nothing */
3479 "<td align=center colspan=5></td></tr>"
3480 "",
3481 px->feconn, px->feconn_max, px->maxconn, px->cum_feconn,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003482 px->bytes_in, px->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003483 px->denied_req, px->denied_resp,
3484 px->failed_req,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003485 px->state == PR_STRUN ? "OPEN" :
3486 px->state == PR_STIDLE ? "FULL" : "STOP");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003487
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003488 if (buffer_write_chunk(rep, &msg) != 0)
3489 return 0;
3490 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003491
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003492 s->data_ctx.stats.sv = px->srv; /* may be NULL */
3493 s->data_ctx.stats.px_st = DATA_ST_PX_SV;
3494 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003495
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003496 case DATA_ST_PX_SV:
3497 /* stats.sv has been initialized above */
3498 while (s->data_ctx.stats.sv != NULL) {
3499 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3500 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP, 4=unchecked */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003501
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003502 sv = s->data_ctx.stats.sv;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003503
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003504 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3505 if (!(sv->state & SRV_CHECKED))
3506 sv_state = 4;
3507 else if (sv->state & SRV_RUNNING)
3508 if (sv->health == sv->rise + sv->fall - 1)
3509 sv_state = 3; /* UP */
3510 else
3511 sv_state = 2; /* going down */
3512 else
3513 if (sv->health)
3514 sv_state = 1; /* going up */
3515 else
3516 sv_state = 0; /* DOWN */
3517
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003518 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003519 /* name */
3520 "<tr align=\"center\" class=\"%s%d\"><td>%s</td>"
3521 /* queue : current, max */
3522 "<td align=right>%d</td><td align=right>%d</td>"
3523 /* sessions : current, max, limit, cumul */
3524 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>"
3525 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003526 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003527 /* denied: req, resp */
3528 "<td align=right></td><td align=right>%d</td>"
3529 /* errors : request, connect, response */
3530 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
3531 "",
Willy Tarreau368e96a2007-01-07 00:16:15 +01003532 (sv->state & SRV_BACKUP) ? "backup" : "active",
Willy Tarreau128e9542007-01-01 22:01:43 +01003533 sv_state, sv->id,
3534 sv->nbpend, sv->nbpend_max,
3535 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003536 sv->bytes_in, sv->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003537 sv->failed_secu,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003538 sv->failed_conns, sv->failed_resp);
Willy Tarreau128e9542007-01-01 22:01:43 +01003539
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003540 /* status */
3541 chunk_printf(&msg, sizeof(trash), "<td nowrap>");
3542 chunk_printf(&msg, sizeof(trash),
3543 srv_hlt_st[sv_state],
3544 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3545 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3546
Willy Tarreau128e9542007-01-01 22:01:43 +01003547 chunk_printf(&msg, sizeof(trash),
3548 /* weight */
3549 "</td><td>%d</td>"
3550 /* act, bck */
3551 "<td>%s</td><td>%s</td>"
3552 "",
3553 sv->uweight+1,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003554 (sv->state & SRV_BACKUP) ? "-" : "Y",
3555 (sv->state & SRV_BACKUP) ? "Y" : "-");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003556
3557 /* check failures : unique, fatal */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003558 if (sv->state & SRV_CHECKED)
3559 chunk_printf(&msg, sizeof(trash),
3560 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3561 sv->failed_checks, sv->down_trans);
3562 else
3563 chunk_printf(&msg, sizeof(trash),
3564 "<td colspan=2></td></tr>\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003565
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003566 if (buffer_write_chunk(rep, &msg) != 0)
3567 return 0;
3568
3569 s->data_ctx.stats.sv = sv->next;
3570 } /* while sv */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003571
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003572 s->data_ctx.stats.px_st = DATA_ST_PX_BE;
3573 /* fall through */
3574
3575 case DATA_ST_PX_BE:
3576 /* print the backend */
3577 if (px->cap & PR_CAP_BE) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003578 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003579 /* name */
3580 "<tr align=center class=\"backend\"><td>Backend</td>"
3581 /* queue : current, max */
3582 "<td align=right>%d</td><td align=right>%d</td>"
3583 /* sessions : current, max, limit, cumul. */
3584 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
3585 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003586 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003587 /* denied: req, resp */
3588 "<td align=right>%d</td><td align=right>%d</td>"
3589 /* errors : request, connect, response */
3590 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
3591 /* server status : reflect backend status (up/down) : we display UP
3592 * if the backend has known working servers or if it has no server at
3593 * all (eg: for stats). Tthen we display the total weight, number of
3594 * active and backups. */
3595 "<td align=center>%s</td><td align=center>%d</td>"
3596 "<td align=center>%d</td><td align=center>%d</td>"
3597 /* rest of server: nothing */
3598 "<td align=center colspan=2></td></tr>"
3599 "",
3600 px->nbpend /* or px->totpend ? */, px->nbpend_max,
3601 px->beconn, px->beconn_max, px->fullconn, px->cum_beconn,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003602 px->bytes_in, px->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003603 px->denied_req, px->denied_resp,
3604 px->failed_conns, px->failed_resp,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003605 (px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN",
3606 px->srv_map_sz, px->srv_act, px->srv_bck);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003607
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003608 if (buffer_write_chunk(rep, &msg) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003609 return 0;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003610 }
3611
3612 s->data_ctx.stats.px_st = DATA_ST_PX_END;
3613 /* fall through */
3614
3615 case DATA_ST_PX_END:
3616 chunk_printf(&msg, sizeof(trash), "</table><p>\n");
3617
3618 if (buffer_write_chunk(rep, &msg) != 0)
3619 return 0;
3620
3621 s->data_ctx.stats.px_st = DATA_ST_PX_FIN;
3622 /* fall through */
3623
3624 case DATA_ST_PX_FIN:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003625 return 1;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003626
3627 default:
3628 /* unknown state, we should put an abort() here ! */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003629 return 1;
3630 }
3631}
3632
3633
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003634/* Iterate the same filter through all request headers.
3635 * Returns 1 if this filter can be stopped upon return, otherwise 0.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003636 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003637int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003638{
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003639 char term;
3640 char *cur_ptr, *cur_end, *cur_next;
3641 int cur_idx, old_idx, last_hdr;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003642 struct http_req *hreq = &t->hreq;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003643 struct hdr_idx_elem *cur_hdr;
3644 int len, delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003645
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003646 last_hdr = 0;
3647
3648 cur_next = req->data + hreq->req.sor + hdr_idx_first_pos(&hreq->hdr_idx);
3649 old_idx = 0;
3650
3651 while (!last_hdr) {
3652 if (unlikely(t->flags & (SN_CLDENY | SN_CLTARPIT)))
3653 return 1;
3654 else if (unlikely(t->flags & SN_CLALLOW) &&
3655 (exp->action == ACT_ALLOW ||
3656 exp->action == ACT_DENY ||
3657 exp->action == ACT_TARPIT))
3658 return 0;
3659
3660 cur_idx = hreq->hdr_idx.v[old_idx].next;
3661 if (!cur_idx)
3662 break;
3663
3664 cur_hdr = &hreq->hdr_idx.v[cur_idx];
3665 cur_ptr = cur_next;
3666 cur_end = cur_ptr + cur_hdr->len;
3667 cur_next = cur_end + cur_hdr->cr + 1;
3668
3669 /* Now we have one header between cur_ptr and cur_end,
3670 * and the next header starts at cur_next.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003671 */
3672
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003673 /* The annoying part is that pattern matching needs
3674 * that we modify the contents to null-terminate all
3675 * strings before testing them.
3676 */
3677
3678 term = *cur_end;
3679 *cur_end = '\0';
3680
3681 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3682 switch (exp->action) {
3683 case ACT_SETBE:
3684 /* It is not possible to jump a second time.
3685 * FIXME: should we return an HTTP/500 here so that
3686 * the admin knows there's a problem ?
3687 */
3688 if (t->be != t->fe)
3689 break;
3690
3691 /* Swithing Proxy */
3692 t->be = (struct proxy *) exp->replace;
3693
3694 /* right now, the backend switch is not too much complicated
3695 * because we have associated req_cap and rsp_cap to the
3696 * frontend, and the beconn will be updated later.
3697 */
3698
3699 t->rep->rto = t->req->wto = t->be->beprm->srvtimeout;
3700 t->req->cto = t->be->beprm->contimeout;
3701 last_hdr = 1;
3702 break;
3703
3704 case ACT_ALLOW:
3705 t->flags |= SN_CLALLOW;
3706 last_hdr = 1;
3707 break;
3708
3709 case ACT_DENY:
3710 t->flags |= SN_CLDENY;
3711 last_hdr = 1;
3712 t->be->beprm->denied_req++;
3713 break;
3714
3715 case ACT_TARPIT:
3716 t->flags |= SN_CLTARPIT;
3717 last_hdr = 1;
3718 t->be->beprm->denied_req++;
3719 break;
3720
3721 case ACT_REPLACE:
3722 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3723 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3724 /* FIXME: if the user adds a newline in the replacement, the
3725 * index will not be recalculated for now, and the new line
3726 * will not be counted as a new header.
3727 */
3728
3729 cur_end += delta;
3730 cur_next += delta;
3731 cur_hdr->len += delta;
3732 hreq->req.eoh += delta;
3733 break;
3734
3735 case ACT_REMOVE:
3736 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3737 cur_next += delta;
3738
3739 /* FIXME: this should be a separate function */
3740 hreq->req.eoh += delta;
3741 hreq->hdr_idx.v[old_idx].next = cur_hdr->next;
3742 hreq->hdr_idx.used--;
3743 cur_hdr->len = 0;
3744 cur_end = NULL; /* null-term has been rewritten */
3745 break;
3746
3747 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01003748 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003749 if (cur_end)
3750 *cur_end = term; /* restore the string terminator */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003751
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003752 /* keep the link from this header to next one in case of later
3753 * removal of next header.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003754 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003755 old_idx = cur_idx;
3756 }
3757 return 0;
3758}
3759
3760
3761/* Apply the filter to the request line.
3762 * Returns 0 if nothing has been done, 1 if the filter has been applied,
3763 * or -1 if a replacement resulted in an invalid request line.
3764 */
3765int apply_filter_to_req_line(struct session *t, struct buffer *req, struct hdr_exp *exp)
3766{
3767 char term;
3768 char *cur_ptr, *cur_end;
3769 int done;
3770 struct http_req *hreq = &t->hreq;
3771 int len, delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003772
Willy Tarreau58f10d72006-12-04 02:26:12 +01003773
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003774 if (unlikely(t->flags & (SN_CLDENY | SN_CLTARPIT)))
3775 return 1;
3776 else if (unlikely(t->flags & SN_CLALLOW) &&
3777 (exp->action == ACT_ALLOW ||
3778 exp->action == ACT_DENY ||
3779 exp->action == ACT_TARPIT))
3780 return 0;
3781 else if (exp->action == ACT_REMOVE)
3782 return 0;
3783
3784 done = 0;
3785
3786 cur_ptr = req->data + hreq->req.sor;
3787 cur_end = cur_ptr + hreq->req.sl.rq.l;
3788
3789 /* Now we have the request line between cur_ptr and cur_end */
3790
3791 /* The annoying part is that pattern matching needs
3792 * that we modify the contents to null-terminate all
3793 * strings before testing them.
3794 */
3795
3796 term = *cur_end;
3797 *cur_end = '\0';
3798
3799 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3800 switch (exp->action) {
3801 case ACT_SETBE:
3802 /* It is not possible to jump a second time.
3803 * FIXME: should we return an HTTP/500 here so that
3804 * the admin knows there's a problem ?
Willy Tarreau58f10d72006-12-04 02:26:12 +01003805 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003806 if (t->be != t->fe)
3807 break;
3808
3809 /* Swithing Proxy */
3810 t->be = (struct proxy *) exp->replace;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003811
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003812 /* right now, the backend switch is not too much complicated
3813 * because we have associated req_cap and rsp_cap to the
3814 * frontend, and the beconn will be updated later.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003815 */
3816
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003817 t->rep->rto = t->req->wto = t->be->beprm->srvtimeout;
3818 t->req->cto = t->be->beprm->contimeout;
3819 done = 1;
3820 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003821
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003822 case ACT_ALLOW:
3823 t->flags |= SN_CLALLOW;
3824 done = 1;
3825 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003826
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003827 case ACT_DENY:
3828 t->flags |= SN_CLDENY;
3829 t->be->beprm->denied_req++;
3830 done = 1;
3831 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003832
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003833 case ACT_TARPIT:
3834 t->flags |= SN_CLTARPIT;
3835 t->be->beprm->denied_req++;
3836 done = 1;
3837 break;
Willy Tarreaua496b602006-12-17 23:15:24 +01003838
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003839 case ACT_REPLACE:
3840 *cur_end = term; /* restore the string terminator */
3841 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3842 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
3843 /* FIXME: if the user adds a newline in the replacement, the
3844 * index will not be recalculated for now, and the new line
3845 * will not be counted as a new header.
3846 */
Willy Tarreaua496b602006-12-17 23:15:24 +01003847
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003848 hreq->req.eoh += delta;
3849 cur_end += delta;
Willy Tarreaua496b602006-12-17 23:15:24 +01003850
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003851 cur_end = (char *)http_parse_reqline(&hreq->req, req->data,
3852 HTTP_MSG_RQMETH,
3853 cur_ptr, cur_end + 1,
3854 NULL, NULL);
3855 if (unlikely(!cur_end))
3856 return -1;
Willy Tarreaua496b602006-12-17 23:15:24 +01003857
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003858 /* we have a full request and we know that we have either a CR
3859 * or an LF at <ptr>.
3860 */
3861 hreq->meth = find_http_meth(cur_ptr, hreq->req.sl.rq.m_l);
3862 hdr_idx_set_start(&hreq->hdr_idx, hreq->req.sl.rq.l, *cur_end == '\r');
3863 /* there is no point trying this regex on headers */
3864 return 1;
3865 }
3866 }
3867 *cur_end = term; /* restore the string terminator */
3868 return done;
3869}
Willy Tarreau97de6242006-12-27 17:18:38 +01003870
Willy Tarreau58f10d72006-12-04 02:26:12 +01003871
Willy Tarreau58f10d72006-12-04 02:26:12 +01003872
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003873/*
3874 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>.
3875 * Returns 0 if everything is alright, or -1 in case a replacement lead to an
3876 * unparsable request.
3877 */
3878int apply_filters_to_request(struct session *t, struct buffer *req, struct hdr_exp *exp)
3879{
3880 /* iterate through the filters in the outer loop */
3881 while (exp && !(t->flags & (SN_CLDENY|SN_CLTARPIT))) {
3882 int ret;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003883
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003884 /*
3885 * The interleaving of transformations and verdicts
3886 * makes it difficult to decide to continue or stop
3887 * the evaluation.
3888 */
3889
3890 if ((t->flags & SN_CLALLOW) &&
3891 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
3892 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
3893 exp = exp->next;
3894 continue;
3895 }
3896
3897 /* Apply the filter to the request line. */
3898 ret = apply_filter_to_req_line(t, req, exp);
3899 if (unlikely(ret < 0))
3900 return -1;
3901
3902 if (likely(ret == 0)) {
3903 /* The filter did not match the request, it can be
3904 * iterated through all headers.
3905 */
3906 apply_filter_to_req_headers(t, req, exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003907 }
3908 exp = exp->next;
3909 }
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003910 return 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003911}
3912
3913
Willy Tarreau58f10d72006-12-04 02:26:12 +01003914/*
3915 * Manager client-side cookie
3916 */
3917void manage_client_side_cookies(struct session *t, struct buffer *req)
3918{
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003919 struct http_req *hreq = &t->hreq;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003920 char *p1, *p2, *p3, *p4;
3921 char *del_colon, *del_cookie, *colon;
3922 int app_cookies;
3923
3924 appsess *asession_temp = NULL;
3925 appsess local_asession;
3926
3927 char *cur_ptr, *cur_end, *cur_next;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01003928 int cur_idx, old_idx;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003929
Willy Tarreau830ff452006-12-17 19:31:23 +01003930 if (t->be->beprm->cookie_name == NULL &&
3931 t->be->beprm->appsession_name ==NULL &&
3932 t->be->fiprm->capture_name != NULL)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003933 return;
3934
Willy Tarreau2a324282006-12-05 00:05:46 +01003935 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003936 * we start with the start line.
3937 */
Willy Tarreau83969f42007-01-22 08:55:47 +01003938 old_idx = 0;
3939 cur_next = req->data + hreq->req.sor + hdr_idx_first_pos(&hreq->hdr_idx);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003940
Willy Tarreau83969f42007-01-22 08:55:47 +01003941 while ((cur_idx = hreq->hdr_idx.v[old_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003942 struct hdr_idx_elem *cur_hdr;
3943
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003944 cur_hdr = &hreq->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003945 cur_ptr = cur_next;
3946 cur_end = cur_ptr + cur_hdr->len;
3947 cur_next = cur_end + cur_hdr->cr + 1;
3948
3949 /* We have one full header between cur_ptr and cur_end, and the
3950 * next header starts at cur_next. We're only interested in
3951 * "Cookie:" headers.
3952 */
3953
3954 if ((cur_end - cur_ptr <= 7) ||
3955 (strncasecmp(cur_ptr, "Cookie:", 7) != 0)) {
3956 old_idx = cur_idx;
3957 continue;
3958 }
3959
3960 /* Now look for cookies. Conforming to RFC2109, we have to support
3961 * attributes whose name begin with a '$', and associate them with
3962 * the right cookie, if we want to delete this cookie.
3963 * So there are 3 cases for each cookie read :
3964 * 1) it's a special attribute, beginning with a '$' : ignore it.
3965 * 2) it's a server id cookie that we *MAY* want to delete : save
3966 * some pointers on it (last semi-colon, beginning of cookie...)
3967 * 3) it's an application cookie : we *MAY* have to delete a previous
3968 * "special" cookie.
3969 * At the end of loop, if a "special" cookie remains, we may have to
3970 * remove it. If no application cookie persists in the header, we
3971 * *MUST* delete it
3972 */
3973
3974
3975 p1 = cur_ptr + 7; /* first char after 'Cookie:' */
3976 if (isspace((int)*p1)) /* try to get the first space with it */
3977 p1++;
3978
3979 colon = p1;
3980 /* del_cookie == NULL => nothing to be deleted */
3981 del_colon = del_cookie = NULL;
3982 app_cookies = 0;
3983
3984 while (p1 < cur_end) {
3985 /* skip spaces and colons, but keep an eye on these ones */
3986 while (p1 < cur_end) {
3987 if (*p1 == ';' || *p1 == ',')
3988 colon = p1;
3989 else if (!isspace((int)*p1))
3990 break;
3991 p1++;
3992 }
3993
3994 if (p1 == cur_end)
3995 break;
3996
3997 /* p1 is at the beginning of the cookie name */
3998 p2 = p1;
3999 while (p2 < cur_end && *p2 != '=')
4000 p2++;
4001
4002 if (p2 == cur_end)
4003 break;
4004
4005 p3 = p2 + 1; /* skips the '=' sign */
4006 if (p3 == cur_end)
4007 break;
4008
4009 p4 = p3;
4010 while (p4 < cur_end && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
4011 p4++;
4012
4013 /* here, we have the cookie name between p1 and p2,
4014 * and its value between p3 and p4.
4015 * we can process it :
4016 *
4017 * Cookie: NAME=VALUE;
4018 * | || || |
4019 * | || || +--> p4
4020 * | || |+-------> p3
4021 * | || +--------> p2
4022 * | |+------------> p1
4023 * | +-------------> colon
4024 * +--------------------> cur_ptr
4025 */
4026
4027 if (*p1 == '$') {
4028 /* skip this one */
4029 }
4030 else {
4031 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01004032 if (t->fe->fiprm->capture_name != NULL &&
Willy Tarreau58f10d72006-12-04 02:26:12 +01004033 t->logs.cli_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01004034 (p4 - p1 >= t->fe->fiprm->capture_namelen) &&
4035 memcmp(p1, t->fe->fiprm->capture_name, t->fe->fiprm->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004036 int log_len = p4 - p1;
4037
4038 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
4039 Alert("HTTP logging : out of memory.\n");
4040 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01004041 if (log_len > t->fe->fiprm->capture_len)
4042 log_len = t->fe->fiprm->capture_len;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004043 memcpy(t->logs.cli_cookie, p1, log_len);
4044 t->logs.cli_cookie[log_len] = 0;
4045 }
4046 }
4047
Willy Tarreau830ff452006-12-17 19:31:23 +01004048 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
4049 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004050 /* Cool... it's the right one */
Willy Tarreau830ff452006-12-17 19:31:23 +01004051 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004052 char *delim;
4053
4054 /* if we're in cookie prefix mode, we'll search the delimitor so that we
4055 * have the server ID betweek p3 and delim, and the original cookie between
4056 * delim+1 and p4. Otherwise, delim==p4 :
4057 *
4058 * Cookie: NAME=SRV~VALUE;
4059 * | || || | |
4060 * | || || | +--> p4
4061 * | || || +--------> delim
4062 * | || |+-----------> p3
4063 * | || +------------> p2
4064 * | |+----------------> p1
4065 * | +-----------------> colon
4066 * +------------------------> cur_ptr
4067 */
4068
Willy Tarreau830ff452006-12-17 19:31:23 +01004069 if (t->be->beprm->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004070 for (delim = p3; delim < p4; delim++)
4071 if (*delim == COOKIE_DELIM)
4072 break;
4073 }
4074 else
4075 delim = p4;
4076
4077
4078 /* Here, we'll look for the first running server which supports the cookie.
4079 * This allows to share a same cookie between several servers, for example
4080 * to dedicate backup servers to specific servers only.
4081 * However, to prevent clients from sticking to cookie-less backup server
4082 * when they have incidentely learned an empty cookie, we simply ignore
4083 * empty cookies and mark them as invalid.
4084 */
4085 if (delim == p3)
4086 srv = NULL;
4087
4088 while (srv) {
4089 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreau830ff452006-12-17 19:31:23 +01004090 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004091 /* we found the server and it's usable */
4092 t->flags &= ~SN_CK_MASK;
4093 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
4094 t->srv = srv;
4095 break;
4096 } else {
4097 /* we found a server, but it's down */
4098 t->flags &= ~SN_CK_MASK;
4099 t->flags |= SN_CK_DOWN;
4100 }
4101 }
4102 srv = srv->next;
4103 }
4104
4105 if (!srv && !(t->flags & SN_CK_DOWN)) {
4106 /* no server matched this cookie */
4107 t->flags &= ~SN_CK_MASK;
4108 t->flags |= SN_CK_INVALID;
4109 }
4110
4111 /* depending on the cookie mode, we may have to either :
4112 * - delete the complete cookie if we're in insert+indirect mode, so that
4113 * the server never sees it ;
4114 * - remove the server id from the cookie value, and tag the cookie as an
4115 * application cookie so that it does not get accidentely removed later,
4116 * if we're in cookie prefix mode
4117 */
Willy Tarreau830ff452006-12-17 19:31:23 +01004118 if ((t->be->beprm->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004119 int delta; /* negative */
4120
4121 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
4122 p4 += delta;
4123 cur_end += delta;
4124 cur_next += delta;
4125 cur_hdr->len += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004126 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004127
4128 del_cookie = del_colon = NULL;
4129 app_cookies++; /* protect the header from deletion */
4130 }
4131 else if (del_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01004132 (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 +01004133 del_cookie = p1;
4134 del_colon = colon;
4135 }
4136 } else {
4137 /* now we know that we must keep this cookie since it's
4138 * not ours. But if we wanted to delete our cookie
4139 * earlier, we cannot remove the complete header, but we
4140 * can remove the previous block itself.
4141 */
4142 app_cookies++;
4143
4144 if (del_cookie != NULL) {
4145 int delta; /* negative */
4146
4147 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
4148 p4 += delta;
4149 cur_end += delta;
4150 cur_next += delta;
4151 cur_hdr->len += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004152 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004153 del_cookie = del_colon = NULL;
4154 }
4155 }
4156
Willy Tarreau830ff452006-12-17 19:31:23 +01004157 if ((t->be->beprm->appsession_name != NULL) &&
4158 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004159 /* first, let's see if the cookie is our appcookie*/
4160
4161 /* Cool... it's the right one */
4162
4163 asession_temp = &local_asession;
4164
4165 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4166 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
4167 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
4168 return;
4169 }
4170
Willy Tarreau830ff452006-12-17 19:31:23 +01004171 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
4172 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004173 asession_temp->serverid = NULL;
4174
4175 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01004176 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004177 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4178 /* free previously allocated memory */
4179 pool_free_to(apools.sessid, local_asession.sessid);
4180 Alert("Not enough memory process_cli():asession:calloc().\n");
4181 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4182 return;
4183 }
4184
4185 asession_temp->sessid = local_asession.sessid;
4186 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01004187 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004188 } else {
4189 /* free previously allocated memory */
4190 pool_free_to(apools.sessid, local_asession.sessid);
4191 }
4192
4193 if (asession_temp->serverid == NULL) {
4194 Alert("Found Application Session without matching server.\n");
4195 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01004196 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004197 while (srv) {
4198 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01004199 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004200 /* we found the server and it's usable */
4201 t->flags &= ~SN_CK_MASK;
4202 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
4203 t->srv = srv;
4204 break;
4205 } else {
4206 t->flags &= ~SN_CK_MASK;
4207 t->flags |= SN_CK_DOWN;
4208 }
4209 }
4210 srv = srv->next;
4211 }/* end while(srv) */
4212 }/* end else if server == NULL */
4213
Willy Tarreau830ff452006-12-17 19:31:23 +01004214 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004215 }/* end if ((t->proxy->appsession_name != NULL) ... */
4216 }
4217
4218 /* we'll have to look for another cookie ... */
4219 p1 = p4;
4220 } /* while (p1 < cur_end) */
4221
4222 /* There's no more cookie on this line.
4223 * We may have marked the last one(s) for deletion.
4224 * We must do this now in two ways :
4225 * - if there is no app cookie, we simply delete the header ;
4226 * - if there are app cookies, we must delete the end of the
4227 * string properly, including the colon/semi-colon before
4228 * the cookie name.
4229 */
4230 if (del_cookie != NULL) {
4231 int delta;
4232 if (app_cookies) {
4233 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
4234 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004235 cur_hdr->len += delta;
4236 } else {
4237 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004238
4239 /* FIXME: this should be a separate function */
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004240 hreq->hdr_idx.v[old_idx].next = cur_hdr->next;
4241 hreq->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004242 cur_hdr->len = 0;
4243 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01004244 cur_next += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004245 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004246 }
4247
4248 /* keep the link from this header to next one */
4249 old_idx = cur_idx;
4250 } /* end of cookie processing on this header */
4251}
4252
4253
Willy Tarreau58f10d72006-12-04 02:26:12 +01004254/*
4255 * Try to retrieve a known appsession in the URI, then the associated server.
4256 * If the server is found, it's assigned to the session.
4257 */
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004258void get_srv_from_appsession(struct session *t, const char *begin, int len)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004259{
4260 appsess *asession_temp = NULL;
4261 appsess local_asession;
4262 char *request_line;
4263
Willy Tarreau830ff452006-12-17 19:31:23 +01004264 if (t->be->beprm->appsession_name == NULL ||
Willy Tarreau921d7c02006-12-17 13:50:27 +01004265 (t->hreq.meth != HTTP_METH_GET && t->hreq.meth != HTTP_METH_POST) ||
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004266 (request_line = memchr(begin, ';', len)) == NULL ||
4267 ((1 + t->be->beprm->appsession_name_len + 1 + t->be->beprm->appsession_len) > (begin + len - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01004268 return;
4269
4270 /* skip ';' */
4271 request_line++;
4272
4273 /* look if we have a jsessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01004274 if (strncasecmp(request_line, t->be->beprm->appsession_name, t->be->beprm->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01004275 return;
4276
4277 /* skip jsessionid= */
Willy Tarreau830ff452006-12-17 19:31:23 +01004278 request_line += t->be->beprm->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004279
4280 /* First try if we already have an appsession */
4281 asession_temp = &local_asession;
4282
4283 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
4284 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
4285 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
4286 return;
4287 }
4288
4289 /* Copy the sessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01004290 memcpy(asession_temp->sessid, request_line, t->be->beprm->appsession_len);
4291 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004292 asession_temp->serverid = NULL;
4293
4294 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01004295 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *)&asession_temp)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004296 if ((asession_temp = pool_alloc(appsess)) == NULL) {
4297 /* free previously allocated memory */
4298 pool_free_to(apools.sessid, local_asession.sessid);
4299 Alert("Not enough memory process_cli():asession:calloc().\n");
4300 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
4301 return;
4302 }
4303 asession_temp->sessid = local_asession.sessid;
4304 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01004305 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004306 }
4307 else {
4308 /* free previously allocated memory */
4309 pool_free_to(apools.sessid, local_asession.sessid);
4310 }
4311
Willy Tarreau830ff452006-12-17 19:31:23 +01004312 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01004313 asession_temp->request_count++;
4314
4315#if defined(DEBUG_HASH)
4316 print_table(&(t->proxy->htbl_proxy));
4317#endif
4318 if (asession_temp->serverid == NULL) {
4319 Alert("Found Application Session without matching server.\n");
4320 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01004321 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01004322 while (srv) {
4323 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01004324 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01004325 /* we found the server and it's usable */
4326 t->flags &= ~SN_CK_MASK;
4327 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
4328 t->srv = srv;
4329 break;
4330 } else {
4331 t->flags &= ~SN_CK_MASK;
4332 t->flags |= SN_CK_DOWN;
4333 }
4334 }
4335 srv = srv->next;
4336 }
4337 }
4338}
4339
4340
Willy Tarreaub2513902006-12-17 14:52:38 +01004341/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004342 * In a GET or HEAD request, check if the requested URI matches the stats uri
4343 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01004344 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004345 * It is assumed that the request is either a HEAD or GET and that the
4346 * t->be->fiprm->uri_auth field is valid. An HTTP/401 response may be sent, or
4347 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01004348 *
4349 * Returns 1 if the session's state changes, otherwise 0.
4350 */
4351int stats_check_uri_auth(struct session *t, struct proxy *backend)
4352{
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004353 struct http_req *hreq = &t->hreq;
Willy Tarreaub2513902006-12-17 14:52:38 +01004354 struct uri_auth *uri_auth = backend->uri_auth;
4355 struct user_auth *user;
4356 int authenticated, cur_idx;
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004357 char *h;
Willy Tarreaub2513902006-12-17 14:52:38 +01004358
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004359 /* check URI size */
4360 if (uri_auth->uri_len > hreq->req.sl.rq.u_l)
Willy Tarreaub2513902006-12-17 14:52:38 +01004361 return 0;
4362
Willy Tarreau8d5d7f22007-01-21 19:16:41 +01004363 h = t->req->data + hreq->req.sl.rq.u;
4364
Willy Tarreau0214c3a2007-01-07 13:47:30 +01004365 /* the URI is in h */
4366 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01004367 return 0;
4368
4369 /* we are in front of a interceptable URI. Let's check
4370 * if there's an authentication and if it's valid.
4371 */
4372 user = uri_auth->users;
4373 if (!user) {
4374 /* no user auth required, it's OK */
4375 authenticated = 1;
4376 } else {
4377 authenticated = 0;
4378
4379 /* a user list is defined, we have to check.
4380 * skip 21 chars for "Authorization: Basic ".
4381 */
4382
4383 /* FIXME: this should move to an earlier place */
4384 cur_idx = 0;
Willy Tarreau83969f42007-01-22 08:55:47 +01004385 h = t->req->data + hreq->req.sor + hdr_idx_first_pos(&hreq->hdr_idx);
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004386 while ((cur_idx = hreq->hdr_idx.v[cur_idx].next)) {
4387 int len = hreq->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01004388 if (len > 14 &&
4389 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004390 hreq->auth_hdr.str = h;
4391 hreq->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01004392 break;
4393 }
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004394 h += len + hreq->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01004395 }
4396
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004397 if (hreq->auth_hdr.len < 21 ||
4398 memcmp(hreq->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01004399 user = NULL;
4400
4401 while (user) {
Willy Tarreau0f7562b2007-01-07 15:46:13 +01004402 if ((hreq->auth_hdr.len == user->user_len + 14 + 7)
4403 && !memcmp(hreq->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01004404 user->user_pwd, user->user_len)) {
4405 authenticated = 1;
4406 break;
4407 }
4408 user = user->next;
4409 }
4410 }
4411
4412 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01004413 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01004414
4415 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01004416 msg.str = trash;
4417 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreaub2513902006-12-17 14:52:38 +01004418 t->logs.status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01004419 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01004420 if (!(t->flags & SN_ERR_MASK))
4421 t->flags |= SN_ERR_PRXCOND;
4422 if (!(t->flags & SN_FINST_MASK))
4423 t->flags |= SN_FINST_R;
4424 return 1;
4425 }
4426
4427 /* The request is valid, the user is authenticate. Let's start sending
4428 * data.
4429 */
4430 t->cli_state = CL_STSHUTR;
4431 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
4432 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
4433 t->data_source = DATA_SRC_STATS;
4434 t->data_state = DATA_ST_INIT;
4435 produce_content(t);
4436 return 1;
4437}
4438
4439
Willy Tarreaubaaee002006-06-26 02:48:02 +02004440/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01004441 * Print a debug line with a header
4442 */
4443void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
4444{
4445 int len, max;
4446 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
4447 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
4448 max = end - start;
4449 UBOUND(max, sizeof(trash) - len - 1);
4450 len += strlcpy2(trash + len, start, max + 1);
4451 trash[len++] = '\n';
4452 write(1, trash, len);
4453}
4454
4455
4456/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02004457 * Local variables:
4458 * c-indent-level: 8
4459 * c-basic-offset: 8
4460 * End:
4461 */