blob: b5f974a4495906f8756803c9cae75cdc8658a6f8 [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
208static struct http_method_desc http_methods[26][3] = {
209 ['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 Tarreaubaaee002006-06-26 02:48:02 +0200233#ifdef DEBUG_FULL
234static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
235static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
236#endif
237
238
239/*
240 * returns a message to the client ; the connection is shut down for read,
241 * and the request is cleared so that no server connection can be initiated.
242 * The client must be in a valid state for this (HEADER, DATA ...).
Willy Tarreau0f772532006-12-23 20:51:41 +0100243 * Nothing is performed on the server side. The message is contained in a
244 * "chunk". If it is null, then an empty message is used.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200245 * The reply buffer doesn't need to be empty before this.
246 */
Willy Tarreau0f772532006-12-23 20:51:41 +0100247void client_retnclose(struct session *s, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200248{
Willy Tarreau2a429502006-10-15 14:52:29 +0200249 MY_FD_CLR(s->cli_fd, StaticReadEvent);
250 MY_FD_SET(s->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +0200251 tv_eternity(&s->req->rex);
Willy Tarreau73de9892006-11-30 11:40:23 +0100252 if (s->fe->clitimeout)
253 tv_delayfrom(&s->rep->wex, &now, s->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200254 else
Willy Tarreaud7971282006-07-29 18:36:34 +0200255 tv_eternity(&s->rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200256 shutdown(s->cli_fd, SHUT_RD);
257 s->cli_state = CL_STSHUTR;
258 buffer_flush(s->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100259 if (msg->len)
260 buffer_write(s->rep, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200261 s->req->l = 0;
262}
263
264
265/*
266 * returns a message into the rep buffer, and flushes the req buffer.
Willy Tarreau0f772532006-12-23 20:51:41 +0100267 * The reply buffer doesn't need to be empty before this. The message
268 * is contained in a "chunk". If it is null, then an empty message is
269 * used.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200270 */
Willy Tarreau0f772532006-12-23 20:51:41 +0100271void client_return(struct session *s, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200272{
273 buffer_flush(s->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100274 if (msg->len)
275 buffer_write(s->rep, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200276 s->req->l = 0;
277}
278
279
280/* This function turns the server state into the SV_STCLOSE, and sets
Willy Tarreau0f772532006-12-23 20:51:41 +0100281 * indicators accordingly. Note that if <status> is 0, or if the message
282 * pointer is NULL, then no message is returned.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200283 */
284void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreau0f772532006-12-23 20:51:41 +0100285 int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200286{
287 t->srv_state = SV_STCLOSE;
Willy Tarreau0f772532006-12-23 20:51:41 +0100288 if (status > 0 && msg) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200289 t->logs.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100290 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100291 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200292 }
293 if (!(t->flags & SN_ERR_MASK))
294 t->flags |= err;
295 if (!(t->flags & SN_FINST_MASK))
296 t->flags |= finst;
297}
298
Willy Tarreau80587432006-12-24 17:47:20 +0100299/* This function returns the appropriate error location for the given session
300 * and message.
301 */
302
303struct chunk *error_message(struct session *s, int msgnum)
304{
305 if (s->be->beprm->errmsg[msgnum].str)
306 return &s->be->beprm->errmsg[msgnum];
307 else if (s->fe->errmsg[msgnum].str)
308 return &s->fe->errmsg[msgnum];
309 else
310 return &http_err_chunks[msgnum];
311}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200312
Willy Tarreau53b6c742006-12-17 13:37:46 +0100313/*
314 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
315 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
316 */
317static http_meth_t find_http_meth(const char *str, const int len)
318{
319 unsigned char m;
320 struct http_method_desc *h;
321
322 m = ((unsigned)*str - 'A');
323
324 if (m < 26) {
325 int l;
326 for (h = http_methods[m]; (l = (h->len)) > 0; h++) {
327 if (len <= l)
328 continue;
329
330 if (str[l] != ' ' && str[l] != '\t')
331 continue;
332
333 if (memcmp(str, h->text, l) == 0) {
334 return h->meth;
335 }
336 };
337 return HTTP_METH_OTHER;
338 }
339 return HTTP_METH_NONE;
340
341}
342
343
Willy Tarreaubaaee002006-06-26 02:48:02 +0200344/* Processes the client and server jobs of a session task, then
345 * puts it back to the wait queue in a clean state, or
346 * cleans up its resources if it must be deleted. Returns
347 * the time the task accepts to wait, or TIME_ETERNITY for
348 * infinity.
349 */
350int process_session(struct task *t)
351{
352 struct session *s = t->context;
353 int fsm_resync = 0;
354
355 do {
356 fsm_resync = 0;
357 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
358 fsm_resync |= process_cli(s);
359 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
360 fsm_resync |= process_srv(s);
361 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
362 } while (fsm_resync);
363
364 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
365 struct timeval min1, min2;
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200366 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
367 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200368
Willy Tarreaud7971282006-07-29 18:36:34 +0200369 tv_min(&min1, &s->req->rex, &s->req->wex);
370 tv_min(&min2, &s->rep->rex, &s->rep->wex);
371 tv_min(&min1, &min1, &s->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200372 tv_min(&t->expire, &min1, &min2);
373
374 /* restore t to its place in the task list */
375 task_queue(t);
376
377#ifdef DEBUG_FULL
378 /* DEBUG code : this should never ever happen, otherwise it indicates
379 * that a task still has something to do and will provoke a quick loop.
380 */
381 if (tv_remain2(&now, &t->expire) <= 0)
382 exit(100);
383#endif
384
385 return tv_remain2(&now, &t->expire); /* nothing more to do */
386 }
387
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100388 s->fe->feconn--;
389 if (s->flags & SN_BE_ASSIGNED)
390 s->be->beprm->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200391 actconn--;
392
393 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
394 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100395 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreau830ff452006-12-17 19:31:23 +0100396 s->uniq_id, s->be->beprm->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100397 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200398 write(1, trash, len);
399 }
400
401 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
Willy Tarreau35d66b02007-01-02 00:28:21 +0100402 if (s->req != NULL)
403 s->logs.bytes_in = s->req->total;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200404 if (s->rep != NULL)
Willy Tarreau35d66b02007-01-02 00:28:21 +0100405 s->logs.bytes_out = s->rep->total;
406
407 s->fe->bytes_in += s->logs.bytes_in;
408 s->fe->bytes_out += s->logs.bytes_out;
409 if (s->be->beprm != s->fe) {
410 s->be->beprm->bytes_in += s->logs.bytes_in;
411 s->be->beprm->bytes_out += s->logs.bytes_out;
412 }
413 if (s->srv) {
414 s->srv->bytes_in += s->logs.bytes_in;
415 s->srv->bytes_out += s->logs.bytes_out;
416 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200417
418 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200419 if (s->logs.logwait &&
420 !(s->flags & SN_MONITOR) &&
Willy Tarreau73de9892006-11-30 11:40:23 +0100421 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total))
Willy Tarreaubaaee002006-06-26 02:48:02 +0200422 sess_log(s);
423
424 /* the task MUST not be in the run queue anymore */
425 task_delete(t);
426 session_free(s);
427 task_free(t);
428 return TIME_ETERNITY; /* rest in peace for eternity */
429}
430
431
432/*
433 * FIXME: This should move to the HTTP_flow_analyzer code
434 */
435
436/*
437 * manages the client FSM and its socket. BTW, it also tries to handle the
438 * cookie. It returns 1 if a state has changed (and a resync may be needed),
439 * 0 else.
440 */
441int process_cli(struct session *t)
442{
443 int s = t->srv_state;
444 int c = t->cli_state;
445 struct buffer *req = t->req;
446 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100447 int delete_header = 0;
448
Willy Tarreaub2513902006-12-17 14:52:38 +0100449 int cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200450
Willy Tarreau45e73e32006-12-17 00:05:15 +0100451 DPRINTF(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
Willy Tarreaubaaee002006-06-26 02:48:02 +0200452 cli_stnames[c], srv_stnames[s],
Willy Tarreau2a429502006-10-15 14:52:29 +0200453 MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
Willy Tarreaud7971282006-07-29 18:36:34 +0200454 req->rex.tv_sec, req->rex.tv_usec,
455 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau45e73e32006-12-17 00:05:15 +0100456
Willy Tarreaubaaee002006-06-26 02:48:02 +0200457 if (c == CL_STHEADERS) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100458 /*
459 * Now parse the partial (or complete) lines.
460 * We will check the request syntax, and also join multi-line
461 * headers. An index of all the lines will be elaborated while
462 * parsing.
463 *
464 * For the parsing, we use a 10 states FSM.
465 *
466 * RFC2616 requires that both LF and CRLF are recognized as
467 * line breaks, but that any other combination is an error.
468 * To avoid duplicating all the states above to check for CR,
469 * we use a special bit HTTP_PA_LF_EXP that we 'OR' with the
470 * state we will switch to if the LF is seen, so that we know
471 * whether there's a pending CR or not. We can check it
472 * globally since all CR followed by anything but LF are
473 * errors. Each state is entered with the first character is
474 * has to process at req->lr. We also have HTTP_PA_CR_SKIP
475 * indicating that a CR has been seen on current line and
476 * skipped.
477 *
478 * Here is the information we currently have :
Willy Tarreau45e73e32006-12-17 00:05:15 +0100479 * req->data + req->sor = beginning of request
480 * req->data + req->eoh = end of (parsed) headers
Willy Tarreau58f10d72006-12-04 02:26:12 +0100481 * req->lr = first non-visited byte
482 * req->r = end of data
483 */
484
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100485 char *sol, *eol; /* Start Of Line, End Of Line */
Willy Tarreau830ff452006-12-17 19:31:23 +0100486 struct proxy *cur_proxy;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100487
Willy Tarreau45e73e32006-12-17 00:05:15 +0100488 eol = sol = req->data + t->hreq.eoh;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100489
Willy Tarreau58f10d72006-12-04 02:26:12 +0100490 while (req->lr < req->r) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100491 int parse;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200492
Willy Tarreau45e73e32006-12-17 00:05:15 +0100493 FSM_PRINTF(stderr, "WHL: hdr_st=0x%02x, hdr_used=%d hdr_tail=%d hdr_last=%d, h=%d, lr=%d, r=%d, eoh=%d\n",
494 t->hreq.hdr_state, t->hreq.hdr_idx.used, t->hreq.hdr_idx.tail, t->hreq.hdr_idx.last,
495 sol - req->data, req->lr - req->data, req->r - req->data, t->hreq.eoh);
496
497 if (t->hreq.hdr_state & HTTP_PA_LF_EXP) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100498 if (*req->lr != '\n') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100499 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100500 break;
501 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100502 t->hreq.hdr_state &= ~HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100503 }
504
Willy Tarreau45e73e32006-12-17 00:05:15 +0100505 parse = t->hreq.hdr_state & ~HTTP_PA_CR_SKIP;;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100506
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100507 if (parse == HTTP_PA_HDR_LF) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100508 parse_hdr_lf:
509 /* The LF validating last header, but it
510 * may also be an LWS, in which case we will
511 * need more data to know if we can close this
512 * header or not. However, we must check right
513 * now if this LF/CRLF closes an empty line, in
514 * which case it means the end of the request.
515 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100516 eol = req->lr;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100517 if (t->hreq.hdr_state & HTTP_PA_CR_SKIP)
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100518 eol--; /* Get back to the CR */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100519
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100520 if (eol == sol) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100521 /* We have found the end of the headers.
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100522 * sol points to the ending LF/CRLF,
Willy Tarreau58f10d72006-12-04 02:26:12 +0100523 * and req->lr points to the first byte
524 * after the LF, so it is easy to append
525 * anything there.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200526 */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100527 t->hreq.hdr_state = HTTP_PA_LFLF;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100528 QUICK_JUMP(parse_lflf, continue);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100529 }
530
531 if (req->lr + 1 >= req->r) /* LF, ?? */
532 break;
533 req->lr++;
534
535 /* Right now, we *know* that there is one char
536 * available at req->lr.
537 */
538
539 if (*req->lr == ' ' || *req->lr == '\t') {
540 /* We have an LWS, we will replace the
541 * CR and LF with spaces as RFC2616
542 * allows it. <lr> now points to the
543 * first space char of the LWS part.
544 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100545 for (;eol < req->lr; eol++)
546 *eol = ' ';
Willy Tarreau58f10d72006-12-04 02:26:12 +0100547
Willy Tarreau45e73e32006-12-17 00:05:15 +0100548 t->hreq.hdr_state = HTTP_PA_HDR_LWS;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100549 QUICK_JUMP(parse_hdr_lws, continue);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100550 }
551
552 /**********************************************
553 * We now have one complete header between *
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100554 * sol and eol, with a possible CR at eol, *
Willy Tarreau58f10d72006-12-04 02:26:12 +0100555 * everything ending before req->lr. Some very*
556 * early processing can be applied. *
557 **********************************************/
558
559 /*
560 * FIXME: insert a REQHEADER hook here.
561 * For instance, we could check the header's
562 * syntax such as forbidding the leading space
563 * in the first header (Apache also has the same problem)
564 */
565
566
567 /* 1: we might have to print this header */
568 if ((global.mode & MODE_DEBUG) &&
569 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100570 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100571
572
573 /* 2: maybe we have to copy this header for the logs ? */
574 if (t->logs.logwait & LW_REQHDR) {
575 /* FIXME: we must *search* the value after the ':' and not
576 * consider that it's necessary after one single space.*/
577 struct cap_hdr *h;
578 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +0100579 for (h = t->fe->fiprm->req_cap; h; h = h->next) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100580 if ((h->namelen + 2 <= eol - sol) &&
581 (sol[h->namelen] == ':') &&
582 (strncasecmp(sol, h->name, h->namelen) == 0)) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100583 if (t->hreq.cap[h->index] == NULL)
584 t->hreq.cap[h->index] =
585 pool_alloc_from(h->pool, h->len + 1);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100586
Willy Tarreau45e73e32006-12-17 00:05:15 +0100587 if (t->hreq.cap[h->index] == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100588 Alert("HTTP capture : out of memory.\n");
589 continue;
590 }
591
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100592 len = eol - (sol + h->namelen + 2);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100593 if (len > h->len)
594 len = h->len;
595
Willy Tarreau45e73e32006-12-17 00:05:15 +0100596 memcpy(t->hreq.cap[h->index], sol + h->namelen + 2, len);
597 t->hreq.cap[h->index][len]=0;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100598 }
599 }
600 }
601
602
603 /* 3: We might need to remove "connection:" */
Willy Tarreaue01954f2006-12-30 23:43:54 +0100604 if (!delete_header &&
605 ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) &&
606 (strncasecmp(sol, "Connection:", 11) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100607 delete_header = 1;
608 }
609
610
Willy Tarreau58f10d72006-12-04 02:26:12 +0100611 /* OK, that's enough processing for the first step.
612 * Now either we index this header or we remove it.
613 */
614
615 if (!delete_header) {
616 /* we insert it into the index */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100617 if (hdr_idx_add(eol - sol, req->lr - eol - 1,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100618 &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0) {
619 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100620 break;
621 }
622 } else {
623 /* we remove it */
624 delete_header = 0;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100625 buffer_replace2(req, sol, req->lr, NULL, 0);
626 /* WARNING: eol is not valid anymore, since the
Willy Tarreau58f10d72006-12-04 02:26:12 +0100627 * header may have been deleted or truncated ! */
628 }
629
630 /* In any case, we set the next header pointer
631 * to the next line.
632 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100633 sol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100634
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100635#ifdef DEBUG_PARSE_NO_SPEEDUP
636 t->hreq.hdr_state = HTTP_PA_HEADER;
637 continue;
638#else
Willy Tarreau58f10d72006-12-04 02:26:12 +0100639 /*
640 * We know that at least one character remains.
641 * It is interesting to directly branch to the
642 * matching state.
643 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100644 eol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100645 if (IS_CTL(*req->lr)) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100646 if (*eol == '\r') {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100647 req->lr++;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100648 t->hreq.hdr_state = HTTP_PA_LFLF | HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100649 continue;
650 }
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100651 else if (*eol == '\n') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100652 t->hreq.hdr_state = HTTP_PA_LFLF;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100653 goto parse_lflf;
654 }
655 else {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100656 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100657 break;
658 }
659 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100660 t->hreq.hdr_state = HTTP_PA_HEADER;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100661 goto parse_inside_hdr;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100662#endif
663
664 } else if (parse == HTTP_PA_STRT_LF) {
665 parse_strt_lf:
666 /* The LF validating the request line */
667
668 eol = req->lr;
669 if (t->hreq.hdr_state & HTTP_PA_CR_SKIP)
670 eol--; /* Get back to the CR */
671
672 /* We have the complete start line between
673 * sol and eol (excluded). lr points to
674 * the LF.
675 */
676
677 /* FIXME: insert a REQUESTURI hook here. */
678
679
680 /* 1: we might have to print this header */
681 if ((global.mode & MODE_DEBUG) &&
682 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
683 debug_hdr("clireq", t, sol, eol);
684
685 /* 2: maybe we have to copy the original REQURI for the logs ? */
686 if (t->logs.logwait & LW_REQ) {
687 /* we have a complete HTTP request that we must log */
688 if ((t->logs.uri = pool_alloc(requri)) != NULL) {
689 int urilen = eol - sol;
690
691 if (urilen >= REQURI_LEN)
692 urilen = REQURI_LEN - 1;
693 memcpy(t->logs.uri, sol, urilen);
694 t->logs.uri[urilen] = 0;
695
696 if (!(t->logs.logwait &= ~LW_REQ))
697 sess_log(t);
698 } else {
699 Alert("HTTP logging : out of memory.\n");
700 }
701 }
702
703 /* 3: reference this line as the start line */
704 if (hdr_idx_add(eol - sol, req->lr - eol,
705 &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0) {
706 t->hreq.hdr_state = HTTP_PA_ERROR;
707 break;
708 }
709
710 req->lr++;
711 sol = req->lr;
712 /* in fact, a state is missing here, we should
713 * be able to distinguish between an empty line
714 * and a header.
715 */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100716 t->hreq.hdr_state = HTTP_PA_HEADER;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100717#ifdef DEBUG_PARSE_NO_SPEEDUP
Willy Tarreau58f10d72006-12-04 02:26:12 +0100718 continue;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100719#else
720 if (req->lr < req->r)
721 goto parse_inside_hdr;
722 else
723 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100724#endif
725
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100726 } else if (parse == HTTP_PA_HEADER) {
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100727 char *ptr;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100728 /* Inside a non-empty header */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100729
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100730 parse_inside_hdr:
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100731 delete_header = 0;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100732
733 ptr = req->lr;
734
735#ifdef GCC_FINALLY_PRODUCES_EFFICIENT_WHILE_LOOPS
736 /* This code is disabled right now because
737 * eventhough it seems straightforward, the
738 * object code produced by GCC is so much
739 * suboptimal that about 10% of the time
740 * spend parsing header is there.
741 */
742 while (ptr < req->r && !IS_CTL(*ptr))
743 ptr++;
744 req->lr = ptr;
745 if (ptr == req->r)
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100746 break;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100747#else
748 /* Just by using this loop instead of the previous one,
749 * the global performance increases by about 2% ! The
750 * code is also smaller by about 50 bytes.
751 */
752 goto reqhdr_loop_chk;
753 reqhdr_loop:
754 ptr++;
755 reqhdr_loop_chk:
756 if (ptr == req->r) {
757 req->lr = ptr;
758 break;
759 }
760 if (*ptr != 0x7F && (unsigned)*ptr >= 0x20)
761 goto reqhdr_loop;
762 req->lr = ptr;
763#endif
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100764
765 /* we have a CTL char */
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100766 if (*ptr == '\r') {
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100767 t->hreq.hdr_state = HTTP_PA_HDR_LF | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
768 req->lr++;
769 continue;
770 }
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100771 else if (*ptr == '\n') {
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100772 t->hreq.hdr_state = HTTP_PA_HDR_LF;
773 QUICK_JUMP(parse_hdr_lf, continue);
774 }
775 t->hreq.hdr_state = HTTP_PA_ERROR;
776 break;
777
778 } else if (parse == HTTP_PA_EMPTY) {
779 /* leading empty lines */
780
781 if (*req->lr == '\n') {
782 req->lr ++;
783 t->hreq.hdr_state = HTTP_PA_EMPTY;
784 continue;
785 }
786 else if (*req->lr == '\r') {
787 req->lr ++;
788 t->hreq.hdr_state = HTTP_PA_EMPTY | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
789 continue;
790 }
791
792 FSM_PRINTF(stderr, "PA_EMPTY[0]: h=%d, lr=%d, r=%d\n",
793 sol - req->data, req->lr - req->data, req->r - req->data);
794
795#if PARSE_PRESERVE_EMPTY_LINES
796 /* only skip empty leading lines, don't remove them */
797 t->hreq.hdr_idx.v[0].len = req->lr - sol;
798 t->hreq.sor = t->hreq.hdr_idx.v[0].len;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100799#else
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100800 /* remove empty leading lines, as recommended by
801 * RFC2616. This takes a lot of time because we
802 * must move all the buffer backwards, but this
803 * is rarely needed. The method above will be
804 * cleaner when we'll be able to start sending
805 * the request from any place in the buffer.
806 */
807 buffer_replace2(req, sol, req->lr, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100808#endif
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100809 sol = req->lr;
810 FSM_PRINTF(stderr, "PA_EMPTY[1]: h=%d, lr=%d, r=%d\n",
811 sol - req->data, req->lr - req->data, req->r - req->data);
812
813 t->hreq.hdr_state = HTTP_PA_START;
814 /* we know that we still have one char available */
815 QUICK_JUMP(parse_start, continue);
816
817 } else if (parse == HTTP_PA_START) {
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100818 char *ptr;
819 /* Inside the start line */
820
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100821 parse_start:
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100822 ptr = req->lr;
823
824#ifdef GCC_FINALLY_PRODUCES_EFFICIENT_WHILE_LOOPS
825 /* This code is disabled right now because
826 * eventhough it seems straightforward, the
827 * object code produced by GCC is so much
828 * suboptimal that about 10% of the time
829 * spend parsing header is there.
830 */
831 while (ptr < req->r && !IS_CTL(*ptr))
832 ptr++;
833 req->lr = ptr;
834 if (ptr == req->r)
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100835 break;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100836#else
837 /* Just by using this loop instead of the previous one,
838 * the global performance increases by about 2% ! The
839 * code is also smaller by about 50 bytes.
840 */
841 goto reqstrt_loop_chk;
842 reqstrt_loop:
843 ptr++;
844 reqstrt_loop_chk:
845 if (ptr == req->r) {
846 req->lr = ptr;
847 break;
848 }
849 if (*ptr != 0x7F && (unsigned)*ptr >= 0x20)
850 goto reqstrt_loop;
851 req->lr = ptr;
852#endif
853
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100854 /* we have a CTL char */
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100855 if (*ptr == '\r') {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100856 req->lr++;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100857 t->hreq.hdr_state = HTTP_PA_STRT_LF | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
858 continue;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100859 }
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100860 else if (*ptr == '\n') {
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100861 t->hreq.hdr_state = HTTP_PA_STRT_LF;
862 /* we know that we still have one char available */
863 QUICK_JUMP(parse_strt_lf, continue);
864 }
865 t->hreq.hdr_state = HTTP_PA_ERROR;
866 break;
867
Willy Tarreau58f10d72006-12-04 02:26:12 +0100868
869 } else if (parse == HTTP_PA_LFLF) {
870 parse_lflf:
871 req->lr ++;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100872 /* sol points to either CR or CRLF, and
Willy Tarreau58f10d72006-12-04 02:26:12 +0100873 * req->lr points to 1 char after LF.
874 */
875
876 /*
877 * FIXME: insert a hook here for the end of the headers
878 */
879 break;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100880
881 } else if (parse == HTTP_PA_HDR_LWS) {
882 parse_hdr_lws:
883 /* Inside an LWS. We just replace tabs with
884 * spaces and fall back to the HEADER state
885 * at the first non-space character
886 */
887
888 while (req->lr < req->r) {
889 if (*req->lr == '\t')
890 *req->lr = ' ';
891 else if (*req->lr != ' ') {
892 t->hreq.hdr_state = HTTP_PA_HEADER;
893 QUICK_JUMP(parse_inside_hdr, break);
894 }
895 req->lr++;
896 }
897 continue;
898
Willy Tarreau58f10d72006-12-04 02:26:12 +0100899 } else if (parse == HTTP_PA_ERROR) {
900 break;
901 }
902
903 } /* end of the "while(req->lr < req->r)" loop */
904
Willy Tarreau45e73e32006-12-17 00:05:15 +0100905 /* update the end of headers */
906 t->hreq.eoh = sol - req->data;
907
908 FSM_PRINTF(stderr, "END: hdr_st=0x%02x, hdr_used=%d hdr_tail=%d hdr_last=%d, h=%d, lr=%d, r=%d, eoh=%d\n",
909 t->hreq.hdr_state, t->hreq.hdr_idx.used, t->hreq.hdr_idx.tail, t->hreq.hdr_idx.last,
910 sol - req->data, req->lr - req->data, req->r - req->data, t->hreq.eoh);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100911
912 /*
913 * Now, let's catch bad requests.
914 */
915
Willy Tarreau06619262006-12-17 08:37:22 +0100916 if (t->hreq.hdr_state == HTTP_PA_ERROR)
917 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100918
919 /*
920 * Now we quickly check if we have found a full request.
921 * If not so, we check the FD and buffer states before leaving.
922 * A full request is indicated by the fact that we have seen
923 * the double LF/CRLF, so the state is HTTP_PA_LFLF.
924 *
925 */
926
Willy Tarreau45e73e32006-12-17 00:05:15 +0100927 if (t->hreq.hdr_state != HTTP_PA_LFLF) { /* Request not complete yet */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100928
929 /* 1: Since we are in header mode, if there's no space
930 * left for headers, we won't be able to free more
931 * later, so the session will never terminate. We
932 * must terminate it now.
933 */
934 if (req->l >= req->rlim - req->data) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100935 /* FIXME: check if hreq.hdr_state & mask < HTTP_PA_HEADER,
Willy Tarreau58f10d72006-12-04 02:26:12 +0100936 * and return Status 414 Request URI too long instead.
937 */
Willy Tarreau06619262006-12-17 08:37:22 +0100938 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100939 }
940
941 /* 2: have we encountered a read error or a close ? */
942 else if (req->flags & (BF_READ_ERROR | BF_READ_NULL)) {
943 /* read error, or last read : give up. */
944 tv_eternity(&req->rex);
945 fd_delete(t->cli_fd);
946 t->cli_state = CL_STCLOSE;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +0100947 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100948 if (!(t->flags & SN_ERR_MASK))
949 t->flags |= SN_ERR_CLICL;
950 if (!(t->flags & SN_FINST_MASK))
951 t->flags |= SN_FINST_R;
952 return 1;
953 }
954
955 /* 3: has the read timeout expired ? */
956 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
957 /* read timeout : give up with an error message. */
958 t->logs.status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +0100959 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +0100960 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100961 if (!(t->flags & SN_ERR_MASK))
962 t->flags |= SN_ERR_CLITO;
963 if (!(t->flags & SN_FINST_MASK))
964 t->flags |= SN_FINST_R;
965 return 1;
966 }
967
968 /* 4: do we need to re-enable the read socket ? */
969 else if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
970 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
971 * full. We cannot loop here since stream_sock_read will disable it only if
972 * req->l == rlim-data
973 */
974 MY_FD_SET(t->cli_fd, StaticReadEvent);
975 if (t->fe->clitimeout)
976 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
977 else
978 tv_eternity(&req->rex);
979 }
980 return t->cli_state != CL_STHEADERS;
981 }
982
983
984 /****************************************************************
985 * More interesting part now : we know that we have a complete *
986 * request which at least looks like HTTP. We have an indicator *
987 * of each header's length, so we can parse them quickly. *
988 ****************************************************************/
989
990
991 /*
Willy Tarreau06619262006-12-17 08:37:22 +0100992 * 1: check if the URI matches the monitor_uri.
993 * We have to do this for every request which gets in, because
994 * the monitor-uri is defined by the frontend. To speed-up the
995 * test, we include the leading and trailing spaces in the
996 * comparison. This is generally not a problem because the
997 * monitor-uri is primarily used by external checkers which
998 * send pre-formatted requests too.
Willy Tarreau58f10d72006-12-04 02:26:12 +0100999 */
1000
Willy Tarreau06619262006-12-17 08:37:22 +01001001 t->hreq.start.str = req->data + t->hreq.sor; /* start of the REQURI */
1002 t->hreq.start.len = t->hreq.hdr_idx.v[t->hreq.hdr_idx.v[0].next].len; /* end of the REQURI */
Willy Tarreaub2513902006-12-17 14:52:38 +01001003 t->hreq.meth = find_http_meth(t->hreq.start.str, t->hreq.start.len);
Willy Tarreau06619262006-12-17 08:37:22 +01001004
1005 if ((t->fe->monitor_uri_len != 0) &&
1006 (t->hreq.start.len >= t->fe->monitor_uri_len)) {
1007 char *p = t->hreq.start.str;
1008 int idx = 0;
1009
1010 /* skip the method so that we accept any method */
1011 while (idx < t->hreq.start.len && p[idx] != ' ')
1012 idx++;
1013 p += idx;
1014
1015 if (t->hreq.start.len - idx >= t->fe->monitor_uri_len &&
1016 !memcmp(p, t->fe->monitor_uri, t->fe->monitor_uri_len)) {
1017 /*
1018 * We have found the monitor URI
1019 */
1020 t->flags |= SN_MONITOR;
1021 t->logs.status = 200;
Willy Tarreau0f772532006-12-23 20:51:41 +01001022 client_retnclose(t, &http_200_chunk);
Willy Tarreau06619262006-12-17 08:37:22 +01001023 goto return_prx_cond;
1024 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001025 }
1026
1027
1028 /*
1029 * 2: we will have to evaluate the filters.
1030 * As opposed to version 1.2, now they will be evaluated in the
1031 * filters order and not in the header order. This means that
1032 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001033 *
1034 * We can now check whether we want to switch to another
1035 * backend, in which case we will re-check the backend's
1036 * filters and various options. In order to support 3-level
1037 * switching, here's how we should proceed :
1038 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001039 * a) run be->fiprm.
1040 * if (switch) then switch ->be to the new backend.
1041 * b) run be->fiprm if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001042 * There cannot be any switch from there, so ->be cannot be
1043 * changed anymore.
1044 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001045 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001046 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001047 * The response path will be able to apply either ->be, or
1048 * ->be then ->fe filters in order to match the reverse of
1049 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001050 */
1051
Willy Tarreau06619262006-12-17 08:37:22 +01001052 do {
Willy Tarreau830ff452006-12-17 19:31:23 +01001053 struct proxy *rule_set = t->be->fiprm;
1054 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001055
Willy Tarreau06619262006-12-17 08:37:22 +01001056 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01001057 if (rule_set->req_exp != NULL) {
Willy Tarreau06619262006-12-17 08:37:22 +01001058 apply_filters_to_session(t, req, rule_set->req_exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001059
Willy Tarreau53b6c742006-12-17 13:37:46 +01001060 /* the start line might have been modified */
1061 t->hreq.start.len = t->hreq.hdr_idx.v[t->hreq.hdr_idx.v[0].next].len;
1062 t->hreq.meth = find_http_meth(t->hreq.start.str, t->hreq.start.len);
Willy Tarreau53b6c742006-12-17 13:37:46 +01001063 }
1064
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001065 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
1066 /* to ensure correct connection accounting on
1067 * the backend, we count the connection for the
1068 * one managing the queue.
1069 */
1070 t->be->beprm->beconn++;
1071 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1072 t->be->beprm->beconn_max = t->be->beprm->beconn;
1073 t->be->beprm->cum_beconn++;
1074 t->flags |= SN_BE_ASSIGNED;
1075 }
1076
Willy Tarreau06619262006-12-17 08:37:22 +01001077 /* has the request been denied ? */
1078 if (t->flags & SN_CLDENY) {
1079 /* no need to go further */
1080 t->logs.status = 403;
1081 /* let's log the request time */
1082 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreau80587432006-12-24 17:47:20 +01001083 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01001084 goto return_prx_cond;
1085 }
1086
1087 /* add request headers from the rule sets in the same order */
1088 for (cur_hdr = 0; cur_hdr < rule_set->nb_reqadd; cur_hdr++) {
1089 int len;
1090
1091 len = sprintf(trash, "%s\r\n", rule_set->req_add[cur_hdr]);
1092 len = buffer_replace2(req, req->data + t->hreq.eoh,
1093 req->data + t->hreq.eoh, trash, len);
1094 t->hreq.eoh += len;
1095
1096 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1097 goto return_bad_req;
1098 }
Willy Tarreaub2513902006-12-17 14:52:38 +01001099
1100 if (rule_set->uri_auth != NULL && t->hreq.meth == HTTP_METH_GET) {
1101 /* we have to check the URI and auth for this request */
1102 if (stats_check_uri_auth(t, rule_set))
1103 return 1;
1104 }
1105
Willy Tarreau5fdfb912007-01-01 23:11:07 +01001106 if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
1107 /* No backend was set, but there was a default
1108 * backend set in the frontend, so we use it and
1109 * loop again.
1110 */
1111 t->be = cur_proxy->defbe.be;
1112 t->be->beprm->beconn++;
1113 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1114 t->be->beprm->beconn_max = t->be->beprm->beconn;
1115 t->be->beprm->cum_beconn++;
1116 t->flags |= SN_BE_ASSIGNED;
1117 }
1118 } while (t->be != cur_proxy); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01001119
Willy Tarreau58f10d72006-12-04 02:26:12 +01001120
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001121 if (!(t->flags & SN_BE_ASSIGNED)) {
1122 /* To ensure correct connection accounting on
1123 * the backend, we count the connection for the
1124 * one managing the queue.
1125 */
1126 t->be->beprm->beconn++;
1127 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1128 t->be->beprm->beconn_max = t->be->beprm->beconn;
1129 t->be->beprm->cum_beconn++;
1130 t->flags |= SN_BE_ASSIGNED;
1131 }
1132
1133
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001134 /*
1135 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01001136 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001137 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01001138 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01001139 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001140
Willy Tarreau58f10d72006-12-04 02:26:12 +01001141
Willy Tarreau58f10d72006-12-04 02:26:12 +01001142
Willy Tarreau58f10d72006-12-04 02:26:12 +01001143
Willy Tarreau2a324282006-12-05 00:05:46 +01001144 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001145 * 3: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01001146 * so let's do the same now.
1147 */
1148
1149 /* It needs to look into the URI */
Willy Tarreau830ff452006-12-17 19:31:23 +01001150 if (t->be->beprm->appsession_name) {
Willy Tarreau06619262006-12-17 08:37:22 +01001151 get_srv_from_appsession(t,
1152 t->hreq.start.str,
1153 t->hreq.start.str + t->hreq.start.len);
1154 }
1155
1156
1157 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001158 * 4: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01001159 * Note that doing so might move headers in the request, but
1160 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01001161 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01001162 */
1163 if (!(t->flags & (SN_CLDENY|SN_CLTARPIT)))
1164 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001165
Willy Tarreau58f10d72006-12-04 02:26:12 +01001166
Willy Tarreau2a324282006-12-05 00:05:46 +01001167 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001168 * 5: add X-Forwarded-For : Should depend on the backend only.
Willy Tarreau2a324282006-12-05 00:05:46 +01001169 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001170 if (t->be->beprm->options & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001171 if (t->cli_addr.ss_family == AF_INET) {
1172 int len;
1173 unsigned char *pn;
1174 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
1175 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
1176 pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001177 len = buffer_replace2(req, req->data + t->hreq.eoh,
1178 req->data + t->hreq.eoh, trash, len);
1179 t->hreq.eoh += len;
1180
Willy Tarreau06619262006-12-17 08:37:22 +01001181 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1182 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001183 }
1184 else if (t->cli_addr.ss_family == AF_INET6) {
1185 int len;
1186 char pn[INET6_ADDRSTRLEN];
1187 inet_ntop(AF_INET6,
1188 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
1189 pn, sizeof(pn));
1190 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001191 len = buffer_replace2(req, req->data + t->hreq.eoh,
1192 req->data + t->hreq.eoh, trash, len);
1193 t->hreq.eoh += len;
1194
Willy Tarreau06619262006-12-17 08:37:22 +01001195 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1196 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001197 }
1198 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001199
Willy Tarreaubaaee002006-06-26 02:48:02 +02001200
Willy Tarreau2a324282006-12-05 00:05:46 +01001201 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001202 * 6: add "Connection:"
Willy Tarreau2a324282006-12-05 00:05:46 +01001203 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001204
Willy Tarreaub2513902006-12-17 14:52:38 +01001205 /* add a "connection: close" line if needed.
1206 * FIXME: this should depend on both the frontend and the backend.
1207 * Header removals should be performed when the filters are run.
1208 */
Willy Tarreaue01954f2006-12-30 23:43:54 +01001209 if ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) {
Willy Tarreau45e73e32006-12-17 00:05:15 +01001210 int len;
1211 len = buffer_replace2(req, req->data + t->hreq.eoh,
1212 req->data + t->hreq.eoh, "Connection: close\r\n", 19);
1213 t->hreq.eoh += len;
1214
Willy Tarreau06619262006-12-17 08:37:22 +01001215 if (hdr_idx_add(17, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1216 goto return_bad_req;
Willy Tarreaue15d9132006-12-14 22:26:42 +01001217 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001218
Willy Tarreaubaaee002006-06-26 02:48:02 +02001219
Willy Tarreaue15d9132006-12-14 22:26:42 +01001220
1221
Willy Tarreau06619262006-12-17 08:37:22 +01001222
Willy Tarreaue15d9132006-12-14 22:26:42 +01001223
Willy Tarreau2a324282006-12-05 00:05:46 +01001224 /*************************************************************
1225 * OK, that's finished for the headers. We have done what we *
1226 * could. Let's switch to the DATA state. *
1227 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02001228
Willy Tarreau2a324282006-12-05 00:05:46 +01001229 t->cli_state = CL_STDATA;
1230 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001231
Willy Tarreau2a324282006-12-05 00:05:46 +01001232 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001233
Willy Tarreaubaaee002006-06-26 02:48:02 +02001234
Willy Tarreau2a324282006-12-05 00:05:46 +01001235 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001236 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001237 /* If the client has no timeout, or if the server is not ready yet,
1238 * and we know for sure that it can expire, then it's cleaner to
1239 * disable the timeout on the client side so that too low values
1240 * cannot make the sessions abort too early.
1241 *
1242 * FIXME-20050705: the server needs a way to re-enable this time-out
1243 * when it switches its state, otherwise a client can stay connected
1244 * indefinitely. This now seems to be OK.
1245 */
1246 tv_eternity(&req->rex);
1247 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001248
Willy Tarreaub8750a82006-09-03 09:56:00 +02001249
Willy Tarreau2a324282006-12-05 00:05:46 +01001250 /* When a connection is tarpitted, we use the queue timeout for the
1251 * tarpit delay, which currently happens to be the server's connect
1252 * timeout. If unset, then set it to zero because we really want it
1253 * to expire at one moment.
1254 */
1255 if (t->flags & SN_CLTARPIT) {
1256 t->req->l = 0;
1257 /* flush the request so that we can drop the connection early
1258 * if the client closes first.
1259 */
1260 tv_delayfrom(&req->cex, &now,
Willy Tarreau830ff452006-12-17 19:31:23 +01001261 t->be->beprm->contimeout ? t->be->beprm->contimeout : 0);
Willy Tarreau2a324282006-12-05 00:05:46 +01001262 }
Willy Tarreaub8750a82006-09-03 09:56:00 +02001263
Willy Tarreau2a324282006-12-05 00:05:46 +01001264#if DEBUG_HTTP_PARSER
1265 /* example: dump each line */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001266
Willy Tarreau2a324282006-12-05 00:05:46 +01001267 fprintf(stderr, "t->flags=0x%08x\n", t->flags & (SN_CLALLOW|SN_CLDENY|SN_CLTARPIT));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001268
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001269 fprintf(stderr, "sol=%d\n", sol - req->data);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001270 sol = req->data + t->hreq.sor;
Willy Tarreau2a324282006-12-05 00:05:46 +01001271 cur_hdr = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001272
Willy Tarreau45e73e32006-12-17 00:05:15 +01001273 cur_idx = t->hreq.hdr_idx.v[0].next;
Willy Tarreau2a324282006-12-05 00:05:46 +01001274 cur_hdr = 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001275
Willy Tarreau45e73e32006-12-17 00:05:15 +01001276 while (cur_hdr < t->hreq.hdr_idx.used) {
1277 eol = sol + t->hreq.hdr_idx.v[cur_idx].len + t->hreq.hdr_idx.v[cur_idx].cr + 1;
Willy Tarreau2a324282006-12-05 00:05:46 +01001278 fprintf(stderr, "lr=%d r=%d hdr=%d idx=%d adr=%d..%d len=%d cr=%d data:\n",
1279 req->lr - req->data, req->r - req->data,
1280 cur_hdr, cur_idx,
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001281 sol - req->data,
Willy Tarreau45e73e32006-12-17 00:05:15 +01001282 sol - req->data + t->hreq.hdr_idx.v[cur_idx].len + t->hreq.hdr_idx.v[cur_idx].cr,
1283 t->hreq.hdr_idx.v[cur_idx].len,
1284 t->hreq.hdr_idx.v[cur_idx].cr);
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001285 write(2, sol, eol - sol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001286
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001287 sol = eol;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001288 cur_idx = t->hreq.hdr_idx.v[cur_idx].next;
Willy Tarreau2a324282006-12-05 00:05:46 +01001289 cur_hdr++;
1290 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001291#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001292
Willy Tarreau06619262006-12-17 08:37:22 +01001293 goto process_data;
1294
1295 return_bad_req: /* let's centralize all bad requests */
1296 t->hreq.hdr_state = HTTP_PA_ERROR;
1297 t->logs.status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01001298 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001299 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01001300 return_prx_cond:
1301 if (!(t->flags & SN_ERR_MASK))
1302 t->flags |= SN_ERR_PRXCOND;
1303 if (!(t->flags & SN_FINST_MASK))
1304 t->flags |= SN_FINST_R;
1305 return 1;
1306
Willy Tarreaubaaee002006-06-26 02:48:02 +02001307 }
1308 else if (c == CL_STDATA) {
1309 process_data:
1310 /* FIXME: this error handling is partly buggy because we always report
1311 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
1312 * or HEADER phase. BTW, it's not logical to expire the client while
1313 * we're waiting for the server to connect.
1314 */
1315 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001316 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001317 tv_eternity(&req->rex);
1318 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001319 fd_delete(t->cli_fd);
1320 t->cli_state = CL_STCLOSE;
1321 if (!(t->flags & SN_ERR_MASK))
1322 t->flags |= SN_ERR_CLICL;
1323 if (!(t->flags & SN_FINST_MASK)) {
1324 if (t->pend_pos)
1325 t->flags |= SN_FINST_Q;
1326 else if (s == SV_STCONN)
1327 t->flags |= SN_FINST_C;
1328 else
1329 t->flags |= SN_FINST_D;
1330 }
1331 return 1;
1332 }
1333 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001334 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001335 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001336 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001337 shutdown(t->cli_fd, SHUT_RD);
1338 t->cli_state = CL_STSHUTR;
1339 return 1;
1340 }
1341 /* last server read and buffer empty */
1342 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001343 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001344 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001345 shutdown(t->cli_fd, SHUT_WR);
1346 /* We must ensure that the read part is still alive when switching
1347 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001348 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001349 if (t->fe->clitimeout)
1350 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001351 t->cli_state = CL_STSHUTW;
1352 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1353 return 1;
1354 }
1355 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001356 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001357 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001358 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001359 shutdown(t->cli_fd, SHUT_RD);
1360 t->cli_state = CL_STSHUTR;
1361 if (!(t->flags & SN_ERR_MASK))
1362 t->flags |= SN_ERR_CLITO;
1363 if (!(t->flags & SN_FINST_MASK)) {
1364 if (t->pend_pos)
1365 t->flags |= SN_FINST_Q;
1366 else if (s == SV_STCONN)
1367 t->flags |= SN_FINST_C;
1368 else
1369 t->flags |= SN_FINST_D;
1370 }
1371 return 1;
1372 }
1373 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001374 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001375 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001376 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001377 shutdown(t->cli_fd, SHUT_WR);
1378 /* We must ensure that the read part is still alive when switching
1379 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001380 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001381 if (t->fe->clitimeout)
1382 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001383
1384 t->cli_state = CL_STSHUTW;
1385 if (!(t->flags & SN_ERR_MASK))
1386 t->flags |= SN_ERR_CLITO;
1387 if (!(t->flags & SN_FINST_MASK)) {
1388 if (t->pend_pos)
1389 t->flags |= SN_FINST_Q;
1390 else if (s == SV_STCONN)
1391 t->flags |= SN_FINST_C;
1392 else
1393 t->flags |= SN_FINST_D;
1394 }
1395 return 1;
1396 }
1397
1398 if (req->l >= req->rlim - req->data) {
1399 /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02001400 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001401 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001402 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001403 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001404 }
1405 } else {
1406 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001407 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1408 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001409 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001410 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001411 /* If the client has no timeout, or if the server not ready yet, and we
1412 * know for sure that it can expire, then it's cleaner to disable the
1413 * timeout on the client side so that too low values cannot make the
1414 * sessions abort too early.
1415 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001416 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001417 else
Willy Tarreau73de9892006-11-30 11:40:23 +01001418 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001419 }
1420 }
1421
1422 if ((rep->l == 0) ||
1423 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001424 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1425 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001426 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001427 }
1428 } else {
1429 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001430 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1431 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001432 if (t->fe->clitimeout) {
1433 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001434 /* FIXME: to prevent the client from expiring read timeouts during writes,
1435 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001436 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001437 }
1438 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001439 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001440 }
1441 }
1442 return 0; /* other cases change nothing */
1443 }
1444 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001445 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001446 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001447 fd_delete(t->cli_fd);
1448 t->cli_state = CL_STCLOSE;
1449 if (!(t->flags & SN_ERR_MASK))
1450 t->flags |= SN_ERR_CLICL;
1451 if (!(t->flags & SN_FINST_MASK)) {
1452 if (t->pend_pos)
1453 t->flags |= SN_FINST_Q;
1454 else if (s == SV_STCONN)
1455 t->flags |= SN_FINST_C;
1456 else
1457 t->flags |= SN_FINST_D;
1458 }
1459 return 1;
1460 }
1461 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
1462 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001463 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001464 fd_delete(t->cli_fd);
1465 t->cli_state = CL_STCLOSE;
1466 return 1;
1467 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001468 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
1469 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001470 fd_delete(t->cli_fd);
1471 t->cli_state = CL_STCLOSE;
1472 if (!(t->flags & SN_ERR_MASK))
1473 t->flags |= SN_ERR_CLITO;
1474 if (!(t->flags & SN_FINST_MASK)) {
1475 if (t->pend_pos)
1476 t->flags |= SN_FINST_Q;
1477 else if (s == SV_STCONN)
1478 t->flags |= SN_FINST_C;
1479 else
1480 t->flags |= SN_FINST_D;
1481 }
1482 return 1;
1483 }
1484
1485 if (t->flags & SN_SELF_GEN) {
1486 produce_content(t);
1487 if (rep->l == 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001488 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001489 fd_delete(t->cli_fd);
1490 t->cli_state = CL_STCLOSE;
1491 return 1;
1492 }
1493 }
1494
1495 if ((rep->l == 0)
1496 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001497 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1498 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001499 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001500 }
1501 } else {
1502 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001503 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1504 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001505 if (t->fe->clitimeout) {
1506 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001507 /* FIXME: to prevent the client from expiring read timeouts during writes,
1508 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001509 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001510 }
1511 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001512 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001513 }
1514 }
1515 return 0;
1516 }
1517 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001518 if (req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001519 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001520 fd_delete(t->cli_fd);
1521 t->cli_state = CL_STCLOSE;
1522 if (!(t->flags & SN_ERR_MASK))
1523 t->flags |= SN_ERR_CLICL;
1524 if (!(t->flags & SN_FINST_MASK)) {
1525 if (t->pend_pos)
1526 t->flags |= SN_FINST_Q;
1527 else if (s == SV_STCONN)
1528 t->flags |= SN_FINST_C;
1529 else
1530 t->flags |= SN_FINST_D;
1531 }
1532 return 1;
1533 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001534 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001535 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001536 fd_delete(t->cli_fd);
1537 t->cli_state = CL_STCLOSE;
1538 return 1;
1539 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001540 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
1541 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001542 fd_delete(t->cli_fd);
1543 t->cli_state = CL_STCLOSE;
1544 if (!(t->flags & SN_ERR_MASK))
1545 t->flags |= SN_ERR_CLITO;
1546 if (!(t->flags & SN_FINST_MASK)) {
1547 if (t->pend_pos)
1548 t->flags |= SN_FINST_Q;
1549 else if (s == SV_STCONN)
1550 t->flags |= SN_FINST_C;
1551 else
1552 t->flags |= SN_FINST_D;
1553 }
1554 return 1;
1555 }
1556 else if (req->l >= req->rlim - req->data) {
1557 /* no room to read more data */
1558
1559 /* FIXME-20050705: is it possible for a client to maintain a session
1560 * after the timeout by sending more data after it receives a close ?
1561 */
1562
Willy Tarreau2a429502006-10-15 14:52:29 +02001563 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001564 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001565 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001566 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001567 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1568 }
1569 } else {
1570 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001571 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1572 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001573 if (t->fe->clitimeout)
1574 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001575 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001576 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001577 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1578 }
1579 }
1580 return 0;
1581 }
1582 else { /* CL_STCLOSE: nothing to do */
1583 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1584 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01001585 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 +02001586 write(1, trash, len);
1587 }
1588 return 0;
1589 }
1590 return 0;
1591}
1592
1593
1594/*
1595 * manages the server FSM and its socket. It returns 1 if a state has changed
1596 * (and a resync may be needed), 0 else.
1597 */
1598int process_srv(struct session *t)
1599{
1600 int s = t->srv_state;
1601 int c = t->cli_state;
1602 struct buffer *req = t->req;
1603 struct buffer *rep = t->rep;
1604 appsess *asession_temp = NULL;
1605 appsess local_asession;
1606 int conn_err;
1607
1608#ifdef DEBUG_FULL
1609 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
1610#endif
1611 //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 +02001612 //MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
1613 //MY_FD_ISSET(t->srv_fd, StaticReadEvent), MY_FD_ISSET(t->srv_fd, StaticWriteEvent)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001614 //);
1615 if (s == SV_STIDLE) {
1616 if (c == CL_STHEADERS)
1617 return 0; /* stay in idle, waiting for data to reach the client side */
1618 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
1619 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001620 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001621 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001622 if (t->pend_pos)
1623 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1624 /* note that this must not return any error because it would be able to
1625 * overwrite the client_retnclose() output.
1626 */
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001627 if (t->flags & SN_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01001628 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001629 else
Willy Tarreau0f772532006-12-23 20:51:41 +01001630 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 +02001631
1632 return 1;
1633 }
1634 else {
Willy Tarreaub8750a82006-09-03 09:56:00 +02001635 if (t->flags & SN_CLTARPIT) {
1636 /* This connection is being tarpitted. The CLIENT side has
1637 * already set the connect expiration date to the right
1638 * timeout. We just have to check that it has not expired.
1639 */
1640 if (tv_cmp2_ms(&req->cex, &now) > 0)
1641 return 0;
1642
1643 /* We will set the queue timer to the time spent, just for
1644 * logging purposes. We fake a 500 server error, so that the
1645 * attacker will not suspect his connection has been tarpitted.
1646 * It will not cause trouble to the logs because we can exclude
1647 * the tarpitted connections by filtering on the 'PT' status flags.
1648 */
1649 tv_eternity(&req->cex);
1650 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1651 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01001652 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02001653 return 1;
1654 }
1655
Willy Tarreaubaaee002006-06-26 02:48:02 +02001656 /* Right now, we will need to create a connection to the server.
1657 * We might already have tried, and got a connection pending, in
1658 * which case we will not do anything till it's pending. It's up
1659 * to any other session to release it and wake us up again.
1660 */
1661 if (t->pend_pos) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001662 if (tv_cmp2_ms(&req->cex, &now) > 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001663 return 0;
1664 else {
1665 /* we've been waiting too long here */
Willy Tarreaud7971282006-07-29 18:36:34 +02001666 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001667 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1668 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01001669 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001670 if (t->srv)
1671 t->srv->failed_conns++;
Willy Tarreau73de9892006-11-30 11:40:23 +01001672 t->fe->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001673 return 1;
1674 }
1675 }
1676
1677 do {
1678 /* first, get a connection */
1679 if (srv_redispatch_connect(t))
1680 return t->srv_state != SV_STIDLE;
1681
1682 /* try to (re-)connect to the server, and fail if we expire the
1683 * number of retries.
1684 */
1685 if (srv_retryable_connect(t)) {
1686 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1687 return t->srv_state != SV_STIDLE;
1688 }
1689
1690 } while (1);
1691 }
1692 }
1693 else if (s == SV_STCONN) { /* connection in progress */
1694 if (c == CL_STCLOSE || c == CL_STSHUTW ||
1695 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001696 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001697 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001698 fd_delete(t->srv_fd);
1699 if (t->srv)
1700 t->srv->cur_sess--;
1701
1702 /* note that this must not return any error because it would be able to
1703 * overwrite the client_retnclose() output.
1704 */
Willy Tarreau0f772532006-12-23 20:51:41 +01001705 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001706 return 1;
1707 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001708 if (!(req->flags & BF_WRITE_STATUS) && tv_cmp2_ms(&req->cex, &now) > 0) {
1709 //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 +02001710 return 0; /* nothing changed */
1711 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001712 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001713 /* timeout, asynchronous connect error or first write error */
1714 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
1715
1716 fd_delete(t->srv_fd);
1717 if (t->srv)
1718 t->srv->cur_sess--;
1719
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001720 if (!(req->flags & BF_WRITE_STATUS))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001721 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
1722 else
1723 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
1724
1725 /* ensure that we have enough retries left */
1726 if (srv_count_retry_down(t, conn_err))
1727 return 1;
1728
Willy Tarreau830ff452006-12-17 19:31:23 +01001729 if (t->srv && t->conn_retries == 0 && t->be->beprm->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001730 /* We're on our last chance, and the REDISP option was specified.
1731 * We will ignore cookie and force to balance or use the dispatcher.
1732 */
1733 /* let's try to offer this slot to anybody */
Willy Tarreau830ff452006-12-17 19:31:23 +01001734 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001735 task_wakeup(&rq, t->srv->queue_mgt);
1736
1737 if (t->srv)
1738 t->srv->failed_conns++;
Willy Tarreau830ff452006-12-17 19:31:23 +01001739 t->be->beprm->failed_conns++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001740
1741 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
1742 t->srv = NULL; /* it's left to the dispatcher to choose a server */
1743 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
1744 t->flags &= ~SN_CK_MASK;
1745 t->flags |= SN_CK_DOWN;
1746 }
1747
1748 /* first, get a connection */
1749 if (srv_redispatch_connect(t))
1750 return t->srv_state != SV_STIDLE;
1751 }
1752
Willy Tarreaubaaee002006-06-26 02:48:02 +02001753 do {
1754 /* Now we will try to either reconnect to the same server or
1755 * connect to another server. If the connection gets queued
1756 * because all servers are saturated, then we will go back to
1757 * the SV_STIDLE state.
1758 */
1759 if (srv_retryable_connect(t)) {
1760 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1761 return t->srv_state != SV_STCONN;
1762 }
1763
1764 /* we need to redispatch the connection to another server */
1765 if (srv_redispatch_connect(t))
1766 return t->srv_state != SV_STCONN;
1767 } while (1);
1768 }
1769 else { /* no error or write 0 */
1770 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
1771
1772 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
1773 if (req->l == 0) /* nothing to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02001774 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001775 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001776 } else /* need the right to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02001777 MY_FD_SET(t->srv_fd, StaticWriteEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001778 if (t->be->beprm->srvtimeout) {
1779 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001780 /* FIXME: to prevent the server from expiring read timeouts during writes,
1781 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001782 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001783 }
1784 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001785 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001786 }
1787
Willy Tarreau830ff452006-12-17 19:31:23 +01001788 if (t->be->beprm->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreau2a429502006-10-15 14:52:29 +02001789 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001790 if (t->be->beprm->srvtimeout)
1791 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001792 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001793 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001794
1795 t->srv_state = SV_STDATA;
1796 if (t->srv)
1797 t->srv->cum_sess++;
1798 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
1799
1800 /* if the user wants to log as soon as possible, without counting
1801 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001802 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001803 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
1804 sess_log(t);
1805 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01001806#ifdef CONFIG_HAP_TCPSPLICE
1807 if ((t->fe->options & t->be->beprm->options) & PR_O_TCPSPLICE) {
1808 /* TCP splicing supported by both FE and BE */
1809 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
1810 }
1811#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001812 }
1813 else {
1814 t->srv_state = SV_STHEADERS;
1815 if (t->srv)
1816 t->srv->cum_sess++;
1817 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
1818 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001819 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001820 return 1;
1821 }
1822 }
1823 else if (s == SV_STHEADERS) { /* receiving server headers */
1824 /* now parse the partial (or complete) headers */
1825 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
1826 char *ptr;
1827 int delete_header;
1828
1829 ptr = rep->lr;
1830
1831 /* look for the end of the current header */
1832 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
1833 ptr++;
1834
1835 if (ptr == rep->h) {
1836 int line, len;
1837
1838 /* we can only get here after an end of headers */
1839
1840 /* first, we'll block if security checks have caught nasty things */
1841 if (t->flags & SN_CACHEABLE) {
1842 if ((t->flags & SN_CACHE_COOK) &&
1843 (t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001844 (t->be->beprm->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001845
1846 /* we're in presence of a cacheable response containing
1847 * a set-cookie header. We'll block it as requested by
1848 * the 'checkcache' option, and send an alert.
1849 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001850 tv_eternity(&rep->rex);
1851 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001852 fd_delete(t->srv_fd);
1853 if (t->srv) {
1854 t->srv->cur_sess--;
1855 t->srv->failed_secu++;
1856 }
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001857 t->be->beprm->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001858 t->srv_state = SV_STCLOSE;
1859 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01001860 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001861 if (!(t->flags & SN_ERR_MASK))
1862 t->flags |= SN_ERR_PRXCOND;
1863 if (!(t->flags & SN_FINST_MASK))
1864 t->flags |= SN_FINST_H;
1865
Willy Tarreau830ff452006-12-17 19:31:23 +01001866 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->be->beprm->id, t->srv->id);
1867 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 +02001868
1869 /* We used to have a free connection slot. Since we'll never use it,
1870 * we have to inform the server that it may be used by another session.
1871 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001872 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001873 task_wakeup(&rq, t->srv->queue_mgt);
1874
1875 return 1;
1876 }
1877 }
1878
1879 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
1880 if (t->flags & SN_SVDENY) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001881 tv_eternity(&rep->rex);
1882 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001883 fd_delete(t->srv_fd);
1884 if (t->srv) {
1885 t->srv->cur_sess--;
1886 t->srv->failed_secu++;
1887 }
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001888 t->be->beprm->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001889 t->srv_state = SV_STCLOSE;
1890 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01001891 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001892 if (!(t->flags & SN_ERR_MASK))
1893 t->flags |= SN_ERR_PRXCOND;
1894 if (!(t->flags & SN_FINST_MASK))
1895 t->flags |= SN_FINST_H;
1896 /* We used to have a free connection slot. Since we'll never use it,
1897 * we have to inform the server that it may be used by another session.
1898 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001899 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001900 task_wakeup(&rq, t->srv->queue_mgt);
1901
1902 return 1;
1903 }
1904
1905 /* we'll have something else to do here : add new headers ... */
1906
Willy Tarreau830ff452006-12-17 19:31:23 +01001907 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_INS) &&
1908 (!(t->be->beprm->options & PR_O_COOK_POST) || (t->hreq.meth == HTTP_METH_POST))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001909 /* the server is known, it's not the one the client requested, we have to
1910 * insert a set-cookie here, except if we want to insert only on POST
1911 * requests and this one isn't. Note that servers which don't have cookies
1912 * (eg: some backup servers) will return a full cookie removal request.
1913 */
1914 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
Willy Tarreau830ff452006-12-17 19:31:23 +01001915 t->be->beprm->cookie_name,
Willy Tarreaubaaee002006-06-26 02:48:02 +02001916 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
1917
1918 t->flags |= SN_SCK_INSERTED;
1919
1920 /* Here, we will tell an eventual cache on the client side that we don't
1921 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
1922 * Some caches understand the correct form: 'no-cache="set-cookie"', but
1923 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
1924 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001925 if (t->be->beprm->options & PR_O_COOK_NOC)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001926 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
1927 len += sprintf(trash + len, "Cache-control: private\r\n");
1928
1929 if (rep->data + rep->l < rep->h)
1930 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
1931 *(int *)0 = 0;
1932 buffer_replace2(rep, rep->h, rep->h, trash, len);
1933 }
1934
1935 /* headers to be added */
Willy Tarreau830ff452006-12-17 19:31:23 +01001936 /* FIXME: we should add headers from BE then from FE */
1937 for (line = 0; line < t->be->fiprm->nb_rspadd; line++) {
1938 len = sprintf(trash, "%s\r\n", t->be->fiprm->rsp_add[line]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001939 buffer_replace2(rep, rep->h, rep->h, trash, len);
1940 }
1941
1942 /* add a "connection: close" line if needed */
Willy Tarreaue01954f2006-12-30 23:43:54 +01001943 if ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001944 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
1945
1946 t->srv_state = SV_STDATA;
1947 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
1948 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
1949
1950 /* client connection already closed or option 'httpclose' required :
1951 * we close the server's outgoing connection right now.
1952 */
1953 if ((req->l == 0) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001954 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->beprm->options & PR_O_FORCE_CLO)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001955 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001956 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001957
1958 /* We must ensure that the read part is still alive when switching
1959 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001960 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001961 if (t->be->beprm->srvtimeout)
1962 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001963
1964 shutdown(t->srv_fd, SHUT_WR);
1965 t->srv_state = SV_STSHUTW;
1966 }
1967
Willy Tarreau6d1a9882007-01-07 02:03:04 +01001968#ifdef CONFIG_HAP_TCPSPLICE
1969 if ((t->fe->options & t->be->beprm->options) & PR_O_TCPSPLICE) {
1970 /* TCP splicing supported by both FE and BE */
1971 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
1972 }
1973#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001974 /* if the user wants to log as soon as possible, without counting
1975 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001976 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001977 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreau35d66b02007-01-02 00:28:21 +01001978 t->logs.bytes_in = rep->h - rep->data;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001979 sess_log(t);
1980 }
1981 break;
1982 }
1983
1984 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1985 if (ptr > rep->r - 2) {
1986 /* this is a partial header, let's wait for more to come */
1987 rep->lr = ptr;
1988 break;
1989 }
1990
1991 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
1992 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
1993
1994 /* now we know that *ptr is either \r or \n,
1995 * and that there are at least 1 char after it.
1996 */
1997 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
1998 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
1999 else
2000 rep->lr = ptr + 2; /* \r\n or \n\r */
2001
2002 /*
2003 * now we know that we have a full header ; we can do whatever
2004 * we want with these pointers :
2005 * rep->h = beginning of header
2006 * ptr = end of header (first \r or \n)
2007 * rep->lr = beginning of next line (next rep->h)
2008 * rep->r = end of data (not used at this stage)
2009 */
2010
2011
2012 if (t->logs.status == -1) {
2013 t->logs.logwait &= ~LW_RESP;
2014 t->logs.status = atoi(rep->h + 9);
2015 switch (t->logs.status) {
2016 case 200:
2017 case 203:
2018 case 206:
2019 case 300:
2020 case 301:
2021 case 410:
2022 /* RFC2616 @13.4:
2023 * "A response received with a status code of
2024 * 200, 203, 206, 300, 301 or 410 MAY be stored
2025 * by a cache (...) unless a cache-control
2026 * directive prohibits caching."
2027 *
2028 * RFC2616 @9.5: POST method :
2029 * "Responses to this method are not cacheable,
2030 * unless the response includes appropriate
2031 * Cache-Control or Expires header fields."
2032 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002033 if (!(t->hreq.meth == HTTP_METH_POST) && (t->be->beprm->options & PR_O_CHK_CACHE))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002034 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
2035 break;
2036 default:
2037 break;
2038 }
2039 }
2040 else if (t->logs.logwait & LW_RSPHDR) {
2041 struct cap_hdr *h;
2042 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01002043 for (h = t->fe->fiprm->rsp_cap; h; h = h->next) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002044 if ((h->namelen + 2 <= ptr - rep->h) &&
2045 (rep->h[h->namelen] == ':') &&
2046 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
2047
2048 if (t->rsp_cap[h->index] == NULL)
2049 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
2050
2051 len = ptr - (rep->h + h->namelen + 2);
2052 if (len > h->len)
2053 len = h->len;
2054
2055 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
2056 t->rsp_cap[h->index][len]=0;
2057 }
2058 }
2059
2060 }
2061
2062 delete_header = 0;
2063
Willy Tarreau58f10d72006-12-04 02:26:12 +01002064 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
2065 debug_hdr("srvhdr", t, rep->h, ptr);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002066
2067 /* remove "connection: " if needed */
Willy Tarreaue01954f2006-12-30 23:43:54 +01002068 if (!delete_header &&
2069 ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) &&
2070 (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002071 delete_header = 1;
2072 }
2073
2074 /* try headers regexps */
Willy Tarreau830ff452006-12-17 19:31:23 +01002075 if (!delete_header && t->be->fiprm->rsp_exp != NULL
Willy Tarreaubaaee002006-06-26 02:48:02 +02002076 && !(t->flags & SN_SVDENY)) {
2077 struct hdr_exp *exp;
2078 char term;
2079
2080 term = *ptr;
2081 *ptr = '\0';
Willy Tarreau830ff452006-12-17 19:31:23 +01002082 exp = t->be->fiprm->rsp_exp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002083 do {
2084 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2085 switch (exp->action) {
2086 case ACT_ALLOW:
2087 if (!(t->flags & SN_SVDENY))
2088 t->flags |= SN_SVALLOW;
2089 break;
2090 case ACT_REPLACE:
2091 if (!(t->flags & SN_SVDENY)) {
2092 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
2093 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2094 }
2095 break;
2096 case ACT_REMOVE:
2097 if (!(t->flags & SN_SVDENY))
2098 delete_header = 1;
2099 break;
2100 case ACT_DENY:
2101 if (!(t->flags & SN_SVALLOW))
2102 t->flags |= SN_SVDENY;
2103 break;
2104 case ACT_PASS: /* we simply don't deny this one */
2105 break;
2106 }
2107 break;
2108 }
2109 } while ((exp = exp->next) != NULL);
2110 *ptr = term; /* restore the string terminator */
2111 }
2112
2113 /* check for cache-control: or pragma: headers */
2114 if (!delete_header && (t->flags & SN_CACHEABLE)) {
2115 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
2116 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2117 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
2118 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
2119 if (rep->h + 23 == ptr || rep->h[23] == ',')
2120 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2121 else {
2122 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
2123 && (rep->h[35] == '"' || rep->h[35] == ','))
2124 t->flags &= ~SN_CACHE_COOK;
2125 }
2126 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
2127 (rep->h + 22 == ptr || rep->h[22] == ','))
2128 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
2129 (rep->h + 23 == ptr || rep->h[23] == ','))) {
2130 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2131 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
2132 (rep->h + 24 == ptr || rep->h[24] == ',')) {
2133 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2134 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
2135 (rep->h + 25 == ptr || rep->h[25] == ',')) {
2136 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2137 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
2138 (rep->h + 21 == ptr || rep->h[21] == ',')) {
2139 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
2140 }
2141 }
2142 }
2143
2144 /* check for server cookies */
2145 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002146 && (t->be->beprm->cookie_name != NULL ||
2147 t->be->fiprm->capture_name != NULL ||
2148 t->be->beprm->appsession_name !=NULL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002149 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2150 char *p1, *p2, *p3, *p4;
2151
2152 t->flags |= SN_SCK_ANY;
2153
2154 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2155
2156 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
2157 while (p1 < ptr && (isspace((int)*p1)))
2158 p1++;
2159
2160 if (p1 == ptr || *p1 == ';') /* end of cookie */
2161 break;
2162
2163 /* p1 is at the beginning of the cookie name */
2164 p2 = p1;
2165
2166 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2167 p2++;
2168
2169 if (p2 == ptr || *p2 == ';') /* next cookie */
2170 break;
2171
2172 p3 = p2 + 1; /* skips the '=' sign */
2173 if (p3 == ptr)
2174 break;
2175
2176 p4 = p3;
2177 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
2178 p4++;
2179
2180 /* here, we have the cookie name between p1 and p2,
2181 * and its value between p3 and p4.
2182 * we can process it.
2183 */
2184
2185 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01002186 if (t->be->fiprm->capture_name != NULL &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002187 t->logs.srv_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002188 (p4 - p1 >= t->be->fiprm->capture_namelen) &&
2189 memcmp(p1, t->be->fiprm->capture_name, t->be->fiprm->capture_namelen) == 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002190 int log_len = p4 - p1;
2191
2192 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
2193 Alert("HTTP logging : out of memory.\n");
2194 }
2195
Willy Tarreau830ff452006-12-17 19:31:23 +01002196 if (log_len > t->be->fiprm->capture_len)
2197 log_len = t->be->fiprm->capture_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002198 memcpy(t->logs.srv_cookie, p1, log_len);
2199 t->logs.srv_cookie[log_len] = 0;
2200 }
2201
Willy Tarreau830ff452006-12-17 19:31:23 +01002202 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
2203 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002204 /* Cool... it's the right one */
2205 t->flags |= SN_SCK_SEEN;
2206
2207 /* If the cookie is in insert mode on a known server, we'll delete
2208 * this occurrence because we'll insert another one later.
2209 * We'll delete it too if the "indirect" option is set and we're in
2210 * a direct access. */
Willy Tarreau830ff452006-12-17 19:31:23 +01002211 if (((t->srv) && (t->be->beprm->options & PR_O_COOK_INS)) ||
2212 ((t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_IND))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002213 /* this header must be deleted */
2214 delete_header = 1;
2215 t->flags |= SN_SCK_DELETED;
2216 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002217 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_RW)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002218 /* replace bytes p3->p4 with the cookie name associated
2219 * with this server since we know it.
2220 */
2221 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2222 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2223 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002224 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_PFX)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002225 /* insert the cookie name associated with this server
2226 * before existing cookie, and insert a delimitor between them..
2227 */
2228 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
2229 p3[t->srv->cklen] = COOKIE_DELIM;
2230 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2231 }
2232 break;
2233 }
2234
2235 /* first, let's see if the cookie is our appcookie*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002236 if ((t->be->beprm->appsession_name != NULL) &&
2237 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002238
2239 /* Cool... it's the right one */
2240
2241 size_t server_id_len = strlen(t->srv->id) + 1;
2242 asession_temp = &local_asession;
2243
2244 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
2245 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002246 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002247 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002248 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
2249 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002250 asession_temp->serverid = NULL;
2251
2252 /* only do insert, if lookup fails */
Willy Tarreau73de9892006-11-30 11:40:23 +01002253 if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002254 if ((asession_temp = pool_alloc(appsess)) == NULL) {
2255 Alert("Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002256 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002257 return 0;
2258 }
2259 asession_temp->sessid = local_asession.sessid;
2260 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01002261 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002262 }/* end if (chtbl_lookup()) */
2263 else {
2264 /* free wasted memory */
2265 pool_free_to(apools.sessid, local_asession.sessid);
2266 } /* end else from if (chtbl_lookup()) */
2267
2268 if (asession_temp->serverid == NULL) {
2269 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
2270 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002271 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002272 }
2273 asession_temp->serverid[0] = '\0';
2274 }
2275
2276 if (asession_temp->serverid[0] == '\0')
2277 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
2278
Willy Tarreau830ff452006-12-17 19:31:23 +01002279 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002280
2281#if defined(DEBUG_HASH)
Willy Tarreau830ff452006-12-17 19:31:23 +01002282 print_table(&(t->be->beprm->htbl_proxy));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002283#endif
2284 break;
2285 }/* end if ((t->proxy->appsession_name != NULL) ... */
2286 else {
2287 // fprintf(stderr,"Ignoring unknown cookie : ");
2288 // write(2, p1, p2-p1);
2289 // fprintf(stderr," = ");
2290 // write(2, p3, p4-p3);
2291 // fprintf(stderr,"\n");
2292 }
2293 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2294 } /* we're now at the end of the cookie value */
2295 } /* end of cookie processing */
2296
2297 /* check for any set-cookie in case we check for cacheability */
2298 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002299 (t->be->beprm->options & PR_O_CHK_CACHE) &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002300 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2301 t->flags |= SN_SCK_ANY;
2302 }
2303
2304 /* let's look if we have to delete this header */
2305 if (delete_header && !(t->flags & SN_SVDENY))
2306 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2307
2308 rep->h = rep->lr;
2309 } /* while (rep->lr < rep->r) */
2310
2311 /* end of header processing (even if incomplete) */
2312
Willy Tarreau2a429502006-10-15 14:52:29 +02002313 if ((rep->l < rep->rlim - rep->data) && ! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002314 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
Willy Tarreaud7971282006-07-29 18:36:34 +02002315 * full. We cannot loop here since stream_sock_read will disable it only if
Willy Tarreaubaaee002006-06-26 02:48:02 +02002316 * rep->l == rlim-data
2317 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002318 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002319 if (t->be->beprm->srvtimeout)
2320 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002321 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002322 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002323 }
2324
2325 /* read error, write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002326 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002327 tv_eternity(&rep->rex);
2328 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002329 fd_delete(t->srv_fd);
2330 if (t->srv) {
2331 t->srv->cur_sess--;
2332 t->srv->failed_resp++;
2333 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002334 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002335
2336 t->srv_state = SV_STCLOSE;
2337 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01002338 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002339 if (!(t->flags & SN_ERR_MASK))
2340 t->flags |= SN_ERR_SRVCL;
2341 if (!(t->flags & SN_FINST_MASK))
2342 t->flags |= SN_FINST_H;
2343 /* We used to have a free connection slot. Since we'll never use it,
2344 * we have to inform the server that it may be used by another session.
2345 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002346 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002347 task_wakeup(&rq, t->srv->queue_mgt);
2348
2349 return 1;
2350 }
2351 /* end of client write or end of server read.
2352 * since we are in header mode, if there's no space left for headers, we
2353 * won't be able to free more later, so the session will never terminate.
2354 */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002355 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 +02002356 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002357 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002358 shutdown(t->srv_fd, SHUT_RD);
2359 t->srv_state = SV_STSHUTR;
2360 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2361 return 1;
2362 }
2363 /* read timeout : return a 504 to the client.
2364 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002365 else if (MY_FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002366 tv_eternity(&rep->rex);
2367 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002368 fd_delete(t->srv_fd);
2369 if (t->srv) {
2370 t->srv->cur_sess--;
2371 t->srv->failed_resp++;
2372 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002373 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002374 t->srv_state = SV_STCLOSE;
2375 t->logs.status = 504;
Willy Tarreau80587432006-12-24 17:47:20 +01002376 client_return(t, error_message(t, HTTP_ERR_504));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002377 if (!(t->flags & SN_ERR_MASK))
2378 t->flags |= SN_ERR_SRVTO;
2379 if (!(t->flags & SN_FINST_MASK))
2380 t->flags |= SN_FINST_H;
2381 /* We used to have a free connection slot. Since we'll never use it,
2382 * we have to inform the server that it may be used by another session.
2383 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002384 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002385 task_wakeup(&rq, t->srv->queue_mgt);
2386
2387 return 1;
2388 }
2389 /* last client read and buffer empty */
2390 /* FIXME!!! here, we don't want to switch to SHUTW if the
2391 * client shuts read too early, because we may still have
2392 * some work to do on the headers.
2393 * The side-effect is that if the client completely closes its
2394 * connection during SV_STHEADER, the connection to the server
2395 * is kept until a response comes back or the timeout is reached.
2396 */
2397 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002398 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002399 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002400
2401 /* We must ensure that the read part is still alive when switching
2402 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002403 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002404 if (t->be->beprm->srvtimeout)
2405 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002406
2407 shutdown(t->srv_fd, SHUT_WR);
2408 t->srv_state = SV_STSHUTW;
2409 return 1;
2410 }
2411 /* write timeout */
2412 /* FIXME!!! here, we don't want to switch to SHUTW if the
2413 * client shuts read too early, because we may still have
2414 * some work to do on the headers.
2415 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002416 else if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&req->wex, &now) <= 0) {
2417 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002418 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002419 shutdown(t->srv_fd, SHUT_WR);
2420 /* We must ensure that the read part is still alive when switching
2421 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002422 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002423 if (t->be->beprm->srvtimeout)
2424 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002425
2426 /* We must ensure that the read part is still alive when switching
2427 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002428 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002429 if (t->be->beprm->srvtimeout)
2430 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002431
2432 t->srv_state = SV_STSHUTW;
2433 if (!(t->flags & SN_ERR_MASK))
2434 t->flags |= SN_ERR_SRVTO;
2435 if (!(t->flags & SN_FINST_MASK))
2436 t->flags |= SN_FINST_H;
2437 return 1;
2438 }
2439
2440 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002441 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2442 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002443 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002444 }
2445 }
2446 else { /* client buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002447 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2448 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002449 if (t->be->beprm->srvtimeout) {
2450 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002451 /* FIXME: to prevent the server from expiring read timeouts during writes,
2452 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002453 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002454 }
2455 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002456 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002457 }
2458 }
2459
2460 /* be nice with the client side which would like to send a complete header
2461 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2462 * would read all remaining data at once ! The client should not write past rep->lr
2463 * when the server is in header state.
2464 */
2465 //return header_processed;
2466 return t->srv_state != SV_STHEADERS;
2467 }
2468 else if (s == SV_STDATA) {
2469 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002470 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002471 tv_eternity(&rep->rex);
2472 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002473 fd_delete(t->srv_fd);
2474 if (t->srv) {
2475 t->srv->cur_sess--;
2476 t->srv->failed_resp++;
2477 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002478 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002479 t->srv_state = SV_STCLOSE;
2480 if (!(t->flags & SN_ERR_MASK))
2481 t->flags |= SN_ERR_SRVCL;
2482 if (!(t->flags & SN_FINST_MASK))
2483 t->flags |= SN_FINST_D;
2484 /* We used to have a free connection slot. Since we'll never use it,
2485 * we have to inform the server that it may be used by another session.
2486 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002487 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002488 task_wakeup(&rq, t->srv->queue_mgt);
2489
2490 return 1;
2491 }
2492 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002493 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002494 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002495 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002496 shutdown(t->srv_fd, SHUT_RD);
2497 t->srv_state = SV_STSHUTR;
2498 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2499 return 1;
2500 }
2501 /* end of client read and no more data to send */
2502 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002503 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002504 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002505 shutdown(t->srv_fd, SHUT_WR);
2506 /* We must ensure that the read part is still alive when switching
2507 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002508 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002509 if (t->be->beprm->srvtimeout)
2510 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002511
2512 t->srv_state = SV_STSHUTW;
2513 return 1;
2514 }
2515 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002516 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002517 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002518 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002519 shutdown(t->srv_fd, SHUT_RD);
2520 t->srv_state = SV_STSHUTR;
2521 if (!(t->flags & SN_ERR_MASK))
2522 t->flags |= SN_ERR_SRVTO;
2523 if (!(t->flags & SN_FINST_MASK))
2524 t->flags |= SN_FINST_D;
2525 return 1;
2526 }
2527 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002528 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002529 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002530 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002531 shutdown(t->srv_fd, SHUT_WR);
2532 /* We must ensure that the read part is still alive when switching
2533 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002534 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002535 if (t->be->beprm->srvtimeout)
2536 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002537 t->srv_state = SV_STSHUTW;
2538 if (!(t->flags & SN_ERR_MASK))
2539 t->flags |= SN_ERR_SRVTO;
2540 if (!(t->flags & SN_FINST_MASK))
2541 t->flags |= SN_FINST_D;
2542 return 1;
2543 }
2544
2545 /* recompute request time-outs */
2546 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002547 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2548 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002549 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002550 }
2551 }
2552 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau2a429502006-10-15 14:52:29 +02002553 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2554 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002555 if (t->be->beprm->srvtimeout) {
2556 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002557 /* FIXME: to prevent the server from expiring read timeouts during writes,
2558 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002559 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002560 }
2561 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002562 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002563 }
2564 }
2565
2566 /* recompute response time-outs */
2567 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002568 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2569 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002570 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002571 }
2572 }
2573 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002574 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2575 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002576 if (t->be->beprm->srvtimeout)
2577 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002578 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002579 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002580 }
2581 }
2582
2583 return 0; /* other cases change nothing */
2584 }
2585 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002586 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002587 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002588 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002589 fd_delete(t->srv_fd);
2590 if (t->srv) {
2591 t->srv->cur_sess--;
2592 t->srv->failed_resp++;
2593 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002594 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002595 //close(t->srv_fd);
2596 t->srv_state = SV_STCLOSE;
2597 if (!(t->flags & SN_ERR_MASK))
2598 t->flags |= SN_ERR_SRVCL;
2599 if (!(t->flags & SN_FINST_MASK))
2600 t->flags |= SN_FINST_D;
2601 /* We used to have a free connection slot. Since we'll never use it,
2602 * we have to inform the server that it may be used by another session.
2603 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002604 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002605 task_wakeup(&rq, t->srv->queue_mgt);
2606
2607 return 1;
2608 }
2609 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002610 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002611 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002612 fd_delete(t->srv_fd);
2613 if (t->srv)
2614 t->srv->cur_sess--;
2615 //close(t->srv_fd);
2616 t->srv_state = SV_STCLOSE;
2617 /* We used to have a free connection slot. Since we'll never use it,
2618 * we have to inform the server that it may be used by another session.
2619 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002620 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002621 task_wakeup(&rq, t->srv->queue_mgt);
2622
2623 return 1;
2624 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002625 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002626 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002627 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002628 fd_delete(t->srv_fd);
2629 if (t->srv)
2630 t->srv->cur_sess--;
2631 //close(t->srv_fd);
2632 t->srv_state = SV_STCLOSE;
2633 if (!(t->flags & SN_ERR_MASK))
2634 t->flags |= SN_ERR_SRVTO;
2635 if (!(t->flags & SN_FINST_MASK))
2636 t->flags |= SN_FINST_D;
2637 /* We used to have a free connection slot. Since we'll never use it,
2638 * we have to inform the server that it may be used by another session.
2639 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002640 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002641 task_wakeup(&rq, t->srv->queue_mgt);
2642
2643 return 1;
2644 }
2645 else if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002646 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2647 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002648 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002649 }
2650 }
2651 else { /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002652 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2653 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002654 if (t->be->beprm->srvtimeout) {
2655 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002656 /* FIXME: to prevent the server from expiring read timeouts during writes,
2657 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002658 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002659 }
2660 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002661 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002662 }
2663 }
2664 return 0;
2665 }
2666 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002667 if (rep->flags & BF_READ_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002668 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002669 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002670 fd_delete(t->srv_fd);
2671 if (t->srv) {
2672 t->srv->cur_sess--;
2673 t->srv->failed_resp++;
2674 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002675 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002676 //close(t->srv_fd);
2677 t->srv_state = SV_STCLOSE;
2678 if (!(t->flags & SN_ERR_MASK))
2679 t->flags |= SN_ERR_SRVCL;
2680 if (!(t->flags & SN_FINST_MASK))
2681 t->flags |= SN_FINST_D;
2682 /* We used to have a free connection slot. Since we'll never use it,
2683 * we have to inform the server that it may be used by another session.
2684 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002685 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002686 task_wakeup(&rq, t->srv->queue_mgt);
2687
2688 return 1;
2689 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002690 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002691 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002692 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002693 fd_delete(t->srv_fd);
2694 if (t->srv)
2695 t->srv->cur_sess--;
2696 //close(t->srv_fd);
2697 t->srv_state = SV_STCLOSE;
2698 /* We used to have a free connection slot. Since we'll never use it,
2699 * we have to inform the server that it may be used by another session.
2700 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002701 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002702 task_wakeup(&rq, t->srv->queue_mgt);
2703
2704 return 1;
2705 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002706 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002707 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002708 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002709 fd_delete(t->srv_fd);
2710 if (t->srv)
2711 t->srv->cur_sess--;
2712 //close(t->srv_fd);
2713 t->srv_state = SV_STCLOSE;
2714 if (!(t->flags & SN_ERR_MASK))
2715 t->flags |= SN_ERR_SRVTO;
2716 if (!(t->flags & SN_FINST_MASK))
2717 t->flags |= SN_FINST_D;
2718 /* We used to have a free connection slot. Since we'll never use it,
2719 * we have to inform the server that it may be used by another session.
2720 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002721 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002722 task_wakeup(&rq, t->srv->queue_mgt);
2723
2724 return 1;
2725 }
2726 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002727 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2728 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002729 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002730 }
2731 }
2732 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002733 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2734 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002735 if (t->be->beprm->srvtimeout)
2736 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002737 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002738 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002739 }
2740 }
2741 return 0;
2742 }
2743 else { /* SV_STCLOSE : nothing to do */
2744 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2745 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01002746 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 +02002747 write(1, trash, len);
2748 }
2749 return 0;
2750 }
2751 return 0;
2752}
2753
2754
2755/*
2756 * Produces data for the session <s> depending on its source. Expects to be
2757 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
2758 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
2759 * session, which it uses to keep on being called when there is free space in
2760 * the buffer, of simply by letting an empty buffer upon return. It returns 1
2761 * if it changes the session state from CL_STSHUTR, otherwise 0.
2762 */
2763int produce_content(struct session *s)
2764{
Willy Tarreaubaaee002006-06-26 02:48:02 +02002765 if (s->data_source == DATA_SRC_NONE) {
2766 s->flags &= ~SN_SELF_GEN;
2767 return 1;
2768 }
2769 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002770 /* dump server statistics */
2771 return produce_content_stats(s);
2772 }
2773 else {
2774 /* unknown data source */
2775 s->logs.status = 500;
2776 client_retnclose(s, error_message(s, HTTP_ERR_500));
2777 if (!(s->flags & SN_ERR_MASK))
2778 s->flags |= SN_ERR_PRXCOND;
2779 if (!(s->flags & SN_FINST_MASK))
2780 s->flags |= SN_FINST_R;
2781 s->flags &= ~SN_SELF_GEN;
2782 return 1;
2783 }
2784}
2785
2786
2787/*
2788 * Produces statistics data for the session <s>. Expects to be called with
2789 * s->cli_state == CL_STSHUTR. It stops by itself by unsetting the SN_SELF_GEN
2790 * flag from the session, which it uses to keep on being called when there is
2791 * free space in the buffer, of simply by letting an empty buffer upon return.
2792 * It returns 1 if it changes the session state from CL_STSHUTR, otherwise 0.
2793 */
2794int produce_content_stats(struct session *s)
2795{
2796 struct buffer *rep = s->rep;
2797 struct proxy *px;
2798 struct chunk msg;
2799 unsigned int up;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002800
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002801 msg.len = 0;
2802 msg.str = trash;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002803
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002804 switch (s->data_state) {
2805 case DATA_ST_INIT:
2806 /* the function had not been called yet */
2807 s->flags |= SN_SELF_GEN; // more data will follow
Willy Tarreaubaaee002006-06-26 02:48:02 +02002808
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002809 chunk_printf(&msg, sizeof(trash),
2810 "HTTP/1.0 200 OK\r\n"
2811 "Cache-Control: no-cache\r\n"
2812 "Connection: close\r\n"
2813 "Content-Type: text/html\r\n"
2814 "\r\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002815
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002816 s->logs.status = 200;
2817 client_retnclose(s, &msg); // send the start of the response.
2818 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002819
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002820 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
2821 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
2822 if (!(s->flags & SN_FINST_MASK))
2823 s->flags |= SN_FINST_R;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002824
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002825 s->data_state = DATA_ST_HEAD; /* let's start producing data */
2826 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002827
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002828 case DATA_ST_HEAD:
2829 /* WARNING! This must fit in the first buffer !!! */
2830 chunk_printf(&msg, sizeof(trash),
2831 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
2832 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
2833 "<style type=\"text/css\"><!--\n"
2834 "body {"
2835 " font-family: helvetica, arial;"
2836 " font-size: 12px;"
2837 " font-weight: normal;"
2838 " color: black;"
2839 " background: white;"
2840 "}\n"
2841 "th,td {"
2842 " font-size: 0.8em;"
2843 " align: center;"
2844 "}"
2845 "h1 {"
2846 " font-size: xx-large;"
2847 " margin-bottom: 0.5em;"
2848 "}\n"
2849 "h2 {"
2850 " font-family: helvetica, arial;"
2851 " font-size: x-large;"
2852 " font-weight: bold;"
2853 " font-style: italic;"
2854 " color: #6020a0;"
2855 " margin-top: 0em;"
2856 " margin-bottom: 0em;"
2857 "}\n"
2858 "h3 {"
2859 " font-family: helvetica, arial;"
2860 " font-size: 16px;"
2861 " font-weight: bold;"
2862 " color: #b00040;"
2863 " background: #e8e8d0;"
2864 " margin-top: 0em;"
2865 " margin-bottom: 0em;"
2866 "}\n"
2867 "li {"
2868 " margin-top: 0.25em;"
2869 " margin-right: 2em;"
2870 "}\n"
2871 ".hr {margin-top: 0.25em;"
2872 " border-color: black;"
2873 " border-bottom-style: solid;"
2874 "}\n"
2875 ".pxname {background: #b00040;color: #ffff40;font-weight: bold;}\n"
2876 ".titre {background: #20D0D0;color: #000000;font-weight: bold;}\n"
2877 ".total {background: #20D0D0;color: #ffff80;}\n"
2878 ".frontend {background: #e8e8d0;}\n"
2879 ".backend {background: #e8e8d0;}\n"
2880 ".active0 {background: #ff9090;}\n"
2881 ".active1 {background: #ffd020;}\n"
2882 ".active2 {background: #ffffa0;}\n"
2883 ".active3 {background: #c0ffc0;}\n"
2884 ".active4 {background: #e0e0e0;}\n"
2885 ".backup0 {background: #ff9090;}\n"
2886 ".backup1 {background: #ff80ff;}\n"
2887 ".backup2 {background: #c060ff;}\n"
2888 ".backup3 {background: #b0d0ff;}\n"
2889 ".backup4 {background: #e0e0e0;}\n"
2890 "table.tbl { border-collapse: collapse; border-style: none;}\n"
Willy Tarreau35d66b02007-01-02 00:28:21 +01002891 "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 +01002892 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}\n"
2893 "table.tbl th.empty { border-style: none; empty-cells: hide;}\n"
2894 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
2895 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
2896 "table.lgd td.noborder { border-style: none; padding: 2px; white-space: nowrap;}\n"
2897 "-->"
2898 "</style></head>");
2899
2900 if (buffer_write_chunk(rep, &msg) != 0)
2901 return 0;
2902
2903 s->data_state = DATA_ST_INFO;
2904 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002905
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002906 case DATA_ST_INFO:
2907 up = (now.tv_sec - start_date.tv_sec);
2908
2909 /* WARNING! this has to fit the first packet too.
2910 * We are around 3.5 kB, add adding entries will
2911 * become tricky if we want to support 4kB buffers !
2912 */
2913 chunk_printf(&msg, sizeof(trash),
2914 "<body><h1><a href=\"" PRODUCT_URL "\" style=\"text-decoration: none;\">"
2915 PRODUCT_NAME "</a></h1>\n"
2916 "<h2>Statistics Report for pid %d</h2>\n"
2917 "<hr width=\"100%%\" class=\"hr\">\n"
2918 "<h3>&gt; General process information</h3>\n"
2919 "<table border=0 cols=3><tr><td align=\"left\" nowrap width=\"1%%\">\n"
2920 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
2921 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
2922 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
2923 "<b>maxsock = </b> %d<br>\n"
2924 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
2925 "</td><td align=\"center\" nowrap>\n"
2926 "<table class=\"lgd\"><tr>"
2927 "<td class=\"active3\">&nbsp;</td><td class=\"noborder\">active UP </td>"
2928 "<td class=\"backup3\">&nbsp;</td><td class=\"noborder\">backup UP </td>"
2929 "</tr><tr>"
2930 "<td class=\"active2\"></td><td class=\"noborder\">active UP, going down </td>"
2931 "<td class=\"backup2\"></td><td class=\"noborder\">backup UP, going down </td>"
2932 "</tr><tr>"
2933 "<td class=\"active1\"></td><td class=\"noborder\">active DOWN, going up </td>"
2934 "<td class=\"backup1\"></td><td class=\"noborder\">backup DOWN, going up </td>"
2935 "</tr><tr>"
2936 "<td class=\"active0\"></td><td class=\"noborder\">active or backup DOWN &nbsp;</td>"
2937 "<td class=\"active4\"></td><td class=\"noborder\">not checked </td>"
2938 "</tr></table>\n"
2939 "</td>"
2940 "<td align=\"left\" nowrap width=\"1%%\">"
2941 "<b>External ressources:</b><ul style=\"margin-top: 0.25em;\">"
2942 "<li><a href=\"" PRODUCT_URL "\">Primary site</a><br>"
2943 "<li><a href=\"" PRODUCT_URL_UPD "\">Updates (v" PRODUCT_BRANCH ")</a><br>"
2944 "<li><a href=\"" PRODUCT_URL_DOC "\">Online manual</a><br>"
2945 "</ul>"
2946 "</td>"
2947 "</tr></table>\n"
2948 "",
2949 pid, pid, global.nbproc,
2950 up / 86400, (up % 86400) / 3600,
2951 (up % 3600) / 60, (up % 60),
2952 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
2953 global.rlimit_memmax ? " MB" : "",
2954 global.rlimit_nofile,
2955 global.maxsock,
2956 global.maxconn,
2957 actconn
2958 );
Willy Tarreaubaaee002006-06-26 02:48:02 +02002959
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002960 if (buffer_write_chunk(rep, &msg) != 0)
2961 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002962
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002963 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002964
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002965 s->data_ctx.stats.px = proxy;
2966 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
2967 s->data_state = DATA_ST_LIST;
2968 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002969
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002970 case DATA_ST_LIST:
2971 /* dump proxies */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002972 while (s->data_ctx.stats.px) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002973 px = s->data_ctx.stats.px;
2974 /* skip the disabled proxies and non-networked ones */
2975 if (px->state != PR_STSTOPPED && (px->cap & (PR_CAP_FE | PR_CAP_BE)))
2976 if (produce_content_stats_proxy(s, px) == 0)
2977 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002978
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002979 s->data_ctx.stats.px = px->next;
2980 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
2981 }
2982 /* here, we just have reached the last proxy */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002983
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002984 s->data_state = DATA_ST_END;
2985 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002986
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002987 case DATA_ST_END:
2988 chunk_printf(&msg, sizeof(trash), "</body></html>");
2989 if (buffer_write_chunk(rep, &msg) != 0)
2990 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002991
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002992 s->data_state = DATA_ST_FIN;
2993 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002994
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002995 case DATA_ST_FIN:
2996 s->flags &= ~SN_SELF_GEN;
2997 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002998
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002999 default:
3000 /* unknown state ! */
3001 s->logs.status = 500;
3002 client_retnclose(s, error_message(s, HTTP_ERR_500));
3003 if (!(s->flags & SN_ERR_MASK))
3004 s->flags |= SN_ERR_PRXCOND;
3005 if (!(s->flags & SN_FINST_MASK))
3006 s->flags |= SN_FINST_R;
3007 s->flags &= ~SN_SELF_GEN;
3008 return 1;
3009 }
3010}
Willy Tarreaubaaee002006-06-26 02:48:02 +02003011
Willy Tarreaubaaee002006-06-26 02:48:02 +02003012
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003013/*
3014 * Dumps statistics for a proxy.
3015 * Returns 0 if it had to stop dumping data because of lack of buffer space,
3016 * ot non-zero if everything completed.
3017 */
3018int produce_content_stats_proxy(struct session *s, struct proxy *px)
3019{
3020 struct buffer *rep = s->rep;
3021 struct server *sv;
3022 struct chunk msg;
3023
3024 msg.len = 0;
3025 msg.str = trash;
3026
3027 switch (s->data_ctx.stats.px_st) {
3028 case DATA_ST_PX_INIT:
3029 /* we are on a new proxy */
3030
3031 if (s->be->fiprm->uri_auth && s->be->fiprm->uri_auth->scope) {
3032 /* we have a limited scope, we have to check the proxy name */
3033 struct stat_scope *scope;
3034 int len;
3035
3036 len = strlen(px->id);
3037 scope = s->be->fiprm->uri_auth->scope;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003038
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003039 while (scope) {
3040 /* match exact proxy name */
3041 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3042 break;
3043
3044 /* match '.' which means 'self' proxy */
3045 if (!strcmp(scope->px_id, ".") && px == s->fe)
3046 break;
3047 scope = scope->next;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003048 }
3049
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003050 /* proxy name not found : don't dump anything */
3051 if (scope == NULL)
3052 return 1;
3053 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003054
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003055 s->data_ctx.stats.px_st = DATA_ST_PX_TH;
3056 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003057
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003058 case DATA_ST_PX_TH:
3059 /* print a new table */
3060 chunk_printf(&msg, sizeof(trash),
3061 "<table cols=\"20\" class=\"tbl\" width=\"100%%\">\n"
3062 "<tr align=\"center\" class=\"titre\">"
3063 "<th colspan=2 class=\"pxname\">%s</th>"
3064 "<th colspan=18 class=\"empty\"></th>"
3065 "</tr>\n"
3066 "<tr align=\"center\" class=\"titre\">"
3067 "<th rowspan=2></th>"
3068 "<th colspan=2>Queue</th><th colspan=4>Sessions</th>"
3069 "<th colspan=2>Bytes</th><th colspan=2>Denied</th>"
3070 "<th colspan=3>Errors</th><th colspan=6>Server</th>"
3071 "</tr>\n"
3072 "<tr align=\"center\" class=\"titre\">"
Willy Tarreau35d66b02007-01-02 00:28:21 +01003073 "<th>Cur</th><th>Max</th><th>Cur</th><th>Max</th>"
3074 "<th>Limit</th><th>Cumul</th><th>In</th><th>Out</th>"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003075 "<th>Req</th><th>Resp</th><th>Req</th><th>Conn</th>"
3076 "<th>Resp</th><th>Status</th><th>Weight</th><th>Act</th>"
3077 "<th>Bck</th><th>Check</th><th>Down</th></tr>\n"
3078 "",
3079 px->id);
3080
3081 if (buffer_write_chunk(rep, &msg) != 0)
3082 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003083
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003084 s->data_ctx.stats.px_st = DATA_ST_PX_FE;
3085 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003086
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003087 case DATA_ST_PX_FE:
3088 /* print the frontend */
3089 if (px->cap & PR_CAP_FE) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003090 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003091 /* name, queue */
3092 "<tr align=center class=\"frontend\"><td>Frontend</td><td colspan=2></td>"
3093 /* sessions : current, max, limit, cumul. */
3094 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
3095 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003096 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003097 /* denied: req, resp */
3098 "<td align=right>%d</td><td align=right>%d</td>"
3099 /* errors : request, connect, response */
3100 "<td align=right>%d</td><td align=right></td><td align=right></td>"
3101 /* server status : reflect backend status */
3102 "<td align=center>%s</td>"
3103 /* rest of server: nothing */
3104 "<td align=center colspan=5></td></tr>"
3105 "",
3106 px->feconn, px->feconn_max, px->maxconn, px->cum_feconn,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003107 px->bytes_in, px->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003108 px->denied_req, px->denied_resp,
3109 px->failed_req,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003110 px->state == PR_STRUN ? "OPEN" :
3111 px->state == PR_STIDLE ? "FULL" : "STOP");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003112
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003113 if (buffer_write_chunk(rep, &msg) != 0)
3114 return 0;
3115 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003116
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003117 s->data_ctx.stats.sv = px->srv; /* may be NULL */
3118 s->data_ctx.stats.px_st = DATA_ST_PX_SV;
3119 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003120
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003121 case DATA_ST_PX_SV:
3122 /* stats.sv has been initialized above */
3123 while (s->data_ctx.stats.sv != NULL) {
3124 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3125 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP, 4=unchecked */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003126
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003127 sv = s->data_ctx.stats.sv;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003128
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003129 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3130 if (!(sv->state & SRV_CHECKED))
3131 sv_state = 4;
3132 else if (sv->state & SRV_RUNNING)
3133 if (sv->health == sv->rise + sv->fall - 1)
3134 sv_state = 3; /* UP */
3135 else
3136 sv_state = 2; /* going down */
3137 else
3138 if (sv->health)
3139 sv_state = 1; /* going up */
3140 else
3141 sv_state = 0; /* DOWN */
3142
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003143 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003144 /* name */
3145 "<tr align=\"center\" class=\"%s%d\"><td>%s</td>"
3146 /* queue : current, max */
3147 "<td align=right>%d</td><td align=right>%d</td>"
3148 /* sessions : current, max, limit, cumul */
3149 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>"
3150 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003151 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003152 /* denied: req, resp */
3153 "<td align=right></td><td align=right>%d</td>"
3154 /* errors : request, connect, response */
3155 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
3156 "",
Willy Tarreau368e96a2007-01-07 00:16:15 +01003157 (sv->state & SRV_BACKUP) ? "backup" : "active",
Willy Tarreau128e9542007-01-01 22:01:43 +01003158 sv_state, sv->id,
3159 sv->nbpend, sv->nbpend_max,
3160 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003161 sv->bytes_in, sv->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003162 sv->failed_secu,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003163 sv->failed_conns, sv->failed_resp);
Willy Tarreau128e9542007-01-01 22:01:43 +01003164
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003165 /* status */
3166 chunk_printf(&msg, sizeof(trash), "<td nowrap>");
3167 chunk_printf(&msg, sizeof(trash),
3168 srv_hlt_st[sv_state],
3169 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3170 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3171
Willy Tarreau128e9542007-01-01 22:01:43 +01003172 chunk_printf(&msg, sizeof(trash),
3173 /* weight */
3174 "</td><td>%d</td>"
3175 /* act, bck */
3176 "<td>%s</td><td>%s</td>"
3177 "",
3178 sv->uweight+1,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003179 (sv->state & SRV_BACKUP) ? "-" : "Y",
3180 (sv->state & SRV_BACKUP) ? "Y" : "-");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003181
3182 /* check failures : unique, fatal */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003183 if (sv->state & SRV_CHECKED)
3184 chunk_printf(&msg, sizeof(trash),
3185 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3186 sv->failed_checks, sv->down_trans);
3187 else
3188 chunk_printf(&msg, sizeof(trash),
3189 "<td colspan=2></td></tr>\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003190
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003191 if (buffer_write_chunk(rep, &msg) != 0)
3192 return 0;
3193
3194 s->data_ctx.stats.sv = sv->next;
3195 } /* while sv */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003196
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003197 s->data_ctx.stats.px_st = DATA_ST_PX_BE;
3198 /* fall through */
3199
3200 case DATA_ST_PX_BE:
3201 /* print the backend */
3202 if (px->cap & PR_CAP_BE) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003203 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003204 /* name */
3205 "<tr align=center class=\"backend\"><td>Backend</td>"
3206 /* queue : current, max */
3207 "<td align=right>%d</td><td align=right>%d</td>"
3208 /* sessions : current, max, limit, cumul. */
3209 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
3210 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003211 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003212 /* denied: req, resp */
3213 "<td align=right>%d</td><td align=right>%d</td>"
3214 /* errors : request, connect, response */
3215 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
3216 /* server status : reflect backend status (up/down) : we display UP
3217 * if the backend has known working servers or if it has no server at
3218 * all (eg: for stats). Tthen we display the total weight, number of
3219 * active and backups. */
3220 "<td align=center>%s</td><td align=center>%d</td>"
3221 "<td align=center>%d</td><td align=center>%d</td>"
3222 /* rest of server: nothing */
3223 "<td align=center colspan=2></td></tr>"
3224 "",
3225 px->nbpend /* or px->totpend ? */, px->nbpend_max,
3226 px->beconn, px->beconn_max, px->fullconn, px->cum_beconn,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003227 px->bytes_in, px->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003228 px->denied_req, px->denied_resp,
3229 px->failed_conns, px->failed_resp,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003230 (px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN",
3231 px->srv_map_sz, px->srv_act, px->srv_bck);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003232
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003233 if (buffer_write_chunk(rep, &msg) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003234 return 0;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003235 }
3236
3237 s->data_ctx.stats.px_st = DATA_ST_PX_END;
3238 /* fall through */
3239
3240 case DATA_ST_PX_END:
3241 chunk_printf(&msg, sizeof(trash), "</table><p>\n");
3242
3243 if (buffer_write_chunk(rep, &msg) != 0)
3244 return 0;
3245
3246 s->data_ctx.stats.px_st = DATA_ST_PX_FIN;
3247 /* fall through */
3248
3249 case DATA_ST_PX_FIN:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003250 return 1;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003251
3252 default:
3253 /* unknown state, we should put an abort() here ! */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003254 return 1;
3255 }
3256}
3257
3258
Willy Tarreau58f10d72006-12-04 02:26:12 +01003259
3260/*
3261 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>
3262 */
3263
3264void apply_filters_to_session(struct session *t, struct buffer *req, struct hdr_exp *exp)
3265{
3266 /* iterate through the filters in the outer loop */
3267 while (exp && !(t->flags & (SN_CLDENY|SN_CLTARPIT))) {
3268 char term;
3269 char *cur_ptr, *cur_end, *cur_next;
3270 int cur_idx, old_idx, abort_filt;
3271
3272
3273 /*
3274 * The interleaving of transformations and verdicts
3275 * makes it difficult to decide to continue or stop
3276 * the evaluation.
3277 */
3278
3279 if ((t->flags & SN_CLALLOW) &&
3280 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
3281 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
3282 exp = exp->next;
3283 continue;
3284 }
3285
3286 /* Iterate through the headers in the inner loop.
3287 * we start with the start line.
3288 */
3289 old_idx = cur_idx = 0;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003290 cur_next = req->data + t->hreq.sor;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003291 abort_filt = 0;
3292
Willy Tarreau45e73e32006-12-17 00:05:15 +01003293 while (!abort_filt && (cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
3294 struct hdr_idx_elem *cur_hdr = &t->hreq.hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003295 cur_ptr = cur_next;
3296 cur_end = cur_ptr + cur_hdr->len;
3297 cur_next = cur_end + cur_hdr->cr + 1;
3298
3299 /* Now we have one header between cur_ptr and cur_end,
3300 * and the next header starts at cur_next.
3301 */
3302
3303 /* The annoying part is that pattern matching needs
3304 * that we modify the contents to null-terminate all
3305 * strings before testing them.
3306 */
3307
3308 term = *cur_end;
3309 *cur_end = '\0';
3310
3311 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3312 switch (exp->action) {
Willy Tarreaua496b602006-12-17 23:15:24 +01003313 case ACT_SETBE:
3314 /* It is not possible to jump a second time.
3315 * FIXME: should we return an HTTP/500 here so that
3316 * the admin knows there's a problem ?
3317 */
3318 if (t->be != t->fe)
3319 break;
3320
3321 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3322 struct proxy *target = (struct proxy *) exp->replace;
3323
3324 /* Swithing Proxy */
3325 *cur_end = term;
3326 cur_end = NULL;
3327
3328 /* right now, the backend switch is not too much complicated
3329 * because we have associated req_cap and rsp_cap to the
3330 * frontend, and the beconn will be updated later.
3331 */
3332
3333 t->rep->rto = t->req->wto = target->beprm->srvtimeout;
3334 t->req->cto = target->beprm->contimeout;
3335
3336 t->be = target;
3337
3338 //t->logs.logwait |= LW_REQ | (target->to_log & (LW_REQHDR | LW_COOKIE));
Willy Tarreau97de6242006-12-27 17:18:38 +01003339 /* FIXME: should we use the backend's log options or not ?
3340 * It would seem far too complicated to configure a service with
3341 * logs defined both in the frontend and the backend.
3342 */
3343 //t->logs.logwait |= (target->to_log | target->beprm->to_log);
3344
Willy Tarreaua496b602006-12-17 23:15:24 +01003345 abort_filt = 1;
3346 }
3347 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003348 case ACT_ALLOW:
3349 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3350 t->flags |= SN_CLALLOW;
3351 abort_filt = 1;
3352 }
3353 break;
3354 case ACT_REPLACE:
3355 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3356 int len, delta;
3357 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3358 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
Willy Tarreaue15d9132006-12-14 22:26:42 +01003359 /* FIXME: if the user adds a newline in the replacement, the
3360 * index will not be recalculated for now, and the new line
3361 * will not be counted for a new header.
3362 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003363 cur_end += delta;
3364 cur_next += delta;
3365 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003366 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003367 }
3368 break;
3369 case ACT_REMOVE:
3370 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3371 int delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3372 cur_next += delta;
3373
3374 /* FIXME: this should be a separate function */
Willy Tarreau45e73e32006-12-17 00:05:15 +01003375 t->hreq.eoh += delta;
3376 t->hreq.hdr_idx.v[old_idx].next = cur_hdr->next;
3377 t->hreq.hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003378 cur_hdr->len = 0;
3379
3380 cur_end = NULL; /* null-term has been rewritten */
3381 }
3382 break;
3383 case ACT_DENY:
3384 if (!(t->flags & (SN_CLALLOW | SN_CLTARPIT))) {
3385 t->flags |= SN_CLDENY;
3386 abort_filt = 1;
3387 }
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003388 t->be->beprm->denied_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003389 break;
3390 case ACT_TARPIT:
3391 if (!(t->flags & (SN_CLALLOW | SN_CLDENY))) {
3392 t->flags |= SN_CLTARPIT;
3393 abort_filt = 1;
3394 }
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003395 t->be->beprm->denied_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003396 break;
3397 //case ACT_PASS: /* FIXME: broken as of now. We should mark the header as "ignored". */
3398 // break;
3399 }
3400 }
3401 if (cur_end)
3402 *cur_end = term; /* restore the string terminator */
3403
3404 /* keep the link from this header to next one */
3405 old_idx = cur_idx;
3406 }
3407 exp = exp->next;
3408 }
3409}
3410
3411
3412
3413/*
3414 * Manager client-side cookie
3415 */
3416void manage_client_side_cookies(struct session *t, struct buffer *req)
3417{
3418 char *p1, *p2, *p3, *p4;
3419 char *del_colon, *del_cookie, *colon;
3420 int app_cookies;
3421
3422 appsess *asession_temp = NULL;
3423 appsess local_asession;
3424
3425 char *cur_ptr, *cur_end, *cur_next;
3426 int cur_idx, old_idx, abort_filt;
3427
Willy Tarreau830ff452006-12-17 19:31:23 +01003428 if (t->be->beprm->cookie_name == NULL &&
3429 t->be->beprm->appsession_name ==NULL &&
3430 t->be->fiprm->capture_name != NULL)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003431 return;
3432
Willy Tarreau2a324282006-12-05 00:05:46 +01003433 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003434 * we start with the start line.
3435 */
3436 old_idx = cur_idx = 0;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003437 cur_next = req->data + t->hreq.sor;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003438 abort_filt = 0;
3439
Willy Tarreau45e73e32006-12-17 00:05:15 +01003440 while ((cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003441 struct hdr_idx_elem *cur_hdr;
3442
Willy Tarreau45e73e32006-12-17 00:05:15 +01003443 cur_hdr = &t->hreq.hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003444 cur_ptr = cur_next;
3445 cur_end = cur_ptr + cur_hdr->len;
3446 cur_next = cur_end + cur_hdr->cr + 1;
3447
3448 /* We have one full header between cur_ptr and cur_end, and the
3449 * next header starts at cur_next. We're only interested in
3450 * "Cookie:" headers.
3451 */
3452
3453 if ((cur_end - cur_ptr <= 7) ||
3454 (strncasecmp(cur_ptr, "Cookie:", 7) != 0)) {
3455 old_idx = cur_idx;
3456 continue;
3457 }
3458
3459 /* Now look for cookies. Conforming to RFC2109, we have to support
3460 * attributes whose name begin with a '$', and associate them with
3461 * the right cookie, if we want to delete this cookie.
3462 * So there are 3 cases for each cookie read :
3463 * 1) it's a special attribute, beginning with a '$' : ignore it.
3464 * 2) it's a server id cookie that we *MAY* want to delete : save
3465 * some pointers on it (last semi-colon, beginning of cookie...)
3466 * 3) it's an application cookie : we *MAY* have to delete a previous
3467 * "special" cookie.
3468 * At the end of loop, if a "special" cookie remains, we may have to
3469 * remove it. If no application cookie persists in the header, we
3470 * *MUST* delete it
3471 */
3472
3473
3474 p1 = cur_ptr + 7; /* first char after 'Cookie:' */
3475 if (isspace((int)*p1)) /* try to get the first space with it */
3476 p1++;
3477
3478 colon = p1;
3479 /* del_cookie == NULL => nothing to be deleted */
3480 del_colon = del_cookie = NULL;
3481 app_cookies = 0;
3482
3483 while (p1 < cur_end) {
3484 /* skip spaces and colons, but keep an eye on these ones */
3485 while (p1 < cur_end) {
3486 if (*p1 == ';' || *p1 == ',')
3487 colon = p1;
3488 else if (!isspace((int)*p1))
3489 break;
3490 p1++;
3491 }
3492
3493 if (p1 == cur_end)
3494 break;
3495
3496 /* p1 is at the beginning of the cookie name */
3497 p2 = p1;
3498 while (p2 < cur_end && *p2 != '=')
3499 p2++;
3500
3501 if (p2 == cur_end)
3502 break;
3503
3504 p3 = p2 + 1; /* skips the '=' sign */
3505 if (p3 == cur_end)
3506 break;
3507
3508 p4 = p3;
3509 while (p4 < cur_end && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
3510 p4++;
3511
3512 /* here, we have the cookie name between p1 and p2,
3513 * and its value between p3 and p4.
3514 * we can process it :
3515 *
3516 * Cookie: NAME=VALUE;
3517 * | || || |
3518 * | || || +--> p4
3519 * | || |+-------> p3
3520 * | || +--------> p2
3521 * | |+------------> p1
3522 * | +-------------> colon
3523 * +--------------------> cur_ptr
3524 */
3525
3526 if (*p1 == '$') {
3527 /* skip this one */
3528 }
3529 else {
3530 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01003531 if (t->fe->fiprm->capture_name != NULL &&
Willy Tarreau58f10d72006-12-04 02:26:12 +01003532 t->logs.cli_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01003533 (p4 - p1 >= t->fe->fiprm->capture_namelen) &&
3534 memcmp(p1, t->fe->fiprm->capture_name, t->fe->fiprm->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003535 int log_len = p4 - p1;
3536
3537 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3538 Alert("HTTP logging : out of memory.\n");
3539 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003540 if (log_len > t->fe->fiprm->capture_len)
3541 log_len = t->fe->fiprm->capture_len;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003542 memcpy(t->logs.cli_cookie, p1, log_len);
3543 t->logs.cli_cookie[log_len] = 0;
3544 }
3545 }
3546
Willy Tarreau830ff452006-12-17 19:31:23 +01003547 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
3548 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003549 /* Cool... it's the right one */
Willy Tarreau830ff452006-12-17 19:31:23 +01003550 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003551 char *delim;
3552
3553 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3554 * have the server ID betweek p3 and delim, and the original cookie between
3555 * delim+1 and p4. Otherwise, delim==p4 :
3556 *
3557 * Cookie: NAME=SRV~VALUE;
3558 * | || || | |
3559 * | || || | +--> p4
3560 * | || || +--------> delim
3561 * | || |+-----------> p3
3562 * | || +------------> p2
3563 * | |+----------------> p1
3564 * | +-----------------> colon
3565 * +------------------------> cur_ptr
3566 */
3567
Willy Tarreau830ff452006-12-17 19:31:23 +01003568 if (t->be->beprm->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003569 for (delim = p3; delim < p4; delim++)
3570 if (*delim == COOKIE_DELIM)
3571 break;
3572 }
3573 else
3574 delim = p4;
3575
3576
3577 /* Here, we'll look for the first running server which supports the cookie.
3578 * This allows to share a same cookie between several servers, for example
3579 * to dedicate backup servers to specific servers only.
3580 * However, to prevent clients from sticking to cookie-less backup server
3581 * when they have incidentely learned an empty cookie, we simply ignore
3582 * empty cookies and mark them as invalid.
3583 */
3584 if (delim == p3)
3585 srv = NULL;
3586
3587 while (srv) {
3588 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003589 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003590 /* we found the server and it's usable */
3591 t->flags &= ~SN_CK_MASK;
3592 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3593 t->srv = srv;
3594 break;
3595 } else {
3596 /* we found a server, but it's down */
3597 t->flags &= ~SN_CK_MASK;
3598 t->flags |= SN_CK_DOWN;
3599 }
3600 }
3601 srv = srv->next;
3602 }
3603
3604 if (!srv && !(t->flags & SN_CK_DOWN)) {
3605 /* no server matched this cookie */
3606 t->flags &= ~SN_CK_MASK;
3607 t->flags |= SN_CK_INVALID;
3608 }
3609
3610 /* depending on the cookie mode, we may have to either :
3611 * - delete the complete cookie if we're in insert+indirect mode, so that
3612 * the server never sees it ;
3613 * - remove the server id from the cookie value, and tag the cookie as an
3614 * application cookie so that it does not get accidentely removed later,
3615 * if we're in cookie prefix mode
3616 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003617 if ((t->be->beprm->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003618 int delta; /* negative */
3619
3620 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
3621 p4 += delta;
3622 cur_end += delta;
3623 cur_next += delta;
3624 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003625 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003626
3627 del_cookie = del_colon = NULL;
3628 app_cookies++; /* protect the header from deletion */
3629 }
3630 else if (del_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01003631 (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 +01003632 del_cookie = p1;
3633 del_colon = colon;
3634 }
3635 } else {
3636 /* now we know that we must keep this cookie since it's
3637 * not ours. But if we wanted to delete our cookie
3638 * earlier, we cannot remove the complete header, but we
3639 * can remove the previous block itself.
3640 */
3641 app_cookies++;
3642
3643 if (del_cookie != NULL) {
3644 int delta; /* negative */
3645
3646 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
3647 p4 += delta;
3648 cur_end += delta;
3649 cur_next += delta;
3650 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003651 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003652 del_cookie = del_colon = NULL;
3653 }
3654 }
3655
Willy Tarreau830ff452006-12-17 19:31:23 +01003656 if ((t->be->beprm->appsession_name != NULL) &&
3657 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003658 /* first, let's see if the cookie is our appcookie*/
3659
3660 /* Cool... it's the right one */
3661
3662 asession_temp = &local_asession;
3663
3664 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3665 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3666 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3667 return;
3668 }
3669
Willy Tarreau830ff452006-12-17 19:31:23 +01003670 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
3671 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003672 asession_temp->serverid = NULL;
3673
3674 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01003675 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003676 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3677 /* free previously allocated memory */
3678 pool_free_to(apools.sessid, local_asession.sessid);
3679 Alert("Not enough memory process_cli():asession:calloc().\n");
3680 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3681 return;
3682 }
3683
3684 asession_temp->sessid = local_asession.sessid;
3685 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01003686 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003687 } else {
3688 /* free previously allocated memory */
3689 pool_free_to(apools.sessid, local_asession.sessid);
3690 }
3691
3692 if (asession_temp->serverid == NULL) {
3693 Alert("Found Application Session without matching server.\n");
3694 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003695 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003696 while (srv) {
3697 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003698 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003699 /* we found the server and it's usable */
3700 t->flags &= ~SN_CK_MASK;
3701 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3702 t->srv = srv;
3703 break;
3704 } else {
3705 t->flags &= ~SN_CK_MASK;
3706 t->flags |= SN_CK_DOWN;
3707 }
3708 }
3709 srv = srv->next;
3710 }/* end while(srv) */
3711 }/* end else if server == NULL */
3712
Willy Tarreau830ff452006-12-17 19:31:23 +01003713 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003714 }/* end if ((t->proxy->appsession_name != NULL) ... */
3715 }
3716
3717 /* we'll have to look for another cookie ... */
3718 p1 = p4;
3719 } /* while (p1 < cur_end) */
3720
3721 /* There's no more cookie on this line.
3722 * We may have marked the last one(s) for deletion.
3723 * We must do this now in two ways :
3724 * - if there is no app cookie, we simply delete the header ;
3725 * - if there are app cookies, we must delete the end of the
3726 * string properly, including the colon/semi-colon before
3727 * the cookie name.
3728 */
3729 if (del_cookie != NULL) {
3730 int delta;
3731 if (app_cookies) {
3732 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
3733 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003734 cur_hdr->len += delta;
3735 } else {
3736 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003737
3738 /* FIXME: this should be a separate function */
Willy Tarreau45e73e32006-12-17 00:05:15 +01003739 t->hreq.hdr_idx.v[old_idx].next = cur_hdr->next;
3740 t->hreq.hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003741 cur_hdr->len = 0;
3742 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01003743 cur_next += delta;
3744 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003745 }
3746
3747 /* keep the link from this header to next one */
3748 old_idx = cur_idx;
3749 } /* end of cookie processing on this header */
3750}
3751
3752
3753
3754/*
3755 * Try to retrieve a known appsession in the URI, then the associated server.
3756 * If the server is found, it's assigned to the session.
3757 */
3758
3759void get_srv_from_appsession(struct session *t, const char *begin, const char *end)
3760{
3761 appsess *asession_temp = NULL;
3762 appsess local_asession;
3763 char *request_line;
3764
Willy Tarreau830ff452006-12-17 19:31:23 +01003765 if (t->be->beprm->appsession_name == NULL ||
Willy Tarreau921d7c02006-12-17 13:50:27 +01003766 (t->hreq.meth != HTTP_METH_GET && t->hreq.meth != HTTP_METH_POST) ||
Willy Tarreau58f10d72006-12-04 02:26:12 +01003767 (request_line = memchr(begin, ';', end - begin)) == NULL ||
Willy Tarreau830ff452006-12-17 19:31:23 +01003768 ((1 + t->be->beprm->appsession_name_len + 1 + t->be->beprm->appsession_len) > (end - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01003769 return;
3770
3771 /* skip ';' */
3772 request_line++;
3773
3774 /* look if we have a jsessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01003775 if (strncasecmp(request_line, t->be->beprm->appsession_name, t->be->beprm->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003776 return;
3777
3778 /* skip jsessionid= */
Willy Tarreau830ff452006-12-17 19:31:23 +01003779 request_line += t->be->beprm->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003780
3781 /* First try if we already have an appsession */
3782 asession_temp = &local_asession;
3783
3784 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3785 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3786 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3787 return;
3788 }
3789
3790 /* Copy the sessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01003791 memcpy(asession_temp->sessid, request_line, t->be->beprm->appsession_len);
3792 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003793 asession_temp->serverid = NULL;
3794
3795 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01003796 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *)&asession_temp)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003797 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3798 /* free previously allocated memory */
3799 pool_free_to(apools.sessid, local_asession.sessid);
3800 Alert("Not enough memory process_cli():asession:calloc().\n");
3801 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3802 return;
3803 }
3804 asession_temp->sessid = local_asession.sessid;
3805 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01003806 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003807 }
3808 else {
3809 /* free previously allocated memory */
3810 pool_free_to(apools.sessid, local_asession.sessid);
3811 }
3812
Willy Tarreau830ff452006-12-17 19:31:23 +01003813 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003814 asession_temp->request_count++;
3815
3816#if defined(DEBUG_HASH)
3817 print_table(&(t->proxy->htbl_proxy));
3818#endif
3819 if (asession_temp->serverid == NULL) {
3820 Alert("Found Application Session without matching server.\n");
3821 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003822 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003823 while (srv) {
3824 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003825 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003826 /* we found the server and it's usable */
3827 t->flags &= ~SN_CK_MASK;
3828 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3829 t->srv = srv;
3830 break;
3831 } else {
3832 t->flags &= ~SN_CK_MASK;
3833 t->flags |= SN_CK_DOWN;
3834 }
3835 }
3836 srv = srv->next;
3837 }
3838 }
3839}
3840
3841
Willy Tarreaub2513902006-12-17 14:52:38 +01003842
3843/*
3844 * In a GET request, check if the requested URI matches the stats uri for the
3845 * current backend, and if an authorization has been passed and is valid.
3846 *
Willy Tarreau830ff452006-12-17 19:31:23 +01003847 * It is assumed that the request is a GET and that the t->be->fiprm->uri_auth field
Willy Tarreaub2513902006-12-17 14:52:38 +01003848 * is valid. An HTTP/401 response may be sent, or produce_content() can be
3849 * called to start sending data.
3850 *
3851 * Returns 1 if the session's state changes, otherwise 0.
3852 */
3853int stats_check_uri_auth(struct session *t, struct proxy *backend)
3854{
3855 struct uri_auth *uri_auth = backend->uri_auth;
3856 struct user_auth *user;
3857 int authenticated, cur_idx;
3858 char *h;
3859
3860 if (t->hreq.start.len < uri_auth->uri_len + 4) /* +4 for "GET " */
3861 return 0;
3862
3863 if (memcmp(t->hreq.start.str + 4, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
3864 return 0;
3865
3866 /* we are in front of a interceptable URI. Let's check
3867 * if there's an authentication and if it's valid.
3868 */
3869 user = uri_auth->users;
3870 if (!user) {
3871 /* no user auth required, it's OK */
3872 authenticated = 1;
3873 } else {
3874 authenticated = 0;
3875
3876 /* a user list is defined, we have to check.
3877 * skip 21 chars for "Authorization: Basic ".
3878 */
3879
3880 /* FIXME: this should move to an earlier place */
3881 cur_idx = 0;
3882 h = t->req->data + t->hreq.sor;
3883 while ((cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
3884 int len = t->hreq.hdr_idx.v[cur_idx].len;
3885 if (len > 14 &&
3886 !strncasecmp("Authorization:", h, 14)) {
3887 t->hreq.auth_hdr.str = h;
3888 t->hreq.auth_hdr.len = len;
3889 break;
3890 }
3891 h += len + t->hreq.hdr_idx.v[cur_idx].cr + 1;
3892 }
3893
3894 if (t->hreq.auth_hdr.len < 21 ||
3895 memcmp(t->hreq.auth_hdr.str + 14, " Basic ", 7))
3896 user = NULL;
3897
3898 while (user) {
3899 if ((t->hreq.auth_hdr.len == user->user_len + 14 + 7)
3900 && !memcmp(t->hreq.auth_hdr.str + 14 + 7,
3901 user->user_pwd, user->user_len)) {
3902 authenticated = 1;
3903 break;
3904 }
3905 user = user->next;
3906 }
3907 }
3908
3909 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01003910 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01003911
3912 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01003913 msg.str = trash;
3914 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreaub2513902006-12-17 14:52:38 +01003915 t->logs.status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01003916 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01003917 if (!(t->flags & SN_ERR_MASK))
3918 t->flags |= SN_ERR_PRXCOND;
3919 if (!(t->flags & SN_FINST_MASK))
3920 t->flags |= SN_FINST_R;
3921 return 1;
3922 }
3923
3924 /* The request is valid, the user is authenticate. Let's start sending
3925 * data.
3926 */
3927 t->cli_state = CL_STSHUTR;
3928 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
3929 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
3930 t->data_source = DATA_SRC_STATS;
3931 t->data_state = DATA_ST_INIT;
3932 produce_content(t);
3933 return 1;
3934}
3935
3936
3937
Willy Tarreaubaaee002006-06-26 02:48:02 +02003938/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01003939 * Print a debug line with a header
3940 */
3941void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
3942{
3943 int len, max;
3944 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
3945 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
3946 max = end - start;
3947 UBOUND(max, sizeof(trash) - len - 1);
3948 len += strlcpy2(trash + len, start, max + 1);
3949 trash[len++] = '\n';
3950 write(1, trash, len);
3951}
3952
3953
3954/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02003955 * Local variables:
3956 * c-indent-level: 8
3957 * c-basic-offset: 8
3958 * End:
3959 */