blob: 9cce59ba769ff93d50671dcc3d35c933e2980843 [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 */
70const char *HTTP_200 =
71 "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 Tarreaubaaee002006-06-26 02:48:02 +020078/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
79const char *HTTP_401_fmt =
80 "HTTP/1.0 401 Unauthorized\r\n"
81 "Cache-Control: no-cache\r\n"
82 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +020083 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +020084 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
85 "\r\n"
86 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
87
88
Willy Tarreau53b6c742006-12-17 13:37:46 +010089/*
90 * We have 26 list of methods (1 per first letter), each of which can have
91 * up to 3 entries (2 valid, 1 null).
92 */
93struct http_method_desc {
94 http_meth_t meth;
95 int len;
96 const char text[8];
97};
98
99static struct http_method_desc http_methods[26][3] = {
100 ['C' - 'A'] = {
101 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
102 },
103 ['D' - 'A'] = {
104 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
105 },
106 ['G' - 'A'] = {
107 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
108 },
109 ['H' - 'A'] = {
110 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
111 },
112 ['P' - 'A'] = {
113 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
114 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
115 },
116 ['T' - 'A'] = {
117 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
118 },
119 /* rest is empty like this :
120 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
121 */
122};
123
Willy Tarreaubaaee002006-06-26 02:48:02 +0200124#ifdef DEBUG_FULL
125static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
126static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
127#endif
128
129
130/*
131 * returns a message to the client ; the connection is shut down for read,
132 * and the request is cleared so that no server connection can be initiated.
133 * The client must be in a valid state for this (HEADER, DATA ...).
134 * Nothing is performed on the server side.
135 * The reply buffer doesn't need to be empty before this.
136 */
137void client_retnclose(struct session *s, int len, const char *msg)
138{
Willy Tarreau2a429502006-10-15 14:52:29 +0200139 MY_FD_CLR(s->cli_fd, StaticReadEvent);
140 MY_FD_SET(s->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +0200141 tv_eternity(&s->req->rex);
Willy Tarreau73de9892006-11-30 11:40:23 +0100142 if (s->fe->clitimeout)
143 tv_delayfrom(&s->rep->wex, &now, s->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200144 else
Willy Tarreaud7971282006-07-29 18:36:34 +0200145 tv_eternity(&s->rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200146 shutdown(s->cli_fd, SHUT_RD);
147 s->cli_state = CL_STSHUTR;
148 buffer_flush(s->rep);
149 buffer_write(s->rep, msg, len);
150 s->req->l = 0;
151}
152
153
154/*
155 * returns a message into the rep buffer, and flushes the req buffer.
156 * The reply buffer doesn't need to be empty before this.
157 */
158void client_return(struct session *s, int len, const char *msg)
159{
160 buffer_flush(s->rep);
161 buffer_write(s->rep, msg, len);
162 s->req->l = 0;
163}
164
165
166/* This function turns the server state into the SV_STCLOSE, and sets
167 * indicators accordingly. Note that if <status> is 0, no message is
168 * returned.
169 */
170void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreaub17916e2006-10-15 15:17:57 +0200171 int status, int msglen, const char *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200172{
173 t->srv_state = SV_STCLOSE;
174 if (status > 0) {
175 t->logs.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100176 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200177 client_return(t, msglen, msg);
178 }
179 if (!(t->flags & SN_ERR_MASK))
180 t->flags |= err;
181 if (!(t->flags & SN_FINST_MASK))
182 t->flags |= finst;
183}
184
185
Willy Tarreau53b6c742006-12-17 13:37:46 +0100186/*
187 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
188 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
189 */
190static http_meth_t find_http_meth(const char *str, const int len)
191{
192 unsigned char m;
193 struct http_method_desc *h;
194
195 m = ((unsigned)*str - 'A');
196
197 if (m < 26) {
198 int l;
199 for (h = http_methods[m]; (l = (h->len)) > 0; h++) {
200 if (len <= l)
201 continue;
202
203 if (str[l] != ' ' && str[l] != '\t')
204 continue;
205
206 if (memcmp(str, h->text, l) == 0) {
207 return h->meth;
208 }
209 };
210 return HTTP_METH_OTHER;
211 }
212 return HTTP_METH_NONE;
213
214}
215
216
Willy Tarreaubaaee002006-06-26 02:48:02 +0200217/* Processes the client and server jobs of a session task, then
218 * puts it back to the wait queue in a clean state, or
219 * cleans up its resources if it must be deleted. Returns
220 * the time the task accepts to wait, or TIME_ETERNITY for
221 * infinity.
222 */
223int process_session(struct task *t)
224{
225 struct session *s = t->context;
226 int fsm_resync = 0;
227
228 do {
229 fsm_resync = 0;
230 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
231 fsm_resync |= process_cli(s);
232 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
233 fsm_resync |= process_srv(s);
234 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
235 } while (fsm_resync);
236
237 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
238 struct timeval min1, min2;
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200239 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
240 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200241
Willy Tarreaud7971282006-07-29 18:36:34 +0200242 tv_min(&min1, &s->req->rex, &s->req->wex);
243 tv_min(&min2, &s->rep->rex, &s->rep->wex);
244 tv_min(&min1, &min1, &s->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200245 tv_min(&t->expire, &min1, &min2);
246
247 /* restore t to its place in the task list */
248 task_queue(t);
249
250#ifdef DEBUG_FULL
251 /* DEBUG code : this should never ever happen, otherwise it indicates
252 * that a task still has something to do and will provoke a quick loop.
253 */
254 if (tv_remain2(&now, &t->expire) <= 0)
255 exit(100);
256#endif
257
258 return tv_remain2(&now, &t->expire); /* nothing more to do */
259 }
260
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100261 s->fe->feconn--;
262 if (s->flags & SN_BE_ASSIGNED)
263 s->be->beprm->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200264 actconn--;
265
266 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
267 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100268 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreau830ff452006-12-17 19:31:23 +0100269 s->uniq_id, s->be->beprm->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100270 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200271 write(1, trash, len);
272 }
273
274 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
275 if (s->rep != NULL)
276 s->logs.bytes = s->rep->total;
277
278 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200279 if (s->logs.logwait &&
280 !(s->flags & SN_MONITOR) &&
Willy Tarreau73de9892006-11-30 11:40:23 +0100281 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total))
Willy Tarreaubaaee002006-06-26 02:48:02 +0200282 sess_log(s);
283
284 /* the task MUST not be in the run queue anymore */
285 task_delete(t);
286 session_free(s);
287 task_free(t);
288 return TIME_ETERNITY; /* rest in peace for eternity */
289}
290
291
292/*
293 * FIXME: This should move to the HTTP_flow_analyzer code
294 */
295
296/*
297 * manages the client FSM and its socket. BTW, it also tries to handle the
298 * cookie. It returns 1 if a state has changed (and a resync may be needed),
299 * 0 else.
300 */
301int process_cli(struct session *t)
302{
303 int s = t->srv_state;
304 int c = t->cli_state;
305 struct buffer *req = t->req;
306 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100307 int delete_header = 0;
308
Willy Tarreaub2513902006-12-17 14:52:38 +0100309 int cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200310
Willy Tarreau45e73e32006-12-17 00:05:15 +0100311 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 +0200312 cli_stnames[c], srv_stnames[s],
Willy Tarreau2a429502006-10-15 14:52:29 +0200313 MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
Willy Tarreaud7971282006-07-29 18:36:34 +0200314 req->rex.tv_sec, req->rex.tv_usec,
315 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau45e73e32006-12-17 00:05:15 +0100316
Willy Tarreaubaaee002006-06-26 02:48:02 +0200317 if (c == CL_STHEADERS) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100318 /*
319 * Now parse the partial (or complete) lines.
320 * We will check the request syntax, and also join multi-line
321 * headers. An index of all the lines will be elaborated while
322 * parsing.
323 *
324 * For the parsing, we use a 10 states FSM.
325 *
326 * RFC2616 requires that both LF and CRLF are recognized as
327 * line breaks, but that any other combination is an error.
328 * To avoid duplicating all the states above to check for CR,
329 * we use a special bit HTTP_PA_LF_EXP that we 'OR' with the
330 * state we will switch to if the LF is seen, so that we know
331 * whether there's a pending CR or not. We can check it
332 * globally since all CR followed by anything but LF are
333 * errors. Each state is entered with the first character is
334 * has to process at req->lr. We also have HTTP_PA_CR_SKIP
335 * indicating that a CR has been seen on current line and
336 * skipped.
337 *
338 * Here is the information we currently have :
Willy Tarreau45e73e32006-12-17 00:05:15 +0100339 * req->data + req->sor = beginning of request
340 * req->data + req->eoh = end of (parsed) headers
Willy Tarreau58f10d72006-12-04 02:26:12 +0100341 * req->lr = first non-visited byte
342 * req->r = end of data
343 */
344
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100345 char *sol, *eol; /* Start Of Line, End Of Line */
Willy Tarreau830ff452006-12-17 19:31:23 +0100346 struct proxy *cur_proxy;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100347
Willy Tarreau45e73e32006-12-17 00:05:15 +0100348 eol = sol = req->data + t->hreq.eoh;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100349
Willy Tarreau58f10d72006-12-04 02:26:12 +0100350 while (req->lr < req->r) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100351 int parse;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200352
Willy Tarreau45e73e32006-12-17 00:05:15 +0100353 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",
354 t->hreq.hdr_state, t->hreq.hdr_idx.used, t->hreq.hdr_idx.tail, t->hreq.hdr_idx.last,
355 sol - req->data, req->lr - req->data, req->r - req->data, t->hreq.eoh);
356
357 if (t->hreq.hdr_state & HTTP_PA_LF_EXP) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100358 if (*req->lr != '\n') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100359 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100360 break;
361 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100362 t->hreq.hdr_state &= ~HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100363 }
364
Willy Tarreau45e73e32006-12-17 00:05:15 +0100365 parse = t->hreq.hdr_state & ~HTTP_PA_CR_SKIP;;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100366
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100367 if (parse == HTTP_PA_HDR_LF) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100368 parse_hdr_lf:
369 /* The LF validating last header, but it
370 * may also be an LWS, in which case we will
371 * need more data to know if we can close this
372 * header or not. However, we must check right
373 * now if this LF/CRLF closes an empty line, in
374 * which case it means the end of the request.
375 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100376 eol = req->lr;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100377 if (t->hreq.hdr_state & HTTP_PA_CR_SKIP)
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100378 eol--; /* Get back to the CR */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100379
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100380 if (eol == sol) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100381 /* We have found the end of the headers.
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100382 * sol points to the ending LF/CRLF,
Willy Tarreau58f10d72006-12-04 02:26:12 +0100383 * and req->lr points to the first byte
384 * after the LF, so it is easy to append
385 * anything there.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200386 */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100387 t->hreq.hdr_state = HTTP_PA_LFLF;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100388 QUICK_JUMP(parse_lflf, continue);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100389 }
390
391 if (req->lr + 1 >= req->r) /* LF, ?? */
392 break;
393 req->lr++;
394
395 /* Right now, we *know* that there is one char
396 * available at req->lr.
397 */
398
399 if (*req->lr == ' ' || *req->lr == '\t') {
400 /* We have an LWS, we will replace the
401 * CR and LF with spaces as RFC2616
402 * allows it. <lr> now points to the
403 * first space char of the LWS part.
404 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100405 for (;eol < req->lr; eol++)
406 *eol = ' ';
Willy Tarreau58f10d72006-12-04 02:26:12 +0100407
Willy Tarreau45e73e32006-12-17 00:05:15 +0100408 t->hreq.hdr_state = HTTP_PA_HDR_LWS;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100409 QUICK_JUMP(parse_hdr_lws, continue);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100410 }
411
412 /**********************************************
413 * We now have one complete header between *
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100414 * sol and eol, with a possible CR at eol, *
Willy Tarreau58f10d72006-12-04 02:26:12 +0100415 * everything ending before req->lr. Some very*
416 * early processing can be applied. *
417 **********************************************/
418
419 /*
420 * FIXME: insert a REQHEADER hook here.
421 * For instance, we could check the header's
422 * syntax such as forbidding the leading space
423 * in the first header (Apache also has the same problem)
424 */
425
426
427 /* 1: we might have to print this header */
428 if ((global.mode & MODE_DEBUG) &&
429 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100430 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100431
432
433 /* 2: maybe we have to copy this header for the logs ? */
434 if (t->logs.logwait & LW_REQHDR) {
435 /* FIXME: we must *search* the value after the ':' and not
436 * consider that it's necessary after one single space.*/
437 struct cap_hdr *h;
438 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +0100439 for (h = t->fe->fiprm->req_cap; h; h = h->next) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100440 if ((h->namelen + 2 <= eol - sol) &&
441 (sol[h->namelen] == ':') &&
442 (strncasecmp(sol, h->name, h->namelen) == 0)) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100443 if (t->hreq.cap[h->index] == NULL)
444 t->hreq.cap[h->index] =
445 pool_alloc_from(h->pool, h->len + 1);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100446
Willy Tarreau45e73e32006-12-17 00:05:15 +0100447 if (t->hreq.cap[h->index] == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100448 Alert("HTTP capture : out of memory.\n");
449 continue;
450 }
451
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100452 len = eol - (sol + h->namelen + 2);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100453 if (len > h->len)
454 len = h->len;
455
Willy Tarreau45e73e32006-12-17 00:05:15 +0100456 memcpy(t->hreq.cap[h->index], sol + h->namelen + 2, len);
457 t->hreq.cap[h->index][len]=0;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100458 }
459 }
460 }
461
462
463 /* 3: We might need to remove "connection:" */
464 if (!delete_header && (t->fe->options & PR_O_HTTP_CLOSE)
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100465 && (strncasecmp(sol, "Connection:", 11) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100466 delete_header = 1;
467 }
468
469
Willy Tarreau58f10d72006-12-04 02:26:12 +0100470 /* OK, that's enough processing for the first step.
471 * Now either we index this header or we remove it.
472 */
473
474 if (!delete_header) {
475 /* we insert it into the index */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100476 if (hdr_idx_add(eol - sol, req->lr - eol - 1,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100477 &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0) {
478 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100479 break;
480 }
481 } else {
482 /* we remove it */
483 delete_header = 0;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100484 buffer_replace2(req, sol, req->lr, NULL, 0);
485 /* WARNING: eol is not valid anymore, since the
Willy Tarreau58f10d72006-12-04 02:26:12 +0100486 * header may have been deleted or truncated ! */
487 }
488
489 /* In any case, we set the next header pointer
490 * to the next line.
491 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100492 sol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100493
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100494#ifdef DEBUG_PARSE_NO_SPEEDUP
495 t->hreq.hdr_state = HTTP_PA_HEADER;
496 continue;
497#else
Willy Tarreau58f10d72006-12-04 02:26:12 +0100498 /*
499 * We know that at least one character remains.
500 * It is interesting to directly branch to the
501 * matching state.
502 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100503 eol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100504 if (IS_CTL(*req->lr)) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100505 if (*eol == '\r') {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100506 req->lr++;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100507 t->hreq.hdr_state = HTTP_PA_LFLF | HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100508 continue;
509 }
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100510 else if (*eol == '\n') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100511 t->hreq.hdr_state = HTTP_PA_LFLF;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100512 goto parse_lflf;
513 }
514 else {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100515 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100516 break;
517 }
518 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100519 t->hreq.hdr_state = HTTP_PA_HEADER;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100520 goto parse_inside_hdr;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100521#endif
522
523 } else if (parse == HTTP_PA_STRT_LF) {
524 parse_strt_lf:
525 /* The LF validating the request line */
526
527 eol = req->lr;
528 if (t->hreq.hdr_state & HTTP_PA_CR_SKIP)
529 eol--; /* Get back to the CR */
530
531 /* We have the complete start line between
532 * sol and eol (excluded). lr points to
533 * the LF.
534 */
535
536 /* FIXME: insert a REQUESTURI hook here. */
537
538
539 /* 1: we might have to print this header */
540 if ((global.mode & MODE_DEBUG) &&
541 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
542 debug_hdr("clireq", t, sol, eol);
543
544 /* 2: maybe we have to copy the original REQURI for the logs ? */
545 if (t->logs.logwait & LW_REQ) {
546 /* we have a complete HTTP request that we must log */
547 if ((t->logs.uri = pool_alloc(requri)) != NULL) {
548 int urilen = eol - sol;
549
550 if (urilen >= REQURI_LEN)
551 urilen = REQURI_LEN - 1;
552 memcpy(t->logs.uri, sol, urilen);
553 t->logs.uri[urilen] = 0;
554
555 if (!(t->logs.logwait &= ~LW_REQ))
556 sess_log(t);
557 } else {
558 Alert("HTTP logging : out of memory.\n");
559 }
560 }
561
562 /* 3: reference this line as the start line */
563 if (hdr_idx_add(eol - sol, req->lr - eol,
564 &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0) {
565 t->hreq.hdr_state = HTTP_PA_ERROR;
566 break;
567 }
568
569 req->lr++;
570 sol = req->lr;
571 /* in fact, a state is missing here, we should
572 * be able to distinguish between an empty line
573 * and a header.
574 */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100575 t->hreq.hdr_state = HTTP_PA_HEADER;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100576#ifdef DEBUG_PARSE_NO_SPEEDUP
Willy Tarreau58f10d72006-12-04 02:26:12 +0100577 continue;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100578#else
579 if (req->lr < req->r)
580 goto parse_inside_hdr;
581 else
582 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100583#endif
584
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100585 } else if (parse == HTTP_PA_HEADER) {
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100586 char *ptr;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100587 /* Inside a non-empty header */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100588
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100589 parse_inside_hdr:
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100590 delete_header = 0;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100591
592 ptr = req->lr;
593
594#ifdef GCC_FINALLY_PRODUCES_EFFICIENT_WHILE_LOOPS
595 /* This code is disabled right now because
596 * eventhough it seems straightforward, the
597 * object code produced by GCC is so much
598 * suboptimal that about 10% of the time
599 * spend parsing header is there.
600 */
601 while (ptr < req->r && !IS_CTL(*ptr))
602 ptr++;
603 req->lr = ptr;
604 if (ptr == req->r)
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100605 break;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100606#else
607 /* Just by using this loop instead of the previous one,
608 * the global performance increases by about 2% ! The
609 * code is also smaller by about 50 bytes.
610 */
611 goto reqhdr_loop_chk;
612 reqhdr_loop:
613 ptr++;
614 reqhdr_loop_chk:
615 if (ptr == req->r) {
616 req->lr = ptr;
617 break;
618 }
619 if (*ptr != 0x7F && (unsigned)*ptr >= 0x20)
620 goto reqhdr_loop;
621 req->lr = ptr;
622#endif
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100623
624 /* we have a CTL char */
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100625 if (*ptr == '\r') {
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100626 t->hreq.hdr_state = HTTP_PA_HDR_LF | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
627 req->lr++;
628 continue;
629 }
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100630 else if (*ptr == '\n') {
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100631 t->hreq.hdr_state = HTTP_PA_HDR_LF;
632 QUICK_JUMP(parse_hdr_lf, continue);
633 }
634 t->hreq.hdr_state = HTTP_PA_ERROR;
635 break;
636
637 } else if (parse == HTTP_PA_EMPTY) {
638 /* leading empty lines */
639
640 if (*req->lr == '\n') {
641 req->lr ++;
642 t->hreq.hdr_state = HTTP_PA_EMPTY;
643 continue;
644 }
645 else if (*req->lr == '\r') {
646 req->lr ++;
647 t->hreq.hdr_state = HTTP_PA_EMPTY | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
648 continue;
649 }
650
651 FSM_PRINTF(stderr, "PA_EMPTY[0]: h=%d, lr=%d, r=%d\n",
652 sol - req->data, req->lr - req->data, req->r - req->data);
653
654#if PARSE_PRESERVE_EMPTY_LINES
655 /* only skip empty leading lines, don't remove them */
656 t->hreq.hdr_idx.v[0].len = req->lr - sol;
657 t->hreq.sor = t->hreq.hdr_idx.v[0].len;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100658#else
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100659 /* remove empty leading lines, as recommended by
660 * RFC2616. This takes a lot of time because we
661 * must move all the buffer backwards, but this
662 * is rarely needed. The method above will be
663 * cleaner when we'll be able to start sending
664 * the request from any place in the buffer.
665 */
666 buffer_replace2(req, sol, req->lr, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100667#endif
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100668 sol = req->lr;
669 FSM_PRINTF(stderr, "PA_EMPTY[1]: h=%d, lr=%d, r=%d\n",
670 sol - req->data, req->lr - req->data, req->r - req->data);
671
672 t->hreq.hdr_state = HTTP_PA_START;
673 /* we know that we still have one char available */
674 QUICK_JUMP(parse_start, continue);
675
676 } else if (parse == HTTP_PA_START) {
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100677 char *ptr;
678 /* Inside the start line */
679
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100680 parse_start:
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100681 ptr = req->lr;
682
683#ifdef GCC_FINALLY_PRODUCES_EFFICIENT_WHILE_LOOPS
684 /* This code is disabled right now because
685 * eventhough it seems straightforward, the
686 * object code produced by GCC is so much
687 * suboptimal that about 10% of the time
688 * spend parsing header is there.
689 */
690 while (ptr < req->r && !IS_CTL(*ptr))
691 ptr++;
692 req->lr = ptr;
693 if (ptr == req->r)
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100694 break;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100695#else
696 /* Just by using this loop instead of the previous one,
697 * the global performance increases by about 2% ! The
698 * code is also smaller by about 50 bytes.
699 */
700 goto reqstrt_loop_chk;
701 reqstrt_loop:
702 ptr++;
703 reqstrt_loop_chk:
704 if (ptr == req->r) {
705 req->lr = ptr;
706 break;
707 }
708 if (*ptr != 0x7F && (unsigned)*ptr >= 0x20)
709 goto reqstrt_loop;
710 req->lr = ptr;
711#endif
712
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100713 /* we have a CTL char */
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100714 if (*ptr == '\r') {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100715 req->lr++;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100716 t->hreq.hdr_state = HTTP_PA_STRT_LF | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
717 continue;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100718 }
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100719 else if (*ptr == '\n') {
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100720 t->hreq.hdr_state = HTTP_PA_STRT_LF;
721 /* we know that we still have one char available */
722 QUICK_JUMP(parse_strt_lf, continue);
723 }
724 t->hreq.hdr_state = HTTP_PA_ERROR;
725 break;
726
Willy Tarreau58f10d72006-12-04 02:26:12 +0100727
728 } else if (parse == HTTP_PA_LFLF) {
729 parse_lflf:
730 req->lr ++;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100731 /* sol points to either CR or CRLF, and
Willy Tarreau58f10d72006-12-04 02:26:12 +0100732 * req->lr points to 1 char after LF.
733 */
734
735 /*
736 * FIXME: insert a hook here for the end of the headers
737 */
738 break;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100739
740 } else if (parse == HTTP_PA_HDR_LWS) {
741 parse_hdr_lws:
742 /* Inside an LWS. We just replace tabs with
743 * spaces and fall back to the HEADER state
744 * at the first non-space character
745 */
746
747 while (req->lr < req->r) {
748 if (*req->lr == '\t')
749 *req->lr = ' ';
750 else if (*req->lr != ' ') {
751 t->hreq.hdr_state = HTTP_PA_HEADER;
752 QUICK_JUMP(parse_inside_hdr, break);
753 }
754 req->lr++;
755 }
756 continue;
757
Willy Tarreau58f10d72006-12-04 02:26:12 +0100758 } else if (parse == HTTP_PA_ERROR) {
759 break;
760 }
761
762 } /* end of the "while(req->lr < req->r)" loop */
763
Willy Tarreau45e73e32006-12-17 00:05:15 +0100764 /* update the end of headers */
765 t->hreq.eoh = sol - req->data;
766
767 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",
768 t->hreq.hdr_state, t->hreq.hdr_idx.used, t->hreq.hdr_idx.tail, t->hreq.hdr_idx.last,
769 sol - req->data, req->lr - req->data, req->r - req->data, t->hreq.eoh);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100770
771 /*
772 * Now, let's catch bad requests.
773 */
774
Willy Tarreau06619262006-12-17 08:37:22 +0100775 if (t->hreq.hdr_state == HTTP_PA_ERROR)
776 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100777
778 /*
779 * Now we quickly check if we have found a full request.
780 * If not so, we check the FD and buffer states before leaving.
781 * A full request is indicated by the fact that we have seen
782 * the double LF/CRLF, so the state is HTTP_PA_LFLF.
783 *
784 */
785
Willy Tarreau45e73e32006-12-17 00:05:15 +0100786 if (t->hreq.hdr_state != HTTP_PA_LFLF) { /* Request not complete yet */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100787
788 /* 1: Since we are in header mode, if there's no space
789 * left for headers, we won't be able to free more
790 * later, so the session will never terminate. We
791 * must terminate it now.
792 */
793 if (req->l >= req->rlim - req->data) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100794 /* FIXME: check if hreq.hdr_state & mask < HTTP_PA_HEADER,
Willy Tarreau58f10d72006-12-04 02:26:12 +0100795 * and return Status 414 Request URI too long instead.
796 */
Willy Tarreau06619262006-12-17 08:37:22 +0100797 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100798 }
799
800 /* 2: have we encountered a read error or a close ? */
801 else if (req->flags & (BF_READ_ERROR | BF_READ_NULL)) {
802 /* read error, or last read : give up. */
803 tv_eternity(&req->rex);
804 fd_delete(t->cli_fd);
805 t->cli_state = CL_STCLOSE;
806 if (!(t->flags & SN_ERR_MASK))
807 t->flags |= SN_ERR_CLICL;
808 if (!(t->flags & SN_FINST_MASK))
809 t->flags |= SN_FINST_R;
810 return 1;
811 }
812
813 /* 3: has the read timeout expired ? */
814 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
815 /* read timeout : give up with an error message. */
816 t->logs.status = 408;
817 client_retnclose(t, t->fe->errmsg.len408, t->fe->errmsg.msg408);
818 if (!(t->flags & SN_ERR_MASK))
819 t->flags |= SN_ERR_CLITO;
820 if (!(t->flags & SN_FINST_MASK))
821 t->flags |= SN_FINST_R;
822 return 1;
823 }
824
825 /* 4: do we need to re-enable the read socket ? */
826 else if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
827 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
828 * full. We cannot loop here since stream_sock_read will disable it only if
829 * req->l == rlim-data
830 */
831 MY_FD_SET(t->cli_fd, StaticReadEvent);
832 if (t->fe->clitimeout)
833 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
834 else
835 tv_eternity(&req->rex);
836 }
837 return t->cli_state != CL_STHEADERS;
838 }
839
840
841 /****************************************************************
842 * More interesting part now : we know that we have a complete *
843 * request which at least looks like HTTP. We have an indicator *
844 * of each header's length, so we can parse them quickly. *
845 ****************************************************************/
846
847
848 /*
Willy Tarreau06619262006-12-17 08:37:22 +0100849 * 1: check if the URI matches the monitor_uri.
850 * We have to do this for every request which gets in, because
851 * the monitor-uri is defined by the frontend. To speed-up the
852 * test, we include the leading and trailing spaces in the
853 * comparison. This is generally not a problem because the
854 * monitor-uri is primarily used by external checkers which
855 * send pre-formatted requests too.
Willy Tarreau58f10d72006-12-04 02:26:12 +0100856 */
857
Willy Tarreau06619262006-12-17 08:37:22 +0100858 t->hreq.start.str = req->data + t->hreq.sor; /* start of the REQURI */
859 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 +0100860 t->hreq.meth = find_http_meth(t->hreq.start.str, t->hreq.start.len);
Willy Tarreau06619262006-12-17 08:37:22 +0100861
862 if ((t->fe->monitor_uri_len != 0) &&
863 (t->hreq.start.len >= t->fe->monitor_uri_len)) {
864 char *p = t->hreq.start.str;
865 int idx = 0;
866
867 /* skip the method so that we accept any method */
868 while (idx < t->hreq.start.len && p[idx] != ' ')
869 idx++;
870 p += idx;
871
872 if (t->hreq.start.len - idx >= t->fe->monitor_uri_len &&
873 !memcmp(p, t->fe->monitor_uri, t->fe->monitor_uri_len)) {
874 /*
875 * We have found the monitor URI
876 */
877 t->flags |= SN_MONITOR;
878 t->logs.status = 200;
879 client_retnclose(t, strlen(HTTP_200), HTTP_200);
880 goto return_prx_cond;
881 }
Willy Tarreau58f10d72006-12-04 02:26:12 +0100882 }
883
884
885 /*
886 * 2: we will have to evaluate the filters.
887 * As opposed to version 1.2, now they will be evaluated in the
888 * filters order and not in the header order. This means that
889 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +0100890 *
891 * We can now check whether we want to switch to another
892 * backend, in which case we will re-check the backend's
893 * filters and various options. In order to support 3-level
894 * switching, here's how we should proceed :
895 *
Willy Tarreau830ff452006-12-17 19:31:23 +0100896 * a) run be->fiprm.
897 * if (switch) then switch ->be to the new backend.
898 * b) run be->fiprm if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +0100899 * There cannot be any switch from there, so ->be cannot be
900 * changed anymore.
901 *
Willy Tarreau830ff452006-12-17 19:31:23 +0100902 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100903 *
Willy Tarreau830ff452006-12-17 19:31:23 +0100904 * The response path will be able to apply either ->be, or
905 * ->be then ->fe filters in order to match the reverse of
906 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +0100907 */
908
Willy Tarreau06619262006-12-17 08:37:22 +0100909 do {
Willy Tarreau830ff452006-12-17 19:31:23 +0100910 struct proxy *rule_set = t->be->fiprm;
911 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100912
Willy Tarreau06619262006-12-17 08:37:22 +0100913 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +0100914 if (rule_set->req_exp != NULL) {
Willy Tarreau06619262006-12-17 08:37:22 +0100915 apply_filters_to_session(t, req, rule_set->req_exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100916
Willy Tarreau53b6c742006-12-17 13:37:46 +0100917 /* the start line might have been modified */
918 t->hreq.start.len = t->hreq.hdr_idx.v[t->hreq.hdr_idx.v[0].next].len;
919 t->hreq.meth = find_http_meth(t->hreq.start.str, t->hreq.start.len);
Willy Tarreau53b6c742006-12-17 13:37:46 +0100920 }
921
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100922 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
923 /* to ensure correct connection accounting on
924 * the backend, we count the connection for the
925 * one managing the queue.
926 */
927 t->be->beprm->beconn++;
928 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
929 t->be->beprm->beconn_max = t->be->beprm->beconn;
930 t->be->beprm->cum_beconn++;
931 t->flags |= SN_BE_ASSIGNED;
932 }
933
Willy Tarreau06619262006-12-17 08:37:22 +0100934 /* has the request been denied ? */
935 if (t->flags & SN_CLDENY) {
936 /* no need to go further */
937 t->logs.status = 403;
938 /* let's log the request time */
939 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
940 client_retnclose(t, t->fe->errmsg.len403, t->fe->errmsg.msg403);
941 goto return_prx_cond;
942 }
943
944 /* add request headers from the rule sets in the same order */
945 for (cur_hdr = 0; cur_hdr < rule_set->nb_reqadd; cur_hdr++) {
946 int len;
947
948 len = sprintf(trash, "%s\r\n", rule_set->req_add[cur_hdr]);
949 len = buffer_replace2(req, req->data + t->hreq.eoh,
950 req->data + t->hreq.eoh, trash, len);
951 t->hreq.eoh += len;
952
953 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
954 goto return_bad_req;
955 }
Willy Tarreaub2513902006-12-17 14:52:38 +0100956
957 if (rule_set->uri_auth != NULL && t->hreq.meth == HTTP_METH_GET) {
958 /* we have to check the URI and auth for this request */
959 if (stats_check_uri_auth(t, rule_set))
960 return 1;
961 }
962
Willy Tarreau830ff452006-12-17 19:31:23 +0100963 } while (cur_proxy != t->be); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +0100964
Willy Tarreau58f10d72006-12-04 02:26:12 +0100965
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100966 if (!(t->flags & SN_BE_ASSIGNED)) {
967 /* To ensure correct connection accounting on
968 * the backend, we count the connection for the
969 * one managing the queue.
970 */
971 t->be->beprm->beconn++;
972 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
973 t->be->beprm->beconn_max = t->be->beprm->beconn;
974 t->be->beprm->cum_beconn++;
975 t->flags |= SN_BE_ASSIGNED;
976 }
977
978
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100979 /*
980 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +0100981 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100982 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +0100983 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +0100984 */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100985
Willy Tarreau58f10d72006-12-04 02:26:12 +0100986
Willy Tarreau58f10d72006-12-04 02:26:12 +0100987
Willy Tarreau58f10d72006-12-04 02:26:12 +0100988
Willy Tarreau2a324282006-12-05 00:05:46 +0100989 /*
Willy Tarreaub2513902006-12-17 14:52:38 +0100990 * 3: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +0100991 * so let's do the same now.
992 */
993
994 /* It needs to look into the URI */
Willy Tarreau830ff452006-12-17 19:31:23 +0100995 if (t->be->beprm->appsession_name) {
Willy Tarreau06619262006-12-17 08:37:22 +0100996 get_srv_from_appsession(t,
997 t->hreq.start.str,
998 t->hreq.start.str + t->hreq.start.len);
999 }
1000
1001
1002 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001003 * 4: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01001004 * Note that doing so might move headers in the request, but
1005 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01001006 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01001007 */
1008 if (!(t->flags & (SN_CLDENY|SN_CLTARPIT)))
1009 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001010
Willy Tarreau58f10d72006-12-04 02:26:12 +01001011
Willy Tarreau2a324282006-12-05 00:05:46 +01001012 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001013 * 5: add X-Forwarded-For : Should depend on the backend only.
Willy Tarreau2a324282006-12-05 00:05:46 +01001014 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001015 if (t->be->beprm->options & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001016 if (t->cli_addr.ss_family == AF_INET) {
1017 int len;
1018 unsigned char *pn;
1019 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
1020 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
1021 pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001022 len = buffer_replace2(req, req->data + t->hreq.eoh,
1023 req->data + t->hreq.eoh, trash, len);
1024 t->hreq.eoh += len;
1025
Willy Tarreau06619262006-12-17 08:37:22 +01001026 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1027 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001028 }
1029 else if (t->cli_addr.ss_family == AF_INET6) {
1030 int len;
1031 char pn[INET6_ADDRSTRLEN];
1032 inet_ntop(AF_INET6,
1033 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
1034 pn, sizeof(pn));
1035 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001036 len = buffer_replace2(req, req->data + t->hreq.eoh,
1037 req->data + t->hreq.eoh, trash, len);
1038 t->hreq.eoh += len;
1039
Willy Tarreau06619262006-12-17 08:37:22 +01001040 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1041 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001042 }
1043 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001044
Willy Tarreaubaaee002006-06-26 02:48:02 +02001045
Willy Tarreau2a324282006-12-05 00:05:46 +01001046 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001047 * 6: add "Connection:"
Willy Tarreau2a324282006-12-05 00:05:46 +01001048 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001049
Willy Tarreaub2513902006-12-17 14:52:38 +01001050 /* add a "connection: close" line if needed.
1051 * FIXME: this should depend on both the frontend and the backend.
1052 * Header removals should be performed when the filters are run.
1053 */
Willy Tarreaue15d9132006-12-14 22:26:42 +01001054 if (t->fe->options & PR_O_HTTP_CLOSE) {
Willy Tarreau45e73e32006-12-17 00:05:15 +01001055 int len;
1056 len = buffer_replace2(req, req->data + t->hreq.eoh,
1057 req->data + t->hreq.eoh, "Connection: close\r\n", 19);
1058 t->hreq.eoh += len;
1059
Willy Tarreau06619262006-12-17 08:37:22 +01001060 if (hdr_idx_add(17, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1061 goto return_bad_req;
Willy Tarreaue15d9132006-12-14 22:26:42 +01001062 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001063
Willy Tarreaubaaee002006-06-26 02:48:02 +02001064
Willy Tarreaue15d9132006-12-14 22:26:42 +01001065
1066
Willy Tarreau06619262006-12-17 08:37:22 +01001067
Willy Tarreaue15d9132006-12-14 22:26:42 +01001068
Willy Tarreau2a324282006-12-05 00:05:46 +01001069 /*************************************************************
1070 * OK, that's finished for the headers. We have done what we *
1071 * could. Let's switch to the DATA state. *
1072 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02001073
Willy Tarreau2a324282006-12-05 00:05:46 +01001074 t->cli_state = CL_STDATA;
1075 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001076
Willy Tarreau2a324282006-12-05 00:05:46 +01001077 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001078
Willy Tarreaubaaee002006-06-26 02:48:02 +02001079
Willy Tarreau2a324282006-12-05 00:05:46 +01001080 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001081 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001082 /* If the client has no timeout, or if the server is not ready yet,
1083 * and we know for sure that it can expire, then it's cleaner to
1084 * disable the timeout on the client side so that too low values
1085 * cannot make the sessions abort too early.
1086 *
1087 * FIXME-20050705: the server needs a way to re-enable this time-out
1088 * when it switches its state, otherwise a client can stay connected
1089 * indefinitely. This now seems to be OK.
1090 */
1091 tv_eternity(&req->rex);
1092 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001093
Willy Tarreaub8750a82006-09-03 09:56:00 +02001094
Willy Tarreau2a324282006-12-05 00:05:46 +01001095 /* When a connection is tarpitted, we use the queue timeout for the
1096 * tarpit delay, which currently happens to be the server's connect
1097 * timeout. If unset, then set it to zero because we really want it
1098 * to expire at one moment.
1099 */
1100 if (t->flags & SN_CLTARPIT) {
1101 t->req->l = 0;
1102 /* flush the request so that we can drop the connection early
1103 * if the client closes first.
1104 */
1105 tv_delayfrom(&req->cex, &now,
Willy Tarreau830ff452006-12-17 19:31:23 +01001106 t->be->beprm->contimeout ? t->be->beprm->contimeout : 0);
Willy Tarreau2a324282006-12-05 00:05:46 +01001107 }
Willy Tarreaub8750a82006-09-03 09:56:00 +02001108
Willy Tarreau2a324282006-12-05 00:05:46 +01001109#if DEBUG_HTTP_PARSER
1110 /* example: dump each line */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001111
Willy Tarreau2a324282006-12-05 00:05:46 +01001112 fprintf(stderr, "t->flags=0x%08x\n", t->flags & (SN_CLALLOW|SN_CLDENY|SN_CLTARPIT));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001113
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001114 fprintf(stderr, "sol=%d\n", sol - req->data);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001115 sol = req->data + t->hreq.sor;
Willy Tarreau2a324282006-12-05 00:05:46 +01001116 cur_hdr = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001117
Willy Tarreau45e73e32006-12-17 00:05:15 +01001118 cur_idx = t->hreq.hdr_idx.v[0].next;
Willy Tarreau2a324282006-12-05 00:05:46 +01001119 cur_hdr = 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001120
Willy Tarreau45e73e32006-12-17 00:05:15 +01001121 while (cur_hdr < t->hreq.hdr_idx.used) {
1122 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 +01001123 fprintf(stderr, "lr=%d r=%d hdr=%d idx=%d adr=%d..%d len=%d cr=%d data:\n",
1124 req->lr - req->data, req->r - req->data,
1125 cur_hdr, cur_idx,
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001126 sol - req->data,
Willy Tarreau45e73e32006-12-17 00:05:15 +01001127 sol - req->data + t->hreq.hdr_idx.v[cur_idx].len + t->hreq.hdr_idx.v[cur_idx].cr,
1128 t->hreq.hdr_idx.v[cur_idx].len,
1129 t->hreq.hdr_idx.v[cur_idx].cr);
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001130 write(2, sol, eol - sol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001131
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001132 sol = eol;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001133 cur_idx = t->hreq.hdr_idx.v[cur_idx].next;
Willy Tarreau2a324282006-12-05 00:05:46 +01001134 cur_hdr++;
1135 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001136#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001137
Willy Tarreau06619262006-12-17 08:37:22 +01001138 goto process_data;
1139
1140 return_bad_req: /* let's centralize all bad requests */
1141 t->hreq.hdr_state = HTTP_PA_ERROR;
1142 t->logs.status = 400;
1143 client_retnclose(t, t->fe->errmsg.len400, t->fe->errmsg.msg400);
1144 return_prx_cond:
1145 if (!(t->flags & SN_ERR_MASK))
1146 t->flags |= SN_ERR_PRXCOND;
1147 if (!(t->flags & SN_FINST_MASK))
1148 t->flags |= SN_FINST_R;
1149 return 1;
1150
Willy Tarreaubaaee002006-06-26 02:48:02 +02001151 }
1152 else if (c == CL_STDATA) {
1153 process_data:
1154 /* FIXME: this error handling is partly buggy because we always report
1155 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
1156 * or HEADER phase. BTW, it's not logical to expire the client while
1157 * we're waiting for the server to connect.
1158 */
1159 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001160 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001161 tv_eternity(&req->rex);
1162 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001163 fd_delete(t->cli_fd);
1164 t->cli_state = CL_STCLOSE;
1165 if (!(t->flags & SN_ERR_MASK))
1166 t->flags |= SN_ERR_CLICL;
1167 if (!(t->flags & SN_FINST_MASK)) {
1168 if (t->pend_pos)
1169 t->flags |= SN_FINST_Q;
1170 else if (s == SV_STCONN)
1171 t->flags |= SN_FINST_C;
1172 else
1173 t->flags |= SN_FINST_D;
1174 }
1175 return 1;
1176 }
1177 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001178 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001179 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001180 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001181 shutdown(t->cli_fd, SHUT_RD);
1182 t->cli_state = CL_STSHUTR;
1183 return 1;
1184 }
1185 /* last server read and buffer empty */
1186 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001187 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001188 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001189 shutdown(t->cli_fd, SHUT_WR);
1190 /* We must ensure that the read part is still alive when switching
1191 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001192 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001193 if (t->fe->clitimeout)
1194 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001195 t->cli_state = CL_STSHUTW;
1196 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1197 return 1;
1198 }
1199 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001200 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001201 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001202 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001203 shutdown(t->cli_fd, SHUT_RD);
1204 t->cli_state = CL_STSHUTR;
1205 if (!(t->flags & SN_ERR_MASK))
1206 t->flags |= SN_ERR_CLITO;
1207 if (!(t->flags & SN_FINST_MASK)) {
1208 if (t->pend_pos)
1209 t->flags |= SN_FINST_Q;
1210 else if (s == SV_STCONN)
1211 t->flags |= SN_FINST_C;
1212 else
1213 t->flags |= SN_FINST_D;
1214 }
1215 return 1;
1216 }
1217 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001218 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001219 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001220 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001221 shutdown(t->cli_fd, SHUT_WR);
1222 /* We must ensure that the read part is still alive when switching
1223 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001224 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001225 if (t->fe->clitimeout)
1226 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001227
1228 t->cli_state = CL_STSHUTW;
1229 if (!(t->flags & SN_ERR_MASK))
1230 t->flags |= SN_ERR_CLITO;
1231 if (!(t->flags & SN_FINST_MASK)) {
1232 if (t->pend_pos)
1233 t->flags |= SN_FINST_Q;
1234 else if (s == SV_STCONN)
1235 t->flags |= SN_FINST_C;
1236 else
1237 t->flags |= SN_FINST_D;
1238 }
1239 return 1;
1240 }
1241
1242 if (req->l >= req->rlim - req->data) {
1243 /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02001244 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001245 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001246 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001247 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001248 }
1249 } else {
1250 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001251 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1252 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001253 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001254 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001255 /* If the client has no timeout, or if the server not ready yet, and we
1256 * know for sure that it can expire, then it's cleaner to disable the
1257 * timeout on the client side so that too low values cannot make the
1258 * sessions abort too early.
1259 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001260 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001261 else
Willy Tarreau73de9892006-11-30 11:40:23 +01001262 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001263 }
1264 }
1265
1266 if ((rep->l == 0) ||
1267 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001268 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1269 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001270 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001271 }
1272 } else {
1273 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001274 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1275 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001276 if (t->fe->clitimeout) {
1277 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001278 /* FIXME: to prevent the client from expiring read timeouts during writes,
1279 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001280 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001281 }
1282 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001283 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001284 }
1285 }
1286 return 0; /* other cases change nothing */
1287 }
1288 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001289 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001290 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001291 fd_delete(t->cli_fd);
1292 t->cli_state = CL_STCLOSE;
1293 if (!(t->flags & SN_ERR_MASK))
1294 t->flags |= SN_ERR_CLICL;
1295 if (!(t->flags & SN_FINST_MASK)) {
1296 if (t->pend_pos)
1297 t->flags |= SN_FINST_Q;
1298 else if (s == SV_STCONN)
1299 t->flags |= SN_FINST_C;
1300 else
1301 t->flags |= SN_FINST_D;
1302 }
1303 return 1;
1304 }
1305 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
1306 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001307 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001308 fd_delete(t->cli_fd);
1309 t->cli_state = CL_STCLOSE;
1310 return 1;
1311 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001312 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
1313 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001314 fd_delete(t->cli_fd);
1315 t->cli_state = CL_STCLOSE;
1316 if (!(t->flags & SN_ERR_MASK))
1317 t->flags |= SN_ERR_CLITO;
1318 if (!(t->flags & SN_FINST_MASK)) {
1319 if (t->pend_pos)
1320 t->flags |= SN_FINST_Q;
1321 else if (s == SV_STCONN)
1322 t->flags |= SN_FINST_C;
1323 else
1324 t->flags |= SN_FINST_D;
1325 }
1326 return 1;
1327 }
1328
1329 if (t->flags & SN_SELF_GEN) {
1330 produce_content(t);
1331 if (rep->l == 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001332 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001333 fd_delete(t->cli_fd);
1334 t->cli_state = CL_STCLOSE;
1335 return 1;
1336 }
1337 }
1338
1339 if ((rep->l == 0)
1340 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001341 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1342 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001343 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001344 }
1345 } else {
1346 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001347 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1348 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001349 if (t->fe->clitimeout) {
1350 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001351 /* FIXME: to prevent the client from expiring read timeouts during writes,
1352 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001353 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001354 }
1355 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001356 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001357 }
1358 }
1359 return 0;
1360 }
1361 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001362 if (req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001363 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001364 fd_delete(t->cli_fd);
1365 t->cli_state = CL_STCLOSE;
1366 if (!(t->flags & SN_ERR_MASK))
1367 t->flags |= SN_ERR_CLICL;
1368 if (!(t->flags & SN_FINST_MASK)) {
1369 if (t->pend_pos)
1370 t->flags |= SN_FINST_Q;
1371 else if (s == SV_STCONN)
1372 t->flags |= SN_FINST_C;
1373 else
1374 t->flags |= SN_FINST_D;
1375 }
1376 return 1;
1377 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001378 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001379 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001380 fd_delete(t->cli_fd);
1381 t->cli_state = CL_STCLOSE;
1382 return 1;
1383 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001384 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
1385 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001386 fd_delete(t->cli_fd);
1387 t->cli_state = CL_STCLOSE;
1388 if (!(t->flags & SN_ERR_MASK))
1389 t->flags |= SN_ERR_CLITO;
1390 if (!(t->flags & SN_FINST_MASK)) {
1391 if (t->pend_pos)
1392 t->flags |= SN_FINST_Q;
1393 else if (s == SV_STCONN)
1394 t->flags |= SN_FINST_C;
1395 else
1396 t->flags |= SN_FINST_D;
1397 }
1398 return 1;
1399 }
1400 else if (req->l >= req->rlim - req->data) {
1401 /* no room to read more data */
1402
1403 /* FIXME-20050705: is it possible for a client to maintain a session
1404 * after the timeout by sending more data after it receives a close ?
1405 */
1406
Willy Tarreau2a429502006-10-15 14:52:29 +02001407 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001408 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001409 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001410 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001411 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1412 }
1413 } else {
1414 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001415 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1416 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001417 if (t->fe->clitimeout)
1418 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001419 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001420 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001421 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1422 }
1423 }
1424 return 0;
1425 }
1426 else { /* CL_STCLOSE: nothing to do */
1427 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1428 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01001429 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 +02001430 write(1, trash, len);
1431 }
1432 return 0;
1433 }
1434 return 0;
1435}
1436
1437
1438/*
1439 * manages the server FSM and its socket. It returns 1 if a state has changed
1440 * (and a resync may be needed), 0 else.
1441 */
1442int process_srv(struct session *t)
1443{
1444 int s = t->srv_state;
1445 int c = t->cli_state;
1446 struct buffer *req = t->req;
1447 struct buffer *rep = t->rep;
1448 appsess *asession_temp = NULL;
1449 appsess local_asession;
1450 int conn_err;
1451
1452#ifdef DEBUG_FULL
1453 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
1454#endif
1455 //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 +02001456 //MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
1457 //MY_FD_ISSET(t->srv_fd, StaticReadEvent), MY_FD_ISSET(t->srv_fd, StaticWriteEvent)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001458 //);
1459 if (s == SV_STIDLE) {
1460 if (c == CL_STHEADERS)
1461 return 0; /* stay in idle, waiting for data to reach the client side */
1462 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
1463 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001464 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001465 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001466 if (t->pend_pos)
1467 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1468 /* note that this must not return any error because it would be able to
1469 * overwrite the client_retnclose() output.
1470 */
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001471 if (t->flags & SN_CLTARPIT)
1472 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, 0, NULL);
1473 else
1474 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C, 0, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001475
1476 return 1;
1477 }
1478 else {
Willy Tarreaub8750a82006-09-03 09:56:00 +02001479 if (t->flags & SN_CLTARPIT) {
1480 /* This connection is being tarpitted. The CLIENT side has
1481 * already set the connect expiration date to the right
1482 * timeout. We just have to check that it has not expired.
1483 */
1484 if (tv_cmp2_ms(&req->cex, &now) > 0)
1485 return 0;
1486
1487 /* We will set the queue timer to the time spent, just for
1488 * logging purposes. We fake a 500 server error, so that the
1489 * attacker will not suspect his connection has been tarpitted.
1490 * It will not cause trouble to the logs because we can exclude
1491 * the tarpitted connections by filtering on the 'PT' status flags.
1492 */
1493 tv_eternity(&req->cex);
1494 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1495 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau73de9892006-11-30 11:40:23 +01001496 500, t->fe->errmsg.len500, t->fe->errmsg.msg500);
Willy Tarreaub8750a82006-09-03 09:56:00 +02001497 return 1;
1498 }
1499
Willy Tarreaubaaee002006-06-26 02:48:02 +02001500 /* Right now, we will need to create a connection to the server.
1501 * We might already have tried, and got a connection pending, in
1502 * which case we will not do anything till it's pending. It's up
1503 * to any other session to release it and wake us up again.
1504 */
1505 if (t->pend_pos) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001506 if (tv_cmp2_ms(&req->cex, &now) > 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001507 return 0;
1508 else {
1509 /* we've been waiting too long here */
Willy Tarreaud7971282006-07-29 18:36:34 +02001510 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001511 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1512 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau73de9892006-11-30 11:40:23 +01001513 503, t->fe->errmsg.len503, t->fe->errmsg.msg503);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001514 if (t->srv)
1515 t->srv->failed_conns++;
Willy Tarreau73de9892006-11-30 11:40:23 +01001516 t->fe->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001517 return 1;
1518 }
1519 }
1520
1521 do {
1522 /* first, get a connection */
1523 if (srv_redispatch_connect(t))
1524 return t->srv_state != SV_STIDLE;
1525
1526 /* try to (re-)connect to the server, and fail if we expire the
1527 * number of retries.
1528 */
1529 if (srv_retryable_connect(t)) {
1530 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1531 return t->srv_state != SV_STIDLE;
1532 }
1533
1534 } while (1);
1535 }
1536 }
1537 else if (s == SV_STCONN) { /* connection in progress */
1538 if (c == CL_STCLOSE || c == CL_STSHUTW ||
1539 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001540 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001541 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001542 fd_delete(t->srv_fd);
1543 if (t->srv)
1544 t->srv->cur_sess--;
1545
1546 /* note that this must not return any error because it would be able to
1547 * overwrite the client_retnclose() output.
1548 */
1549 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, 0, NULL);
1550 return 1;
1551 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001552 if (!(req->flags & BF_WRITE_STATUS) && tv_cmp2_ms(&req->cex, &now) > 0) {
1553 //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 +02001554 return 0; /* nothing changed */
1555 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001556 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001557 /* timeout, asynchronous connect error or first write error */
1558 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
1559
1560 fd_delete(t->srv_fd);
1561 if (t->srv)
1562 t->srv->cur_sess--;
1563
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001564 if (!(req->flags & BF_WRITE_STATUS))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001565 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
1566 else
1567 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
1568
1569 /* ensure that we have enough retries left */
1570 if (srv_count_retry_down(t, conn_err))
1571 return 1;
1572
Willy Tarreau830ff452006-12-17 19:31:23 +01001573 if (t->srv && t->conn_retries == 0 && t->be->beprm->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001574 /* We're on our last chance, and the REDISP option was specified.
1575 * We will ignore cookie and force to balance or use the dispatcher.
1576 */
1577 /* let's try to offer this slot to anybody */
Willy Tarreau830ff452006-12-17 19:31:23 +01001578 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001579 task_wakeup(&rq, t->srv->queue_mgt);
1580
1581 if (t->srv)
1582 t->srv->failed_conns++;
Willy Tarreau830ff452006-12-17 19:31:23 +01001583 t->be->beprm->failed_conns++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001584
1585 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
1586 t->srv = NULL; /* it's left to the dispatcher to choose a server */
1587 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
1588 t->flags &= ~SN_CK_MASK;
1589 t->flags |= SN_CK_DOWN;
1590 }
1591
1592 /* first, get a connection */
1593 if (srv_redispatch_connect(t))
1594 return t->srv_state != SV_STIDLE;
1595 }
1596
Willy Tarreaubaaee002006-06-26 02:48:02 +02001597 do {
1598 /* Now we will try to either reconnect to the same server or
1599 * connect to another server. If the connection gets queued
1600 * because all servers are saturated, then we will go back to
1601 * the SV_STIDLE state.
1602 */
1603 if (srv_retryable_connect(t)) {
1604 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1605 return t->srv_state != SV_STCONN;
1606 }
1607
1608 /* we need to redispatch the connection to another server */
1609 if (srv_redispatch_connect(t))
1610 return t->srv_state != SV_STCONN;
1611 } while (1);
1612 }
1613 else { /* no error or write 0 */
1614 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
1615
1616 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
1617 if (req->l == 0) /* nothing to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02001618 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001619 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001620 } else /* need the right to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02001621 MY_FD_SET(t->srv_fd, StaticWriteEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001622 if (t->be->beprm->srvtimeout) {
1623 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001624 /* FIXME: to prevent the server from expiring read timeouts during writes,
1625 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001626 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001627 }
1628 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001629 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001630 }
1631
Willy Tarreau830ff452006-12-17 19:31:23 +01001632 if (t->be->beprm->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreau2a429502006-10-15 14:52:29 +02001633 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001634 if (t->be->beprm->srvtimeout)
1635 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001636 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001637 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001638
1639 t->srv_state = SV_STDATA;
1640 if (t->srv)
1641 t->srv->cum_sess++;
1642 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
1643
1644 /* if the user wants to log as soon as possible, without counting
1645 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001646 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001647 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
1648 sess_log(t);
1649 }
1650 }
1651 else {
1652 t->srv_state = SV_STHEADERS;
1653 if (t->srv)
1654 t->srv->cum_sess++;
1655 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
1656 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001657 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001658 return 1;
1659 }
1660 }
1661 else if (s == SV_STHEADERS) { /* receiving server headers */
1662 /* now parse the partial (or complete) headers */
1663 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
1664 char *ptr;
1665 int delete_header;
1666
1667 ptr = rep->lr;
1668
1669 /* look for the end of the current header */
1670 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
1671 ptr++;
1672
1673 if (ptr == rep->h) {
1674 int line, len;
1675
1676 /* we can only get here after an end of headers */
1677
1678 /* first, we'll block if security checks have caught nasty things */
1679 if (t->flags & SN_CACHEABLE) {
1680 if ((t->flags & SN_CACHE_COOK) &&
1681 (t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001682 (t->be->beprm->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001683
1684 /* we're in presence of a cacheable response containing
1685 * a set-cookie header. We'll block it as requested by
1686 * the 'checkcache' option, and send an alert.
1687 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001688 tv_eternity(&rep->rex);
1689 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001690 fd_delete(t->srv_fd);
1691 if (t->srv) {
1692 t->srv->cur_sess--;
1693 t->srv->failed_secu++;
1694 }
Willy Tarreau73de9892006-11-30 11:40:23 +01001695 t->be->failed_secu++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001696 t->srv_state = SV_STCLOSE;
1697 t->logs.status = 502;
Willy Tarreau73de9892006-11-30 11:40:23 +01001698 client_return(t, t->fe->errmsg.len502, t->fe->errmsg.msg502);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001699 if (!(t->flags & SN_ERR_MASK))
1700 t->flags |= SN_ERR_PRXCOND;
1701 if (!(t->flags & SN_FINST_MASK))
1702 t->flags |= SN_FINST_H;
1703
Willy Tarreau830ff452006-12-17 19:31:23 +01001704 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->be->beprm->id, t->srv->id);
1705 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 +02001706
1707 /* We used to have a free connection slot. Since we'll never use it,
1708 * we have to inform the server that it may be used by another session.
1709 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001710 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001711 task_wakeup(&rq, t->srv->queue_mgt);
1712
1713 return 1;
1714 }
1715 }
1716
1717 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
1718 if (t->flags & SN_SVDENY) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001719 tv_eternity(&rep->rex);
1720 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001721 fd_delete(t->srv_fd);
1722 if (t->srv) {
1723 t->srv->cur_sess--;
1724 t->srv->failed_secu++;
1725 }
Willy Tarreau73de9892006-11-30 11:40:23 +01001726 t->be->failed_secu++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001727 t->srv_state = SV_STCLOSE;
1728 t->logs.status = 502;
Willy Tarreau73de9892006-11-30 11:40:23 +01001729 client_return(t, t->fe->errmsg.len502, t->fe->errmsg.msg502);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001730 if (!(t->flags & SN_ERR_MASK))
1731 t->flags |= SN_ERR_PRXCOND;
1732 if (!(t->flags & SN_FINST_MASK))
1733 t->flags |= SN_FINST_H;
1734 /* We used to have a free connection slot. Since we'll never use it,
1735 * we have to inform the server that it may be used by another session.
1736 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001737 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001738 task_wakeup(&rq, t->srv->queue_mgt);
1739
1740 return 1;
1741 }
1742
1743 /* we'll have something else to do here : add new headers ... */
1744
Willy Tarreau830ff452006-12-17 19:31:23 +01001745 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_INS) &&
1746 (!(t->be->beprm->options & PR_O_COOK_POST) || (t->hreq.meth == HTTP_METH_POST))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001747 /* the server is known, it's not the one the client requested, we have to
1748 * insert a set-cookie here, except if we want to insert only on POST
1749 * requests and this one isn't. Note that servers which don't have cookies
1750 * (eg: some backup servers) will return a full cookie removal request.
1751 */
1752 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
Willy Tarreau830ff452006-12-17 19:31:23 +01001753 t->be->beprm->cookie_name,
Willy Tarreaubaaee002006-06-26 02:48:02 +02001754 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
1755
1756 t->flags |= SN_SCK_INSERTED;
1757
1758 /* Here, we will tell an eventual cache on the client side that we don't
1759 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
1760 * Some caches understand the correct form: 'no-cache="set-cookie"', but
1761 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
1762 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001763 if (t->be->beprm->options & PR_O_COOK_NOC)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001764 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
1765 len += sprintf(trash + len, "Cache-control: private\r\n");
1766
1767 if (rep->data + rep->l < rep->h)
1768 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
1769 *(int *)0 = 0;
1770 buffer_replace2(rep, rep->h, rep->h, trash, len);
1771 }
1772
1773 /* headers to be added */
Willy Tarreau830ff452006-12-17 19:31:23 +01001774 /* FIXME: we should add headers from BE then from FE */
1775 for (line = 0; line < t->be->fiprm->nb_rspadd; line++) {
1776 len = sprintf(trash, "%s\r\n", t->be->fiprm->rsp_add[line]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001777 buffer_replace2(rep, rep->h, rep->h, trash, len);
1778 }
1779
1780 /* add a "connection: close" line if needed */
Willy Tarreau73de9892006-11-30 11:40:23 +01001781 if (t->fe->options & PR_O_HTTP_CLOSE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001782 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
1783
1784 t->srv_state = SV_STDATA;
1785 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
1786 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
1787
1788 /* client connection already closed or option 'httpclose' required :
1789 * we close the server's outgoing connection right now.
1790 */
1791 if ((req->l == 0) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001792 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->beprm->options & PR_O_FORCE_CLO)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001793 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001794 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001795
1796 /* We must ensure that the read part is still alive when switching
1797 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001798 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001799 if (t->be->beprm->srvtimeout)
1800 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001801
1802 shutdown(t->srv_fd, SHUT_WR);
1803 t->srv_state = SV_STSHUTW;
1804 }
1805
1806 /* if the user wants to log as soon as possible, without counting
1807 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001808 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001809 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
1810 t->logs.bytes = rep->h - rep->data;
1811 sess_log(t);
1812 }
1813 break;
1814 }
1815
1816 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1817 if (ptr > rep->r - 2) {
1818 /* this is a partial header, let's wait for more to come */
1819 rep->lr = ptr;
1820 break;
1821 }
1822
1823 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
1824 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
1825
1826 /* now we know that *ptr is either \r or \n,
1827 * and that there are at least 1 char after it.
1828 */
1829 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
1830 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
1831 else
1832 rep->lr = ptr + 2; /* \r\n or \n\r */
1833
1834 /*
1835 * now we know that we have a full header ; we can do whatever
1836 * we want with these pointers :
1837 * rep->h = beginning of header
1838 * ptr = end of header (first \r or \n)
1839 * rep->lr = beginning of next line (next rep->h)
1840 * rep->r = end of data (not used at this stage)
1841 */
1842
1843
1844 if (t->logs.status == -1) {
1845 t->logs.logwait &= ~LW_RESP;
1846 t->logs.status = atoi(rep->h + 9);
1847 switch (t->logs.status) {
1848 case 200:
1849 case 203:
1850 case 206:
1851 case 300:
1852 case 301:
1853 case 410:
1854 /* RFC2616 @13.4:
1855 * "A response received with a status code of
1856 * 200, 203, 206, 300, 301 or 410 MAY be stored
1857 * by a cache (...) unless a cache-control
1858 * directive prohibits caching."
1859 *
1860 * RFC2616 @9.5: POST method :
1861 * "Responses to this method are not cacheable,
1862 * unless the response includes appropriate
1863 * Cache-Control or Expires header fields."
1864 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001865 if (!(t->hreq.meth == HTTP_METH_POST) && (t->be->beprm->options & PR_O_CHK_CACHE))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001866 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
1867 break;
1868 default:
1869 break;
1870 }
1871 }
1872 else if (t->logs.logwait & LW_RSPHDR) {
1873 struct cap_hdr *h;
1874 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01001875 for (h = t->fe->fiprm->rsp_cap; h; h = h->next) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001876 if ((h->namelen + 2 <= ptr - rep->h) &&
1877 (rep->h[h->namelen] == ':') &&
1878 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
1879
1880 if (t->rsp_cap[h->index] == NULL)
1881 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
1882
1883 len = ptr - (rep->h + h->namelen + 2);
1884 if (len > h->len)
1885 len = h->len;
1886
1887 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
1888 t->rsp_cap[h->index][len]=0;
1889 }
1890 }
1891
1892 }
1893
1894 delete_header = 0;
1895
Willy Tarreau58f10d72006-12-04 02:26:12 +01001896 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
1897 debug_hdr("srvhdr", t, rep->h, ptr);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001898
1899 /* remove "connection: " if needed */
Willy Tarreau73de9892006-11-30 11:40:23 +01001900 if (!delete_header && (t->fe->options & PR_O_HTTP_CLOSE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001901 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
1902 delete_header = 1;
1903 }
1904
1905 /* try headers regexps */
Willy Tarreau830ff452006-12-17 19:31:23 +01001906 if (!delete_header && t->be->fiprm->rsp_exp != NULL
Willy Tarreaubaaee002006-06-26 02:48:02 +02001907 && !(t->flags & SN_SVDENY)) {
1908 struct hdr_exp *exp;
1909 char term;
1910
1911 term = *ptr;
1912 *ptr = '\0';
Willy Tarreau830ff452006-12-17 19:31:23 +01001913 exp = t->be->fiprm->rsp_exp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001914 do {
1915 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
1916 switch (exp->action) {
1917 case ACT_ALLOW:
1918 if (!(t->flags & SN_SVDENY))
1919 t->flags |= SN_SVALLOW;
1920 break;
1921 case ACT_REPLACE:
1922 if (!(t->flags & SN_SVDENY)) {
1923 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
1924 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
1925 }
1926 break;
1927 case ACT_REMOVE:
1928 if (!(t->flags & SN_SVDENY))
1929 delete_header = 1;
1930 break;
1931 case ACT_DENY:
1932 if (!(t->flags & SN_SVALLOW))
1933 t->flags |= SN_SVDENY;
1934 break;
1935 case ACT_PASS: /* we simply don't deny this one */
1936 break;
1937 }
1938 break;
1939 }
1940 } while ((exp = exp->next) != NULL);
1941 *ptr = term; /* restore the string terminator */
1942 }
1943
1944 /* check for cache-control: or pragma: headers */
1945 if (!delete_header && (t->flags & SN_CACHEABLE)) {
1946 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
1947 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1948 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
1949 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
1950 if (rep->h + 23 == ptr || rep->h[23] == ',')
1951 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1952 else {
1953 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
1954 && (rep->h[35] == '"' || rep->h[35] == ','))
1955 t->flags &= ~SN_CACHE_COOK;
1956 }
1957 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
1958 (rep->h + 22 == ptr || rep->h[22] == ','))
1959 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
1960 (rep->h + 23 == ptr || rep->h[23] == ','))) {
1961 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1962 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
1963 (rep->h + 24 == ptr || rep->h[24] == ',')) {
1964 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1965 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
1966 (rep->h + 25 == ptr || rep->h[25] == ',')) {
1967 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1968 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
1969 (rep->h + 21 == ptr || rep->h[21] == ',')) {
1970 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
1971 }
1972 }
1973 }
1974
1975 /* check for server cookies */
1976 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
Willy Tarreau830ff452006-12-17 19:31:23 +01001977 && (t->be->beprm->cookie_name != NULL ||
1978 t->be->fiprm->capture_name != NULL ||
1979 t->be->beprm->appsession_name !=NULL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001980 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
1981 char *p1, *p2, *p3, *p4;
1982
1983 t->flags |= SN_SCK_ANY;
1984
1985 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
1986
1987 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
1988 while (p1 < ptr && (isspace((int)*p1)))
1989 p1++;
1990
1991 if (p1 == ptr || *p1 == ';') /* end of cookie */
1992 break;
1993
1994 /* p1 is at the beginning of the cookie name */
1995 p2 = p1;
1996
1997 while (p2 < ptr && *p2 != '=' && *p2 != ';')
1998 p2++;
1999
2000 if (p2 == ptr || *p2 == ';') /* next cookie */
2001 break;
2002
2003 p3 = p2 + 1; /* skips the '=' sign */
2004 if (p3 == ptr)
2005 break;
2006
2007 p4 = p3;
2008 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
2009 p4++;
2010
2011 /* here, we have the cookie name between p1 and p2,
2012 * and its value between p3 and p4.
2013 * we can process it.
2014 */
2015
2016 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01002017 if (t->be->fiprm->capture_name != NULL &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002018 t->logs.srv_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002019 (p4 - p1 >= t->be->fiprm->capture_namelen) &&
2020 memcmp(p1, t->be->fiprm->capture_name, t->be->fiprm->capture_namelen) == 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002021 int log_len = p4 - p1;
2022
2023 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
2024 Alert("HTTP logging : out of memory.\n");
2025 }
2026
Willy Tarreau830ff452006-12-17 19:31:23 +01002027 if (log_len > t->be->fiprm->capture_len)
2028 log_len = t->be->fiprm->capture_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002029 memcpy(t->logs.srv_cookie, p1, log_len);
2030 t->logs.srv_cookie[log_len] = 0;
2031 }
2032
Willy Tarreau830ff452006-12-17 19:31:23 +01002033 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
2034 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002035 /* Cool... it's the right one */
2036 t->flags |= SN_SCK_SEEN;
2037
2038 /* If the cookie is in insert mode on a known server, we'll delete
2039 * this occurrence because we'll insert another one later.
2040 * We'll delete it too if the "indirect" option is set and we're in
2041 * a direct access. */
Willy Tarreau830ff452006-12-17 19:31:23 +01002042 if (((t->srv) && (t->be->beprm->options & PR_O_COOK_INS)) ||
2043 ((t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_IND))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002044 /* this header must be deleted */
2045 delete_header = 1;
2046 t->flags |= SN_SCK_DELETED;
2047 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002048 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_RW)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002049 /* replace bytes p3->p4 with the cookie name associated
2050 * with this server since we know it.
2051 */
2052 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2053 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2054 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002055 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_PFX)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002056 /* insert the cookie name associated with this server
2057 * before existing cookie, and insert a delimitor between them..
2058 */
2059 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
2060 p3[t->srv->cklen] = COOKIE_DELIM;
2061 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2062 }
2063 break;
2064 }
2065
2066 /* first, let's see if the cookie is our appcookie*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002067 if ((t->be->beprm->appsession_name != NULL) &&
2068 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002069
2070 /* Cool... it's the right one */
2071
2072 size_t server_id_len = strlen(t->srv->id) + 1;
2073 asession_temp = &local_asession;
2074
2075 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
2076 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002077 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002078 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002079 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
2080 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002081 asession_temp->serverid = NULL;
2082
2083 /* only do insert, if lookup fails */
Willy Tarreau73de9892006-11-30 11:40:23 +01002084 if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002085 if ((asession_temp = pool_alloc(appsess)) == NULL) {
2086 Alert("Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002087 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002088 return 0;
2089 }
2090 asession_temp->sessid = local_asession.sessid;
2091 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01002092 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002093 }/* end if (chtbl_lookup()) */
2094 else {
2095 /* free wasted memory */
2096 pool_free_to(apools.sessid, local_asession.sessid);
2097 } /* end else from if (chtbl_lookup()) */
2098
2099 if (asession_temp->serverid == NULL) {
2100 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
2101 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002102 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002103 }
2104 asession_temp->serverid[0] = '\0';
2105 }
2106
2107 if (asession_temp->serverid[0] == '\0')
2108 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
2109
Willy Tarreau830ff452006-12-17 19:31:23 +01002110 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002111
2112#if defined(DEBUG_HASH)
Willy Tarreau830ff452006-12-17 19:31:23 +01002113 print_table(&(t->be->beprm->htbl_proxy));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002114#endif
2115 break;
2116 }/* end if ((t->proxy->appsession_name != NULL) ... */
2117 else {
2118 // fprintf(stderr,"Ignoring unknown cookie : ");
2119 // write(2, p1, p2-p1);
2120 // fprintf(stderr," = ");
2121 // write(2, p3, p4-p3);
2122 // fprintf(stderr,"\n");
2123 }
2124 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2125 } /* we're now at the end of the cookie value */
2126 } /* end of cookie processing */
2127
2128 /* check for any set-cookie in case we check for cacheability */
2129 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002130 (t->be->beprm->options & PR_O_CHK_CACHE) &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002131 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2132 t->flags |= SN_SCK_ANY;
2133 }
2134
2135 /* let's look if we have to delete this header */
2136 if (delete_header && !(t->flags & SN_SVDENY))
2137 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2138
2139 rep->h = rep->lr;
2140 } /* while (rep->lr < rep->r) */
2141
2142 /* end of header processing (even if incomplete) */
2143
Willy Tarreau2a429502006-10-15 14:52:29 +02002144 if ((rep->l < rep->rlim - rep->data) && ! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002145 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
Willy Tarreaud7971282006-07-29 18:36:34 +02002146 * full. We cannot loop here since stream_sock_read will disable it only if
Willy Tarreaubaaee002006-06-26 02:48:02 +02002147 * rep->l == rlim-data
2148 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002149 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002150 if (t->be->beprm->srvtimeout)
2151 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002152 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002153 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002154 }
2155
2156 /* read error, write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002157 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002158 tv_eternity(&rep->rex);
2159 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002160 fd_delete(t->srv_fd);
2161 if (t->srv) {
2162 t->srv->cur_sess--;
2163 t->srv->failed_resp++;
2164 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002165 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002166
2167 t->srv_state = SV_STCLOSE;
2168 t->logs.status = 502;
Willy Tarreau73de9892006-11-30 11:40:23 +01002169 client_return(t, t->fe->errmsg.len502, t->fe->errmsg.msg502);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002170 if (!(t->flags & SN_ERR_MASK))
2171 t->flags |= SN_ERR_SRVCL;
2172 if (!(t->flags & SN_FINST_MASK))
2173 t->flags |= SN_FINST_H;
2174 /* We used to have a free connection slot. Since we'll never use it,
2175 * we have to inform the server that it may be used by another session.
2176 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002177 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002178 task_wakeup(&rq, t->srv->queue_mgt);
2179
2180 return 1;
2181 }
2182 /* end of client write or end of server read.
2183 * since we are in header mode, if there's no space left for headers, we
2184 * won't be able to free more later, so the session will never terminate.
2185 */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002186 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 +02002187 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002188 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002189 shutdown(t->srv_fd, SHUT_RD);
2190 t->srv_state = SV_STSHUTR;
2191 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2192 return 1;
2193 }
2194 /* read timeout : return a 504 to the client.
2195 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002196 else if (MY_FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002197 tv_eternity(&rep->rex);
2198 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002199 fd_delete(t->srv_fd);
2200 if (t->srv) {
2201 t->srv->cur_sess--;
2202 t->srv->failed_resp++;
2203 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002204 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002205 t->srv_state = SV_STCLOSE;
2206 t->logs.status = 504;
Willy Tarreau73de9892006-11-30 11:40:23 +01002207 client_return(t, t->fe->errmsg.len504, t->fe->errmsg.msg504);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002208 if (!(t->flags & SN_ERR_MASK))
2209 t->flags |= SN_ERR_SRVTO;
2210 if (!(t->flags & SN_FINST_MASK))
2211 t->flags |= SN_FINST_H;
2212 /* We used to have a free connection slot. Since we'll never use it,
2213 * we have to inform the server that it may be used by another session.
2214 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002215 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002216 task_wakeup(&rq, t->srv->queue_mgt);
2217
2218 return 1;
2219 }
2220 /* last client read and buffer empty */
2221 /* FIXME!!! here, we don't want to switch to SHUTW if the
2222 * client shuts read too early, because we may still have
2223 * some work to do on the headers.
2224 * The side-effect is that if the client completely closes its
2225 * connection during SV_STHEADER, the connection to the server
2226 * is kept until a response comes back or the timeout is reached.
2227 */
2228 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002229 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002230 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002231
2232 /* We must ensure that the read part is still alive when switching
2233 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002234 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002235 if (t->be->beprm->srvtimeout)
2236 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002237
2238 shutdown(t->srv_fd, SHUT_WR);
2239 t->srv_state = SV_STSHUTW;
2240 return 1;
2241 }
2242 /* write timeout */
2243 /* FIXME!!! here, we don't want to switch to SHUTW if the
2244 * client shuts read too early, because we may still have
2245 * some work to do on the headers.
2246 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002247 else if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&req->wex, &now) <= 0) {
2248 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002249 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002250 shutdown(t->srv_fd, SHUT_WR);
2251 /* We must ensure that the read part is still alive when switching
2252 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002253 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002254 if (t->be->beprm->srvtimeout)
2255 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002256
2257 /* We must ensure that the read part is still alive when switching
2258 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002259 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002260 if (t->be->beprm->srvtimeout)
2261 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002262
2263 t->srv_state = SV_STSHUTW;
2264 if (!(t->flags & SN_ERR_MASK))
2265 t->flags |= SN_ERR_SRVTO;
2266 if (!(t->flags & SN_FINST_MASK))
2267 t->flags |= SN_FINST_H;
2268 return 1;
2269 }
2270
2271 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002272 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2273 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002274 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002275 }
2276 }
2277 else { /* client buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002278 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2279 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002280 if (t->be->beprm->srvtimeout) {
2281 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002282 /* FIXME: to prevent the server from expiring read timeouts during writes,
2283 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002284 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002285 }
2286 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002287 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002288 }
2289 }
2290
2291 /* be nice with the client side which would like to send a complete header
2292 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2293 * would read all remaining data at once ! The client should not write past rep->lr
2294 * when the server is in header state.
2295 */
2296 //return header_processed;
2297 return t->srv_state != SV_STHEADERS;
2298 }
2299 else if (s == SV_STDATA) {
2300 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002301 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002302 tv_eternity(&rep->rex);
2303 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002304 fd_delete(t->srv_fd);
2305 if (t->srv) {
2306 t->srv->cur_sess--;
2307 t->srv->failed_resp++;
2308 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002309 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002310 t->srv_state = SV_STCLOSE;
2311 if (!(t->flags & SN_ERR_MASK))
2312 t->flags |= SN_ERR_SRVCL;
2313 if (!(t->flags & SN_FINST_MASK))
2314 t->flags |= SN_FINST_D;
2315 /* We used to have a free connection slot. Since we'll never use it,
2316 * we have to inform the server that it may be used by another session.
2317 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002318 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002319 task_wakeup(&rq, t->srv->queue_mgt);
2320
2321 return 1;
2322 }
2323 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002324 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002325 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002326 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002327 shutdown(t->srv_fd, SHUT_RD);
2328 t->srv_state = SV_STSHUTR;
2329 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2330 return 1;
2331 }
2332 /* end of client read and no more data to send */
2333 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002334 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002335 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002336 shutdown(t->srv_fd, SHUT_WR);
2337 /* We must ensure that the read part is still alive when switching
2338 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002339 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002340 if (t->be->beprm->srvtimeout)
2341 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002342
2343 t->srv_state = SV_STSHUTW;
2344 return 1;
2345 }
2346 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002347 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002348 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002349 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002350 shutdown(t->srv_fd, SHUT_RD);
2351 t->srv_state = SV_STSHUTR;
2352 if (!(t->flags & SN_ERR_MASK))
2353 t->flags |= SN_ERR_SRVTO;
2354 if (!(t->flags & SN_FINST_MASK))
2355 t->flags |= SN_FINST_D;
2356 return 1;
2357 }
2358 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002359 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002360 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002361 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002362 shutdown(t->srv_fd, SHUT_WR);
2363 /* We must ensure that the read part is still alive when switching
2364 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002365 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002366 if (t->be->beprm->srvtimeout)
2367 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002368 t->srv_state = SV_STSHUTW;
2369 if (!(t->flags & SN_ERR_MASK))
2370 t->flags |= SN_ERR_SRVTO;
2371 if (!(t->flags & SN_FINST_MASK))
2372 t->flags |= SN_FINST_D;
2373 return 1;
2374 }
2375
2376 /* recompute request time-outs */
2377 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002378 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2379 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002380 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002381 }
2382 }
2383 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau2a429502006-10-15 14:52:29 +02002384 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2385 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002386 if (t->be->beprm->srvtimeout) {
2387 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002388 /* FIXME: to prevent the server from expiring read timeouts during writes,
2389 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002390 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002391 }
2392 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002393 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002394 }
2395 }
2396
2397 /* recompute response time-outs */
2398 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002399 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2400 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002401 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002402 }
2403 }
2404 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002405 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2406 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002407 if (t->be->beprm->srvtimeout)
2408 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002409 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002410 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002411 }
2412 }
2413
2414 return 0; /* other cases change nothing */
2415 }
2416 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002417 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002418 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002419 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002420 fd_delete(t->srv_fd);
2421 if (t->srv) {
2422 t->srv->cur_sess--;
2423 t->srv->failed_resp++;
2424 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002425 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002426 //close(t->srv_fd);
2427 t->srv_state = SV_STCLOSE;
2428 if (!(t->flags & SN_ERR_MASK))
2429 t->flags |= SN_ERR_SRVCL;
2430 if (!(t->flags & SN_FINST_MASK))
2431 t->flags |= SN_FINST_D;
2432 /* We used to have a free connection slot. Since we'll never use it,
2433 * we have to inform the server that it may be used by another session.
2434 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002435 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002436 task_wakeup(&rq, t->srv->queue_mgt);
2437
2438 return 1;
2439 }
2440 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002441 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002442 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002443 fd_delete(t->srv_fd);
2444 if (t->srv)
2445 t->srv->cur_sess--;
2446 //close(t->srv_fd);
2447 t->srv_state = SV_STCLOSE;
2448 /* We used to have a free connection slot. Since we'll never use it,
2449 * we have to inform the server that it may be used by another session.
2450 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002451 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002452 task_wakeup(&rq, t->srv->queue_mgt);
2453
2454 return 1;
2455 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002456 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002457 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002458 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002459 fd_delete(t->srv_fd);
2460 if (t->srv)
2461 t->srv->cur_sess--;
2462 //close(t->srv_fd);
2463 t->srv_state = SV_STCLOSE;
2464 if (!(t->flags & SN_ERR_MASK))
2465 t->flags |= SN_ERR_SRVTO;
2466 if (!(t->flags & SN_FINST_MASK))
2467 t->flags |= SN_FINST_D;
2468 /* We used to have a free connection slot. Since we'll never use it,
2469 * we have to inform the server that it may be used by another session.
2470 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002471 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002472 task_wakeup(&rq, t->srv->queue_mgt);
2473
2474 return 1;
2475 }
2476 else if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002477 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2478 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002479 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002480 }
2481 }
2482 else { /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002483 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2484 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002485 if (t->be->beprm->srvtimeout) {
2486 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002487 /* FIXME: to prevent the server from expiring read timeouts during writes,
2488 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002489 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002490 }
2491 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002492 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002493 }
2494 }
2495 return 0;
2496 }
2497 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002498 if (rep->flags & BF_READ_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002499 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002500 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002501 fd_delete(t->srv_fd);
2502 if (t->srv) {
2503 t->srv->cur_sess--;
2504 t->srv->failed_resp++;
2505 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002506 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002507 //close(t->srv_fd);
2508 t->srv_state = SV_STCLOSE;
2509 if (!(t->flags & SN_ERR_MASK))
2510 t->flags |= SN_ERR_SRVCL;
2511 if (!(t->flags & SN_FINST_MASK))
2512 t->flags |= SN_FINST_D;
2513 /* We used to have a free connection slot. Since we'll never use it,
2514 * we have to inform the server that it may be used by another session.
2515 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002516 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002517 task_wakeup(&rq, t->srv->queue_mgt);
2518
2519 return 1;
2520 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002521 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002522 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002523 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002524 fd_delete(t->srv_fd);
2525 if (t->srv)
2526 t->srv->cur_sess--;
2527 //close(t->srv_fd);
2528 t->srv_state = SV_STCLOSE;
2529 /* We used to have a free connection slot. Since we'll never use it,
2530 * we have to inform the server that it may be used by another session.
2531 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002532 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002533 task_wakeup(&rq, t->srv->queue_mgt);
2534
2535 return 1;
2536 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002537 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002538 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002539 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002540 fd_delete(t->srv_fd);
2541 if (t->srv)
2542 t->srv->cur_sess--;
2543 //close(t->srv_fd);
2544 t->srv_state = SV_STCLOSE;
2545 if (!(t->flags & SN_ERR_MASK))
2546 t->flags |= SN_ERR_SRVTO;
2547 if (!(t->flags & SN_FINST_MASK))
2548 t->flags |= SN_FINST_D;
2549 /* We used to have a free connection slot. Since we'll never use it,
2550 * we have to inform the server that it may be used by another session.
2551 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002552 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002553 task_wakeup(&rq, t->srv->queue_mgt);
2554
2555 return 1;
2556 }
2557 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002558 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2559 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002560 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002561 }
2562 }
2563 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002564 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2565 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002566 if (t->be->beprm->srvtimeout)
2567 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002568 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002569 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002570 }
2571 }
2572 return 0;
2573 }
2574 else { /* SV_STCLOSE : nothing to do */
2575 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2576 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01002577 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 +02002578 write(1, trash, len);
2579 }
2580 return 0;
2581 }
2582 return 0;
2583}
2584
2585
2586/*
2587 * Produces data for the session <s> depending on its source. Expects to be
2588 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
2589 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
2590 * session, which it uses to keep on being called when there is free space in
2591 * the buffer, of simply by letting an empty buffer upon return. It returns 1
2592 * if it changes the session state from CL_STSHUTR, otherwise 0.
2593 */
2594int produce_content(struct session *s)
2595{
2596 struct buffer *rep = s->rep;
2597 struct proxy *px;
2598 struct server *sv;
2599 int msglen;
2600
2601 if (s->data_source == DATA_SRC_NONE) {
2602 s->flags &= ~SN_SELF_GEN;
2603 return 1;
2604 }
2605 else if (s->data_source == DATA_SRC_STATS) {
2606 msglen = 0;
2607
2608 if (s->data_state == DATA_ST_INIT) { /* the function had not been called yet */
2609 unsigned int up;
2610
2611 s->flags |= SN_SELF_GEN; // more data will follow
2612
2613 /* send the start of the HTTP response */
2614 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2615 "HTTP/1.0 200 OK\r\n"
2616 "Cache-Control: no-cache\r\n"
2617 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +02002618 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +02002619 "\r\n\r\n");
2620
2621 s->logs.status = 200;
2622 client_retnclose(s, msglen, trash); // send the start of the response.
2623 msglen = 0;
2624
2625 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
2626 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
2627 if (!(s->flags & SN_FINST_MASK))
2628 s->flags |= SN_FINST_R;
2629
2630 /* WARNING! This must fit in the first buffer !!! */
2631 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2632 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
2633 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
2634 "<style type=\"text/css\"><!--\n"
2635 "body {"
2636 " font-family: helvetica, arial;"
2637 " font-size: 12px;"
2638 " font-weight: normal;"
2639 " color: black;"
2640 " background: white;"
2641 "}\n"
2642 "td {"
2643 " font-size: 12px;"
2644 " align: center;"
2645 "}\n"
2646 "h1 {"
2647 " font-size: xx-large;"
2648 " margin-bottom: 0.5em;"
2649 "}\n"
2650 "h2 {"
2651 " font-family: helvetica, arial;"
2652 " font-size: x-large;"
2653 " font-weight: bold;"
2654 " font-style: italic;"
2655 " color: #6020a0;"
2656 " margin-top: 0em;"
2657 " margin-bottom: 0em;"
2658 "}\n"
2659 "h3 {"
2660 " font-family: helvetica, arial;"
2661 " font-size: 16px;"
2662 " font-weight: bold;"
2663 " color: #b00040;"
2664 " background: #e8e8d0;"
2665 " margin-top: 0em;"
2666 " margin-bottom: 0em;"
2667 "}\n"
2668 "li {"
2669 " margin-top: 0.25em;"
2670 " margin-right: 2em;"
2671 "}\n"
2672 ".hr {"
2673 " margin-top: 0.25em;"
2674 " border-color: black;"
2675 " border-bottom-style: solid;"
2676 "}\n"
2677 "table.tbl { border-collapse: collapse; border-width: 1px; border-style: solid; border-color: gray;}\n"
2678 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; border-color: gray; }\n"
2679 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray; }\n"
2680 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
2681 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
2682 "-->"
2683 "</style></head>");
2684
2685 if (buffer_write(rep, trash, msglen) != 0)
2686 return 0;
2687 msglen = 0;
2688
2689 up = (now.tv_sec - start_date.tv_sec);
2690
2691 /* WARNING! this has to fit the first packet too */
2692 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2693 "<body><h1>" PRODUCT_NAME "</h1>\n"
2694 "<h2>Statistics Report for pid %d</h2>\n"
2695 "<hr width=\"100%%\" class=\"hr\">\n"
2696 "<h3>&gt; General process information</h3>\n"
2697 "<table border=0><tr><td align=\"left\">\n"
2698 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
2699 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
2700 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
2701 "<b>maxsock = </b> %d<br>\n"
2702 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
2703 "</td><td width=\"10%%\">\n"
2704 "</td><td align=\"right\">\n"
2705 "<table class=\"lgd\">"
2706 "<tr><td bgcolor=\"#C0FFC0\">&nbsp;</td><td style=\"border-style: none;\">active UP </td>"
2707 "<td bgcolor=\"#B0D0FF\">&nbsp;</td><td style=\"border-style: none;\">backup UP </td></tr>"
2708 "<tr><td bgcolor=\"#FFFFA0\"></td><td style=\"border-style: none;\">active UP, going down </td>"
2709 "<td bgcolor=\"#C060FF\"></td><td style=\"border-style: none;\">backup UP, going down </td></tr>"
2710 "<tr><td bgcolor=\"#FFD020\"></td><td style=\"border-style: none;\">active DOWN, going up </td>"
2711 "<td bgcolor=\"#FF80FF\"></td><td style=\"border-style: none;\">backup DOWN, going up </td></tr>"
2712 "<tr><td bgcolor=\"#FF9090\"></td><td style=\"border-style: none;\">active or backup DOWN &nbsp;</td>"
2713 "<td bgcolor=\"#E0E0E0\"></td><td style=\"border-style: none;\">not checked </td></tr>"
2714 "</table>\n"
2715 "</tr></table>\n"
2716 "",
2717 pid, pid, global.nbproc,
2718 up / 86400, (up % 86400) / 3600,
2719 (up % 3600) / 60, (up % 60),
2720 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
2721 global.rlimit_memmax ? " MB" : "",
2722 global.rlimit_nofile,
2723 global.maxsock,
2724 global.maxconn,
2725 actconn
2726 );
2727
2728 if (buffer_write(rep, trash, msglen) != 0)
2729 return 0;
2730 msglen = 0;
2731
2732 s->data_state = DATA_ST_DATA;
2733 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
2734
2735 px = s->data_ctx.stats.px = proxy;
2736 s->data_ctx.stats.px_st = DATA_ST_INIT;
2737 }
2738
2739 while (s->data_ctx.stats.px) {
2740 int dispatch_sess, dispatch_cum;
2741 int failed_checks, down_trans;
2742 int failed_secu, failed_conns, failed_resp;
2743
2744 if (s->data_ctx.stats.px_st == DATA_ST_INIT) {
2745 /* we are on a new proxy */
2746 px = s->data_ctx.stats.px;
2747
2748 /* skip the disabled proxies */
2749 if (px->state == PR_STSTOPPED)
2750 goto next_proxy;
2751
Willy Tarreau830ff452006-12-17 19:31:23 +01002752 if (s->be->fiprm->uri_auth && s->be->fiprm->uri_auth->scope) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002753 /* we have a limited scope, we have to check the proxy name */
2754 struct stat_scope *scope;
2755 int len;
2756
2757 len = strlen(px->id);
Willy Tarreau830ff452006-12-17 19:31:23 +01002758 scope = s->be->fiprm->uri_auth->scope;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002759
2760 while (scope) {
2761 /* match exact proxy name */
2762 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
2763 break;
2764
2765 /* match '.' which means 'self' proxy */
Willy Tarreau73de9892006-11-30 11:40:23 +01002766 if (!strcmp(scope->px_id, ".") && px == s->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002767 break;
2768 scope = scope->next;
2769 }
2770
2771 /* proxy name not found */
2772 if (scope == NULL)
2773 goto next_proxy;
2774 }
2775
2776 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2777 "<h3>&gt; Proxy instance %s : "
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002778 "%d front conns (max=%d), %d back, "
2779 "%d queued (%d unassigned), %d total front conns, %d back</h3>\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +02002780 "",
2781 px->id,
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002782 px->feconn, px->maxconn, px->beconn,
2783 px->totpend, px->nbpend, px->cum_feconn, px->cum_beconn);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002784
2785 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2786 "<table cols=\"16\" class=\"tbl\">\n"
2787 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
2788 "<th colspan=5>Server</th>"
2789 "<th colspan=2>Queue</th>"
2790 "<th colspan=4>Sessions</th>"
2791 "<th colspan=5>Errors</th></tr>\n"
2792 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
2793 "<th>Name</th><th>Weight</th><th>Status</th><th>Act.</th><th>Bck.</th>"
2794 "<th>Curr.</th><th>Max.</th>"
2795 "<th>Curr.</th><th>Max.</th><th>Limit</th><th>Cumul.</th>"
2796 "<th>Conn.</th><th>Resp.</th><th>Sec.</th><th>Check</th><th>Down</th></tr>\n");
2797
2798 if (buffer_write(rep, trash, msglen) != 0)
2799 return 0;
2800 msglen = 0;
2801
2802 s->data_ctx.stats.sv = px->srv;
2803 s->data_ctx.stats.px_st = DATA_ST_DATA;
2804 }
2805
2806 px = s->data_ctx.stats.px;
2807
2808 /* stats.sv has been initialized above */
2809 while (s->data_ctx.stats.sv != NULL) {
2810 static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
2811 static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
2812 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
2813 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
2814
2815 sv = s->data_ctx.stats.sv;
2816
2817 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
2818 if (!(sv->state & SRV_CHECKED))
2819 sv_state = 4;
2820 else if (sv->state & SRV_RUNNING)
2821 if (sv->health == sv->rise + sv->fall - 1)
2822 sv_state = 3; /* UP */
2823 else
2824 sv_state = 2; /* going down */
2825 else
2826 if (sv->health)
2827 sv_state = 1; /* going up */
2828 else
2829 sv_state = 0; /* DOWN */
2830
2831 /* name, weight */
2832 msglen += snprintf(trash, sizeof(trash),
2833 "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
2834 (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
2835 sv->id, sv->uweight+1);
2836 /* status */
2837 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, srv_hlt_st[sv_state],
2838 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
2839 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
2840
2841 /* act, bck */
2842 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2843 "</td><td>%s</td><td>%s</td>",
2844 (sv->state & SRV_BACKUP) ? "-" : "Y",
2845 (sv->state & SRV_BACKUP) ? "Y" : "-");
2846
2847 /* queue : current, max */
2848 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2849 "<td align=right>%d</td><td align=right>%d</td>",
2850 sv->nbpend, sv->nbpend_max);
2851
2852 /* sessions : current, max, limit, cumul */
2853 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2854 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>",
2855 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess);
2856
2857 /* errors : connect, response, security */
2858 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2859 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
2860 sv->failed_conns, sv->failed_resp, sv->failed_secu);
2861
2862 /* check failures : unique, fatal */
2863 if (sv->state & SRV_CHECKED)
2864 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2865 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
2866 sv->failed_checks, sv->down_trans);
2867 else
2868 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2869 "<td align=right>-</td><td align=right>-</td></tr>\n");
2870
2871 if (buffer_write(rep, trash, msglen) != 0)
2872 return 0;
2873 msglen = 0;
2874
2875 s->data_ctx.stats.sv = sv->next;
2876 } /* while sv */
2877
2878 /* now we are past the last server, we'll dump information about the dispatcher */
2879
2880 /* We have to count down from the proxy to the servers to tell how
2881 * many sessions are on the dispatcher, and how many checks have
2882 * failed. We cannot count this during the servers dump because it
2883 * might be interrupted multiple times.
2884 */
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002885 dispatch_sess = px->beconn;
2886 dispatch_cum = px->cum_beconn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002887 failed_secu = px->failed_secu;
2888 failed_conns = px->failed_conns;
2889 failed_resp = px->failed_resp;
2890 failed_checks = down_trans = 0;
2891
2892 sv = px->srv;
2893 while (sv) {
2894 dispatch_sess -= sv->cur_sess;
2895 dispatch_cum -= sv->cum_sess;
2896 failed_conns -= sv->failed_conns;
2897 failed_resp -= sv->failed_resp;
2898 failed_secu -= sv->failed_secu;
2899 if (sv->state & SRV_CHECKED) {
2900 failed_checks += sv->failed_checks;
2901 down_trans += sv->down_trans;
2902 }
2903 sv = sv->next;
2904 }
2905
2906 /* name, weight, status, act, bck */
2907 msglen += snprintf(trash + msglen, sizeof(trash),
2908 "<tr align=center bgcolor=\"#e8e8d0\">"
2909 "<td>Dispatcher</td><td>-</td>"
2910 "<td>%s</td><td>-</td><td>-</td>",
2911 px->state == PR_STRUN ? "UP" : "DOWN");
2912
2913 /* queue : current, max */
2914 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2915 "<td align=right>%d</td><td align=right>%d</td>",
2916 px->nbpend, px->nbpend_max);
2917
2918 /* sessions : current, max, limit, cumul. */
2919 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002920 "<td align=right>%d</td><td align=right>%d</td><td align=right>-</td><td align=right>%d</td>",
2921 dispatch_sess, px->beconn_max, dispatch_cum);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002922
2923 /* errors : connect, response, security */
2924 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2925 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
2926 failed_conns, failed_resp, failed_secu);
2927
2928 /* check failures : unique, fatal */
2929 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2930 "<td align=right>-</td><td align=right>-</td></tr>\n");
2931
2932
2933 /* now the summary for the whole proxy */
2934 /* name, weight, status, act, bck */
2935 msglen += snprintf(trash + msglen, sizeof(trash),
2936 "<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
2937 "<td><b>Total</b></td><td>-</td>"
2938 "<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
2939 (px->state == PR_STRUN && ((px->srv == NULL) || px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
2940 px->srv_act, px->srv_bck);
2941
2942 /* queue : current, max */
2943 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2944 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
2945 px->totpend, px->nbpend_max);
2946
2947 /* sessions : current, max, limit, cumul */
2948 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002949 "<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>",
2950 px->beconn, px->beconn_max, px->cum_beconn);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002951
2952 /* errors : connect, response, security */
2953 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2954 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
2955 px->failed_conns, px->failed_resp, px->failed_secu);
2956
2957 /* check failures : unique, fatal */
2958 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2959 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
2960 failed_checks, down_trans);
2961
2962 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, "</table><p>\n");
2963
2964 if (buffer_write(rep, trash, msglen) != 0)
2965 return 0;
2966 msglen = 0;
2967
2968 s->data_ctx.stats.px_st = DATA_ST_INIT;
2969 next_proxy:
2970 s->data_ctx.stats.px = px->next;
2971 } /* proxy loop */
2972 /* here, we just have reached the sv == NULL and px == NULL */
2973 s->flags &= ~SN_SELF_GEN;
2974 return 1;
2975 }
2976 else {
2977 /* unknown data source */
2978 s->logs.status = 500;
Willy Tarreau73de9892006-11-30 11:40:23 +01002979 client_retnclose(s, s->fe->errmsg.len500, s->fe->errmsg.msg500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002980 if (!(s->flags & SN_ERR_MASK))
2981 s->flags |= SN_ERR_PRXCOND;
2982 if (!(s->flags & SN_FINST_MASK))
2983 s->flags |= SN_FINST_R;
2984 s->flags &= SN_SELF_GEN;
2985 return 1;
2986 }
2987}
2988
2989
Willy Tarreau58f10d72006-12-04 02:26:12 +01002990
2991/*
2992 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>
2993 */
2994
2995void apply_filters_to_session(struct session *t, struct buffer *req, struct hdr_exp *exp)
2996{
2997 /* iterate through the filters in the outer loop */
2998 while (exp && !(t->flags & (SN_CLDENY|SN_CLTARPIT))) {
2999 char term;
3000 char *cur_ptr, *cur_end, *cur_next;
3001 int cur_idx, old_idx, abort_filt;
3002
3003
3004 /*
3005 * The interleaving of transformations and verdicts
3006 * makes it difficult to decide to continue or stop
3007 * the evaluation.
3008 */
3009
3010 if ((t->flags & SN_CLALLOW) &&
3011 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
3012 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
3013 exp = exp->next;
3014 continue;
3015 }
3016
3017 /* Iterate through the headers in the inner loop.
3018 * we start with the start line.
3019 */
3020 old_idx = cur_idx = 0;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003021 cur_next = req->data + t->hreq.sor;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003022 abort_filt = 0;
3023
Willy Tarreau45e73e32006-12-17 00:05:15 +01003024 while (!abort_filt && (cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
3025 struct hdr_idx_elem *cur_hdr = &t->hreq.hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003026 cur_ptr = cur_next;
3027 cur_end = cur_ptr + cur_hdr->len;
3028 cur_next = cur_end + cur_hdr->cr + 1;
3029
3030 /* Now we have one header between cur_ptr and cur_end,
3031 * and the next header starts at cur_next.
3032 */
3033
3034 /* The annoying part is that pattern matching needs
3035 * that we modify the contents to null-terminate all
3036 * strings before testing them.
3037 */
3038
3039 term = *cur_end;
3040 *cur_end = '\0';
3041
3042 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3043 switch (exp->action) {
Willy Tarreaua496b602006-12-17 23:15:24 +01003044 case ACT_SETBE:
3045 /* It is not possible to jump a second time.
3046 * FIXME: should we return an HTTP/500 here so that
3047 * the admin knows there's a problem ?
3048 */
3049 if (t->be != t->fe)
3050 break;
3051
3052 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3053 struct proxy *target = (struct proxy *) exp->replace;
3054
3055 /* Swithing Proxy */
3056 *cur_end = term;
3057 cur_end = NULL;
3058
3059 /* right now, the backend switch is not too much complicated
3060 * because we have associated req_cap and rsp_cap to the
3061 * frontend, and the beconn will be updated later.
3062 */
3063
3064 t->rep->rto = t->req->wto = target->beprm->srvtimeout;
3065 t->req->cto = target->beprm->contimeout;
3066
3067 t->be = target;
3068
3069 //t->logs.logwait |= LW_REQ | (target->to_log & (LW_REQHDR | LW_COOKIE));
3070 t->logs.logwait |= (target->to_log | target->beprm->to_log);
3071 abort_filt = 1;
3072 }
3073 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003074 case ACT_ALLOW:
3075 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3076 t->flags |= SN_CLALLOW;
3077 abort_filt = 1;
3078 }
3079 break;
3080 case ACT_REPLACE:
3081 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3082 int len, delta;
3083 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3084 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
Willy Tarreaue15d9132006-12-14 22:26:42 +01003085 /* FIXME: if the user adds a newline in the replacement, the
3086 * index will not be recalculated for now, and the new line
3087 * will not be counted for a new header.
3088 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003089 cur_end += delta;
3090 cur_next += delta;
3091 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003092 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003093 }
3094 break;
3095 case ACT_REMOVE:
3096 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3097 int delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3098 cur_next += delta;
3099
3100 /* FIXME: this should be a separate function */
Willy Tarreau45e73e32006-12-17 00:05:15 +01003101 t->hreq.eoh += delta;
3102 t->hreq.hdr_idx.v[old_idx].next = cur_hdr->next;
3103 t->hreq.hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003104 cur_hdr->len = 0;
3105
3106 cur_end = NULL; /* null-term has been rewritten */
3107 }
3108 break;
3109 case ACT_DENY:
3110 if (!(t->flags & (SN_CLALLOW | SN_CLTARPIT))) {
3111 t->flags |= SN_CLDENY;
3112 abort_filt = 1;
3113 }
3114 break;
3115 case ACT_TARPIT:
3116 if (!(t->flags & (SN_CLALLOW | SN_CLDENY))) {
3117 t->flags |= SN_CLTARPIT;
3118 abort_filt = 1;
3119 }
3120 break;
3121 //case ACT_PASS: /* FIXME: broken as of now. We should mark the header as "ignored". */
3122 // break;
3123 }
3124 }
3125 if (cur_end)
3126 *cur_end = term; /* restore the string terminator */
3127
3128 /* keep the link from this header to next one */
3129 old_idx = cur_idx;
3130 }
3131 exp = exp->next;
3132 }
3133}
3134
3135
3136
3137/*
3138 * Manager client-side cookie
3139 */
3140void manage_client_side_cookies(struct session *t, struct buffer *req)
3141{
3142 char *p1, *p2, *p3, *p4;
3143 char *del_colon, *del_cookie, *colon;
3144 int app_cookies;
3145
3146 appsess *asession_temp = NULL;
3147 appsess local_asession;
3148
3149 char *cur_ptr, *cur_end, *cur_next;
3150 int cur_idx, old_idx, abort_filt;
3151
Willy Tarreau830ff452006-12-17 19:31:23 +01003152 if (t->be->beprm->cookie_name == NULL &&
3153 t->be->beprm->appsession_name ==NULL &&
3154 t->be->fiprm->capture_name != NULL)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003155 return;
3156
Willy Tarreau2a324282006-12-05 00:05:46 +01003157 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003158 * we start with the start line.
3159 */
3160 old_idx = cur_idx = 0;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003161 cur_next = req->data + t->hreq.sor;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003162 abort_filt = 0;
3163
Willy Tarreau45e73e32006-12-17 00:05:15 +01003164 while ((cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003165 struct hdr_idx_elem *cur_hdr;
3166
Willy Tarreau45e73e32006-12-17 00:05:15 +01003167 cur_hdr = &t->hreq.hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003168 cur_ptr = cur_next;
3169 cur_end = cur_ptr + cur_hdr->len;
3170 cur_next = cur_end + cur_hdr->cr + 1;
3171
3172 /* We have one full header between cur_ptr and cur_end, and the
3173 * next header starts at cur_next. We're only interested in
3174 * "Cookie:" headers.
3175 */
3176
3177 if ((cur_end - cur_ptr <= 7) ||
3178 (strncasecmp(cur_ptr, "Cookie:", 7) != 0)) {
3179 old_idx = cur_idx;
3180 continue;
3181 }
3182
3183 /* Now look for cookies. Conforming to RFC2109, we have to support
3184 * attributes whose name begin with a '$', and associate them with
3185 * the right cookie, if we want to delete this cookie.
3186 * So there are 3 cases for each cookie read :
3187 * 1) it's a special attribute, beginning with a '$' : ignore it.
3188 * 2) it's a server id cookie that we *MAY* want to delete : save
3189 * some pointers on it (last semi-colon, beginning of cookie...)
3190 * 3) it's an application cookie : we *MAY* have to delete a previous
3191 * "special" cookie.
3192 * At the end of loop, if a "special" cookie remains, we may have to
3193 * remove it. If no application cookie persists in the header, we
3194 * *MUST* delete it
3195 */
3196
3197
3198 p1 = cur_ptr + 7; /* first char after 'Cookie:' */
3199 if (isspace((int)*p1)) /* try to get the first space with it */
3200 p1++;
3201
3202 colon = p1;
3203 /* del_cookie == NULL => nothing to be deleted */
3204 del_colon = del_cookie = NULL;
3205 app_cookies = 0;
3206
3207 while (p1 < cur_end) {
3208 /* skip spaces and colons, but keep an eye on these ones */
3209 while (p1 < cur_end) {
3210 if (*p1 == ';' || *p1 == ',')
3211 colon = p1;
3212 else if (!isspace((int)*p1))
3213 break;
3214 p1++;
3215 }
3216
3217 if (p1 == cur_end)
3218 break;
3219
3220 /* p1 is at the beginning of the cookie name */
3221 p2 = p1;
3222 while (p2 < cur_end && *p2 != '=')
3223 p2++;
3224
3225 if (p2 == cur_end)
3226 break;
3227
3228 p3 = p2 + 1; /* skips the '=' sign */
3229 if (p3 == cur_end)
3230 break;
3231
3232 p4 = p3;
3233 while (p4 < cur_end && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
3234 p4++;
3235
3236 /* here, we have the cookie name between p1 and p2,
3237 * and its value between p3 and p4.
3238 * we can process it :
3239 *
3240 * Cookie: NAME=VALUE;
3241 * | || || |
3242 * | || || +--> p4
3243 * | || |+-------> p3
3244 * | || +--------> p2
3245 * | |+------------> p1
3246 * | +-------------> colon
3247 * +--------------------> cur_ptr
3248 */
3249
3250 if (*p1 == '$') {
3251 /* skip this one */
3252 }
3253 else {
3254 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01003255 if (t->fe->fiprm->capture_name != NULL &&
Willy Tarreau58f10d72006-12-04 02:26:12 +01003256 t->logs.cli_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01003257 (p4 - p1 >= t->fe->fiprm->capture_namelen) &&
3258 memcmp(p1, t->fe->fiprm->capture_name, t->fe->fiprm->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003259 int log_len = p4 - p1;
3260
3261 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3262 Alert("HTTP logging : out of memory.\n");
3263 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003264 if (log_len > t->fe->fiprm->capture_len)
3265 log_len = t->fe->fiprm->capture_len;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003266 memcpy(t->logs.cli_cookie, p1, log_len);
3267 t->logs.cli_cookie[log_len] = 0;
3268 }
3269 }
3270
Willy Tarreau830ff452006-12-17 19:31:23 +01003271 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
3272 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003273 /* Cool... it's the right one */
Willy Tarreau830ff452006-12-17 19:31:23 +01003274 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003275 char *delim;
3276
3277 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3278 * have the server ID betweek p3 and delim, and the original cookie between
3279 * delim+1 and p4. Otherwise, delim==p4 :
3280 *
3281 * Cookie: NAME=SRV~VALUE;
3282 * | || || | |
3283 * | || || | +--> p4
3284 * | || || +--------> delim
3285 * | || |+-----------> p3
3286 * | || +------------> p2
3287 * | |+----------------> p1
3288 * | +-----------------> colon
3289 * +------------------------> cur_ptr
3290 */
3291
Willy Tarreau830ff452006-12-17 19:31:23 +01003292 if (t->be->beprm->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003293 for (delim = p3; delim < p4; delim++)
3294 if (*delim == COOKIE_DELIM)
3295 break;
3296 }
3297 else
3298 delim = p4;
3299
3300
3301 /* Here, we'll look for the first running server which supports the cookie.
3302 * This allows to share a same cookie between several servers, for example
3303 * to dedicate backup servers to specific servers only.
3304 * However, to prevent clients from sticking to cookie-less backup server
3305 * when they have incidentely learned an empty cookie, we simply ignore
3306 * empty cookies and mark them as invalid.
3307 */
3308 if (delim == p3)
3309 srv = NULL;
3310
3311 while (srv) {
3312 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003313 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003314 /* we found the server and it's usable */
3315 t->flags &= ~SN_CK_MASK;
3316 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3317 t->srv = srv;
3318 break;
3319 } else {
3320 /* we found a server, but it's down */
3321 t->flags &= ~SN_CK_MASK;
3322 t->flags |= SN_CK_DOWN;
3323 }
3324 }
3325 srv = srv->next;
3326 }
3327
3328 if (!srv && !(t->flags & SN_CK_DOWN)) {
3329 /* no server matched this cookie */
3330 t->flags &= ~SN_CK_MASK;
3331 t->flags |= SN_CK_INVALID;
3332 }
3333
3334 /* depending on the cookie mode, we may have to either :
3335 * - delete the complete cookie if we're in insert+indirect mode, so that
3336 * the server never sees it ;
3337 * - remove the server id from the cookie value, and tag the cookie as an
3338 * application cookie so that it does not get accidentely removed later,
3339 * if we're in cookie prefix mode
3340 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003341 if ((t->be->beprm->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003342 int delta; /* negative */
3343
3344 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
3345 p4 += delta;
3346 cur_end += delta;
3347 cur_next += delta;
3348 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003349 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003350
3351 del_cookie = del_colon = NULL;
3352 app_cookies++; /* protect the header from deletion */
3353 }
3354 else if (del_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01003355 (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 +01003356 del_cookie = p1;
3357 del_colon = colon;
3358 }
3359 } else {
3360 /* now we know that we must keep this cookie since it's
3361 * not ours. But if we wanted to delete our cookie
3362 * earlier, we cannot remove the complete header, but we
3363 * can remove the previous block itself.
3364 */
3365 app_cookies++;
3366
3367 if (del_cookie != NULL) {
3368 int delta; /* negative */
3369
3370 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
3371 p4 += delta;
3372 cur_end += delta;
3373 cur_next += delta;
3374 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003375 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003376 del_cookie = del_colon = NULL;
3377 }
3378 }
3379
Willy Tarreau830ff452006-12-17 19:31:23 +01003380 if ((t->be->beprm->appsession_name != NULL) &&
3381 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003382 /* first, let's see if the cookie is our appcookie*/
3383
3384 /* Cool... it's the right one */
3385
3386 asession_temp = &local_asession;
3387
3388 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3389 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3390 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3391 return;
3392 }
3393
Willy Tarreau830ff452006-12-17 19:31:23 +01003394 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
3395 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003396 asession_temp->serverid = NULL;
3397
3398 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01003399 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003400 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3401 /* free previously allocated memory */
3402 pool_free_to(apools.sessid, local_asession.sessid);
3403 Alert("Not enough memory process_cli():asession:calloc().\n");
3404 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3405 return;
3406 }
3407
3408 asession_temp->sessid = local_asession.sessid;
3409 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01003410 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003411 } else {
3412 /* free previously allocated memory */
3413 pool_free_to(apools.sessid, local_asession.sessid);
3414 }
3415
3416 if (asession_temp->serverid == NULL) {
3417 Alert("Found Application Session without matching server.\n");
3418 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003419 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003420 while (srv) {
3421 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003422 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003423 /* we found the server and it's usable */
3424 t->flags &= ~SN_CK_MASK;
3425 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3426 t->srv = srv;
3427 break;
3428 } else {
3429 t->flags &= ~SN_CK_MASK;
3430 t->flags |= SN_CK_DOWN;
3431 }
3432 }
3433 srv = srv->next;
3434 }/* end while(srv) */
3435 }/* end else if server == NULL */
3436
Willy Tarreau830ff452006-12-17 19:31:23 +01003437 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003438 }/* end if ((t->proxy->appsession_name != NULL) ... */
3439 }
3440
3441 /* we'll have to look for another cookie ... */
3442 p1 = p4;
3443 } /* while (p1 < cur_end) */
3444
3445 /* There's no more cookie on this line.
3446 * We may have marked the last one(s) for deletion.
3447 * We must do this now in two ways :
3448 * - if there is no app cookie, we simply delete the header ;
3449 * - if there are app cookies, we must delete the end of the
3450 * string properly, including the colon/semi-colon before
3451 * the cookie name.
3452 */
3453 if (del_cookie != NULL) {
3454 int delta;
3455 if (app_cookies) {
3456 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
3457 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003458 cur_hdr->len += delta;
3459 } else {
3460 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003461
3462 /* FIXME: this should be a separate function */
Willy Tarreau45e73e32006-12-17 00:05:15 +01003463 t->hreq.hdr_idx.v[old_idx].next = cur_hdr->next;
3464 t->hreq.hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003465 cur_hdr->len = 0;
3466 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01003467 cur_next += delta;
3468 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003469 }
3470
3471 /* keep the link from this header to next one */
3472 old_idx = cur_idx;
3473 } /* end of cookie processing on this header */
3474}
3475
3476
3477
3478/*
3479 * Try to retrieve a known appsession in the URI, then the associated server.
3480 * If the server is found, it's assigned to the session.
3481 */
3482
3483void get_srv_from_appsession(struct session *t, const char *begin, const char *end)
3484{
3485 appsess *asession_temp = NULL;
3486 appsess local_asession;
3487 char *request_line;
3488
Willy Tarreau830ff452006-12-17 19:31:23 +01003489 if (t->be->beprm->appsession_name == NULL ||
Willy Tarreau921d7c02006-12-17 13:50:27 +01003490 (t->hreq.meth != HTTP_METH_GET && t->hreq.meth != HTTP_METH_POST) ||
Willy Tarreau58f10d72006-12-04 02:26:12 +01003491 (request_line = memchr(begin, ';', end - begin)) == NULL ||
Willy Tarreau830ff452006-12-17 19:31:23 +01003492 ((1 + t->be->beprm->appsession_name_len + 1 + t->be->beprm->appsession_len) > (end - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01003493 return;
3494
3495 /* skip ';' */
3496 request_line++;
3497
3498 /* look if we have a jsessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01003499 if (strncasecmp(request_line, t->be->beprm->appsession_name, t->be->beprm->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003500 return;
3501
3502 /* skip jsessionid= */
Willy Tarreau830ff452006-12-17 19:31:23 +01003503 request_line += t->be->beprm->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003504
3505 /* First try if we already have an appsession */
3506 asession_temp = &local_asession;
3507
3508 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3509 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3510 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3511 return;
3512 }
3513
3514 /* Copy the sessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01003515 memcpy(asession_temp->sessid, request_line, t->be->beprm->appsession_len);
3516 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003517 asession_temp->serverid = NULL;
3518
3519 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01003520 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *)&asession_temp)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003521 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3522 /* free previously allocated memory */
3523 pool_free_to(apools.sessid, local_asession.sessid);
3524 Alert("Not enough memory process_cli():asession:calloc().\n");
3525 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3526 return;
3527 }
3528 asession_temp->sessid = local_asession.sessid;
3529 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01003530 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003531 }
3532 else {
3533 /* free previously allocated memory */
3534 pool_free_to(apools.sessid, local_asession.sessid);
3535 }
3536
Willy Tarreau830ff452006-12-17 19:31:23 +01003537 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003538 asession_temp->request_count++;
3539
3540#if defined(DEBUG_HASH)
3541 print_table(&(t->proxy->htbl_proxy));
3542#endif
3543 if (asession_temp->serverid == NULL) {
3544 Alert("Found Application Session without matching server.\n");
3545 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003546 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003547 while (srv) {
3548 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003549 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003550 /* we found the server and it's usable */
3551 t->flags &= ~SN_CK_MASK;
3552 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3553 t->srv = srv;
3554 break;
3555 } else {
3556 t->flags &= ~SN_CK_MASK;
3557 t->flags |= SN_CK_DOWN;
3558 }
3559 }
3560 srv = srv->next;
3561 }
3562 }
3563}
3564
3565
Willy Tarreaub2513902006-12-17 14:52:38 +01003566
3567/*
3568 * In a GET request, check if the requested URI matches the stats uri for the
3569 * current backend, and if an authorization has been passed and is valid.
3570 *
Willy Tarreau830ff452006-12-17 19:31:23 +01003571 * 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 +01003572 * is valid. An HTTP/401 response may be sent, or produce_content() can be
3573 * called to start sending data.
3574 *
3575 * Returns 1 if the session's state changes, otherwise 0.
3576 */
3577int stats_check_uri_auth(struct session *t, struct proxy *backend)
3578{
3579 struct uri_auth *uri_auth = backend->uri_auth;
3580 struct user_auth *user;
3581 int authenticated, cur_idx;
3582 char *h;
3583
3584 if (t->hreq.start.len < uri_auth->uri_len + 4) /* +4 for "GET " */
3585 return 0;
3586
3587 if (memcmp(t->hreq.start.str + 4, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
3588 return 0;
3589
3590 /* we are in front of a interceptable URI. Let's check
3591 * if there's an authentication and if it's valid.
3592 */
3593 user = uri_auth->users;
3594 if (!user) {
3595 /* no user auth required, it's OK */
3596 authenticated = 1;
3597 } else {
3598 authenticated = 0;
3599
3600 /* a user list is defined, we have to check.
3601 * skip 21 chars for "Authorization: Basic ".
3602 */
3603
3604 /* FIXME: this should move to an earlier place */
3605 cur_idx = 0;
3606 h = t->req->data + t->hreq.sor;
3607 while ((cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
3608 int len = t->hreq.hdr_idx.v[cur_idx].len;
3609 if (len > 14 &&
3610 !strncasecmp("Authorization:", h, 14)) {
3611 t->hreq.auth_hdr.str = h;
3612 t->hreq.auth_hdr.len = len;
3613 break;
3614 }
3615 h += len + t->hreq.hdr_idx.v[cur_idx].cr + 1;
3616 }
3617
3618 if (t->hreq.auth_hdr.len < 21 ||
3619 memcmp(t->hreq.auth_hdr.str + 14, " Basic ", 7))
3620 user = NULL;
3621
3622 while (user) {
3623 if ((t->hreq.auth_hdr.len == user->user_len + 14 + 7)
3624 && !memcmp(t->hreq.auth_hdr.str + 14 + 7,
3625 user->user_pwd, user->user_len)) {
3626 authenticated = 1;
3627 break;
3628 }
3629 user = user->next;
3630 }
3631 }
3632
3633 if (!authenticated) {
3634 int msglen;
3635
3636 /* no need to go further */
3637 msglen = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
3638 t->logs.status = 401;
3639 client_retnclose(t, msglen, trash);
3640 if (!(t->flags & SN_ERR_MASK))
3641 t->flags |= SN_ERR_PRXCOND;
3642 if (!(t->flags & SN_FINST_MASK))
3643 t->flags |= SN_FINST_R;
3644 return 1;
3645 }
3646
3647 /* The request is valid, the user is authenticate. Let's start sending
3648 * data.
3649 */
3650 t->cli_state = CL_STSHUTR;
3651 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
3652 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
3653 t->data_source = DATA_SRC_STATS;
3654 t->data_state = DATA_ST_INIT;
3655 produce_content(t);
3656 return 1;
3657}
3658
3659
3660
Willy Tarreaubaaee002006-06-26 02:48:02 +02003661/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01003662 * Print a debug line with a header
3663 */
3664void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
3665{
3666 int len, max;
3667 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
3668 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
3669 max = end - start;
3670 UBOUND(max, sizeof(trash) - len - 1);
3671 len += strlcpy2(trash + len, start, max + 1);
3672 trash[len++] = '\n';
3673 write(1, trash, len);
3674}
3675
3676
3677/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02003678 * Local variables:
3679 * c-indent-level: 8
3680 * c-basic-offset: 8
3681 * End:
3682 */