blob: 89b5b60f6ce9ce7b874c7e6edf91f960d0372695 [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
54
Willy Tarreau58f10d72006-12-04 02:26:12 +010055#define DEBUG_PARSE_NO_SPEEDUP
56#undef DEBUG_PARSE_NO_SPEEDUP
57
Willy Tarreau976f1ee2006-12-17 10:06:03 +010058/* This is used to perform a quick jump as an alternative to a break/continue
59 * instruction. The first argument is the label for normal operation, and the
60 * second one is the break/continue instruction in the no_speedup mode.
61 */
62
63#ifdef DEBUG_PARSE_NO_SPEEDUP
64#define QUICK_JUMP(x,y) y
65#else
66#define QUICK_JUMP(x,y) goto x
67#endif
68
Willy Tarreau1c47f852006-07-09 08:22:27 +020069/* This is used by remote monitoring */
Willy Tarreau0f772532006-12-23 20:51:41 +010070const char HTTP_200[] =
Willy Tarreau1c47f852006-07-09 08:22:27 +020071 "HTTP/1.0 200 OK\r\n"
72 "Cache-Control: no-cache\r\n"
73 "Connection: close\r\n"
74 "Content-Type: text/html\r\n"
75 "\r\n"
76 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
77
Willy Tarreau0f772532006-12-23 20:51:41 +010078const struct chunk http_200_chunk = {
79 .str = (char *)&HTTP_200,
80 .len = sizeof(HTTP_200)-1
81};
82
83const char *HTTP_302 =
84 "HTTP/1.0 302 Found\r\n"
85 "Cache-Control: no-cache\r\n"
86 "Connection: close\r\n"
87 "Location: "; /* not terminated since it will be concatenated with the URL */
88
89/* same as 302 except that the browser MUST retry with the GET method */
90const char *HTTP_303 =
91 "HTTP/1.0 303 See Other\r\n"
92 "Cache-Control: no-cache\r\n"
93 "Connection: close\r\n"
94 "Location: "; /* not terminated since it will be concatenated with the URL */
95
Willy Tarreaubaaee002006-06-26 02:48:02 +020096/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
97const char *HTTP_401_fmt =
98 "HTTP/1.0 401 Unauthorized\r\n"
99 "Cache-Control: no-cache\r\n"
100 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +0200101 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200102 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
103 "\r\n"
104 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
105
Willy Tarreau0f772532006-12-23 20:51:41 +0100106
107const int http_err_codes[HTTP_ERR_SIZE] = {
108 [HTTP_ERR_400] = 400,
109 [HTTP_ERR_403] = 403,
110 [HTTP_ERR_408] = 408,
111 [HTTP_ERR_500] = 500,
112 [HTTP_ERR_502] = 502,
113 [HTTP_ERR_503] = 503,
114 [HTTP_ERR_504] = 504,
115};
116
117const char *http_err_msgs[HTTP_ERR_SIZE] = {
118 [HTTP_ERR_400] =
119 "HTTP/1.0 400 Bad request\r\n"
120 "Cache-Control: no-cache\r\n"
121 "Connection: close\r\n"
122 "Content-Type: text/html\r\n"
123 "\r\n"
124 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
125
126 [HTTP_ERR_403] =
127 "HTTP/1.0 403 Forbidden\r\n"
128 "Cache-Control: no-cache\r\n"
129 "Connection: close\r\n"
130 "Content-Type: text/html\r\n"
131 "\r\n"
132 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
133
134 [HTTP_ERR_408] =
135 "HTTP/1.0 408 Request Time-out\r\n"
136 "Cache-Control: no-cache\r\n"
137 "Connection: close\r\n"
138 "Content-Type: text/html\r\n"
139 "\r\n"
140 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
141
142 [HTTP_ERR_500] =
143 "HTTP/1.0 500 Server Error\r\n"
144 "Cache-Control: no-cache\r\n"
145 "Connection: close\r\n"
146 "Content-Type: text/html\r\n"
147 "\r\n"
148 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n",
149
150 [HTTP_ERR_502] =
151 "HTTP/1.0 502 Bad Gateway\r\n"
152 "Cache-Control: no-cache\r\n"
153 "Connection: close\r\n"
154 "Content-Type: text/html\r\n"
155 "\r\n"
156 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n",
157
158 [HTTP_ERR_503] =
159 "HTTP/1.0 503 Service Unavailable\r\n"
160 "Cache-Control: no-cache\r\n"
161 "Connection: close\r\n"
162 "Content-Type: text/html\r\n"
163 "\r\n"
164 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n",
165
166 [HTTP_ERR_504] =
167 "HTTP/1.0 504 Gateway Time-out\r\n"
168 "Cache-Control: no-cache\r\n"
169 "Connection: close\r\n"
170 "Content-Type: text/html\r\n"
171 "\r\n"
172 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n",
173
174};
175
Willy Tarreaubaaee002006-06-26 02:48:02 +0200176
Willy Tarreau53b6c742006-12-17 13:37:46 +0100177/*
178 * We have 26 list of methods (1 per first letter), each of which can have
179 * up to 3 entries (2 valid, 1 null).
180 */
181struct http_method_desc {
182 http_meth_t meth;
183 int len;
184 const char text[8];
185};
186
187static struct http_method_desc http_methods[26][3] = {
188 ['C' - 'A'] = {
189 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
190 },
191 ['D' - 'A'] = {
192 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
193 },
194 ['G' - 'A'] = {
195 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
196 },
197 ['H' - 'A'] = {
198 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
199 },
200 ['P' - 'A'] = {
201 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
202 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
203 },
204 ['T' - 'A'] = {
205 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
206 },
207 /* rest is empty like this :
208 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
209 */
210};
211
Willy Tarreaubaaee002006-06-26 02:48:02 +0200212#ifdef DEBUG_FULL
213static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
214static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
215#endif
216
217
218/*
219 * returns a message to the client ; the connection is shut down for read,
220 * and the request is cleared so that no server connection can be initiated.
221 * The client must be in a valid state for this (HEADER, DATA ...).
Willy Tarreau0f772532006-12-23 20:51:41 +0100222 * Nothing is performed on the server side. The message is contained in a
223 * "chunk". If it is null, then an empty message is used.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200224 * The reply buffer doesn't need to be empty before this.
225 */
Willy Tarreau0f772532006-12-23 20:51:41 +0100226void client_retnclose(struct session *s, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200227{
Willy Tarreau2a429502006-10-15 14:52:29 +0200228 MY_FD_CLR(s->cli_fd, StaticReadEvent);
229 MY_FD_SET(s->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +0200230 tv_eternity(&s->req->rex);
Willy Tarreau73de9892006-11-30 11:40:23 +0100231 if (s->fe->clitimeout)
232 tv_delayfrom(&s->rep->wex, &now, s->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200233 else
Willy Tarreaud7971282006-07-29 18:36:34 +0200234 tv_eternity(&s->rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200235 shutdown(s->cli_fd, SHUT_RD);
236 s->cli_state = CL_STSHUTR;
237 buffer_flush(s->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100238 if (msg->len)
239 buffer_write(s->rep, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200240 s->req->l = 0;
241}
242
243
244/*
245 * returns a message into the rep buffer, and flushes the req buffer.
Willy Tarreau0f772532006-12-23 20:51:41 +0100246 * The reply buffer doesn't need to be empty before this. The message
247 * is contained in a "chunk". If it is null, then an empty message is
248 * used.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200249 */
Willy Tarreau0f772532006-12-23 20:51:41 +0100250void client_return(struct session *s, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200251{
252 buffer_flush(s->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100253 if (msg->len)
254 buffer_write(s->rep, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200255 s->req->l = 0;
256}
257
258
259/* This function turns the server state into the SV_STCLOSE, and sets
Willy Tarreau0f772532006-12-23 20:51:41 +0100260 * indicators accordingly. Note that if <status> is 0, or if the message
261 * pointer is NULL, then no message is returned.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200262 */
263void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreau0f772532006-12-23 20:51:41 +0100264 int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200265{
266 t->srv_state = SV_STCLOSE;
Willy Tarreau0f772532006-12-23 20:51:41 +0100267 if (status > 0 && msg) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200268 t->logs.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100269 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100270 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200271 }
272 if (!(t->flags & SN_ERR_MASK))
273 t->flags |= err;
274 if (!(t->flags & SN_FINST_MASK))
275 t->flags |= finst;
276}
277
278
Willy Tarreau53b6c742006-12-17 13:37:46 +0100279/*
280 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
281 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
282 */
283static http_meth_t find_http_meth(const char *str, const int len)
284{
285 unsigned char m;
286 struct http_method_desc *h;
287
288 m = ((unsigned)*str - 'A');
289
290 if (m < 26) {
291 int l;
292 for (h = http_methods[m]; (l = (h->len)) > 0; h++) {
293 if (len <= l)
294 continue;
295
296 if (str[l] != ' ' && str[l] != '\t')
297 continue;
298
299 if (memcmp(str, h->text, l) == 0) {
300 return h->meth;
301 }
302 };
303 return HTTP_METH_OTHER;
304 }
305 return HTTP_METH_NONE;
306
307}
308
309
Willy Tarreaubaaee002006-06-26 02:48:02 +0200310/* Processes the client and server jobs of a session task, then
311 * puts it back to the wait queue in a clean state, or
312 * cleans up its resources if it must be deleted. Returns
313 * the time the task accepts to wait, or TIME_ETERNITY for
314 * infinity.
315 */
316int process_session(struct task *t)
317{
318 struct session *s = t->context;
319 int fsm_resync = 0;
320
321 do {
322 fsm_resync = 0;
323 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
324 fsm_resync |= process_cli(s);
325 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
326 fsm_resync |= process_srv(s);
327 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
328 } while (fsm_resync);
329
330 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
331 struct timeval min1, min2;
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200332 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
333 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200334
Willy Tarreaud7971282006-07-29 18:36:34 +0200335 tv_min(&min1, &s->req->rex, &s->req->wex);
336 tv_min(&min2, &s->rep->rex, &s->rep->wex);
337 tv_min(&min1, &min1, &s->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200338 tv_min(&t->expire, &min1, &min2);
339
340 /* restore t to its place in the task list */
341 task_queue(t);
342
343#ifdef DEBUG_FULL
344 /* DEBUG code : this should never ever happen, otherwise it indicates
345 * that a task still has something to do and will provoke a quick loop.
346 */
347 if (tv_remain2(&now, &t->expire) <= 0)
348 exit(100);
349#endif
350
351 return tv_remain2(&now, &t->expire); /* nothing more to do */
352 }
353
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100354 s->fe->feconn--;
355 if (s->flags & SN_BE_ASSIGNED)
356 s->be->beprm->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200357 actconn--;
358
359 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
360 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100361 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreau830ff452006-12-17 19:31:23 +0100362 s->uniq_id, s->be->beprm->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100363 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200364 write(1, trash, len);
365 }
366
367 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
368 if (s->rep != NULL)
369 s->logs.bytes = s->rep->total;
370
371 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200372 if (s->logs.logwait &&
373 !(s->flags & SN_MONITOR) &&
Willy Tarreau73de9892006-11-30 11:40:23 +0100374 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total))
Willy Tarreaubaaee002006-06-26 02:48:02 +0200375 sess_log(s);
376
377 /* the task MUST not be in the run queue anymore */
378 task_delete(t);
379 session_free(s);
380 task_free(t);
381 return TIME_ETERNITY; /* rest in peace for eternity */
382}
383
384
385/*
386 * FIXME: This should move to the HTTP_flow_analyzer code
387 */
388
389/*
390 * manages the client FSM and its socket. BTW, it also tries to handle the
391 * cookie. It returns 1 if a state has changed (and a resync may be needed),
392 * 0 else.
393 */
394int process_cli(struct session *t)
395{
396 int s = t->srv_state;
397 int c = t->cli_state;
398 struct buffer *req = t->req;
399 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100400 int delete_header = 0;
401
Willy Tarreaub2513902006-12-17 14:52:38 +0100402 int cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200403
Willy Tarreau45e73e32006-12-17 00:05:15 +0100404 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 +0200405 cli_stnames[c], srv_stnames[s],
Willy Tarreau2a429502006-10-15 14:52:29 +0200406 MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
Willy Tarreaud7971282006-07-29 18:36:34 +0200407 req->rex.tv_sec, req->rex.tv_usec,
408 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau45e73e32006-12-17 00:05:15 +0100409
Willy Tarreaubaaee002006-06-26 02:48:02 +0200410 if (c == CL_STHEADERS) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100411 /*
412 * Now parse the partial (or complete) lines.
413 * We will check the request syntax, and also join multi-line
414 * headers. An index of all the lines will be elaborated while
415 * parsing.
416 *
417 * For the parsing, we use a 10 states FSM.
418 *
419 * RFC2616 requires that both LF and CRLF are recognized as
420 * line breaks, but that any other combination is an error.
421 * To avoid duplicating all the states above to check for CR,
422 * we use a special bit HTTP_PA_LF_EXP that we 'OR' with the
423 * state we will switch to if the LF is seen, so that we know
424 * whether there's a pending CR or not. We can check it
425 * globally since all CR followed by anything but LF are
426 * errors. Each state is entered with the first character is
427 * has to process at req->lr. We also have HTTP_PA_CR_SKIP
428 * indicating that a CR has been seen on current line and
429 * skipped.
430 *
431 * Here is the information we currently have :
Willy Tarreau45e73e32006-12-17 00:05:15 +0100432 * req->data + req->sor = beginning of request
433 * req->data + req->eoh = end of (parsed) headers
Willy Tarreau58f10d72006-12-04 02:26:12 +0100434 * req->lr = first non-visited byte
435 * req->r = end of data
436 */
437
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100438 char *sol, *eol; /* Start Of Line, End Of Line */
Willy Tarreau830ff452006-12-17 19:31:23 +0100439 struct proxy *cur_proxy;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100440
Willy Tarreau45e73e32006-12-17 00:05:15 +0100441 eol = sol = req->data + t->hreq.eoh;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100442
Willy Tarreau58f10d72006-12-04 02:26:12 +0100443 while (req->lr < req->r) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100444 int parse;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200445
Willy Tarreau45e73e32006-12-17 00:05:15 +0100446 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",
447 t->hreq.hdr_state, t->hreq.hdr_idx.used, t->hreq.hdr_idx.tail, t->hreq.hdr_idx.last,
448 sol - req->data, req->lr - req->data, req->r - req->data, t->hreq.eoh);
449
450 if (t->hreq.hdr_state & HTTP_PA_LF_EXP) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100451 if (*req->lr != '\n') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100452 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100453 break;
454 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100455 t->hreq.hdr_state &= ~HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100456 }
457
Willy Tarreau45e73e32006-12-17 00:05:15 +0100458 parse = t->hreq.hdr_state & ~HTTP_PA_CR_SKIP;;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100459
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100460 if (parse == HTTP_PA_HDR_LF) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100461 parse_hdr_lf:
462 /* The LF validating last header, but it
463 * may also be an LWS, in which case we will
464 * need more data to know if we can close this
465 * header or not. However, we must check right
466 * now if this LF/CRLF closes an empty line, in
467 * which case it means the end of the request.
468 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100469 eol = req->lr;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100470 if (t->hreq.hdr_state & HTTP_PA_CR_SKIP)
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100471 eol--; /* Get back to the CR */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100472
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100473 if (eol == sol) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100474 /* We have found the end of the headers.
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100475 * sol points to the ending LF/CRLF,
Willy Tarreau58f10d72006-12-04 02:26:12 +0100476 * and req->lr points to the first byte
477 * after the LF, so it is easy to append
478 * anything there.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200479 */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100480 t->hreq.hdr_state = HTTP_PA_LFLF;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100481 QUICK_JUMP(parse_lflf, continue);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100482 }
483
484 if (req->lr + 1 >= req->r) /* LF, ?? */
485 break;
486 req->lr++;
487
488 /* Right now, we *know* that there is one char
489 * available at req->lr.
490 */
491
492 if (*req->lr == ' ' || *req->lr == '\t') {
493 /* We have an LWS, we will replace the
494 * CR and LF with spaces as RFC2616
495 * allows it. <lr> now points to the
496 * first space char of the LWS part.
497 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100498 for (;eol < req->lr; eol++)
499 *eol = ' ';
Willy Tarreau58f10d72006-12-04 02:26:12 +0100500
Willy Tarreau45e73e32006-12-17 00:05:15 +0100501 t->hreq.hdr_state = HTTP_PA_HDR_LWS;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100502 QUICK_JUMP(parse_hdr_lws, continue);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100503 }
504
505 /**********************************************
506 * We now have one complete header between *
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100507 * sol and eol, with a possible CR at eol, *
Willy Tarreau58f10d72006-12-04 02:26:12 +0100508 * everything ending before req->lr. Some very*
509 * early processing can be applied. *
510 **********************************************/
511
512 /*
513 * FIXME: insert a REQHEADER hook here.
514 * For instance, we could check the header's
515 * syntax such as forbidding the leading space
516 * in the first header (Apache also has the same problem)
517 */
518
519
520 /* 1: we might have to print this header */
521 if ((global.mode & MODE_DEBUG) &&
522 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100523 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100524
525
526 /* 2: maybe we have to copy this header for the logs ? */
527 if (t->logs.logwait & LW_REQHDR) {
528 /* FIXME: we must *search* the value after the ':' and not
529 * consider that it's necessary after one single space.*/
530 struct cap_hdr *h;
531 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +0100532 for (h = t->fe->fiprm->req_cap; h; h = h->next) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100533 if ((h->namelen + 2 <= eol - sol) &&
534 (sol[h->namelen] == ':') &&
535 (strncasecmp(sol, h->name, h->namelen) == 0)) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100536 if (t->hreq.cap[h->index] == NULL)
537 t->hreq.cap[h->index] =
538 pool_alloc_from(h->pool, h->len + 1);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100539
Willy Tarreau45e73e32006-12-17 00:05:15 +0100540 if (t->hreq.cap[h->index] == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100541 Alert("HTTP capture : out of memory.\n");
542 continue;
543 }
544
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100545 len = eol - (sol + h->namelen + 2);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100546 if (len > h->len)
547 len = h->len;
548
Willy Tarreau45e73e32006-12-17 00:05:15 +0100549 memcpy(t->hreq.cap[h->index], sol + h->namelen + 2, len);
550 t->hreq.cap[h->index][len]=0;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100551 }
552 }
553 }
554
555
556 /* 3: We might need to remove "connection:" */
557 if (!delete_header && (t->fe->options & PR_O_HTTP_CLOSE)
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100558 && (strncasecmp(sol, "Connection:", 11) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100559 delete_header = 1;
560 }
561
562
Willy Tarreau58f10d72006-12-04 02:26:12 +0100563 /* OK, that's enough processing for the first step.
564 * Now either we index this header or we remove it.
565 */
566
567 if (!delete_header) {
568 /* we insert it into the index */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100569 if (hdr_idx_add(eol - sol, req->lr - eol - 1,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100570 &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0) {
571 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100572 break;
573 }
574 } else {
575 /* we remove it */
576 delete_header = 0;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100577 buffer_replace2(req, sol, req->lr, NULL, 0);
578 /* WARNING: eol is not valid anymore, since the
Willy Tarreau58f10d72006-12-04 02:26:12 +0100579 * header may have been deleted or truncated ! */
580 }
581
582 /* In any case, we set the next header pointer
583 * to the next line.
584 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100585 sol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100586
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100587#ifdef DEBUG_PARSE_NO_SPEEDUP
588 t->hreq.hdr_state = HTTP_PA_HEADER;
589 continue;
590#else
Willy Tarreau58f10d72006-12-04 02:26:12 +0100591 /*
592 * We know that at least one character remains.
593 * It is interesting to directly branch to the
594 * matching state.
595 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100596 eol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100597 if (IS_CTL(*req->lr)) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100598 if (*eol == '\r') {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100599 req->lr++;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100600 t->hreq.hdr_state = HTTP_PA_LFLF | HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100601 continue;
602 }
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100603 else if (*eol == '\n') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100604 t->hreq.hdr_state = HTTP_PA_LFLF;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100605 goto parse_lflf;
606 }
607 else {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100608 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100609 break;
610 }
611 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100612 t->hreq.hdr_state = HTTP_PA_HEADER;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100613 goto parse_inside_hdr;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100614#endif
615
616 } else if (parse == HTTP_PA_STRT_LF) {
617 parse_strt_lf:
618 /* The LF validating the request line */
619
620 eol = req->lr;
621 if (t->hreq.hdr_state & HTTP_PA_CR_SKIP)
622 eol--; /* Get back to the CR */
623
624 /* We have the complete start line between
625 * sol and eol (excluded). lr points to
626 * the LF.
627 */
628
629 /* FIXME: insert a REQUESTURI hook here. */
630
631
632 /* 1: we might have to print this header */
633 if ((global.mode & MODE_DEBUG) &&
634 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
635 debug_hdr("clireq", t, sol, eol);
636
637 /* 2: maybe we have to copy the original REQURI for the logs ? */
638 if (t->logs.logwait & LW_REQ) {
639 /* we have a complete HTTP request that we must log */
640 if ((t->logs.uri = pool_alloc(requri)) != NULL) {
641 int urilen = eol - sol;
642
643 if (urilen >= REQURI_LEN)
644 urilen = REQURI_LEN - 1;
645 memcpy(t->logs.uri, sol, urilen);
646 t->logs.uri[urilen] = 0;
647
648 if (!(t->logs.logwait &= ~LW_REQ))
649 sess_log(t);
650 } else {
651 Alert("HTTP logging : out of memory.\n");
652 }
653 }
654
655 /* 3: reference this line as the start line */
656 if (hdr_idx_add(eol - sol, req->lr - eol,
657 &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0) {
658 t->hreq.hdr_state = HTTP_PA_ERROR;
659 break;
660 }
661
662 req->lr++;
663 sol = req->lr;
664 /* in fact, a state is missing here, we should
665 * be able to distinguish between an empty line
666 * and a header.
667 */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100668 t->hreq.hdr_state = HTTP_PA_HEADER;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100669#ifdef DEBUG_PARSE_NO_SPEEDUP
Willy Tarreau58f10d72006-12-04 02:26:12 +0100670 continue;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100671#else
672 if (req->lr < req->r)
673 goto parse_inside_hdr;
674 else
675 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100676#endif
677
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100678 } else if (parse == HTTP_PA_HEADER) {
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100679 char *ptr;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100680 /* Inside a non-empty header */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100681
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100682 parse_inside_hdr:
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100683 delete_header = 0;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100684
685 ptr = req->lr;
686
687#ifdef GCC_FINALLY_PRODUCES_EFFICIENT_WHILE_LOOPS
688 /* This code is disabled right now because
689 * eventhough it seems straightforward, the
690 * object code produced by GCC is so much
691 * suboptimal that about 10% of the time
692 * spend parsing header is there.
693 */
694 while (ptr < req->r && !IS_CTL(*ptr))
695 ptr++;
696 req->lr = ptr;
697 if (ptr == req->r)
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100698 break;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100699#else
700 /* Just by using this loop instead of the previous one,
701 * the global performance increases by about 2% ! The
702 * code is also smaller by about 50 bytes.
703 */
704 goto reqhdr_loop_chk;
705 reqhdr_loop:
706 ptr++;
707 reqhdr_loop_chk:
708 if (ptr == req->r) {
709 req->lr = ptr;
710 break;
711 }
712 if (*ptr != 0x7F && (unsigned)*ptr >= 0x20)
713 goto reqhdr_loop;
714 req->lr = ptr;
715#endif
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100716
717 /* we have a CTL char */
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100718 if (*ptr == '\r') {
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100719 t->hreq.hdr_state = HTTP_PA_HDR_LF | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
720 req->lr++;
721 continue;
722 }
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100723 else if (*ptr == '\n') {
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100724 t->hreq.hdr_state = HTTP_PA_HDR_LF;
725 QUICK_JUMP(parse_hdr_lf, continue);
726 }
727 t->hreq.hdr_state = HTTP_PA_ERROR;
728 break;
729
730 } else if (parse == HTTP_PA_EMPTY) {
731 /* leading empty lines */
732
733 if (*req->lr == '\n') {
734 req->lr ++;
735 t->hreq.hdr_state = HTTP_PA_EMPTY;
736 continue;
737 }
738 else if (*req->lr == '\r') {
739 req->lr ++;
740 t->hreq.hdr_state = HTTP_PA_EMPTY | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
741 continue;
742 }
743
744 FSM_PRINTF(stderr, "PA_EMPTY[0]: h=%d, lr=%d, r=%d\n",
745 sol - req->data, req->lr - req->data, req->r - req->data);
746
747#if PARSE_PRESERVE_EMPTY_LINES
748 /* only skip empty leading lines, don't remove them */
749 t->hreq.hdr_idx.v[0].len = req->lr - sol;
750 t->hreq.sor = t->hreq.hdr_idx.v[0].len;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100751#else
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100752 /* remove empty leading lines, as recommended by
753 * RFC2616. This takes a lot of time because we
754 * must move all the buffer backwards, but this
755 * is rarely needed. The method above will be
756 * cleaner when we'll be able to start sending
757 * the request from any place in the buffer.
758 */
759 buffer_replace2(req, sol, req->lr, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100760#endif
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100761 sol = req->lr;
762 FSM_PRINTF(stderr, "PA_EMPTY[1]: h=%d, lr=%d, r=%d\n",
763 sol - req->data, req->lr - req->data, req->r - req->data);
764
765 t->hreq.hdr_state = HTTP_PA_START;
766 /* we know that we still have one char available */
767 QUICK_JUMP(parse_start, continue);
768
769 } else if (parse == HTTP_PA_START) {
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100770 char *ptr;
771 /* Inside the start line */
772
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100773 parse_start:
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100774 ptr = req->lr;
775
776#ifdef GCC_FINALLY_PRODUCES_EFFICIENT_WHILE_LOOPS
777 /* This code is disabled right now because
778 * eventhough it seems straightforward, the
779 * object code produced by GCC is so much
780 * suboptimal that about 10% of the time
781 * spend parsing header is there.
782 */
783 while (ptr < req->r && !IS_CTL(*ptr))
784 ptr++;
785 req->lr = ptr;
786 if (ptr == req->r)
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100787 break;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100788#else
789 /* Just by using this loop instead of the previous one,
790 * the global performance increases by about 2% ! The
791 * code is also smaller by about 50 bytes.
792 */
793 goto reqstrt_loop_chk;
794 reqstrt_loop:
795 ptr++;
796 reqstrt_loop_chk:
797 if (ptr == req->r) {
798 req->lr = ptr;
799 break;
800 }
801 if (*ptr != 0x7F && (unsigned)*ptr >= 0x20)
802 goto reqstrt_loop;
803 req->lr = ptr;
804#endif
805
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100806 /* we have a CTL char */
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100807 if (*ptr == '\r') {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100808 req->lr++;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100809 t->hreq.hdr_state = HTTP_PA_STRT_LF | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
810 continue;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100811 }
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100812 else if (*ptr == '\n') {
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100813 t->hreq.hdr_state = HTTP_PA_STRT_LF;
814 /* we know that we still have one char available */
815 QUICK_JUMP(parse_strt_lf, continue);
816 }
817 t->hreq.hdr_state = HTTP_PA_ERROR;
818 break;
819
Willy Tarreau58f10d72006-12-04 02:26:12 +0100820
821 } else if (parse == HTTP_PA_LFLF) {
822 parse_lflf:
823 req->lr ++;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100824 /* sol points to either CR or CRLF, and
Willy Tarreau58f10d72006-12-04 02:26:12 +0100825 * req->lr points to 1 char after LF.
826 */
827
828 /*
829 * FIXME: insert a hook here for the end of the headers
830 */
831 break;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100832
833 } else if (parse == HTTP_PA_HDR_LWS) {
834 parse_hdr_lws:
835 /* Inside an LWS. We just replace tabs with
836 * spaces and fall back to the HEADER state
837 * at the first non-space character
838 */
839
840 while (req->lr < req->r) {
841 if (*req->lr == '\t')
842 *req->lr = ' ';
843 else if (*req->lr != ' ') {
844 t->hreq.hdr_state = HTTP_PA_HEADER;
845 QUICK_JUMP(parse_inside_hdr, break);
846 }
847 req->lr++;
848 }
849 continue;
850
Willy Tarreau58f10d72006-12-04 02:26:12 +0100851 } else if (parse == HTTP_PA_ERROR) {
852 break;
853 }
854
855 } /* end of the "while(req->lr < req->r)" loop */
856
Willy Tarreau45e73e32006-12-17 00:05:15 +0100857 /* update the end of headers */
858 t->hreq.eoh = sol - req->data;
859
860 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",
861 t->hreq.hdr_state, t->hreq.hdr_idx.used, t->hreq.hdr_idx.tail, t->hreq.hdr_idx.last,
862 sol - req->data, req->lr - req->data, req->r - req->data, t->hreq.eoh);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100863
864 /*
865 * Now, let's catch bad requests.
866 */
867
Willy Tarreau06619262006-12-17 08:37:22 +0100868 if (t->hreq.hdr_state == HTTP_PA_ERROR)
869 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100870
871 /*
872 * Now we quickly check if we have found a full request.
873 * If not so, we check the FD and buffer states before leaving.
874 * A full request is indicated by the fact that we have seen
875 * the double LF/CRLF, so the state is HTTP_PA_LFLF.
876 *
877 */
878
Willy Tarreau45e73e32006-12-17 00:05:15 +0100879 if (t->hreq.hdr_state != HTTP_PA_LFLF) { /* Request not complete yet */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100880
881 /* 1: Since we are in header mode, if there's no space
882 * left for headers, we won't be able to free more
883 * later, so the session will never terminate. We
884 * must terminate it now.
885 */
886 if (req->l >= req->rlim - req->data) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100887 /* FIXME: check if hreq.hdr_state & mask < HTTP_PA_HEADER,
Willy Tarreau58f10d72006-12-04 02:26:12 +0100888 * and return Status 414 Request URI too long instead.
889 */
Willy Tarreau06619262006-12-17 08:37:22 +0100890 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100891 }
892
893 /* 2: have we encountered a read error or a close ? */
894 else if (req->flags & (BF_READ_ERROR | BF_READ_NULL)) {
895 /* read error, or last read : give up. */
896 tv_eternity(&req->rex);
897 fd_delete(t->cli_fd);
898 t->cli_state = CL_STCLOSE;
899 if (!(t->flags & SN_ERR_MASK))
900 t->flags |= SN_ERR_CLICL;
901 if (!(t->flags & SN_FINST_MASK))
902 t->flags |= SN_FINST_R;
903 return 1;
904 }
905
906 /* 3: has the read timeout expired ? */
907 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
908 /* read timeout : give up with an error message. */
909 t->logs.status = 408;
Willy Tarreau0f772532006-12-23 20:51:41 +0100910 client_retnclose(t, &t->fe->errmsg[HTTP_ERR_408]);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100911 if (!(t->flags & SN_ERR_MASK))
912 t->flags |= SN_ERR_CLITO;
913 if (!(t->flags & SN_FINST_MASK))
914 t->flags |= SN_FINST_R;
915 return 1;
916 }
917
918 /* 4: do we need to re-enable the read socket ? */
919 else if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
920 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
921 * full. We cannot loop here since stream_sock_read will disable it only if
922 * req->l == rlim-data
923 */
924 MY_FD_SET(t->cli_fd, StaticReadEvent);
925 if (t->fe->clitimeout)
926 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
927 else
928 tv_eternity(&req->rex);
929 }
930 return t->cli_state != CL_STHEADERS;
931 }
932
933
934 /****************************************************************
935 * More interesting part now : we know that we have a complete *
936 * request which at least looks like HTTP. We have an indicator *
937 * of each header's length, so we can parse them quickly. *
938 ****************************************************************/
939
940
941 /*
Willy Tarreau06619262006-12-17 08:37:22 +0100942 * 1: check if the URI matches the monitor_uri.
943 * We have to do this for every request which gets in, because
944 * the monitor-uri is defined by the frontend. To speed-up the
945 * test, we include the leading and trailing spaces in the
946 * comparison. This is generally not a problem because the
947 * monitor-uri is primarily used by external checkers which
948 * send pre-formatted requests too.
Willy Tarreau58f10d72006-12-04 02:26:12 +0100949 */
950
Willy Tarreau06619262006-12-17 08:37:22 +0100951 t->hreq.start.str = req->data + t->hreq.sor; /* start of the REQURI */
952 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 +0100953 t->hreq.meth = find_http_meth(t->hreq.start.str, t->hreq.start.len);
Willy Tarreau06619262006-12-17 08:37:22 +0100954
955 if ((t->fe->monitor_uri_len != 0) &&
956 (t->hreq.start.len >= t->fe->monitor_uri_len)) {
957 char *p = t->hreq.start.str;
958 int idx = 0;
959
960 /* skip the method so that we accept any method */
961 while (idx < t->hreq.start.len && p[idx] != ' ')
962 idx++;
963 p += idx;
964
965 if (t->hreq.start.len - idx >= t->fe->monitor_uri_len &&
966 !memcmp(p, t->fe->monitor_uri, t->fe->monitor_uri_len)) {
967 /*
968 * We have found the monitor URI
969 */
970 t->flags |= SN_MONITOR;
971 t->logs.status = 200;
Willy Tarreau0f772532006-12-23 20:51:41 +0100972 client_retnclose(t, &http_200_chunk);
Willy Tarreau06619262006-12-17 08:37:22 +0100973 goto return_prx_cond;
974 }
Willy Tarreau58f10d72006-12-04 02:26:12 +0100975 }
976
977
978 /*
979 * 2: we will have to evaluate the filters.
980 * As opposed to version 1.2, now they will be evaluated in the
981 * filters order and not in the header order. This means that
982 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +0100983 *
984 * We can now check whether we want to switch to another
985 * backend, in which case we will re-check the backend's
986 * filters and various options. In order to support 3-level
987 * switching, here's how we should proceed :
988 *
Willy Tarreau830ff452006-12-17 19:31:23 +0100989 * a) run be->fiprm.
990 * if (switch) then switch ->be to the new backend.
991 * b) run be->fiprm if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +0100992 * There cannot be any switch from there, so ->be cannot be
993 * changed anymore.
994 *
Willy Tarreau830ff452006-12-17 19:31:23 +0100995 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100996 *
Willy Tarreau830ff452006-12-17 19:31:23 +0100997 * The response path will be able to apply either ->be, or
998 * ->be then ->fe filters in order to match the reverse of
999 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001000 */
1001
Willy Tarreau06619262006-12-17 08:37:22 +01001002 do {
Willy Tarreau830ff452006-12-17 19:31:23 +01001003 struct proxy *rule_set = t->be->fiprm;
1004 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001005
Willy Tarreau06619262006-12-17 08:37:22 +01001006 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01001007 if (rule_set->req_exp != NULL) {
Willy Tarreau06619262006-12-17 08:37:22 +01001008 apply_filters_to_session(t, req, rule_set->req_exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001009
Willy Tarreau53b6c742006-12-17 13:37:46 +01001010 /* the start line might have been modified */
1011 t->hreq.start.len = t->hreq.hdr_idx.v[t->hreq.hdr_idx.v[0].next].len;
1012 t->hreq.meth = find_http_meth(t->hreq.start.str, t->hreq.start.len);
Willy Tarreau53b6c742006-12-17 13:37:46 +01001013 }
1014
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001015 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
1016 /* to ensure correct connection accounting on
1017 * the backend, we count the connection for the
1018 * one managing the queue.
1019 */
1020 t->be->beprm->beconn++;
1021 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1022 t->be->beprm->beconn_max = t->be->beprm->beconn;
1023 t->be->beprm->cum_beconn++;
1024 t->flags |= SN_BE_ASSIGNED;
1025 }
1026
Willy Tarreau06619262006-12-17 08:37:22 +01001027 /* has the request been denied ? */
1028 if (t->flags & SN_CLDENY) {
1029 /* no need to go further */
1030 t->logs.status = 403;
1031 /* let's log the request time */
1032 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreau0f772532006-12-23 20:51:41 +01001033 client_retnclose(t, &t->fe->errmsg[HTTP_ERR_403]);
Willy Tarreau06619262006-12-17 08:37:22 +01001034 goto return_prx_cond;
1035 }
1036
1037 /* add request headers from the rule sets in the same order */
1038 for (cur_hdr = 0; cur_hdr < rule_set->nb_reqadd; cur_hdr++) {
1039 int len;
1040
1041 len = sprintf(trash, "%s\r\n", rule_set->req_add[cur_hdr]);
1042 len = buffer_replace2(req, req->data + t->hreq.eoh,
1043 req->data + t->hreq.eoh, trash, len);
1044 t->hreq.eoh += len;
1045
1046 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1047 goto return_bad_req;
1048 }
Willy Tarreaub2513902006-12-17 14:52:38 +01001049
1050 if (rule_set->uri_auth != NULL && t->hreq.meth == HTTP_METH_GET) {
1051 /* we have to check the URI and auth for this request */
1052 if (stats_check_uri_auth(t, rule_set))
1053 return 1;
1054 }
1055
Willy Tarreau830ff452006-12-17 19:31:23 +01001056 } while (cur_proxy != t->be); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01001057
Willy Tarreau58f10d72006-12-04 02:26:12 +01001058
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001059 if (!(t->flags & SN_BE_ASSIGNED)) {
1060 /* To ensure correct connection accounting on
1061 * the backend, we count the connection for the
1062 * one managing the queue.
1063 */
1064 t->be->beprm->beconn++;
1065 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1066 t->be->beprm->beconn_max = t->be->beprm->beconn;
1067 t->be->beprm->cum_beconn++;
1068 t->flags |= SN_BE_ASSIGNED;
1069 }
1070
1071
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001072 /*
1073 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01001074 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001075 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01001076 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01001077 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001078
Willy Tarreau58f10d72006-12-04 02:26:12 +01001079
Willy Tarreau58f10d72006-12-04 02:26:12 +01001080
Willy Tarreau58f10d72006-12-04 02:26:12 +01001081
Willy Tarreau2a324282006-12-05 00:05:46 +01001082 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001083 * 3: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01001084 * so let's do the same now.
1085 */
1086
1087 /* It needs to look into the URI */
Willy Tarreau830ff452006-12-17 19:31:23 +01001088 if (t->be->beprm->appsession_name) {
Willy Tarreau06619262006-12-17 08:37:22 +01001089 get_srv_from_appsession(t,
1090 t->hreq.start.str,
1091 t->hreq.start.str + t->hreq.start.len);
1092 }
1093
1094
1095 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001096 * 4: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01001097 * Note that doing so might move headers in the request, but
1098 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01001099 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01001100 */
1101 if (!(t->flags & (SN_CLDENY|SN_CLTARPIT)))
1102 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001103
Willy Tarreau58f10d72006-12-04 02:26:12 +01001104
Willy Tarreau2a324282006-12-05 00:05:46 +01001105 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001106 * 5: add X-Forwarded-For : Should depend on the backend only.
Willy Tarreau2a324282006-12-05 00:05:46 +01001107 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001108 if (t->be->beprm->options & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001109 if (t->cli_addr.ss_family == AF_INET) {
1110 int len;
1111 unsigned char *pn;
1112 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
1113 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
1114 pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001115 len = buffer_replace2(req, req->data + t->hreq.eoh,
1116 req->data + t->hreq.eoh, trash, len);
1117 t->hreq.eoh += len;
1118
Willy Tarreau06619262006-12-17 08:37:22 +01001119 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1120 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001121 }
1122 else if (t->cli_addr.ss_family == AF_INET6) {
1123 int len;
1124 char pn[INET6_ADDRSTRLEN];
1125 inet_ntop(AF_INET6,
1126 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
1127 pn, sizeof(pn));
1128 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001129 len = buffer_replace2(req, req->data + t->hreq.eoh,
1130 req->data + t->hreq.eoh, trash, len);
1131 t->hreq.eoh += len;
1132
Willy Tarreau06619262006-12-17 08:37:22 +01001133 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1134 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001135 }
1136 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001137
Willy Tarreaubaaee002006-06-26 02:48:02 +02001138
Willy Tarreau2a324282006-12-05 00:05:46 +01001139 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001140 * 6: add "Connection:"
Willy Tarreau2a324282006-12-05 00:05:46 +01001141 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001142
Willy Tarreaub2513902006-12-17 14:52:38 +01001143 /* add a "connection: close" line if needed.
1144 * FIXME: this should depend on both the frontend and the backend.
1145 * Header removals should be performed when the filters are run.
1146 */
Willy Tarreaue15d9132006-12-14 22:26:42 +01001147 if (t->fe->options & PR_O_HTTP_CLOSE) {
Willy Tarreau45e73e32006-12-17 00:05:15 +01001148 int len;
1149 len = buffer_replace2(req, req->data + t->hreq.eoh,
1150 req->data + t->hreq.eoh, "Connection: close\r\n", 19);
1151 t->hreq.eoh += len;
1152
Willy Tarreau06619262006-12-17 08:37:22 +01001153 if (hdr_idx_add(17, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1154 goto return_bad_req;
Willy Tarreaue15d9132006-12-14 22:26:42 +01001155 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001156
Willy Tarreaubaaee002006-06-26 02:48:02 +02001157
Willy Tarreaue15d9132006-12-14 22:26:42 +01001158
1159
Willy Tarreau06619262006-12-17 08:37:22 +01001160
Willy Tarreaue15d9132006-12-14 22:26:42 +01001161
Willy Tarreau2a324282006-12-05 00:05:46 +01001162 /*************************************************************
1163 * OK, that's finished for the headers. We have done what we *
1164 * could. Let's switch to the DATA state. *
1165 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02001166
Willy Tarreau2a324282006-12-05 00:05:46 +01001167 t->cli_state = CL_STDATA;
1168 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001169
Willy Tarreau2a324282006-12-05 00:05:46 +01001170 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001171
Willy Tarreaubaaee002006-06-26 02:48:02 +02001172
Willy Tarreau2a324282006-12-05 00:05:46 +01001173 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001174 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001175 /* If the client has no timeout, or if the server is not ready yet,
1176 * and we know for sure that it can expire, then it's cleaner to
1177 * disable the timeout on the client side so that too low values
1178 * cannot make the sessions abort too early.
1179 *
1180 * FIXME-20050705: the server needs a way to re-enable this time-out
1181 * when it switches its state, otherwise a client can stay connected
1182 * indefinitely. This now seems to be OK.
1183 */
1184 tv_eternity(&req->rex);
1185 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001186
Willy Tarreaub8750a82006-09-03 09:56:00 +02001187
Willy Tarreau2a324282006-12-05 00:05:46 +01001188 /* When a connection is tarpitted, we use the queue timeout for the
1189 * tarpit delay, which currently happens to be the server's connect
1190 * timeout. If unset, then set it to zero because we really want it
1191 * to expire at one moment.
1192 */
1193 if (t->flags & SN_CLTARPIT) {
1194 t->req->l = 0;
1195 /* flush the request so that we can drop the connection early
1196 * if the client closes first.
1197 */
1198 tv_delayfrom(&req->cex, &now,
Willy Tarreau830ff452006-12-17 19:31:23 +01001199 t->be->beprm->contimeout ? t->be->beprm->contimeout : 0);
Willy Tarreau2a324282006-12-05 00:05:46 +01001200 }
Willy Tarreaub8750a82006-09-03 09:56:00 +02001201
Willy Tarreau2a324282006-12-05 00:05:46 +01001202#if DEBUG_HTTP_PARSER
1203 /* example: dump each line */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001204
Willy Tarreau2a324282006-12-05 00:05:46 +01001205 fprintf(stderr, "t->flags=0x%08x\n", t->flags & (SN_CLALLOW|SN_CLDENY|SN_CLTARPIT));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001206
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001207 fprintf(stderr, "sol=%d\n", sol - req->data);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001208 sol = req->data + t->hreq.sor;
Willy Tarreau2a324282006-12-05 00:05:46 +01001209 cur_hdr = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001210
Willy Tarreau45e73e32006-12-17 00:05:15 +01001211 cur_idx = t->hreq.hdr_idx.v[0].next;
Willy Tarreau2a324282006-12-05 00:05:46 +01001212 cur_hdr = 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001213
Willy Tarreau45e73e32006-12-17 00:05:15 +01001214 while (cur_hdr < t->hreq.hdr_idx.used) {
1215 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 +01001216 fprintf(stderr, "lr=%d r=%d hdr=%d idx=%d adr=%d..%d len=%d cr=%d data:\n",
1217 req->lr - req->data, req->r - req->data,
1218 cur_hdr, cur_idx,
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001219 sol - req->data,
Willy Tarreau45e73e32006-12-17 00:05:15 +01001220 sol - req->data + t->hreq.hdr_idx.v[cur_idx].len + t->hreq.hdr_idx.v[cur_idx].cr,
1221 t->hreq.hdr_idx.v[cur_idx].len,
1222 t->hreq.hdr_idx.v[cur_idx].cr);
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001223 write(2, sol, eol - sol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001224
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001225 sol = eol;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001226 cur_idx = t->hreq.hdr_idx.v[cur_idx].next;
Willy Tarreau2a324282006-12-05 00:05:46 +01001227 cur_hdr++;
1228 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001229#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001230
Willy Tarreau06619262006-12-17 08:37:22 +01001231 goto process_data;
1232
1233 return_bad_req: /* let's centralize all bad requests */
1234 t->hreq.hdr_state = HTTP_PA_ERROR;
1235 t->logs.status = 400;
Willy Tarreau0f772532006-12-23 20:51:41 +01001236 client_retnclose(t, &t->fe->errmsg[HTTP_ERR_400]);
Willy Tarreau06619262006-12-17 08:37:22 +01001237 return_prx_cond:
1238 if (!(t->flags & SN_ERR_MASK))
1239 t->flags |= SN_ERR_PRXCOND;
1240 if (!(t->flags & SN_FINST_MASK))
1241 t->flags |= SN_FINST_R;
1242 return 1;
1243
Willy Tarreaubaaee002006-06-26 02:48:02 +02001244 }
1245 else if (c == CL_STDATA) {
1246 process_data:
1247 /* FIXME: this error handling is partly buggy because we always report
1248 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
1249 * or HEADER phase. BTW, it's not logical to expire the client while
1250 * we're waiting for the server to connect.
1251 */
1252 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001253 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001254 tv_eternity(&req->rex);
1255 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001256 fd_delete(t->cli_fd);
1257 t->cli_state = CL_STCLOSE;
1258 if (!(t->flags & SN_ERR_MASK))
1259 t->flags |= SN_ERR_CLICL;
1260 if (!(t->flags & SN_FINST_MASK)) {
1261 if (t->pend_pos)
1262 t->flags |= SN_FINST_Q;
1263 else if (s == SV_STCONN)
1264 t->flags |= SN_FINST_C;
1265 else
1266 t->flags |= SN_FINST_D;
1267 }
1268 return 1;
1269 }
1270 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001271 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001272 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001273 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001274 shutdown(t->cli_fd, SHUT_RD);
1275 t->cli_state = CL_STSHUTR;
1276 return 1;
1277 }
1278 /* last server read and buffer empty */
1279 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001280 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001281 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001282 shutdown(t->cli_fd, SHUT_WR);
1283 /* We must ensure that the read part is still alive when switching
1284 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001285 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001286 if (t->fe->clitimeout)
1287 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001288 t->cli_state = CL_STSHUTW;
1289 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1290 return 1;
1291 }
1292 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001293 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001294 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001295 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001296 shutdown(t->cli_fd, SHUT_RD);
1297 t->cli_state = CL_STSHUTR;
1298 if (!(t->flags & SN_ERR_MASK))
1299 t->flags |= SN_ERR_CLITO;
1300 if (!(t->flags & SN_FINST_MASK)) {
1301 if (t->pend_pos)
1302 t->flags |= SN_FINST_Q;
1303 else if (s == SV_STCONN)
1304 t->flags |= SN_FINST_C;
1305 else
1306 t->flags |= SN_FINST_D;
1307 }
1308 return 1;
1309 }
1310 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001311 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001312 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001313 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001314 shutdown(t->cli_fd, SHUT_WR);
1315 /* We must ensure that the read part is still alive when switching
1316 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001317 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001318 if (t->fe->clitimeout)
1319 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001320
1321 t->cli_state = CL_STSHUTW;
1322 if (!(t->flags & SN_ERR_MASK))
1323 t->flags |= SN_ERR_CLITO;
1324 if (!(t->flags & SN_FINST_MASK)) {
1325 if (t->pend_pos)
1326 t->flags |= SN_FINST_Q;
1327 else if (s == SV_STCONN)
1328 t->flags |= SN_FINST_C;
1329 else
1330 t->flags |= SN_FINST_D;
1331 }
1332 return 1;
1333 }
1334
1335 if (req->l >= req->rlim - req->data) {
1336 /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02001337 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001338 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001339 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001340 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001341 }
1342 } else {
1343 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001344 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1345 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001346 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001347 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001348 /* If the client has no timeout, or if the server not ready yet, and we
1349 * know for sure that it can expire, then it's cleaner to disable the
1350 * timeout on the client side so that too low values cannot make the
1351 * sessions abort too early.
1352 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001353 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001354 else
Willy Tarreau73de9892006-11-30 11:40:23 +01001355 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001356 }
1357 }
1358
1359 if ((rep->l == 0) ||
1360 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001361 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1362 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001363 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001364 }
1365 } else {
1366 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001367 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1368 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001369 if (t->fe->clitimeout) {
1370 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001371 /* FIXME: to prevent the client from expiring read timeouts during writes,
1372 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001373 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001374 }
1375 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001376 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001377 }
1378 }
1379 return 0; /* other cases change nothing */
1380 }
1381 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001382 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001383 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001384 fd_delete(t->cli_fd);
1385 t->cli_state = CL_STCLOSE;
1386 if (!(t->flags & SN_ERR_MASK))
1387 t->flags |= SN_ERR_CLICL;
1388 if (!(t->flags & SN_FINST_MASK)) {
1389 if (t->pend_pos)
1390 t->flags |= SN_FINST_Q;
1391 else if (s == SV_STCONN)
1392 t->flags |= SN_FINST_C;
1393 else
1394 t->flags |= SN_FINST_D;
1395 }
1396 return 1;
1397 }
1398 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
1399 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001400 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001401 fd_delete(t->cli_fd);
1402 t->cli_state = CL_STCLOSE;
1403 return 1;
1404 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001405 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
1406 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001407 fd_delete(t->cli_fd);
1408 t->cli_state = CL_STCLOSE;
1409 if (!(t->flags & SN_ERR_MASK))
1410 t->flags |= SN_ERR_CLITO;
1411 if (!(t->flags & SN_FINST_MASK)) {
1412 if (t->pend_pos)
1413 t->flags |= SN_FINST_Q;
1414 else if (s == SV_STCONN)
1415 t->flags |= SN_FINST_C;
1416 else
1417 t->flags |= SN_FINST_D;
1418 }
1419 return 1;
1420 }
1421
1422 if (t->flags & SN_SELF_GEN) {
1423 produce_content(t);
1424 if (rep->l == 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001425 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001426 fd_delete(t->cli_fd);
1427 t->cli_state = CL_STCLOSE;
1428 return 1;
1429 }
1430 }
1431
1432 if ((rep->l == 0)
1433 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001434 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1435 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001436 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001437 }
1438 } else {
1439 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001440 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1441 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001442 if (t->fe->clitimeout) {
1443 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001444 /* FIXME: to prevent the client from expiring read timeouts during writes,
1445 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001446 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001447 }
1448 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001449 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001450 }
1451 }
1452 return 0;
1453 }
1454 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001455 if (req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001456 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001457 fd_delete(t->cli_fd);
1458 t->cli_state = CL_STCLOSE;
1459 if (!(t->flags & SN_ERR_MASK))
1460 t->flags |= SN_ERR_CLICL;
1461 if (!(t->flags & SN_FINST_MASK)) {
1462 if (t->pend_pos)
1463 t->flags |= SN_FINST_Q;
1464 else if (s == SV_STCONN)
1465 t->flags |= SN_FINST_C;
1466 else
1467 t->flags |= SN_FINST_D;
1468 }
1469 return 1;
1470 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001471 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001472 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001473 fd_delete(t->cli_fd);
1474 t->cli_state = CL_STCLOSE;
1475 return 1;
1476 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001477 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
1478 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001479 fd_delete(t->cli_fd);
1480 t->cli_state = CL_STCLOSE;
1481 if (!(t->flags & SN_ERR_MASK))
1482 t->flags |= SN_ERR_CLITO;
1483 if (!(t->flags & SN_FINST_MASK)) {
1484 if (t->pend_pos)
1485 t->flags |= SN_FINST_Q;
1486 else if (s == SV_STCONN)
1487 t->flags |= SN_FINST_C;
1488 else
1489 t->flags |= SN_FINST_D;
1490 }
1491 return 1;
1492 }
1493 else if (req->l >= req->rlim - req->data) {
1494 /* no room to read more data */
1495
1496 /* FIXME-20050705: is it possible for a client to maintain a session
1497 * after the timeout by sending more data after it receives a close ?
1498 */
1499
Willy Tarreau2a429502006-10-15 14:52:29 +02001500 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001501 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001502 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001503 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001504 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1505 }
1506 } else {
1507 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001508 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1509 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001510 if (t->fe->clitimeout)
1511 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001512 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001513 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001514 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1515 }
1516 }
1517 return 0;
1518 }
1519 else { /* CL_STCLOSE: nothing to do */
1520 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1521 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01001522 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 +02001523 write(1, trash, len);
1524 }
1525 return 0;
1526 }
1527 return 0;
1528}
1529
1530
1531/*
1532 * manages the server FSM and its socket. It returns 1 if a state has changed
1533 * (and a resync may be needed), 0 else.
1534 */
1535int process_srv(struct session *t)
1536{
1537 int s = t->srv_state;
1538 int c = t->cli_state;
1539 struct buffer *req = t->req;
1540 struct buffer *rep = t->rep;
1541 appsess *asession_temp = NULL;
1542 appsess local_asession;
1543 int conn_err;
1544
1545#ifdef DEBUG_FULL
1546 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
1547#endif
1548 //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 +02001549 //MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
1550 //MY_FD_ISSET(t->srv_fd, StaticReadEvent), MY_FD_ISSET(t->srv_fd, StaticWriteEvent)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001551 //);
1552 if (s == SV_STIDLE) {
1553 if (c == CL_STHEADERS)
1554 return 0; /* stay in idle, waiting for data to reach the client side */
1555 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
1556 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001557 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001558 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001559 if (t->pend_pos)
1560 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1561 /* note that this must not return any error because it would be able to
1562 * overwrite the client_retnclose() output.
1563 */
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001564 if (t->flags & SN_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01001565 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001566 else
Willy Tarreau0f772532006-12-23 20:51:41 +01001567 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 +02001568
1569 return 1;
1570 }
1571 else {
Willy Tarreaub8750a82006-09-03 09:56:00 +02001572 if (t->flags & SN_CLTARPIT) {
1573 /* This connection is being tarpitted. The CLIENT side has
1574 * already set the connect expiration date to the right
1575 * timeout. We just have to check that it has not expired.
1576 */
1577 if (tv_cmp2_ms(&req->cex, &now) > 0)
1578 return 0;
1579
1580 /* We will set the queue timer to the time spent, just for
1581 * logging purposes. We fake a 500 server error, so that the
1582 * attacker will not suspect his connection has been tarpitted.
1583 * It will not cause trouble to the logs because we can exclude
1584 * the tarpitted connections by filtering on the 'PT' status flags.
1585 */
1586 tv_eternity(&req->cex);
1587 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1588 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau0f772532006-12-23 20:51:41 +01001589 500, &t->fe->errmsg[HTTP_ERR_500]);
Willy Tarreaub8750a82006-09-03 09:56:00 +02001590 return 1;
1591 }
1592
Willy Tarreaubaaee002006-06-26 02:48:02 +02001593 /* Right now, we will need to create a connection to the server.
1594 * We might already have tried, and got a connection pending, in
1595 * which case we will not do anything till it's pending. It's up
1596 * to any other session to release it and wake us up again.
1597 */
1598 if (t->pend_pos) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001599 if (tv_cmp2_ms(&req->cex, &now) > 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001600 return 0;
1601 else {
1602 /* we've been waiting too long here */
Willy Tarreaud7971282006-07-29 18:36:34 +02001603 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001604 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1605 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau0f772532006-12-23 20:51:41 +01001606 503, &t->fe->errmsg[HTTP_ERR_503]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001607 if (t->srv)
1608 t->srv->failed_conns++;
Willy Tarreau73de9892006-11-30 11:40:23 +01001609 t->fe->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001610 return 1;
1611 }
1612 }
1613
1614 do {
1615 /* first, get a connection */
1616 if (srv_redispatch_connect(t))
1617 return t->srv_state != SV_STIDLE;
1618
1619 /* try to (re-)connect to the server, and fail if we expire the
1620 * number of retries.
1621 */
1622 if (srv_retryable_connect(t)) {
1623 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1624 return t->srv_state != SV_STIDLE;
1625 }
1626
1627 } while (1);
1628 }
1629 }
1630 else if (s == SV_STCONN) { /* connection in progress */
1631 if (c == CL_STCLOSE || c == CL_STSHUTW ||
1632 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001633 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001634 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001635 fd_delete(t->srv_fd);
1636 if (t->srv)
1637 t->srv->cur_sess--;
1638
1639 /* note that this must not return any error because it would be able to
1640 * overwrite the client_retnclose() output.
1641 */
Willy Tarreau0f772532006-12-23 20:51:41 +01001642 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001643 return 1;
1644 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001645 if (!(req->flags & BF_WRITE_STATUS) && tv_cmp2_ms(&req->cex, &now) > 0) {
1646 //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 +02001647 return 0; /* nothing changed */
1648 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001649 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001650 /* timeout, asynchronous connect error or first write error */
1651 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
1652
1653 fd_delete(t->srv_fd);
1654 if (t->srv)
1655 t->srv->cur_sess--;
1656
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001657 if (!(req->flags & BF_WRITE_STATUS))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001658 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
1659 else
1660 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
1661
1662 /* ensure that we have enough retries left */
1663 if (srv_count_retry_down(t, conn_err))
1664 return 1;
1665
Willy Tarreau830ff452006-12-17 19:31:23 +01001666 if (t->srv && t->conn_retries == 0 && t->be->beprm->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001667 /* We're on our last chance, and the REDISP option was specified.
1668 * We will ignore cookie and force to balance or use the dispatcher.
1669 */
1670 /* let's try to offer this slot to anybody */
Willy Tarreau830ff452006-12-17 19:31:23 +01001671 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001672 task_wakeup(&rq, t->srv->queue_mgt);
1673
1674 if (t->srv)
1675 t->srv->failed_conns++;
Willy Tarreau830ff452006-12-17 19:31:23 +01001676 t->be->beprm->failed_conns++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001677
1678 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
1679 t->srv = NULL; /* it's left to the dispatcher to choose a server */
1680 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
1681 t->flags &= ~SN_CK_MASK;
1682 t->flags |= SN_CK_DOWN;
1683 }
1684
1685 /* first, get a connection */
1686 if (srv_redispatch_connect(t))
1687 return t->srv_state != SV_STIDLE;
1688 }
1689
Willy Tarreaubaaee002006-06-26 02:48:02 +02001690 do {
1691 /* Now we will try to either reconnect to the same server or
1692 * connect to another server. If the connection gets queued
1693 * because all servers are saturated, then we will go back to
1694 * the SV_STIDLE state.
1695 */
1696 if (srv_retryable_connect(t)) {
1697 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1698 return t->srv_state != SV_STCONN;
1699 }
1700
1701 /* we need to redispatch the connection to another server */
1702 if (srv_redispatch_connect(t))
1703 return t->srv_state != SV_STCONN;
1704 } while (1);
1705 }
1706 else { /* no error or write 0 */
1707 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
1708
1709 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
1710 if (req->l == 0) /* nothing to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02001711 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001712 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001713 } else /* need the right to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02001714 MY_FD_SET(t->srv_fd, StaticWriteEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001715 if (t->be->beprm->srvtimeout) {
1716 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001717 /* FIXME: to prevent the server from expiring read timeouts during writes,
1718 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001719 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001720 }
1721 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001722 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001723 }
1724
Willy Tarreau830ff452006-12-17 19:31:23 +01001725 if (t->be->beprm->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreau2a429502006-10-15 14:52:29 +02001726 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001727 if (t->be->beprm->srvtimeout)
1728 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001729 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001730 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001731
1732 t->srv_state = SV_STDATA;
1733 if (t->srv)
1734 t->srv->cum_sess++;
1735 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
1736
1737 /* if the user wants to log as soon as possible, without counting
1738 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001739 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001740 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
1741 sess_log(t);
1742 }
1743 }
1744 else {
1745 t->srv_state = SV_STHEADERS;
1746 if (t->srv)
1747 t->srv->cum_sess++;
1748 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
1749 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001750 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001751 return 1;
1752 }
1753 }
1754 else if (s == SV_STHEADERS) { /* receiving server headers */
1755 /* now parse the partial (or complete) headers */
1756 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
1757 char *ptr;
1758 int delete_header;
1759
1760 ptr = rep->lr;
1761
1762 /* look for the end of the current header */
1763 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
1764 ptr++;
1765
1766 if (ptr == rep->h) {
1767 int line, len;
1768
1769 /* we can only get here after an end of headers */
1770
1771 /* first, we'll block if security checks have caught nasty things */
1772 if (t->flags & SN_CACHEABLE) {
1773 if ((t->flags & SN_CACHE_COOK) &&
1774 (t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001775 (t->be->beprm->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001776
1777 /* we're in presence of a cacheable response containing
1778 * a set-cookie header. We'll block it as requested by
1779 * the 'checkcache' option, and send an alert.
1780 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001781 tv_eternity(&rep->rex);
1782 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001783 fd_delete(t->srv_fd);
1784 if (t->srv) {
1785 t->srv->cur_sess--;
1786 t->srv->failed_secu++;
1787 }
Willy Tarreau73de9892006-11-30 11:40:23 +01001788 t->be->failed_secu++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001789 t->srv_state = SV_STCLOSE;
1790 t->logs.status = 502;
Willy Tarreau0f772532006-12-23 20:51:41 +01001791 client_return(t, &t->fe->errmsg[HTTP_ERR_502]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001792 if (!(t->flags & SN_ERR_MASK))
1793 t->flags |= SN_ERR_PRXCOND;
1794 if (!(t->flags & SN_FINST_MASK))
1795 t->flags |= SN_FINST_H;
1796
Willy Tarreau830ff452006-12-17 19:31:23 +01001797 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->be->beprm->id, t->srv->id);
1798 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 +02001799
1800 /* We used to have a free connection slot. Since we'll never use it,
1801 * we have to inform the server that it may be used by another session.
1802 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001803 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001804 task_wakeup(&rq, t->srv->queue_mgt);
1805
1806 return 1;
1807 }
1808 }
1809
1810 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
1811 if (t->flags & SN_SVDENY) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001812 tv_eternity(&rep->rex);
1813 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001814 fd_delete(t->srv_fd);
1815 if (t->srv) {
1816 t->srv->cur_sess--;
1817 t->srv->failed_secu++;
1818 }
Willy Tarreau73de9892006-11-30 11:40:23 +01001819 t->be->failed_secu++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001820 t->srv_state = SV_STCLOSE;
1821 t->logs.status = 502;
Willy Tarreau0f772532006-12-23 20:51:41 +01001822 client_return(t, &t->fe->errmsg[HTTP_ERR_502]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001823 if (!(t->flags & SN_ERR_MASK))
1824 t->flags |= SN_ERR_PRXCOND;
1825 if (!(t->flags & SN_FINST_MASK))
1826 t->flags |= SN_FINST_H;
1827 /* We used to have a free connection slot. Since we'll never use it,
1828 * we have to inform the server that it may be used by another session.
1829 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001830 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001831 task_wakeup(&rq, t->srv->queue_mgt);
1832
1833 return 1;
1834 }
1835
1836 /* we'll have something else to do here : add new headers ... */
1837
Willy Tarreau830ff452006-12-17 19:31:23 +01001838 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_INS) &&
1839 (!(t->be->beprm->options & PR_O_COOK_POST) || (t->hreq.meth == HTTP_METH_POST))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001840 /* the server is known, it's not the one the client requested, we have to
1841 * insert a set-cookie here, except if we want to insert only on POST
1842 * requests and this one isn't. Note that servers which don't have cookies
1843 * (eg: some backup servers) will return a full cookie removal request.
1844 */
1845 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
Willy Tarreau830ff452006-12-17 19:31:23 +01001846 t->be->beprm->cookie_name,
Willy Tarreaubaaee002006-06-26 02:48:02 +02001847 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
1848
1849 t->flags |= SN_SCK_INSERTED;
1850
1851 /* Here, we will tell an eventual cache on the client side that we don't
1852 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
1853 * Some caches understand the correct form: 'no-cache="set-cookie"', but
1854 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
1855 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001856 if (t->be->beprm->options & PR_O_COOK_NOC)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001857 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
1858 len += sprintf(trash + len, "Cache-control: private\r\n");
1859
1860 if (rep->data + rep->l < rep->h)
1861 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
1862 *(int *)0 = 0;
1863 buffer_replace2(rep, rep->h, rep->h, trash, len);
1864 }
1865
1866 /* headers to be added */
Willy Tarreau830ff452006-12-17 19:31:23 +01001867 /* FIXME: we should add headers from BE then from FE */
1868 for (line = 0; line < t->be->fiprm->nb_rspadd; line++) {
1869 len = sprintf(trash, "%s\r\n", t->be->fiprm->rsp_add[line]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001870 buffer_replace2(rep, rep->h, rep->h, trash, len);
1871 }
1872
1873 /* add a "connection: close" line if needed */
Willy Tarreau73de9892006-11-30 11:40:23 +01001874 if (t->fe->options & PR_O_HTTP_CLOSE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001875 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
1876
1877 t->srv_state = SV_STDATA;
1878 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
1879 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
1880
1881 /* client connection already closed or option 'httpclose' required :
1882 * we close the server's outgoing connection right now.
1883 */
1884 if ((req->l == 0) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001885 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->beprm->options & PR_O_FORCE_CLO)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001886 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001887 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001888
1889 /* We must ensure that the read part is still alive when switching
1890 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001891 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001892 if (t->be->beprm->srvtimeout)
1893 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001894
1895 shutdown(t->srv_fd, SHUT_WR);
1896 t->srv_state = SV_STSHUTW;
1897 }
1898
1899 /* if the user wants to log as soon as possible, without counting
1900 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001901 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001902 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
1903 t->logs.bytes = rep->h - rep->data;
1904 sess_log(t);
1905 }
1906 break;
1907 }
1908
1909 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1910 if (ptr > rep->r - 2) {
1911 /* this is a partial header, let's wait for more to come */
1912 rep->lr = ptr;
1913 break;
1914 }
1915
1916 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
1917 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
1918
1919 /* now we know that *ptr is either \r or \n,
1920 * and that there are at least 1 char after it.
1921 */
1922 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
1923 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
1924 else
1925 rep->lr = ptr + 2; /* \r\n or \n\r */
1926
1927 /*
1928 * now we know that we have a full header ; we can do whatever
1929 * we want with these pointers :
1930 * rep->h = beginning of header
1931 * ptr = end of header (first \r or \n)
1932 * rep->lr = beginning of next line (next rep->h)
1933 * rep->r = end of data (not used at this stage)
1934 */
1935
1936
1937 if (t->logs.status == -1) {
1938 t->logs.logwait &= ~LW_RESP;
1939 t->logs.status = atoi(rep->h + 9);
1940 switch (t->logs.status) {
1941 case 200:
1942 case 203:
1943 case 206:
1944 case 300:
1945 case 301:
1946 case 410:
1947 /* RFC2616 @13.4:
1948 * "A response received with a status code of
1949 * 200, 203, 206, 300, 301 or 410 MAY be stored
1950 * by a cache (...) unless a cache-control
1951 * directive prohibits caching."
1952 *
1953 * RFC2616 @9.5: POST method :
1954 * "Responses to this method are not cacheable,
1955 * unless the response includes appropriate
1956 * Cache-Control or Expires header fields."
1957 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001958 if (!(t->hreq.meth == HTTP_METH_POST) && (t->be->beprm->options & PR_O_CHK_CACHE))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001959 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
1960 break;
1961 default:
1962 break;
1963 }
1964 }
1965 else if (t->logs.logwait & LW_RSPHDR) {
1966 struct cap_hdr *h;
1967 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01001968 for (h = t->fe->fiprm->rsp_cap; h; h = h->next) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001969 if ((h->namelen + 2 <= ptr - rep->h) &&
1970 (rep->h[h->namelen] == ':') &&
1971 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
1972
1973 if (t->rsp_cap[h->index] == NULL)
1974 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
1975
1976 len = ptr - (rep->h + h->namelen + 2);
1977 if (len > h->len)
1978 len = h->len;
1979
1980 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
1981 t->rsp_cap[h->index][len]=0;
1982 }
1983 }
1984
1985 }
1986
1987 delete_header = 0;
1988
Willy Tarreau58f10d72006-12-04 02:26:12 +01001989 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
1990 debug_hdr("srvhdr", t, rep->h, ptr);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001991
1992 /* remove "connection: " if needed */
Willy Tarreau73de9892006-11-30 11:40:23 +01001993 if (!delete_header && (t->fe->options & PR_O_HTTP_CLOSE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001994 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
1995 delete_header = 1;
1996 }
1997
1998 /* try headers regexps */
Willy Tarreau830ff452006-12-17 19:31:23 +01001999 if (!delete_header && t->be->fiprm->rsp_exp != NULL
Willy Tarreaubaaee002006-06-26 02:48:02 +02002000 && !(t->flags & SN_SVDENY)) {
2001 struct hdr_exp *exp;
2002 char term;
2003
2004 term = *ptr;
2005 *ptr = '\0';
Willy Tarreau830ff452006-12-17 19:31:23 +01002006 exp = t->be->fiprm->rsp_exp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002007 do {
2008 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2009 switch (exp->action) {
2010 case ACT_ALLOW:
2011 if (!(t->flags & SN_SVDENY))
2012 t->flags |= SN_SVALLOW;
2013 break;
2014 case ACT_REPLACE:
2015 if (!(t->flags & SN_SVDENY)) {
2016 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
2017 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2018 }
2019 break;
2020 case ACT_REMOVE:
2021 if (!(t->flags & SN_SVDENY))
2022 delete_header = 1;
2023 break;
2024 case ACT_DENY:
2025 if (!(t->flags & SN_SVALLOW))
2026 t->flags |= SN_SVDENY;
2027 break;
2028 case ACT_PASS: /* we simply don't deny this one */
2029 break;
2030 }
2031 break;
2032 }
2033 } while ((exp = exp->next) != NULL);
2034 *ptr = term; /* restore the string terminator */
2035 }
2036
2037 /* check for cache-control: or pragma: headers */
2038 if (!delete_header && (t->flags & SN_CACHEABLE)) {
2039 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
2040 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2041 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
2042 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
2043 if (rep->h + 23 == ptr || rep->h[23] == ',')
2044 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2045 else {
2046 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
2047 && (rep->h[35] == '"' || rep->h[35] == ','))
2048 t->flags &= ~SN_CACHE_COOK;
2049 }
2050 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
2051 (rep->h + 22 == ptr || rep->h[22] == ','))
2052 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
2053 (rep->h + 23 == ptr || rep->h[23] == ','))) {
2054 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2055 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
2056 (rep->h + 24 == ptr || rep->h[24] == ',')) {
2057 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2058 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
2059 (rep->h + 25 == ptr || rep->h[25] == ',')) {
2060 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2061 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
2062 (rep->h + 21 == ptr || rep->h[21] == ',')) {
2063 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
2064 }
2065 }
2066 }
2067
2068 /* check for server cookies */
2069 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002070 && (t->be->beprm->cookie_name != NULL ||
2071 t->be->fiprm->capture_name != NULL ||
2072 t->be->beprm->appsession_name !=NULL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002073 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2074 char *p1, *p2, *p3, *p4;
2075
2076 t->flags |= SN_SCK_ANY;
2077
2078 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2079
2080 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
2081 while (p1 < ptr && (isspace((int)*p1)))
2082 p1++;
2083
2084 if (p1 == ptr || *p1 == ';') /* end of cookie */
2085 break;
2086
2087 /* p1 is at the beginning of the cookie name */
2088 p2 = p1;
2089
2090 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2091 p2++;
2092
2093 if (p2 == ptr || *p2 == ';') /* next cookie */
2094 break;
2095
2096 p3 = p2 + 1; /* skips the '=' sign */
2097 if (p3 == ptr)
2098 break;
2099
2100 p4 = p3;
2101 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
2102 p4++;
2103
2104 /* here, we have the cookie name between p1 and p2,
2105 * and its value between p3 and p4.
2106 * we can process it.
2107 */
2108
2109 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01002110 if (t->be->fiprm->capture_name != NULL &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002111 t->logs.srv_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002112 (p4 - p1 >= t->be->fiprm->capture_namelen) &&
2113 memcmp(p1, t->be->fiprm->capture_name, t->be->fiprm->capture_namelen) == 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002114 int log_len = p4 - p1;
2115
2116 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
2117 Alert("HTTP logging : out of memory.\n");
2118 }
2119
Willy Tarreau830ff452006-12-17 19:31:23 +01002120 if (log_len > t->be->fiprm->capture_len)
2121 log_len = t->be->fiprm->capture_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002122 memcpy(t->logs.srv_cookie, p1, log_len);
2123 t->logs.srv_cookie[log_len] = 0;
2124 }
2125
Willy Tarreau830ff452006-12-17 19:31:23 +01002126 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
2127 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002128 /* Cool... it's the right one */
2129 t->flags |= SN_SCK_SEEN;
2130
2131 /* If the cookie is in insert mode on a known server, we'll delete
2132 * this occurrence because we'll insert another one later.
2133 * We'll delete it too if the "indirect" option is set and we're in
2134 * a direct access. */
Willy Tarreau830ff452006-12-17 19:31:23 +01002135 if (((t->srv) && (t->be->beprm->options & PR_O_COOK_INS)) ||
2136 ((t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_IND))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002137 /* this header must be deleted */
2138 delete_header = 1;
2139 t->flags |= SN_SCK_DELETED;
2140 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002141 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_RW)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002142 /* replace bytes p3->p4 with the cookie name associated
2143 * with this server since we know it.
2144 */
2145 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2146 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2147 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002148 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_PFX)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002149 /* insert the cookie name associated with this server
2150 * before existing cookie, and insert a delimitor between them..
2151 */
2152 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
2153 p3[t->srv->cklen] = COOKIE_DELIM;
2154 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2155 }
2156 break;
2157 }
2158
2159 /* first, let's see if the cookie is our appcookie*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002160 if ((t->be->beprm->appsession_name != NULL) &&
2161 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002162
2163 /* Cool... it's the right one */
2164
2165 size_t server_id_len = strlen(t->srv->id) + 1;
2166 asession_temp = &local_asession;
2167
2168 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
2169 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002170 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002171 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002172 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
2173 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002174 asession_temp->serverid = NULL;
2175
2176 /* only do insert, if lookup fails */
Willy Tarreau73de9892006-11-30 11:40:23 +01002177 if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002178 if ((asession_temp = pool_alloc(appsess)) == NULL) {
2179 Alert("Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002180 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002181 return 0;
2182 }
2183 asession_temp->sessid = local_asession.sessid;
2184 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01002185 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002186 }/* end if (chtbl_lookup()) */
2187 else {
2188 /* free wasted memory */
2189 pool_free_to(apools.sessid, local_asession.sessid);
2190 } /* end else from if (chtbl_lookup()) */
2191
2192 if (asession_temp->serverid == NULL) {
2193 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
2194 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002195 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002196 }
2197 asession_temp->serverid[0] = '\0';
2198 }
2199
2200 if (asession_temp->serverid[0] == '\0')
2201 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
2202
Willy Tarreau830ff452006-12-17 19:31:23 +01002203 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002204
2205#if defined(DEBUG_HASH)
Willy Tarreau830ff452006-12-17 19:31:23 +01002206 print_table(&(t->be->beprm->htbl_proxy));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002207#endif
2208 break;
2209 }/* end if ((t->proxy->appsession_name != NULL) ... */
2210 else {
2211 // fprintf(stderr,"Ignoring unknown cookie : ");
2212 // write(2, p1, p2-p1);
2213 // fprintf(stderr," = ");
2214 // write(2, p3, p4-p3);
2215 // fprintf(stderr,"\n");
2216 }
2217 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2218 } /* we're now at the end of the cookie value */
2219 } /* end of cookie processing */
2220
2221 /* check for any set-cookie in case we check for cacheability */
2222 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002223 (t->be->beprm->options & PR_O_CHK_CACHE) &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002224 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2225 t->flags |= SN_SCK_ANY;
2226 }
2227
2228 /* let's look if we have to delete this header */
2229 if (delete_header && !(t->flags & SN_SVDENY))
2230 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2231
2232 rep->h = rep->lr;
2233 } /* while (rep->lr < rep->r) */
2234
2235 /* end of header processing (even if incomplete) */
2236
Willy Tarreau2a429502006-10-15 14:52:29 +02002237 if ((rep->l < rep->rlim - rep->data) && ! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002238 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
Willy Tarreaud7971282006-07-29 18:36:34 +02002239 * full. We cannot loop here since stream_sock_read will disable it only if
Willy Tarreaubaaee002006-06-26 02:48:02 +02002240 * rep->l == rlim-data
2241 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002242 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002243 if (t->be->beprm->srvtimeout)
2244 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002245 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002246 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002247 }
2248
2249 /* read error, write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002250 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002251 tv_eternity(&rep->rex);
2252 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002253 fd_delete(t->srv_fd);
2254 if (t->srv) {
2255 t->srv->cur_sess--;
2256 t->srv->failed_resp++;
2257 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002258 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002259
2260 t->srv_state = SV_STCLOSE;
2261 t->logs.status = 502;
Willy Tarreau0f772532006-12-23 20:51:41 +01002262 client_return(t, &t->fe->errmsg[HTTP_ERR_502]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002263 if (!(t->flags & SN_ERR_MASK))
2264 t->flags |= SN_ERR_SRVCL;
2265 if (!(t->flags & SN_FINST_MASK))
2266 t->flags |= SN_FINST_H;
2267 /* We used to have a free connection slot. Since we'll never use it,
2268 * we have to inform the server that it may be used by another session.
2269 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002270 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002271 task_wakeup(&rq, t->srv->queue_mgt);
2272
2273 return 1;
2274 }
2275 /* end of client write or end of server read.
2276 * since we are in header mode, if there's no space left for headers, we
2277 * won't be able to free more later, so the session will never terminate.
2278 */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002279 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 +02002280 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002281 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002282 shutdown(t->srv_fd, SHUT_RD);
2283 t->srv_state = SV_STSHUTR;
2284 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2285 return 1;
2286 }
2287 /* read timeout : return a 504 to the client.
2288 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002289 else if (MY_FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002290 tv_eternity(&rep->rex);
2291 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002292 fd_delete(t->srv_fd);
2293 if (t->srv) {
2294 t->srv->cur_sess--;
2295 t->srv->failed_resp++;
2296 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002297 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002298 t->srv_state = SV_STCLOSE;
2299 t->logs.status = 504;
Willy Tarreau0f772532006-12-23 20:51:41 +01002300 client_return(t, &t->fe->errmsg[HTTP_ERR_504]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002301 if (!(t->flags & SN_ERR_MASK))
2302 t->flags |= SN_ERR_SRVTO;
2303 if (!(t->flags & SN_FINST_MASK))
2304 t->flags |= SN_FINST_H;
2305 /* We used to have a free connection slot. Since we'll never use it,
2306 * we have to inform the server that it may be used by another session.
2307 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002308 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002309 task_wakeup(&rq, t->srv->queue_mgt);
2310
2311 return 1;
2312 }
2313 /* last client read and buffer empty */
2314 /* FIXME!!! here, we don't want to switch to SHUTW if the
2315 * client shuts read too early, because we may still have
2316 * some work to do on the headers.
2317 * The side-effect is that if the client completely closes its
2318 * connection during SV_STHEADER, the connection to the server
2319 * is kept until a response comes back or the timeout is reached.
2320 */
2321 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002322 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002323 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002324
2325 /* We must ensure that the read part is still alive when switching
2326 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002327 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002328 if (t->be->beprm->srvtimeout)
2329 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002330
2331 shutdown(t->srv_fd, SHUT_WR);
2332 t->srv_state = SV_STSHUTW;
2333 return 1;
2334 }
2335 /* write timeout */
2336 /* FIXME!!! here, we don't want to switch to SHUTW if the
2337 * client shuts read too early, because we may still have
2338 * some work to do on the headers.
2339 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002340 else if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&req->wex, &now) <= 0) {
2341 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002342 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002343 shutdown(t->srv_fd, SHUT_WR);
2344 /* We must ensure that the read part is still alive when switching
2345 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002346 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002347 if (t->be->beprm->srvtimeout)
2348 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002349
2350 /* We must ensure that the read part is still alive when switching
2351 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002352 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002353 if (t->be->beprm->srvtimeout)
2354 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002355
2356 t->srv_state = SV_STSHUTW;
2357 if (!(t->flags & SN_ERR_MASK))
2358 t->flags |= SN_ERR_SRVTO;
2359 if (!(t->flags & SN_FINST_MASK))
2360 t->flags |= SN_FINST_H;
2361 return 1;
2362 }
2363
2364 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002365 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2366 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002367 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002368 }
2369 }
2370 else { /* client buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002371 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2372 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002373 if (t->be->beprm->srvtimeout) {
2374 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002375 /* FIXME: to prevent the server from expiring read timeouts during writes,
2376 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002377 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002378 }
2379 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002380 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002381 }
2382 }
2383
2384 /* be nice with the client side which would like to send a complete header
2385 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2386 * would read all remaining data at once ! The client should not write past rep->lr
2387 * when the server is in header state.
2388 */
2389 //return header_processed;
2390 return t->srv_state != SV_STHEADERS;
2391 }
2392 else if (s == SV_STDATA) {
2393 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002394 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002395 tv_eternity(&rep->rex);
2396 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002397 fd_delete(t->srv_fd);
2398 if (t->srv) {
2399 t->srv->cur_sess--;
2400 t->srv->failed_resp++;
2401 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002402 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002403 t->srv_state = SV_STCLOSE;
2404 if (!(t->flags & SN_ERR_MASK))
2405 t->flags |= SN_ERR_SRVCL;
2406 if (!(t->flags & SN_FINST_MASK))
2407 t->flags |= SN_FINST_D;
2408 /* We used to have a free connection slot. Since we'll never use it,
2409 * we have to inform the server that it may be used by another session.
2410 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002411 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002412 task_wakeup(&rq, t->srv->queue_mgt);
2413
2414 return 1;
2415 }
2416 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002417 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002418 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002419 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002420 shutdown(t->srv_fd, SHUT_RD);
2421 t->srv_state = SV_STSHUTR;
2422 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2423 return 1;
2424 }
2425 /* end of client read and no more data to send */
2426 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002427 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002428 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002429 shutdown(t->srv_fd, SHUT_WR);
2430 /* We must ensure that the read part is still alive when switching
2431 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002432 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002433 if (t->be->beprm->srvtimeout)
2434 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002435
2436 t->srv_state = SV_STSHUTW;
2437 return 1;
2438 }
2439 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002440 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002441 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002442 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002443 shutdown(t->srv_fd, SHUT_RD);
2444 t->srv_state = SV_STSHUTR;
2445 if (!(t->flags & SN_ERR_MASK))
2446 t->flags |= SN_ERR_SRVTO;
2447 if (!(t->flags & SN_FINST_MASK))
2448 t->flags |= SN_FINST_D;
2449 return 1;
2450 }
2451 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002452 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002453 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002454 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002455 shutdown(t->srv_fd, SHUT_WR);
2456 /* We must ensure that the read part is still alive when switching
2457 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002458 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002459 if (t->be->beprm->srvtimeout)
2460 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002461 t->srv_state = SV_STSHUTW;
2462 if (!(t->flags & SN_ERR_MASK))
2463 t->flags |= SN_ERR_SRVTO;
2464 if (!(t->flags & SN_FINST_MASK))
2465 t->flags |= SN_FINST_D;
2466 return 1;
2467 }
2468
2469 /* recompute request time-outs */
2470 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002471 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2472 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002473 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002474 }
2475 }
2476 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau2a429502006-10-15 14:52:29 +02002477 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2478 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002479 if (t->be->beprm->srvtimeout) {
2480 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002481 /* FIXME: to prevent the server from expiring read timeouts during writes,
2482 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002483 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002484 }
2485 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002486 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002487 }
2488 }
2489
2490 /* recompute response time-outs */
2491 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002492 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2493 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002494 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002495 }
2496 }
2497 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002498 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2499 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002500 if (t->be->beprm->srvtimeout)
2501 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002502 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002503 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002504 }
2505 }
2506
2507 return 0; /* other cases change nothing */
2508 }
2509 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002510 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002511 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002512 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002513 fd_delete(t->srv_fd);
2514 if (t->srv) {
2515 t->srv->cur_sess--;
2516 t->srv->failed_resp++;
2517 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002518 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002519 //close(t->srv_fd);
2520 t->srv_state = SV_STCLOSE;
2521 if (!(t->flags & SN_ERR_MASK))
2522 t->flags |= SN_ERR_SRVCL;
2523 if (!(t->flags & SN_FINST_MASK))
2524 t->flags |= SN_FINST_D;
2525 /* We used to have a free connection slot. Since we'll never use it,
2526 * we have to inform the server that it may be used by another session.
2527 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002528 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002529 task_wakeup(&rq, t->srv->queue_mgt);
2530
2531 return 1;
2532 }
2533 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002534 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002535 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002536 fd_delete(t->srv_fd);
2537 if (t->srv)
2538 t->srv->cur_sess--;
2539 //close(t->srv_fd);
2540 t->srv_state = SV_STCLOSE;
2541 /* We used to have a free connection slot. Since we'll never use it,
2542 * we have to inform the server that it may be used by another session.
2543 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002544 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002545 task_wakeup(&rq, t->srv->queue_mgt);
2546
2547 return 1;
2548 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002549 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002550 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002551 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002552 fd_delete(t->srv_fd);
2553 if (t->srv)
2554 t->srv->cur_sess--;
2555 //close(t->srv_fd);
2556 t->srv_state = SV_STCLOSE;
2557 if (!(t->flags & SN_ERR_MASK))
2558 t->flags |= SN_ERR_SRVTO;
2559 if (!(t->flags & SN_FINST_MASK))
2560 t->flags |= SN_FINST_D;
2561 /* We used to have a free connection slot. Since we'll never use it,
2562 * we have to inform the server that it may be used by another session.
2563 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002564 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002565 task_wakeup(&rq, t->srv->queue_mgt);
2566
2567 return 1;
2568 }
2569 else if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002570 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2571 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002572 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002573 }
2574 }
2575 else { /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002576 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2577 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002578 if (t->be->beprm->srvtimeout) {
2579 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002580 /* FIXME: to prevent the server from expiring read timeouts during writes,
2581 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002582 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002583 }
2584 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002585 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002586 }
2587 }
2588 return 0;
2589 }
2590 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002591 if (rep->flags & BF_READ_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002592 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002593 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002594 fd_delete(t->srv_fd);
2595 if (t->srv) {
2596 t->srv->cur_sess--;
2597 t->srv->failed_resp++;
2598 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002599 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002600 //close(t->srv_fd);
2601 t->srv_state = SV_STCLOSE;
2602 if (!(t->flags & SN_ERR_MASK))
2603 t->flags |= SN_ERR_SRVCL;
2604 if (!(t->flags & SN_FINST_MASK))
2605 t->flags |= SN_FINST_D;
2606 /* We used to have a free connection slot. Since we'll never use it,
2607 * we have to inform the server that it may be used by another session.
2608 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002609 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002610 task_wakeup(&rq, t->srv->queue_mgt);
2611
2612 return 1;
2613 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002614 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002615 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002616 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002617 fd_delete(t->srv_fd);
2618 if (t->srv)
2619 t->srv->cur_sess--;
2620 //close(t->srv_fd);
2621 t->srv_state = SV_STCLOSE;
2622 /* We used to have a free connection slot. Since we'll never use it,
2623 * we have to inform the server that it may be used by another session.
2624 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002625 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002626 task_wakeup(&rq, t->srv->queue_mgt);
2627
2628 return 1;
2629 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002630 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002631 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002632 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002633 fd_delete(t->srv_fd);
2634 if (t->srv)
2635 t->srv->cur_sess--;
2636 //close(t->srv_fd);
2637 t->srv_state = SV_STCLOSE;
2638 if (!(t->flags & SN_ERR_MASK))
2639 t->flags |= SN_ERR_SRVTO;
2640 if (!(t->flags & SN_FINST_MASK))
2641 t->flags |= SN_FINST_D;
2642 /* We used to have a free connection slot. Since we'll never use it,
2643 * we have to inform the server that it may be used by another session.
2644 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002645 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002646 task_wakeup(&rq, t->srv->queue_mgt);
2647
2648 return 1;
2649 }
2650 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002651 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2652 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002653 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002654 }
2655 }
2656 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002657 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2658 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002659 if (t->be->beprm->srvtimeout)
2660 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002661 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002662 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002663 }
2664 }
2665 return 0;
2666 }
2667 else { /* SV_STCLOSE : nothing to do */
2668 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2669 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01002670 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 +02002671 write(1, trash, len);
2672 }
2673 return 0;
2674 }
2675 return 0;
2676}
2677
2678
2679/*
2680 * Produces data for the session <s> depending on its source. Expects to be
2681 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
2682 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
2683 * session, which it uses to keep on being called when there is free space in
2684 * the buffer, of simply by letting an empty buffer upon return. It returns 1
2685 * if it changes the session state from CL_STSHUTR, otherwise 0.
2686 */
2687int produce_content(struct session *s)
2688{
2689 struct buffer *rep = s->rep;
2690 struct proxy *px;
2691 struct server *sv;
Willy Tarreau0f772532006-12-23 20:51:41 +01002692 struct chunk msg;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002693
2694 if (s->data_source == DATA_SRC_NONE) {
2695 s->flags &= ~SN_SELF_GEN;
2696 return 1;
2697 }
2698 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreau0f772532006-12-23 20:51:41 +01002699 msg.len = 0;
2700 msg.str = trash;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002701
2702 if (s->data_state == DATA_ST_INIT) { /* the function had not been called yet */
2703 unsigned int up;
2704
2705 s->flags |= SN_SELF_GEN; // more data will follow
2706
2707 /* send the start of the HTTP response */
Willy Tarreau0f772532006-12-23 20:51:41 +01002708 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002709 "HTTP/1.0 200 OK\r\n"
2710 "Cache-Control: no-cache\r\n"
2711 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +02002712 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +02002713 "\r\n\r\n");
2714
2715 s->logs.status = 200;
Willy Tarreau0f772532006-12-23 20:51:41 +01002716 client_retnclose(s, &msg); // send the start of the response.
2717 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002718
2719 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
2720 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
2721 if (!(s->flags & SN_FINST_MASK))
2722 s->flags |= SN_FINST_R;
2723
2724 /* WARNING! This must fit in the first buffer !!! */
Willy Tarreau0f772532006-12-23 20:51:41 +01002725 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002726 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
2727 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
2728 "<style type=\"text/css\"><!--\n"
2729 "body {"
2730 " font-family: helvetica, arial;"
2731 " font-size: 12px;"
2732 " font-weight: normal;"
2733 " color: black;"
2734 " background: white;"
2735 "}\n"
2736 "td {"
2737 " font-size: 12px;"
2738 " align: center;"
2739 "}\n"
2740 "h1 {"
2741 " font-size: xx-large;"
2742 " margin-bottom: 0.5em;"
2743 "}\n"
2744 "h2 {"
2745 " font-family: helvetica, arial;"
2746 " font-size: x-large;"
2747 " font-weight: bold;"
2748 " font-style: italic;"
2749 " color: #6020a0;"
2750 " margin-top: 0em;"
2751 " margin-bottom: 0em;"
2752 "}\n"
2753 "h3 {"
2754 " font-family: helvetica, arial;"
2755 " font-size: 16px;"
2756 " font-weight: bold;"
2757 " color: #b00040;"
2758 " background: #e8e8d0;"
2759 " margin-top: 0em;"
2760 " margin-bottom: 0em;"
2761 "}\n"
2762 "li {"
2763 " margin-top: 0.25em;"
2764 " margin-right: 2em;"
2765 "}\n"
2766 ".hr {"
2767 " margin-top: 0.25em;"
2768 " border-color: black;"
2769 " border-bottom-style: solid;"
2770 "}\n"
2771 "table.tbl { border-collapse: collapse; border-width: 1px; border-style: solid; border-color: gray;}\n"
2772 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; border-color: gray; }\n"
2773 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray; }\n"
2774 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
2775 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
2776 "-->"
2777 "</style></head>");
2778
Willy Tarreau0f772532006-12-23 20:51:41 +01002779 if (buffer_write(rep, trash, msg.len) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002780 return 0;
Willy Tarreau0f772532006-12-23 20:51:41 +01002781 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002782
2783 up = (now.tv_sec - start_date.tv_sec);
2784
2785 /* WARNING! this has to fit the first packet too */
Willy Tarreau0f772532006-12-23 20:51:41 +01002786 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002787 "<body><h1>" PRODUCT_NAME "</h1>\n"
2788 "<h2>Statistics Report for pid %d</h2>\n"
2789 "<hr width=\"100%%\" class=\"hr\">\n"
2790 "<h3>&gt; General process information</h3>\n"
2791 "<table border=0><tr><td align=\"left\">\n"
2792 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
2793 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
2794 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
2795 "<b>maxsock = </b> %d<br>\n"
2796 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
2797 "</td><td width=\"10%%\">\n"
2798 "</td><td align=\"right\">\n"
2799 "<table class=\"lgd\">"
2800 "<tr><td bgcolor=\"#C0FFC0\">&nbsp;</td><td style=\"border-style: none;\">active UP </td>"
2801 "<td bgcolor=\"#B0D0FF\">&nbsp;</td><td style=\"border-style: none;\">backup UP </td></tr>"
2802 "<tr><td bgcolor=\"#FFFFA0\"></td><td style=\"border-style: none;\">active UP, going down </td>"
2803 "<td bgcolor=\"#C060FF\"></td><td style=\"border-style: none;\">backup UP, going down </td></tr>"
2804 "<tr><td bgcolor=\"#FFD020\"></td><td style=\"border-style: none;\">active DOWN, going up </td>"
2805 "<td bgcolor=\"#FF80FF\"></td><td style=\"border-style: none;\">backup DOWN, going up </td></tr>"
2806 "<tr><td bgcolor=\"#FF9090\"></td><td style=\"border-style: none;\">active or backup DOWN &nbsp;</td>"
2807 "<td bgcolor=\"#E0E0E0\"></td><td style=\"border-style: none;\">not checked </td></tr>"
2808 "</table>\n"
2809 "</tr></table>\n"
2810 "",
2811 pid, pid, global.nbproc,
2812 up / 86400, (up % 86400) / 3600,
2813 (up % 3600) / 60, (up % 60),
2814 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
2815 global.rlimit_memmax ? " MB" : "",
2816 global.rlimit_nofile,
2817 global.maxsock,
2818 global.maxconn,
2819 actconn
2820 );
2821
Willy Tarreau0f772532006-12-23 20:51:41 +01002822 if (buffer_write(rep, trash, msg.len) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002823 return 0;
Willy Tarreau0f772532006-12-23 20:51:41 +01002824 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002825
2826 s->data_state = DATA_ST_DATA;
2827 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
2828
2829 px = s->data_ctx.stats.px = proxy;
2830 s->data_ctx.stats.px_st = DATA_ST_INIT;
2831 }
2832
2833 while (s->data_ctx.stats.px) {
2834 int dispatch_sess, dispatch_cum;
2835 int failed_checks, down_trans;
2836 int failed_secu, failed_conns, failed_resp;
2837
2838 if (s->data_ctx.stats.px_st == DATA_ST_INIT) {
2839 /* we are on a new proxy */
2840 px = s->data_ctx.stats.px;
2841
2842 /* skip the disabled proxies */
2843 if (px->state == PR_STSTOPPED)
2844 goto next_proxy;
2845
Willy Tarreau830ff452006-12-17 19:31:23 +01002846 if (s->be->fiprm->uri_auth && s->be->fiprm->uri_auth->scope) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002847 /* we have a limited scope, we have to check the proxy name */
2848 struct stat_scope *scope;
2849 int len;
2850
2851 len = strlen(px->id);
Willy Tarreau830ff452006-12-17 19:31:23 +01002852 scope = s->be->fiprm->uri_auth->scope;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002853
2854 while (scope) {
2855 /* match exact proxy name */
2856 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
2857 break;
2858
2859 /* match '.' which means 'self' proxy */
Willy Tarreau73de9892006-11-30 11:40:23 +01002860 if (!strcmp(scope->px_id, ".") && px == s->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002861 break;
2862 scope = scope->next;
2863 }
2864
2865 /* proxy name not found */
2866 if (scope == NULL)
2867 goto next_proxy;
2868 }
2869
Willy Tarreau0f772532006-12-23 20:51:41 +01002870 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002871 "<h3>&gt; Proxy instance %s : "
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002872 "%d front conns (max=%d), %d back, "
2873 "%d queued (%d unassigned), %d total front conns, %d back</h3>\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +02002874 "",
2875 px->id,
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002876 px->feconn, px->maxconn, px->beconn,
2877 px->totpend, px->nbpend, px->cum_feconn, px->cum_beconn);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002878
Willy Tarreau0f772532006-12-23 20:51:41 +01002879 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002880 "<table cols=\"16\" class=\"tbl\">\n"
2881 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
2882 "<th colspan=5>Server</th>"
2883 "<th colspan=2>Queue</th>"
2884 "<th colspan=4>Sessions</th>"
2885 "<th colspan=5>Errors</th></tr>\n"
2886 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
2887 "<th>Name</th><th>Weight</th><th>Status</th><th>Act.</th><th>Bck.</th>"
2888 "<th>Curr.</th><th>Max.</th>"
2889 "<th>Curr.</th><th>Max.</th><th>Limit</th><th>Cumul.</th>"
2890 "<th>Conn.</th><th>Resp.</th><th>Sec.</th><th>Check</th><th>Down</th></tr>\n");
2891
Willy Tarreau0f772532006-12-23 20:51:41 +01002892 if (buffer_write(rep, trash, msg.len) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002893 return 0;
Willy Tarreau0f772532006-12-23 20:51:41 +01002894 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002895
2896 s->data_ctx.stats.sv = px->srv;
2897 s->data_ctx.stats.px_st = DATA_ST_DATA;
2898 }
2899
2900 px = s->data_ctx.stats.px;
2901
2902 /* stats.sv has been initialized above */
2903 while (s->data_ctx.stats.sv != NULL) {
2904 static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
2905 static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
2906 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
2907 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
2908
2909 sv = s->data_ctx.stats.sv;
2910
2911 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
2912 if (!(sv->state & SRV_CHECKED))
2913 sv_state = 4;
2914 else if (sv->state & SRV_RUNNING)
2915 if (sv->health == sv->rise + sv->fall - 1)
2916 sv_state = 3; /* UP */
2917 else
2918 sv_state = 2; /* going down */
2919 else
2920 if (sv->health)
2921 sv_state = 1; /* going up */
2922 else
2923 sv_state = 0; /* DOWN */
2924
2925 /* name, weight */
Willy Tarreau0f772532006-12-23 20:51:41 +01002926 msg.len += snprintf(trash, sizeof(trash),
Willy Tarreaubaaee002006-06-26 02:48:02 +02002927 "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
2928 (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
2929 sv->id, sv->uweight+1);
2930 /* status */
Willy Tarreau0f772532006-12-23 20:51:41 +01002931 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len, srv_hlt_st[sv_state],
Willy Tarreaubaaee002006-06-26 02:48:02 +02002932 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
2933 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
2934
2935 /* act, bck */
Willy Tarreau0f772532006-12-23 20:51:41 +01002936 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002937 "</td><td>%s</td><td>%s</td>",
2938 (sv->state & SRV_BACKUP) ? "-" : "Y",
2939 (sv->state & SRV_BACKUP) ? "Y" : "-");
2940
2941 /* queue : current, max */
Willy Tarreau0f772532006-12-23 20:51:41 +01002942 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002943 "<td align=right>%d</td><td align=right>%d</td>",
2944 sv->nbpend, sv->nbpend_max);
2945
2946 /* sessions : current, max, limit, cumul */
Willy Tarreau0f772532006-12-23 20:51:41 +01002947 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002948 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>",
2949 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess);
2950
2951 /* errors : connect, response, security */
Willy Tarreau0f772532006-12-23 20:51:41 +01002952 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002953 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
2954 sv->failed_conns, sv->failed_resp, sv->failed_secu);
2955
2956 /* check failures : unique, fatal */
2957 if (sv->state & SRV_CHECKED)
Willy Tarreau0f772532006-12-23 20:51:41 +01002958 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002959 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
2960 sv->failed_checks, sv->down_trans);
2961 else
Willy Tarreau0f772532006-12-23 20:51:41 +01002962 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002963 "<td align=right>-</td><td align=right>-</td></tr>\n");
2964
Willy Tarreau0f772532006-12-23 20:51:41 +01002965 if (buffer_write(rep, trash, msg.len) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002966 return 0;
Willy Tarreau0f772532006-12-23 20:51:41 +01002967 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002968
2969 s->data_ctx.stats.sv = sv->next;
2970 } /* while sv */
2971
2972 /* now we are past the last server, we'll dump information about the dispatcher */
2973
2974 /* We have to count down from the proxy to the servers to tell how
2975 * many sessions are on the dispatcher, and how many checks have
2976 * failed. We cannot count this during the servers dump because it
2977 * might be interrupted multiple times.
2978 */
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002979 dispatch_sess = px->beconn;
2980 dispatch_cum = px->cum_beconn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002981 failed_secu = px->failed_secu;
2982 failed_conns = px->failed_conns;
2983 failed_resp = px->failed_resp;
2984 failed_checks = down_trans = 0;
2985
2986 sv = px->srv;
2987 while (sv) {
2988 dispatch_sess -= sv->cur_sess;
2989 dispatch_cum -= sv->cum_sess;
2990 failed_conns -= sv->failed_conns;
2991 failed_resp -= sv->failed_resp;
2992 failed_secu -= sv->failed_secu;
2993 if (sv->state & SRV_CHECKED) {
2994 failed_checks += sv->failed_checks;
2995 down_trans += sv->down_trans;
2996 }
2997 sv = sv->next;
2998 }
2999
3000 /* name, weight, status, act, bck */
Willy Tarreau0f772532006-12-23 20:51:41 +01003001 msg.len += snprintf(trash + msg.len, sizeof(trash),
Willy Tarreaubaaee002006-06-26 02:48:02 +02003002 "<tr align=center bgcolor=\"#e8e8d0\">"
3003 "<td>Dispatcher</td><td>-</td>"
3004 "<td>%s</td><td>-</td><td>-</td>",
3005 px->state == PR_STRUN ? "UP" : "DOWN");
3006
3007 /* queue : current, max */
Willy Tarreau0f772532006-12-23 20:51:41 +01003008 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02003009 "<td align=right>%d</td><td align=right>%d</td>",
3010 px->nbpend, px->nbpend_max);
3011
3012 /* sessions : current, max, limit, cumul. */
Willy Tarreau0f772532006-12-23 20:51:41 +01003013 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreauf1221aa2006-12-17 22:14:12 +01003014 "<td align=right>%d</td><td align=right>%d</td><td align=right>-</td><td align=right>%d</td>",
3015 dispatch_sess, px->beconn_max, dispatch_cum);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003016
3017 /* errors : connect, response, security */
Willy Tarreau0f772532006-12-23 20:51:41 +01003018 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02003019 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3020 failed_conns, failed_resp, failed_secu);
3021
3022 /* check failures : unique, fatal */
Willy Tarreau0f772532006-12-23 20:51:41 +01003023 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02003024 "<td align=right>-</td><td align=right>-</td></tr>\n");
3025
3026
3027 /* now the summary for the whole proxy */
3028 /* name, weight, status, act, bck */
Willy Tarreau0f772532006-12-23 20:51:41 +01003029 msg.len += snprintf(trash + msg.len, sizeof(trash),
Willy Tarreaubaaee002006-06-26 02:48:02 +02003030 "<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
3031 "<td><b>Total</b></td><td>-</td>"
3032 "<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
3033 (px->state == PR_STRUN && ((px->srv == NULL) || px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
3034 px->srv_act, px->srv_bck);
3035
3036 /* queue : current, max */
Willy Tarreau0f772532006-12-23 20:51:41 +01003037 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02003038 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
3039 px->totpend, px->nbpend_max);
3040
3041 /* sessions : current, max, limit, cumul */
Willy Tarreau0f772532006-12-23 20:51:41 +01003042 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreauf1221aa2006-12-17 22:14:12 +01003043 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>-</b></td><td align=right><b>%d</b></td>",
3044 px->beconn, px->beconn_max, px->cum_beconn);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003045
3046 /* errors : connect, response, security */
Willy Tarreau0f772532006-12-23 20:51:41 +01003047 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02003048 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3049 px->failed_conns, px->failed_resp, px->failed_secu);
3050
3051 /* check failures : unique, fatal */
Willy Tarreau0f772532006-12-23 20:51:41 +01003052 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02003053 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3054 failed_checks, down_trans);
3055
Willy Tarreau0f772532006-12-23 20:51:41 +01003056 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len, "</table><p>\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003057
Willy Tarreau0f772532006-12-23 20:51:41 +01003058 if (buffer_write(rep, trash, msg.len) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003059 return 0;
Willy Tarreau0f772532006-12-23 20:51:41 +01003060 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003061
3062 s->data_ctx.stats.px_st = DATA_ST_INIT;
3063 next_proxy:
3064 s->data_ctx.stats.px = px->next;
3065 } /* proxy loop */
3066 /* here, we just have reached the sv == NULL and px == NULL */
3067 s->flags &= ~SN_SELF_GEN;
3068 return 1;
3069 }
3070 else {
3071 /* unknown data source */
3072 s->logs.status = 500;
Willy Tarreau0f772532006-12-23 20:51:41 +01003073 client_retnclose(s, &s->fe->errmsg[HTTP_ERR_500]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003074 if (!(s->flags & SN_ERR_MASK))
3075 s->flags |= SN_ERR_PRXCOND;
3076 if (!(s->flags & SN_FINST_MASK))
3077 s->flags |= SN_FINST_R;
3078 s->flags &= SN_SELF_GEN;
3079 return 1;
3080 }
3081}
3082
3083
Willy Tarreau58f10d72006-12-04 02:26:12 +01003084
3085/*
3086 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>
3087 */
3088
3089void apply_filters_to_session(struct session *t, struct buffer *req, struct hdr_exp *exp)
3090{
3091 /* iterate through the filters in the outer loop */
3092 while (exp && !(t->flags & (SN_CLDENY|SN_CLTARPIT))) {
3093 char term;
3094 char *cur_ptr, *cur_end, *cur_next;
3095 int cur_idx, old_idx, abort_filt;
3096
3097
3098 /*
3099 * The interleaving of transformations and verdicts
3100 * makes it difficult to decide to continue or stop
3101 * the evaluation.
3102 */
3103
3104 if ((t->flags & SN_CLALLOW) &&
3105 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
3106 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
3107 exp = exp->next;
3108 continue;
3109 }
3110
3111 /* Iterate through the headers in the inner loop.
3112 * we start with the start line.
3113 */
3114 old_idx = cur_idx = 0;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003115 cur_next = req->data + t->hreq.sor;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003116 abort_filt = 0;
3117
Willy Tarreau45e73e32006-12-17 00:05:15 +01003118 while (!abort_filt && (cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
3119 struct hdr_idx_elem *cur_hdr = &t->hreq.hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003120 cur_ptr = cur_next;
3121 cur_end = cur_ptr + cur_hdr->len;
3122 cur_next = cur_end + cur_hdr->cr + 1;
3123
3124 /* Now we have one header between cur_ptr and cur_end,
3125 * and the next header starts at cur_next.
3126 */
3127
3128 /* The annoying part is that pattern matching needs
3129 * that we modify the contents to null-terminate all
3130 * strings before testing them.
3131 */
3132
3133 term = *cur_end;
3134 *cur_end = '\0';
3135
3136 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3137 switch (exp->action) {
Willy Tarreaua496b602006-12-17 23:15:24 +01003138 case ACT_SETBE:
3139 /* It is not possible to jump a second time.
3140 * FIXME: should we return an HTTP/500 here so that
3141 * the admin knows there's a problem ?
3142 */
3143 if (t->be != t->fe)
3144 break;
3145
3146 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3147 struct proxy *target = (struct proxy *) exp->replace;
3148
3149 /* Swithing Proxy */
3150 *cur_end = term;
3151 cur_end = NULL;
3152
3153 /* right now, the backend switch is not too much complicated
3154 * because we have associated req_cap and rsp_cap to the
3155 * frontend, and the beconn will be updated later.
3156 */
3157
3158 t->rep->rto = t->req->wto = target->beprm->srvtimeout;
3159 t->req->cto = target->beprm->contimeout;
3160
3161 t->be = target;
3162
3163 //t->logs.logwait |= LW_REQ | (target->to_log & (LW_REQHDR | LW_COOKIE));
3164 t->logs.logwait |= (target->to_log | target->beprm->to_log);
3165 abort_filt = 1;
3166 }
3167 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003168 case ACT_ALLOW:
3169 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3170 t->flags |= SN_CLALLOW;
3171 abort_filt = 1;
3172 }
3173 break;
3174 case ACT_REPLACE:
3175 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3176 int len, delta;
3177 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3178 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
Willy Tarreaue15d9132006-12-14 22:26:42 +01003179 /* FIXME: if the user adds a newline in the replacement, the
3180 * index will not be recalculated for now, and the new line
3181 * will not be counted for a new header.
3182 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003183 cur_end += delta;
3184 cur_next += delta;
3185 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003186 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003187 }
3188 break;
3189 case ACT_REMOVE:
3190 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3191 int delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3192 cur_next += delta;
3193
3194 /* FIXME: this should be a separate function */
Willy Tarreau45e73e32006-12-17 00:05:15 +01003195 t->hreq.eoh += delta;
3196 t->hreq.hdr_idx.v[old_idx].next = cur_hdr->next;
3197 t->hreq.hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003198 cur_hdr->len = 0;
3199
3200 cur_end = NULL; /* null-term has been rewritten */
3201 }
3202 break;
3203 case ACT_DENY:
3204 if (!(t->flags & (SN_CLALLOW | SN_CLTARPIT))) {
3205 t->flags |= SN_CLDENY;
3206 abort_filt = 1;
3207 }
3208 break;
3209 case ACT_TARPIT:
3210 if (!(t->flags & (SN_CLALLOW | SN_CLDENY))) {
3211 t->flags |= SN_CLTARPIT;
3212 abort_filt = 1;
3213 }
3214 break;
3215 //case ACT_PASS: /* FIXME: broken as of now. We should mark the header as "ignored". */
3216 // break;
3217 }
3218 }
3219 if (cur_end)
3220 *cur_end = term; /* restore the string terminator */
3221
3222 /* keep the link from this header to next one */
3223 old_idx = cur_idx;
3224 }
3225 exp = exp->next;
3226 }
3227}
3228
3229
3230
3231/*
3232 * Manager client-side cookie
3233 */
3234void manage_client_side_cookies(struct session *t, struct buffer *req)
3235{
3236 char *p1, *p2, *p3, *p4;
3237 char *del_colon, *del_cookie, *colon;
3238 int app_cookies;
3239
3240 appsess *asession_temp = NULL;
3241 appsess local_asession;
3242
3243 char *cur_ptr, *cur_end, *cur_next;
3244 int cur_idx, old_idx, abort_filt;
3245
Willy Tarreau830ff452006-12-17 19:31:23 +01003246 if (t->be->beprm->cookie_name == NULL &&
3247 t->be->beprm->appsession_name ==NULL &&
3248 t->be->fiprm->capture_name != NULL)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003249 return;
3250
Willy Tarreau2a324282006-12-05 00:05:46 +01003251 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003252 * we start with the start line.
3253 */
3254 old_idx = cur_idx = 0;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003255 cur_next = req->data + t->hreq.sor;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003256 abort_filt = 0;
3257
Willy Tarreau45e73e32006-12-17 00:05:15 +01003258 while ((cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003259 struct hdr_idx_elem *cur_hdr;
3260
Willy Tarreau45e73e32006-12-17 00:05:15 +01003261 cur_hdr = &t->hreq.hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003262 cur_ptr = cur_next;
3263 cur_end = cur_ptr + cur_hdr->len;
3264 cur_next = cur_end + cur_hdr->cr + 1;
3265
3266 /* We have one full header between cur_ptr and cur_end, and the
3267 * next header starts at cur_next. We're only interested in
3268 * "Cookie:" headers.
3269 */
3270
3271 if ((cur_end - cur_ptr <= 7) ||
3272 (strncasecmp(cur_ptr, "Cookie:", 7) != 0)) {
3273 old_idx = cur_idx;
3274 continue;
3275 }
3276
3277 /* Now look for cookies. Conforming to RFC2109, we have to support
3278 * attributes whose name begin with a '$', and associate them with
3279 * the right cookie, if we want to delete this cookie.
3280 * So there are 3 cases for each cookie read :
3281 * 1) it's a special attribute, beginning with a '$' : ignore it.
3282 * 2) it's a server id cookie that we *MAY* want to delete : save
3283 * some pointers on it (last semi-colon, beginning of cookie...)
3284 * 3) it's an application cookie : we *MAY* have to delete a previous
3285 * "special" cookie.
3286 * At the end of loop, if a "special" cookie remains, we may have to
3287 * remove it. If no application cookie persists in the header, we
3288 * *MUST* delete it
3289 */
3290
3291
3292 p1 = cur_ptr + 7; /* first char after 'Cookie:' */
3293 if (isspace((int)*p1)) /* try to get the first space with it */
3294 p1++;
3295
3296 colon = p1;
3297 /* del_cookie == NULL => nothing to be deleted */
3298 del_colon = del_cookie = NULL;
3299 app_cookies = 0;
3300
3301 while (p1 < cur_end) {
3302 /* skip spaces and colons, but keep an eye on these ones */
3303 while (p1 < cur_end) {
3304 if (*p1 == ';' || *p1 == ',')
3305 colon = p1;
3306 else if (!isspace((int)*p1))
3307 break;
3308 p1++;
3309 }
3310
3311 if (p1 == cur_end)
3312 break;
3313
3314 /* p1 is at the beginning of the cookie name */
3315 p2 = p1;
3316 while (p2 < cur_end && *p2 != '=')
3317 p2++;
3318
3319 if (p2 == cur_end)
3320 break;
3321
3322 p3 = p2 + 1; /* skips the '=' sign */
3323 if (p3 == cur_end)
3324 break;
3325
3326 p4 = p3;
3327 while (p4 < cur_end && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
3328 p4++;
3329
3330 /* here, we have the cookie name between p1 and p2,
3331 * and its value between p3 and p4.
3332 * we can process it :
3333 *
3334 * Cookie: NAME=VALUE;
3335 * | || || |
3336 * | || || +--> p4
3337 * | || |+-------> p3
3338 * | || +--------> p2
3339 * | |+------------> p1
3340 * | +-------------> colon
3341 * +--------------------> cur_ptr
3342 */
3343
3344 if (*p1 == '$') {
3345 /* skip this one */
3346 }
3347 else {
3348 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01003349 if (t->fe->fiprm->capture_name != NULL &&
Willy Tarreau58f10d72006-12-04 02:26:12 +01003350 t->logs.cli_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01003351 (p4 - p1 >= t->fe->fiprm->capture_namelen) &&
3352 memcmp(p1, t->fe->fiprm->capture_name, t->fe->fiprm->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003353 int log_len = p4 - p1;
3354
3355 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3356 Alert("HTTP logging : out of memory.\n");
3357 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003358 if (log_len > t->fe->fiprm->capture_len)
3359 log_len = t->fe->fiprm->capture_len;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003360 memcpy(t->logs.cli_cookie, p1, log_len);
3361 t->logs.cli_cookie[log_len] = 0;
3362 }
3363 }
3364
Willy Tarreau830ff452006-12-17 19:31:23 +01003365 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
3366 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003367 /* Cool... it's the right one */
Willy Tarreau830ff452006-12-17 19:31:23 +01003368 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003369 char *delim;
3370
3371 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3372 * have the server ID betweek p3 and delim, and the original cookie between
3373 * delim+1 and p4. Otherwise, delim==p4 :
3374 *
3375 * Cookie: NAME=SRV~VALUE;
3376 * | || || | |
3377 * | || || | +--> p4
3378 * | || || +--------> delim
3379 * | || |+-----------> p3
3380 * | || +------------> p2
3381 * | |+----------------> p1
3382 * | +-----------------> colon
3383 * +------------------------> cur_ptr
3384 */
3385
Willy Tarreau830ff452006-12-17 19:31:23 +01003386 if (t->be->beprm->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003387 for (delim = p3; delim < p4; delim++)
3388 if (*delim == COOKIE_DELIM)
3389 break;
3390 }
3391 else
3392 delim = p4;
3393
3394
3395 /* Here, we'll look for the first running server which supports the cookie.
3396 * This allows to share a same cookie between several servers, for example
3397 * to dedicate backup servers to specific servers only.
3398 * However, to prevent clients from sticking to cookie-less backup server
3399 * when they have incidentely learned an empty cookie, we simply ignore
3400 * empty cookies and mark them as invalid.
3401 */
3402 if (delim == p3)
3403 srv = NULL;
3404
3405 while (srv) {
3406 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003407 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003408 /* we found the server and it's usable */
3409 t->flags &= ~SN_CK_MASK;
3410 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3411 t->srv = srv;
3412 break;
3413 } else {
3414 /* we found a server, but it's down */
3415 t->flags &= ~SN_CK_MASK;
3416 t->flags |= SN_CK_DOWN;
3417 }
3418 }
3419 srv = srv->next;
3420 }
3421
3422 if (!srv && !(t->flags & SN_CK_DOWN)) {
3423 /* no server matched this cookie */
3424 t->flags &= ~SN_CK_MASK;
3425 t->flags |= SN_CK_INVALID;
3426 }
3427
3428 /* depending on the cookie mode, we may have to either :
3429 * - delete the complete cookie if we're in insert+indirect mode, so that
3430 * the server never sees it ;
3431 * - remove the server id from the cookie value, and tag the cookie as an
3432 * application cookie so that it does not get accidentely removed later,
3433 * if we're in cookie prefix mode
3434 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003435 if ((t->be->beprm->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003436 int delta; /* negative */
3437
3438 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
3439 p4 += delta;
3440 cur_end += delta;
3441 cur_next += delta;
3442 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003443 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003444
3445 del_cookie = del_colon = NULL;
3446 app_cookies++; /* protect the header from deletion */
3447 }
3448 else if (del_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01003449 (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 +01003450 del_cookie = p1;
3451 del_colon = colon;
3452 }
3453 } else {
3454 /* now we know that we must keep this cookie since it's
3455 * not ours. But if we wanted to delete our cookie
3456 * earlier, we cannot remove the complete header, but we
3457 * can remove the previous block itself.
3458 */
3459 app_cookies++;
3460
3461 if (del_cookie != NULL) {
3462 int delta; /* negative */
3463
3464 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
3465 p4 += delta;
3466 cur_end += delta;
3467 cur_next += delta;
3468 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003469 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003470 del_cookie = del_colon = NULL;
3471 }
3472 }
3473
Willy Tarreau830ff452006-12-17 19:31:23 +01003474 if ((t->be->beprm->appsession_name != NULL) &&
3475 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003476 /* first, let's see if the cookie is our appcookie*/
3477
3478 /* Cool... it's the right one */
3479
3480 asession_temp = &local_asession;
3481
3482 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3483 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3484 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3485 return;
3486 }
3487
Willy Tarreau830ff452006-12-17 19:31:23 +01003488 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
3489 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003490 asession_temp->serverid = NULL;
3491
3492 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01003493 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003494 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3495 /* free previously allocated memory */
3496 pool_free_to(apools.sessid, local_asession.sessid);
3497 Alert("Not enough memory process_cli():asession:calloc().\n");
3498 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3499 return;
3500 }
3501
3502 asession_temp->sessid = local_asession.sessid;
3503 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01003504 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003505 } else {
3506 /* free previously allocated memory */
3507 pool_free_to(apools.sessid, local_asession.sessid);
3508 }
3509
3510 if (asession_temp->serverid == NULL) {
3511 Alert("Found Application Session without matching server.\n");
3512 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003513 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003514 while (srv) {
3515 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003516 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003517 /* we found the server and it's usable */
3518 t->flags &= ~SN_CK_MASK;
3519 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3520 t->srv = srv;
3521 break;
3522 } else {
3523 t->flags &= ~SN_CK_MASK;
3524 t->flags |= SN_CK_DOWN;
3525 }
3526 }
3527 srv = srv->next;
3528 }/* end while(srv) */
3529 }/* end else if server == NULL */
3530
Willy Tarreau830ff452006-12-17 19:31:23 +01003531 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003532 }/* end if ((t->proxy->appsession_name != NULL) ... */
3533 }
3534
3535 /* we'll have to look for another cookie ... */
3536 p1 = p4;
3537 } /* while (p1 < cur_end) */
3538
3539 /* There's no more cookie on this line.
3540 * We may have marked the last one(s) for deletion.
3541 * We must do this now in two ways :
3542 * - if there is no app cookie, we simply delete the header ;
3543 * - if there are app cookies, we must delete the end of the
3544 * string properly, including the colon/semi-colon before
3545 * the cookie name.
3546 */
3547 if (del_cookie != NULL) {
3548 int delta;
3549 if (app_cookies) {
3550 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
3551 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003552 cur_hdr->len += delta;
3553 } else {
3554 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003555
3556 /* FIXME: this should be a separate function */
Willy Tarreau45e73e32006-12-17 00:05:15 +01003557 t->hreq.hdr_idx.v[old_idx].next = cur_hdr->next;
3558 t->hreq.hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003559 cur_hdr->len = 0;
3560 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01003561 cur_next += delta;
3562 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003563 }
3564
3565 /* keep the link from this header to next one */
3566 old_idx = cur_idx;
3567 } /* end of cookie processing on this header */
3568}
3569
3570
3571
3572/*
3573 * Try to retrieve a known appsession in the URI, then the associated server.
3574 * If the server is found, it's assigned to the session.
3575 */
3576
3577void get_srv_from_appsession(struct session *t, const char *begin, const char *end)
3578{
3579 appsess *asession_temp = NULL;
3580 appsess local_asession;
3581 char *request_line;
3582
Willy Tarreau830ff452006-12-17 19:31:23 +01003583 if (t->be->beprm->appsession_name == NULL ||
Willy Tarreau921d7c02006-12-17 13:50:27 +01003584 (t->hreq.meth != HTTP_METH_GET && t->hreq.meth != HTTP_METH_POST) ||
Willy Tarreau58f10d72006-12-04 02:26:12 +01003585 (request_line = memchr(begin, ';', end - begin)) == NULL ||
Willy Tarreau830ff452006-12-17 19:31:23 +01003586 ((1 + t->be->beprm->appsession_name_len + 1 + t->be->beprm->appsession_len) > (end - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01003587 return;
3588
3589 /* skip ';' */
3590 request_line++;
3591
3592 /* look if we have a jsessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01003593 if (strncasecmp(request_line, t->be->beprm->appsession_name, t->be->beprm->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003594 return;
3595
3596 /* skip jsessionid= */
Willy Tarreau830ff452006-12-17 19:31:23 +01003597 request_line += t->be->beprm->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003598
3599 /* First try if we already have an appsession */
3600 asession_temp = &local_asession;
3601
3602 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3603 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3604 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3605 return;
3606 }
3607
3608 /* Copy the sessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01003609 memcpy(asession_temp->sessid, request_line, t->be->beprm->appsession_len);
3610 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003611 asession_temp->serverid = NULL;
3612
3613 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01003614 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *)&asession_temp)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003615 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3616 /* free previously allocated memory */
3617 pool_free_to(apools.sessid, local_asession.sessid);
3618 Alert("Not enough memory process_cli():asession:calloc().\n");
3619 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3620 return;
3621 }
3622 asession_temp->sessid = local_asession.sessid;
3623 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01003624 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003625 }
3626 else {
3627 /* free previously allocated memory */
3628 pool_free_to(apools.sessid, local_asession.sessid);
3629 }
3630
Willy Tarreau830ff452006-12-17 19:31:23 +01003631 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003632 asession_temp->request_count++;
3633
3634#if defined(DEBUG_HASH)
3635 print_table(&(t->proxy->htbl_proxy));
3636#endif
3637 if (asession_temp->serverid == NULL) {
3638 Alert("Found Application Session without matching server.\n");
3639 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003640 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003641 while (srv) {
3642 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003643 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003644 /* we found the server and it's usable */
3645 t->flags &= ~SN_CK_MASK;
3646 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3647 t->srv = srv;
3648 break;
3649 } else {
3650 t->flags &= ~SN_CK_MASK;
3651 t->flags |= SN_CK_DOWN;
3652 }
3653 }
3654 srv = srv->next;
3655 }
3656 }
3657}
3658
3659
Willy Tarreaub2513902006-12-17 14:52:38 +01003660
3661/*
3662 * In a GET request, check if the requested URI matches the stats uri for the
3663 * current backend, and if an authorization has been passed and is valid.
3664 *
Willy Tarreau830ff452006-12-17 19:31:23 +01003665 * 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 +01003666 * is valid. An HTTP/401 response may be sent, or produce_content() can be
3667 * called to start sending data.
3668 *
3669 * Returns 1 if the session's state changes, otherwise 0.
3670 */
3671int stats_check_uri_auth(struct session *t, struct proxy *backend)
3672{
3673 struct uri_auth *uri_auth = backend->uri_auth;
3674 struct user_auth *user;
3675 int authenticated, cur_idx;
3676 char *h;
3677
3678 if (t->hreq.start.len < uri_auth->uri_len + 4) /* +4 for "GET " */
3679 return 0;
3680
3681 if (memcmp(t->hreq.start.str + 4, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
3682 return 0;
3683
3684 /* we are in front of a interceptable URI. Let's check
3685 * if there's an authentication and if it's valid.
3686 */
3687 user = uri_auth->users;
3688 if (!user) {
3689 /* no user auth required, it's OK */
3690 authenticated = 1;
3691 } else {
3692 authenticated = 0;
3693
3694 /* a user list is defined, we have to check.
3695 * skip 21 chars for "Authorization: Basic ".
3696 */
3697
3698 /* FIXME: this should move to an earlier place */
3699 cur_idx = 0;
3700 h = t->req->data + t->hreq.sor;
3701 while ((cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
3702 int len = t->hreq.hdr_idx.v[cur_idx].len;
3703 if (len > 14 &&
3704 !strncasecmp("Authorization:", h, 14)) {
3705 t->hreq.auth_hdr.str = h;
3706 t->hreq.auth_hdr.len = len;
3707 break;
3708 }
3709 h += len + t->hreq.hdr_idx.v[cur_idx].cr + 1;
3710 }
3711
3712 if (t->hreq.auth_hdr.len < 21 ||
3713 memcmp(t->hreq.auth_hdr.str + 14, " Basic ", 7))
3714 user = NULL;
3715
3716 while (user) {
3717 if ((t->hreq.auth_hdr.len == user->user_len + 14 + 7)
3718 && !memcmp(t->hreq.auth_hdr.str + 14 + 7,
3719 user->user_pwd, user->user_len)) {
3720 authenticated = 1;
3721 break;
3722 }
3723 user = user->next;
3724 }
3725 }
3726
3727 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01003728 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01003729
3730 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01003731 msg.str = trash;
3732 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreaub2513902006-12-17 14:52:38 +01003733 t->logs.status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01003734 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01003735 if (!(t->flags & SN_ERR_MASK))
3736 t->flags |= SN_ERR_PRXCOND;
3737 if (!(t->flags & SN_FINST_MASK))
3738 t->flags |= SN_FINST_R;
3739 return 1;
3740 }
3741
3742 /* The request is valid, the user is authenticate. Let's start sending
3743 * data.
3744 */
3745 t->cli_state = CL_STSHUTR;
3746 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
3747 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
3748 t->data_source = DATA_SRC_STATS;
3749 t->data_state = DATA_ST_INIT;
3750 produce_content(t);
3751 return 1;
3752}
3753
3754
3755
Willy Tarreaubaaee002006-06-26 02:48:02 +02003756/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01003757 * Print a debug line with a header
3758 */
3759void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
3760{
3761 int len, max;
3762 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
3763 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
3764 max = end - start;
3765 UBOUND(max, sizeof(trash) - len - 1);
3766 len += strlcpy2(trash + len, start, max + 1);
3767 trash[len++] = '\n';
3768 write(1, trash, len);
3769}
3770
3771
3772/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02003773 * Local variables:
3774 * c-indent-level: 8
3775 * c-basic-offset: 8
3776 * End:
3777 */