blob: 21ea4c91078f9b7c68f6a7a37fd9c99ab65ffb71 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * HTTP protocol analyzer
3 *
4 * Copyright 2000-2006 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <syslog.h>
20
21#include <sys/socket.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24
Willy Tarreau2dd0d472006-06-29 17:53:05 +020025#include <common/appsession.h>
26#include <common/compat.h>
27#include <common/config.h>
Willy Tarreaua4cd1f52006-12-16 19:57:26 +010028#include <common/debug.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020029#include <common/memory.h>
30#include <common/mini-clist.h>
31#include <common/standard.h>
32#include <common/time.h>
33#include <common/uri_auth.h>
34#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020035
36#include <types/capture.h>
37#include <types/client.h>
38#include <types/global.h>
39#include <types/httperr.h>
40#include <types/polling.h>
41#include <types/proxy.h>
42#include <types/server.h>
43
44#include <proto/backend.h>
45#include <proto/buffers.h>
46#include <proto/fd.h>
47#include <proto/log.h>
Willy Tarreau58f10d72006-12-04 02:26:12 +010048#include <proto/hdr_idx.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020049#include <proto/proto_http.h>
50#include <proto/queue.h>
51#include <proto/session.h>
52#include <proto/task.h>
53
54
Willy Tarreau58f10d72006-12-04 02:26:12 +010055#define DEBUG_PARSE_NO_SPEEDUP
56#undef DEBUG_PARSE_NO_SPEEDUP
57
Willy Tarreau976f1ee2006-12-17 10:06:03 +010058/* This is used to perform a quick jump as an alternative to a break/continue
59 * instruction. The first argument is the label for normal operation, and the
60 * second one is the break/continue instruction in the no_speedup mode.
61 */
62
63#ifdef DEBUG_PARSE_NO_SPEEDUP
64#define QUICK_JUMP(x,y) y
65#else
66#define QUICK_JUMP(x,y) goto x
67#endif
68
Willy Tarreau1c47f852006-07-09 08:22:27 +020069/* This is used by remote monitoring */
Willy Tarreau0f772532006-12-23 20:51:41 +010070const char HTTP_200[] =
Willy Tarreau1c47f852006-07-09 08:22:27 +020071 "HTTP/1.0 200 OK\r\n"
72 "Cache-Control: no-cache\r\n"
73 "Connection: close\r\n"
74 "Content-Type: text/html\r\n"
75 "\r\n"
76 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
77
Willy Tarreau0f772532006-12-23 20:51:41 +010078const struct chunk http_200_chunk = {
79 .str = (char *)&HTTP_200,
80 .len = sizeof(HTTP_200)-1
81};
82
83const char *HTTP_302 =
84 "HTTP/1.0 302 Found\r\n"
85 "Cache-Control: no-cache\r\n"
86 "Connection: close\r\n"
87 "Location: "; /* not terminated since it will be concatenated with the URL */
88
89/* same as 302 except that the browser MUST retry with the GET method */
90const char *HTTP_303 =
91 "HTTP/1.0 303 See Other\r\n"
92 "Cache-Control: no-cache\r\n"
93 "Connection: close\r\n"
94 "Location: "; /* not terminated since it will be concatenated with the URL */
95
Willy Tarreaubaaee002006-06-26 02:48:02 +020096/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
97const char *HTTP_401_fmt =
98 "HTTP/1.0 401 Unauthorized\r\n"
99 "Cache-Control: no-cache\r\n"
100 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +0200101 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200102 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
103 "\r\n"
104 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
105
Willy Tarreau0f772532006-12-23 20:51:41 +0100106
107const int http_err_codes[HTTP_ERR_SIZE] = {
108 [HTTP_ERR_400] = 400,
109 [HTTP_ERR_403] = 403,
110 [HTTP_ERR_408] = 408,
111 [HTTP_ERR_500] = 500,
112 [HTTP_ERR_502] = 502,
113 [HTTP_ERR_503] = 503,
114 [HTTP_ERR_504] = 504,
115};
116
Willy Tarreau80587432006-12-24 17:47:20 +0100117static const char *http_err_msgs[HTTP_ERR_SIZE] = {
Willy Tarreau0f772532006-12-23 20:51:41 +0100118 [HTTP_ERR_400] =
Willy Tarreau80587432006-12-24 17:47:20 +0100119 "HTTP/1.0 400 Bad request\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +0100120 "Cache-Control: no-cache\r\n"
121 "Connection: close\r\n"
122 "Content-Type: text/html\r\n"
123 "\r\n"
124 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
125
126 [HTTP_ERR_403] =
127 "HTTP/1.0 403 Forbidden\r\n"
128 "Cache-Control: no-cache\r\n"
129 "Connection: close\r\n"
130 "Content-Type: text/html\r\n"
131 "\r\n"
132 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
133
134 [HTTP_ERR_408] =
135 "HTTP/1.0 408 Request Time-out\r\n"
136 "Cache-Control: no-cache\r\n"
137 "Connection: close\r\n"
138 "Content-Type: text/html\r\n"
139 "\r\n"
140 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
141
142 [HTTP_ERR_500] =
143 "HTTP/1.0 500 Server Error\r\n"
144 "Cache-Control: no-cache\r\n"
145 "Connection: close\r\n"
146 "Content-Type: text/html\r\n"
147 "\r\n"
148 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n",
149
150 [HTTP_ERR_502] =
151 "HTTP/1.0 502 Bad Gateway\r\n"
152 "Cache-Control: no-cache\r\n"
153 "Connection: close\r\n"
154 "Content-Type: text/html\r\n"
155 "\r\n"
156 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n",
157
158 [HTTP_ERR_503] =
159 "HTTP/1.0 503 Service Unavailable\r\n"
160 "Cache-Control: no-cache\r\n"
161 "Connection: close\r\n"
162 "Content-Type: text/html\r\n"
163 "\r\n"
164 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n",
165
166 [HTTP_ERR_504] =
167 "HTTP/1.0 504 Gateway Time-out\r\n"
168 "Cache-Control: no-cache\r\n"
169 "Connection: close\r\n"
170 "Content-Type: text/html\r\n"
171 "\r\n"
172 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n",
173
174};
175
Willy Tarreau80587432006-12-24 17:47:20 +0100176/* We must put the messages here since GCC cannot initialize consts depending
177 * on strlen().
178 */
179struct chunk http_err_chunks[HTTP_ERR_SIZE];
180
181void init_proto_http()
182{
183 int msg;
184 for (msg = 0; msg < HTTP_ERR_SIZE; msg++) {
185 if (!http_err_msgs[msg]) {
186 Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n", msg);
187 abort();
188 }
189
190 http_err_chunks[msg].str = (char *)http_err_msgs[msg];
191 http_err_chunks[msg].len = strlen(http_err_msgs[msg]);
192 }
193}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200194
Willy Tarreau53b6c742006-12-17 13:37:46 +0100195/*
196 * We have 26 list of methods (1 per first letter), each of which can have
197 * up to 3 entries (2 valid, 1 null).
198 */
199struct http_method_desc {
200 http_meth_t meth;
201 int len;
202 const char text[8];
203};
204
205static struct http_method_desc http_methods[26][3] = {
206 ['C' - 'A'] = {
207 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
208 },
209 ['D' - 'A'] = {
210 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
211 },
212 ['G' - 'A'] = {
213 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
214 },
215 ['H' - 'A'] = {
216 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
217 },
218 ['P' - 'A'] = {
219 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
220 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
221 },
222 ['T' - 'A'] = {
223 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
224 },
225 /* rest is empty like this :
226 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
227 */
228};
229
Willy Tarreaubaaee002006-06-26 02:48:02 +0200230#ifdef DEBUG_FULL
231static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
232static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
233#endif
234
235
236/*
237 * returns a message to the client ; the connection is shut down for read,
238 * and the request is cleared so that no server connection can be initiated.
239 * The client must be in a valid state for this (HEADER, DATA ...).
Willy Tarreau0f772532006-12-23 20:51:41 +0100240 * Nothing is performed on the server side. The message is contained in a
241 * "chunk". If it is null, then an empty message is used.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200242 * The reply buffer doesn't need to be empty before this.
243 */
Willy Tarreau0f772532006-12-23 20:51:41 +0100244void client_retnclose(struct session *s, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200245{
Willy Tarreau2a429502006-10-15 14:52:29 +0200246 MY_FD_CLR(s->cli_fd, StaticReadEvent);
247 MY_FD_SET(s->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +0200248 tv_eternity(&s->req->rex);
Willy Tarreau73de9892006-11-30 11:40:23 +0100249 if (s->fe->clitimeout)
250 tv_delayfrom(&s->rep->wex, &now, s->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200251 else
Willy Tarreaud7971282006-07-29 18:36:34 +0200252 tv_eternity(&s->rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200253 shutdown(s->cli_fd, SHUT_RD);
254 s->cli_state = CL_STSHUTR;
255 buffer_flush(s->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100256 if (msg->len)
257 buffer_write(s->rep, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200258 s->req->l = 0;
259}
260
261
262/*
263 * returns a message into the rep buffer, and flushes the req buffer.
Willy Tarreau0f772532006-12-23 20:51:41 +0100264 * The reply buffer doesn't need to be empty before this. The message
265 * is contained in a "chunk". If it is null, then an empty message is
266 * used.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200267 */
Willy Tarreau0f772532006-12-23 20:51:41 +0100268void client_return(struct session *s, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200269{
270 buffer_flush(s->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100271 if (msg->len)
272 buffer_write(s->rep, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200273 s->req->l = 0;
274}
275
276
277/* This function turns the server state into the SV_STCLOSE, and sets
Willy Tarreau0f772532006-12-23 20:51:41 +0100278 * indicators accordingly. Note that if <status> is 0, or if the message
279 * pointer is NULL, then no message is returned.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200280 */
281void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreau0f772532006-12-23 20:51:41 +0100282 int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200283{
284 t->srv_state = SV_STCLOSE;
Willy Tarreau0f772532006-12-23 20:51:41 +0100285 if (status > 0 && msg) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200286 t->logs.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100287 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100288 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200289 }
290 if (!(t->flags & SN_ERR_MASK))
291 t->flags |= err;
292 if (!(t->flags & SN_FINST_MASK))
293 t->flags |= finst;
294}
295
Willy Tarreau80587432006-12-24 17:47:20 +0100296/* This function returns the appropriate error location for the given session
297 * and message.
298 */
299
300struct chunk *error_message(struct session *s, int msgnum)
301{
302 if (s->be->beprm->errmsg[msgnum].str)
303 return &s->be->beprm->errmsg[msgnum];
304 else if (s->fe->errmsg[msgnum].str)
305 return &s->fe->errmsg[msgnum];
306 else
307 return &http_err_chunks[msgnum];
308}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200309
Willy Tarreau53b6c742006-12-17 13:37:46 +0100310/*
311 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
312 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
313 */
314static http_meth_t find_http_meth(const char *str, const int len)
315{
316 unsigned char m;
317 struct http_method_desc *h;
318
319 m = ((unsigned)*str - 'A');
320
321 if (m < 26) {
322 int l;
323 for (h = http_methods[m]; (l = (h->len)) > 0; h++) {
324 if (len <= l)
325 continue;
326
327 if (str[l] != ' ' && str[l] != '\t')
328 continue;
329
330 if (memcmp(str, h->text, l) == 0) {
331 return h->meth;
332 }
333 };
334 return HTTP_METH_OTHER;
335 }
336 return HTTP_METH_NONE;
337
338}
339
340
Willy Tarreaubaaee002006-06-26 02:48:02 +0200341/* Processes the client and server jobs of a session task, then
342 * puts it back to the wait queue in a clean state, or
343 * cleans up its resources if it must be deleted. Returns
344 * the time the task accepts to wait, or TIME_ETERNITY for
345 * infinity.
346 */
347int process_session(struct task *t)
348{
349 struct session *s = t->context;
350 int fsm_resync = 0;
351
352 do {
353 fsm_resync = 0;
354 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
355 fsm_resync |= process_cli(s);
356 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
357 fsm_resync |= process_srv(s);
358 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
359 } while (fsm_resync);
360
361 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
362 struct timeval min1, min2;
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200363 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
364 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200365
Willy Tarreaud7971282006-07-29 18:36:34 +0200366 tv_min(&min1, &s->req->rex, &s->req->wex);
367 tv_min(&min2, &s->rep->rex, &s->rep->wex);
368 tv_min(&min1, &min1, &s->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200369 tv_min(&t->expire, &min1, &min2);
370
371 /* restore t to its place in the task list */
372 task_queue(t);
373
374#ifdef DEBUG_FULL
375 /* DEBUG code : this should never ever happen, otherwise it indicates
376 * that a task still has something to do and will provoke a quick loop.
377 */
378 if (tv_remain2(&now, &t->expire) <= 0)
379 exit(100);
380#endif
381
382 return tv_remain2(&now, &t->expire); /* nothing more to do */
383 }
384
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100385 s->fe->feconn--;
386 if (s->flags & SN_BE_ASSIGNED)
387 s->be->beprm->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200388 actconn--;
389
390 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
391 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100392 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreau830ff452006-12-17 19:31:23 +0100393 s->uniq_id, s->be->beprm->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100394 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200395 write(1, trash, len);
396 }
397
398 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
399 if (s->rep != NULL)
400 s->logs.bytes = s->rep->total;
401
402 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200403 if (s->logs.logwait &&
404 !(s->flags & SN_MONITOR) &&
Willy Tarreau73de9892006-11-30 11:40:23 +0100405 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total))
Willy Tarreaubaaee002006-06-26 02:48:02 +0200406 sess_log(s);
407
408 /* the task MUST not be in the run queue anymore */
409 task_delete(t);
410 session_free(s);
411 task_free(t);
412 return TIME_ETERNITY; /* rest in peace for eternity */
413}
414
415
416/*
417 * FIXME: This should move to the HTTP_flow_analyzer code
418 */
419
420/*
421 * manages the client FSM and its socket. BTW, it also tries to handle the
422 * cookie. It returns 1 if a state has changed (and a resync may be needed),
423 * 0 else.
424 */
425int process_cli(struct session *t)
426{
427 int s = t->srv_state;
428 int c = t->cli_state;
429 struct buffer *req = t->req;
430 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100431 int delete_header = 0;
432
Willy Tarreaub2513902006-12-17 14:52:38 +0100433 int cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200434
Willy Tarreau45e73e32006-12-17 00:05:15 +0100435 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 +0200436 cli_stnames[c], srv_stnames[s],
Willy Tarreau2a429502006-10-15 14:52:29 +0200437 MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
Willy Tarreaud7971282006-07-29 18:36:34 +0200438 req->rex.tv_sec, req->rex.tv_usec,
439 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau45e73e32006-12-17 00:05:15 +0100440
Willy Tarreaubaaee002006-06-26 02:48:02 +0200441 if (c == CL_STHEADERS) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100442 /*
443 * Now parse the partial (or complete) lines.
444 * We will check the request syntax, and also join multi-line
445 * headers. An index of all the lines will be elaborated while
446 * parsing.
447 *
448 * For the parsing, we use a 10 states FSM.
449 *
450 * RFC2616 requires that both LF and CRLF are recognized as
451 * line breaks, but that any other combination is an error.
452 * To avoid duplicating all the states above to check for CR,
453 * we use a special bit HTTP_PA_LF_EXP that we 'OR' with the
454 * state we will switch to if the LF is seen, so that we know
455 * whether there's a pending CR or not. We can check it
456 * globally since all CR followed by anything but LF are
457 * errors. Each state is entered with the first character is
458 * has to process at req->lr. We also have HTTP_PA_CR_SKIP
459 * indicating that a CR has been seen on current line and
460 * skipped.
461 *
462 * Here is the information we currently have :
Willy Tarreau45e73e32006-12-17 00:05:15 +0100463 * req->data + req->sor = beginning of request
464 * req->data + req->eoh = end of (parsed) headers
Willy Tarreau58f10d72006-12-04 02:26:12 +0100465 * req->lr = first non-visited byte
466 * req->r = end of data
467 */
468
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100469 char *sol, *eol; /* Start Of Line, End Of Line */
Willy Tarreau830ff452006-12-17 19:31:23 +0100470 struct proxy *cur_proxy;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100471
Willy Tarreau45e73e32006-12-17 00:05:15 +0100472 eol = sol = req->data + t->hreq.eoh;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100473
Willy Tarreau58f10d72006-12-04 02:26:12 +0100474 while (req->lr < req->r) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100475 int parse;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200476
Willy Tarreau45e73e32006-12-17 00:05:15 +0100477 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",
478 t->hreq.hdr_state, t->hreq.hdr_idx.used, t->hreq.hdr_idx.tail, t->hreq.hdr_idx.last,
479 sol - req->data, req->lr - req->data, req->r - req->data, t->hreq.eoh);
480
481 if (t->hreq.hdr_state & HTTP_PA_LF_EXP) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100482 if (*req->lr != '\n') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100483 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100484 break;
485 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100486 t->hreq.hdr_state &= ~HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100487 }
488
Willy Tarreau45e73e32006-12-17 00:05:15 +0100489 parse = t->hreq.hdr_state & ~HTTP_PA_CR_SKIP;;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100490
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100491 if (parse == HTTP_PA_HDR_LF) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100492 parse_hdr_lf:
493 /* The LF validating last header, but it
494 * may also be an LWS, in which case we will
495 * need more data to know if we can close this
496 * header or not. However, we must check right
497 * now if this LF/CRLF closes an empty line, in
498 * which case it means the end of the request.
499 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100500 eol = req->lr;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100501 if (t->hreq.hdr_state & HTTP_PA_CR_SKIP)
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100502 eol--; /* Get back to the CR */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100503
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100504 if (eol == sol) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100505 /* We have found the end of the headers.
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100506 * sol points to the ending LF/CRLF,
Willy Tarreau58f10d72006-12-04 02:26:12 +0100507 * and req->lr points to the first byte
508 * after the LF, so it is easy to append
509 * anything there.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200510 */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100511 t->hreq.hdr_state = HTTP_PA_LFLF;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100512 QUICK_JUMP(parse_lflf, continue);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100513 }
514
515 if (req->lr + 1 >= req->r) /* LF, ?? */
516 break;
517 req->lr++;
518
519 /* Right now, we *know* that there is one char
520 * available at req->lr.
521 */
522
523 if (*req->lr == ' ' || *req->lr == '\t') {
524 /* We have an LWS, we will replace the
525 * CR and LF with spaces as RFC2616
526 * allows it. <lr> now points to the
527 * first space char of the LWS part.
528 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100529 for (;eol < req->lr; eol++)
530 *eol = ' ';
Willy Tarreau58f10d72006-12-04 02:26:12 +0100531
Willy Tarreau45e73e32006-12-17 00:05:15 +0100532 t->hreq.hdr_state = HTTP_PA_HDR_LWS;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100533 QUICK_JUMP(parse_hdr_lws, continue);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100534 }
535
536 /**********************************************
537 * We now have one complete header between *
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100538 * sol and eol, with a possible CR at eol, *
Willy Tarreau58f10d72006-12-04 02:26:12 +0100539 * everything ending before req->lr. Some very*
540 * early processing can be applied. *
541 **********************************************/
542
543 /*
544 * FIXME: insert a REQHEADER hook here.
545 * For instance, we could check the header's
546 * syntax such as forbidding the leading space
547 * in the first header (Apache also has the same problem)
548 */
549
550
551 /* 1: we might have to print this header */
552 if ((global.mode & MODE_DEBUG) &&
553 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100554 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100555
556
557 /* 2: maybe we have to copy this header for the logs ? */
558 if (t->logs.logwait & LW_REQHDR) {
559 /* FIXME: we must *search* the value after the ':' and not
560 * consider that it's necessary after one single space.*/
561 struct cap_hdr *h;
562 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +0100563 for (h = t->fe->fiprm->req_cap; h; h = h->next) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100564 if ((h->namelen + 2 <= eol - sol) &&
565 (sol[h->namelen] == ':') &&
566 (strncasecmp(sol, h->name, h->namelen) == 0)) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100567 if (t->hreq.cap[h->index] == NULL)
568 t->hreq.cap[h->index] =
569 pool_alloc_from(h->pool, h->len + 1);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100570
Willy Tarreau45e73e32006-12-17 00:05:15 +0100571 if (t->hreq.cap[h->index] == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100572 Alert("HTTP capture : out of memory.\n");
573 continue;
574 }
575
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100576 len = eol - (sol + h->namelen + 2);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100577 if (len > h->len)
578 len = h->len;
579
Willy Tarreau45e73e32006-12-17 00:05:15 +0100580 memcpy(t->hreq.cap[h->index], sol + h->namelen + 2, len);
581 t->hreq.cap[h->index][len]=0;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100582 }
583 }
584 }
585
586
587 /* 3: We might need to remove "connection:" */
Willy Tarreaue01954f2006-12-30 23:43:54 +0100588 if (!delete_header &&
589 ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) &&
590 (strncasecmp(sol, "Connection:", 11) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100591 delete_header = 1;
592 }
593
594
Willy Tarreau58f10d72006-12-04 02:26:12 +0100595 /* OK, that's enough processing for the first step.
596 * Now either we index this header or we remove it.
597 */
598
599 if (!delete_header) {
600 /* we insert it into the index */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100601 if (hdr_idx_add(eol - sol, req->lr - eol - 1,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100602 &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0) {
603 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100604 break;
605 }
606 } else {
607 /* we remove it */
608 delete_header = 0;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100609 buffer_replace2(req, sol, req->lr, NULL, 0);
610 /* WARNING: eol is not valid anymore, since the
Willy Tarreau58f10d72006-12-04 02:26:12 +0100611 * header may have been deleted or truncated ! */
612 }
613
614 /* In any case, we set the next header pointer
615 * to the next line.
616 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100617 sol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100618
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100619#ifdef DEBUG_PARSE_NO_SPEEDUP
620 t->hreq.hdr_state = HTTP_PA_HEADER;
621 continue;
622#else
Willy Tarreau58f10d72006-12-04 02:26:12 +0100623 /*
624 * We know that at least one character remains.
625 * It is interesting to directly branch to the
626 * matching state.
627 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100628 eol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100629 if (IS_CTL(*req->lr)) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100630 if (*eol == '\r') {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100631 req->lr++;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100632 t->hreq.hdr_state = HTTP_PA_LFLF | HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100633 continue;
634 }
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100635 else if (*eol == '\n') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100636 t->hreq.hdr_state = HTTP_PA_LFLF;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100637 goto parse_lflf;
638 }
639 else {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100640 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100641 break;
642 }
643 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100644 t->hreq.hdr_state = HTTP_PA_HEADER;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100645 goto parse_inside_hdr;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100646#endif
647
648 } else if (parse == HTTP_PA_STRT_LF) {
649 parse_strt_lf:
650 /* The LF validating the request line */
651
652 eol = req->lr;
653 if (t->hreq.hdr_state & HTTP_PA_CR_SKIP)
654 eol--; /* Get back to the CR */
655
656 /* We have the complete start line between
657 * sol and eol (excluded). lr points to
658 * the LF.
659 */
660
661 /* FIXME: insert a REQUESTURI hook here. */
662
663
664 /* 1: we might have to print this header */
665 if ((global.mode & MODE_DEBUG) &&
666 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
667 debug_hdr("clireq", t, sol, eol);
668
669 /* 2: maybe we have to copy the original REQURI for the logs ? */
670 if (t->logs.logwait & LW_REQ) {
671 /* we have a complete HTTP request that we must log */
672 if ((t->logs.uri = pool_alloc(requri)) != NULL) {
673 int urilen = eol - sol;
674
675 if (urilen >= REQURI_LEN)
676 urilen = REQURI_LEN - 1;
677 memcpy(t->logs.uri, sol, urilen);
678 t->logs.uri[urilen] = 0;
679
680 if (!(t->logs.logwait &= ~LW_REQ))
681 sess_log(t);
682 } else {
683 Alert("HTTP logging : out of memory.\n");
684 }
685 }
686
687 /* 3: reference this line as the start line */
688 if (hdr_idx_add(eol - sol, req->lr - eol,
689 &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0) {
690 t->hreq.hdr_state = HTTP_PA_ERROR;
691 break;
692 }
693
694 req->lr++;
695 sol = req->lr;
696 /* in fact, a state is missing here, we should
697 * be able to distinguish between an empty line
698 * and a header.
699 */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100700 t->hreq.hdr_state = HTTP_PA_HEADER;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100701#ifdef DEBUG_PARSE_NO_SPEEDUP
Willy Tarreau58f10d72006-12-04 02:26:12 +0100702 continue;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100703#else
704 if (req->lr < req->r)
705 goto parse_inside_hdr;
706 else
707 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100708#endif
709
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100710 } else if (parse == HTTP_PA_HEADER) {
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100711 char *ptr;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100712 /* Inside a non-empty header */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100713
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100714 parse_inside_hdr:
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100715 delete_header = 0;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100716
717 ptr = req->lr;
718
719#ifdef GCC_FINALLY_PRODUCES_EFFICIENT_WHILE_LOOPS
720 /* This code is disabled right now because
721 * eventhough it seems straightforward, the
722 * object code produced by GCC is so much
723 * suboptimal that about 10% of the time
724 * spend parsing header is there.
725 */
726 while (ptr < req->r && !IS_CTL(*ptr))
727 ptr++;
728 req->lr = ptr;
729 if (ptr == req->r)
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100730 break;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100731#else
732 /* Just by using this loop instead of the previous one,
733 * the global performance increases by about 2% ! The
734 * code is also smaller by about 50 bytes.
735 */
736 goto reqhdr_loop_chk;
737 reqhdr_loop:
738 ptr++;
739 reqhdr_loop_chk:
740 if (ptr == req->r) {
741 req->lr = ptr;
742 break;
743 }
744 if (*ptr != 0x7F && (unsigned)*ptr >= 0x20)
745 goto reqhdr_loop;
746 req->lr = ptr;
747#endif
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100748
749 /* we have a CTL char */
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100750 if (*ptr == '\r') {
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100751 t->hreq.hdr_state = HTTP_PA_HDR_LF | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
752 req->lr++;
753 continue;
754 }
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100755 else if (*ptr == '\n') {
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100756 t->hreq.hdr_state = HTTP_PA_HDR_LF;
757 QUICK_JUMP(parse_hdr_lf, continue);
758 }
759 t->hreq.hdr_state = HTTP_PA_ERROR;
760 break;
761
762 } else if (parse == HTTP_PA_EMPTY) {
763 /* leading empty lines */
764
765 if (*req->lr == '\n') {
766 req->lr ++;
767 t->hreq.hdr_state = HTTP_PA_EMPTY;
768 continue;
769 }
770 else if (*req->lr == '\r') {
771 req->lr ++;
772 t->hreq.hdr_state = HTTP_PA_EMPTY | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
773 continue;
774 }
775
776 FSM_PRINTF(stderr, "PA_EMPTY[0]: h=%d, lr=%d, r=%d\n",
777 sol - req->data, req->lr - req->data, req->r - req->data);
778
779#if PARSE_PRESERVE_EMPTY_LINES
780 /* only skip empty leading lines, don't remove them */
781 t->hreq.hdr_idx.v[0].len = req->lr - sol;
782 t->hreq.sor = t->hreq.hdr_idx.v[0].len;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100783#else
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100784 /* remove empty leading lines, as recommended by
785 * RFC2616. This takes a lot of time because we
786 * must move all the buffer backwards, but this
787 * is rarely needed. The method above will be
788 * cleaner when we'll be able to start sending
789 * the request from any place in the buffer.
790 */
791 buffer_replace2(req, sol, req->lr, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100792#endif
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100793 sol = req->lr;
794 FSM_PRINTF(stderr, "PA_EMPTY[1]: h=%d, lr=%d, r=%d\n",
795 sol - req->data, req->lr - req->data, req->r - req->data);
796
797 t->hreq.hdr_state = HTTP_PA_START;
798 /* we know that we still have one char available */
799 QUICK_JUMP(parse_start, continue);
800
801 } else if (parse == HTTP_PA_START) {
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100802 char *ptr;
803 /* Inside the start line */
804
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100805 parse_start:
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100806 ptr = req->lr;
807
808#ifdef GCC_FINALLY_PRODUCES_EFFICIENT_WHILE_LOOPS
809 /* This code is disabled right now because
810 * eventhough it seems straightforward, the
811 * object code produced by GCC is so much
812 * suboptimal that about 10% of the time
813 * spend parsing header is there.
814 */
815 while (ptr < req->r && !IS_CTL(*ptr))
816 ptr++;
817 req->lr = ptr;
818 if (ptr == req->r)
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100819 break;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100820#else
821 /* Just by using this loop instead of the previous one,
822 * the global performance increases by about 2% ! The
823 * code is also smaller by about 50 bytes.
824 */
825 goto reqstrt_loop_chk;
826 reqstrt_loop:
827 ptr++;
828 reqstrt_loop_chk:
829 if (ptr == req->r) {
830 req->lr = ptr;
831 break;
832 }
833 if (*ptr != 0x7F && (unsigned)*ptr >= 0x20)
834 goto reqstrt_loop;
835 req->lr = ptr;
836#endif
837
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100838 /* we have a CTL char */
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100839 if (*ptr == '\r') {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100840 req->lr++;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100841 t->hreq.hdr_state = HTTP_PA_STRT_LF | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
842 continue;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100843 }
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100844 else if (*ptr == '\n') {
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100845 t->hreq.hdr_state = HTTP_PA_STRT_LF;
846 /* we know that we still have one char available */
847 QUICK_JUMP(parse_strt_lf, continue);
848 }
849 t->hreq.hdr_state = HTTP_PA_ERROR;
850 break;
851
Willy Tarreau58f10d72006-12-04 02:26:12 +0100852
853 } else if (parse == HTTP_PA_LFLF) {
854 parse_lflf:
855 req->lr ++;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100856 /* sol points to either CR or CRLF, and
Willy Tarreau58f10d72006-12-04 02:26:12 +0100857 * req->lr points to 1 char after LF.
858 */
859
860 /*
861 * FIXME: insert a hook here for the end of the headers
862 */
863 break;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100864
865 } else if (parse == HTTP_PA_HDR_LWS) {
866 parse_hdr_lws:
867 /* Inside an LWS. We just replace tabs with
868 * spaces and fall back to the HEADER state
869 * at the first non-space character
870 */
871
872 while (req->lr < req->r) {
873 if (*req->lr == '\t')
874 *req->lr = ' ';
875 else if (*req->lr != ' ') {
876 t->hreq.hdr_state = HTTP_PA_HEADER;
877 QUICK_JUMP(parse_inside_hdr, break);
878 }
879 req->lr++;
880 }
881 continue;
882
Willy Tarreau58f10d72006-12-04 02:26:12 +0100883 } else if (parse == HTTP_PA_ERROR) {
884 break;
885 }
886
887 } /* end of the "while(req->lr < req->r)" loop */
888
Willy Tarreau45e73e32006-12-17 00:05:15 +0100889 /* update the end of headers */
890 t->hreq.eoh = sol - req->data;
891
892 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",
893 t->hreq.hdr_state, t->hreq.hdr_idx.used, t->hreq.hdr_idx.tail, t->hreq.hdr_idx.last,
894 sol - req->data, req->lr - req->data, req->r - req->data, t->hreq.eoh);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100895
896 /*
897 * Now, let's catch bad requests.
898 */
899
Willy Tarreau06619262006-12-17 08:37:22 +0100900 if (t->hreq.hdr_state == HTTP_PA_ERROR)
901 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100902
903 /*
904 * Now we quickly check if we have found a full request.
905 * If not so, we check the FD and buffer states before leaving.
906 * A full request is indicated by the fact that we have seen
907 * the double LF/CRLF, so the state is HTTP_PA_LFLF.
908 *
909 */
910
Willy Tarreau45e73e32006-12-17 00:05:15 +0100911 if (t->hreq.hdr_state != HTTP_PA_LFLF) { /* Request not complete yet */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100912
913 /* 1: Since we are in header mode, if there's no space
914 * left for headers, we won't be able to free more
915 * later, so the session will never terminate. We
916 * must terminate it now.
917 */
918 if (req->l >= req->rlim - req->data) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100919 /* FIXME: check if hreq.hdr_state & mask < HTTP_PA_HEADER,
Willy Tarreau58f10d72006-12-04 02:26:12 +0100920 * and return Status 414 Request URI too long instead.
921 */
Willy Tarreau06619262006-12-17 08:37:22 +0100922 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100923 }
924
925 /* 2: have we encountered a read error or a close ? */
926 else if (req->flags & (BF_READ_ERROR | BF_READ_NULL)) {
927 /* read error, or last read : give up. */
928 tv_eternity(&req->rex);
929 fd_delete(t->cli_fd);
930 t->cli_state = CL_STCLOSE;
931 if (!(t->flags & SN_ERR_MASK))
932 t->flags |= SN_ERR_CLICL;
933 if (!(t->flags & SN_FINST_MASK))
934 t->flags |= SN_FINST_R;
935 return 1;
936 }
937
938 /* 3: has the read timeout expired ? */
939 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
940 /* read timeout : give up with an error message. */
941 t->logs.status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +0100942 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreau58f10d72006-12-04 02:26:12 +0100943 if (!(t->flags & SN_ERR_MASK))
944 t->flags |= SN_ERR_CLITO;
945 if (!(t->flags & SN_FINST_MASK))
946 t->flags |= SN_FINST_R;
947 return 1;
948 }
949
950 /* 4: do we need to re-enable the read socket ? */
951 else if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
952 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
953 * full. We cannot loop here since stream_sock_read will disable it only if
954 * req->l == rlim-data
955 */
956 MY_FD_SET(t->cli_fd, StaticReadEvent);
957 if (t->fe->clitimeout)
958 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
959 else
960 tv_eternity(&req->rex);
961 }
962 return t->cli_state != CL_STHEADERS;
963 }
964
965
966 /****************************************************************
967 * More interesting part now : we know that we have a complete *
968 * request which at least looks like HTTP. We have an indicator *
969 * of each header's length, so we can parse them quickly. *
970 ****************************************************************/
971
972
973 /*
Willy Tarreau06619262006-12-17 08:37:22 +0100974 * 1: check if the URI matches the monitor_uri.
975 * We have to do this for every request which gets in, because
976 * the monitor-uri is defined by the frontend. To speed-up the
977 * test, we include the leading and trailing spaces in the
978 * comparison. This is generally not a problem because the
979 * monitor-uri is primarily used by external checkers which
980 * send pre-formatted requests too.
Willy Tarreau58f10d72006-12-04 02:26:12 +0100981 */
982
Willy Tarreau06619262006-12-17 08:37:22 +0100983 t->hreq.start.str = req->data + t->hreq.sor; /* start of the REQURI */
984 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 +0100985 t->hreq.meth = find_http_meth(t->hreq.start.str, t->hreq.start.len);
Willy Tarreau06619262006-12-17 08:37:22 +0100986
987 if ((t->fe->monitor_uri_len != 0) &&
988 (t->hreq.start.len >= t->fe->monitor_uri_len)) {
989 char *p = t->hreq.start.str;
990 int idx = 0;
991
992 /* skip the method so that we accept any method */
993 while (idx < t->hreq.start.len && p[idx] != ' ')
994 idx++;
995 p += idx;
996
997 if (t->hreq.start.len - idx >= t->fe->monitor_uri_len &&
998 !memcmp(p, t->fe->monitor_uri, t->fe->monitor_uri_len)) {
999 /*
1000 * We have found the monitor URI
1001 */
1002 t->flags |= SN_MONITOR;
1003 t->logs.status = 200;
Willy Tarreau0f772532006-12-23 20:51:41 +01001004 client_retnclose(t, &http_200_chunk);
Willy Tarreau06619262006-12-17 08:37:22 +01001005 goto return_prx_cond;
1006 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001007 }
1008
1009
1010 /*
1011 * 2: we will have to evaluate the filters.
1012 * As opposed to version 1.2, now they will be evaluated in the
1013 * filters order and not in the header order. This means that
1014 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001015 *
1016 * We can now check whether we want to switch to another
1017 * backend, in which case we will re-check the backend's
1018 * filters and various options. In order to support 3-level
1019 * switching, here's how we should proceed :
1020 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001021 * a) run be->fiprm.
1022 * if (switch) then switch ->be to the new backend.
1023 * b) run be->fiprm if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001024 * There cannot be any switch from there, so ->be cannot be
1025 * changed anymore.
1026 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001027 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001028 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001029 * The response path will be able to apply either ->be, or
1030 * ->be then ->fe filters in order to match the reverse of
1031 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001032 */
1033
Willy Tarreau06619262006-12-17 08:37:22 +01001034 do {
Willy Tarreau830ff452006-12-17 19:31:23 +01001035 struct proxy *rule_set = t->be->fiprm;
1036 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001037
Willy Tarreau06619262006-12-17 08:37:22 +01001038 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01001039 if (rule_set->req_exp != NULL) {
Willy Tarreau06619262006-12-17 08:37:22 +01001040 apply_filters_to_session(t, req, rule_set->req_exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001041
Willy Tarreau53b6c742006-12-17 13:37:46 +01001042 /* the start line might have been modified */
1043 t->hreq.start.len = t->hreq.hdr_idx.v[t->hreq.hdr_idx.v[0].next].len;
1044 t->hreq.meth = find_http_meth(t->hreq.start.str, t->hreq.start.len);
Willy Tarreau53b6c742006-12-17 13:37:46 +01001045 }
1046
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001047 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
1048 /* to ensure correct connection accounting on
1049 * the backend, we count the connection for the
1050 * one managing the queue.
1051 */
1052 t->be->beprm->beconn++;
1053 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1054 t->be->beprm->beconn_max = t->be->beprm->beconn;
1055 t->be->beprm->cum_beconn++;
1056 t->flags |= SN_BE_ASSIGNED;
1057 }
1058
Willy Tarreau06619262006-12-17 08:37:22 +01001059 /* has the request been denied ? */
1060 if (t->flags & SN_CLDENY) {
1061 /* no need to go further */
1062 t->logs.status = 403;
1063 /* let's log the request time */
1064 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreau80587432006-12-24 17:47:20 +01001065 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01001066 goto return_prx_cond;
1067 }
1068
1069 /* add request headers from the rule sets in the same order */
1070 for (cur_hdr = 0; cur_hdr < rule_set->nb_reqadd; cur_hdr++) {
1071 int len;
1072
1073 len = sprintf(trash, "%s\r\n", rule_set->req_add[cur_hdr]);
1074 len = buffer_replace2(req, req->data + t->hreq.eoh,
1075 req->data + t->hreq.eoh, trash, len);
1076 t->hreq.eoh += len;
1077
1078 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1079 goto return_bad_req;
1080 }
Willy Tarreaub2513902006-12-17 14:52:38 +01001081
1082 if (rule_set->uri_auth != NULL && t->hreq.meth == HTTP_METH_GET) {
1083 /* we have to check the URI and auth for this request */
1084 if (stats_check_uri_auth(t, rule_set))
1085 return 1;
1086 }
1087
Willy Tarreau830ff452006-12-17 19:31:23 +01001088 } while (cur_proxy != t->be); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01001089
Willy Tarreau58f10d72006-12-04 02:26:12 +01001090
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001091 if (!(t->flags & SN_BE_ASSIGNED)) {
1092 /* To ensure correct connection accounting on
1093 * the backend, we count the connection for the
1094 * one managing the queue.
1095 */
1096 t->be->beprm->beconn++;
1097 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1098 t->be->beprm->beconn_max = t->be->beprm->beconn;
1099 t->be->beprm->cum_beconn++;
1100 t->flags |= SN_BE_ASSIGNED;
1101 }
1102
1103
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001104 /*
1105 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01001106 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001107 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01001108 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01001109 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001110
Willy Tarreau58f10d72006-12-04 02:26:12 +01001111
Willy Tarreau58f10d72006-12-04 02:26:12 +01001112
Willy Tarreau58f10d72006-12-04 02:26:12 +01001113
Willy Tarreau2a324282006-12-05 00:05:46 +01001114 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001115 * 3: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01001116 * so let's do the same now.
1117 */
1118
1119 /* It needs to look into the URI */
Willy Tarreau830ff452006-12-17 19:31:23 +01001120 if (t->be->beprm->appsession_name) {
Willy Tarreau06619262006-12-17 08:37:22 +01001121 get_srv_from_appsession(t,
1122 t->hreq.start.str,
1123 t->hreq.start.str + t->hreq.start.len);
1124 }
1125
1126
1127 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001128 * 4: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01001129 * Note that doing so might move headers in the request, but
1130 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01001131 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01001132 */
1133 if (!(t->flags & (SN_CLDENY|SN_CLTARPIT)))
1134 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001135
Willy Tarreau58f10d72006-12-04 02:26:12 +01001136
Willy Tarreau2a324282006-12-05 00:05:46 +01001137 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001138 * 5: add X-Forwarded-For : Should depend on the backend only.
Willy Tarreau2a324282006-12-05 00:05:46 +01001139 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001140 if (t->be->beprm->options & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001141 if (t->cli_addr.ss_family == AF_INET) {
1142 int len;
1143 unsigned char *pn;
1144 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
1145 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
1146 pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001147 len = buffer_replace2(req, req->data + t->hreq.eoh,
1148 req->data + t->hreq.eoh, trash, len);
1149 t->hreq.eoh += len;
1150
Willy Tarreau06619262006-12-17 08:37:22 +01001151 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1152 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001153 }
1154 else if (t->cli_addr.ss_family == AF_INET6) {
1155 int len;
1156 char pn[INET6_ADDRSTRLEN];
1157 inet_ntop(AF_INET6,
1158 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
1159 pn, sizeof(pn));
1160 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001161 len = buffer_replace2(req, req->data + t->hreq.eoh,
1162 req->data + t->hreq.eoh, trash, len);
1163 t->hreq.eoh += len;
1164
Willy Tarreau06619262006-12-17 08:37:22 +01001165 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1166 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001167 }
1168 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001169
Willy Tarreaubaaee002006-06-26 02:48:02 +02001170
Willy Tarreau2a324282006-12-05 00:05:46 +01001171 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001172 * 6: add "Connection:"
Willy Tarreau2a324282006-12-05 00:05:46 +01001173 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001174
Willy Tarreaub2513902006-12-17 14:52:38 +01001175 /* add a "connection: close" line if needed.
1176 * FIXME: this should depend on both the frontend and the backend.
1177 * Header removals should be performed when the filters are run.
1178 */
Willy Tarreaue01954f2006-12-30 23:43:54 +01001179 if ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) {
Willy Tarreau45e73e32006-12-17 00:05:15 +01001180 int len;
1181 len = buffer_replace2(req, req->data + t->hreq.eoh,
1182 req->data + t->hreq.eoh, "Connection: close\r\n", 19);
1183 t->hreq.eoh += len;
1184
Willy Tarreau06619262006-12-17 08:37:22 +01001185 if (hdr_idx_add(17, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
1186 goto return_bad_req;
Willy Tarreaue15d9132006-12-14 22:26:42 +01001187 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001188
Willy Tarreaubaaee002006-06-26 02:48:02 +02001189
Willy Tarreaue15d9132006-12-14 22:26:42 +01001190
1191
Willy Tarreau06619262006-12-17 08:37:22 +01001192
Willy Tarreaue15d9132006-12-14 22:26:42 +01001193
Willy Tarreau2a324282006-12-05 00:05:46 +01001194 /*************************************************************
1195 * OK, that's finished for the headers. We have done what we *
1196 * could. Let's switch to the DATA state. *
1197 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02001198
Willy Tarreau2a324282006-12-05 00:05:46 +01001199 t->cli_state = CL_STDATA;
1200 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001201
Willy Tarreau2a324282006-12-05 00:05:46 +01001202 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001203
Willy Tarreaubaaee002006-06-26 02:48:02 +02001204
Willy Tarreau2a324282006-12-05 00:05:46 +01001205 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001206 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001207 /* If the client has no timeout, or if the server is not ready yet,
1208 * and we know for sure that it can expire, then it's cleaner to
1209 * disable the timeout on the client side so that too low values
1210 * cannot make the sessions abort too early.
1211 *
1212 * FIXME-20050705: the server needs a way to re-enable this time-out
1213 * when it switches its state, otherwise a client can stay connected
1214 * indefinitely. This now seems to be OK.
1215 */
1216 tv_eternity(&req->rex);
1217 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001218
Willy Tarreaub8750a82006-09-03 09:56:00 +02001219
Willy Tarreau2a324282006-12-05 00:05:46 +01001220 /* When a connection is tarpitted, we use the queue timeout for the
1221 * tarpit delay, which currently happens to be the server's connect
1222 * timeout. If unset, then set it to zero because we really want it
1223 * to expire at one moment.
1224 */
1225 if (t->flags & SN_CLTARPIT) {
1226 t->req->l = 0;
1227 /* flush the request so that we can drop the connection early
1228 * if the client closes first.
1229 */
1230 tv_delayfrom(&req->cex, &now,
Willy Tarreau830ff452006-12-17 19:31:23 +01001231 t->be->beprm->contimeout ? t->be->beprm->contimeout : 0);
Willy Tarreau2a324282006-12-05 00:05:46 +01001232 }
Willy Tarreaub8750a82006-09-03 09:56:00 +02001233
Willy Tarreau2a324282006-12-05 00:05:46 +01001234#if DEBUG_HTTP_PARSER
1235 /* example: dump each line */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001236
Willy Tarreau2a324282006-12-05 00:05:46 +01001237 fprintf(stderr, "t->flags=0x%08x\n", t->flags & (SN_CLALLOW|SN_CLDENY|SN_CLTARPIT));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001238
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001239 fprintf(stderr, "sol=%d\n", sol - req->data);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001240 sol = req->data + t->hreq.sor;
Willy Tarreau2a324282006-12-05 00:05:46 +01001241 cur_hdr = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001242
Willy Tarreau45e73e32006-12-17 00:05:15 +01001243 cur_idx = t->hreq.hdr_idx.v[0].next;
Willy Tarreau2a324282006-12-05 00:05:46 +01001244 cur_hdr = 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001245
Willy Tarreau45e73e32006-12-17 00:05:15 +01001246 while (cur_hdr < t->hreq.hdr_idx.used) {
1247 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 +01001248 fprintf(stderr, "lr=%d r=%d hdr=%d idx=%d adr=%d..%d len=%d cr=%d data:\n",
1249 req->lr - req->data, req->r - req->data,
1250 cur_hdr, cur_idx,
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001251 sol - req->data,
Willy Tarreau45e73e32006-12-17 00:05:15 +01001252 sol - req->data + t->hreq.hdr_idx.v[cur_idx].len + t->hreq.hdr_idx.v[cur_idx].cr,
1253 t->hreq.hdr_idx.v[cur_idx].len,
1254 t->hreq.hdr_idx.v[cur_idx].cr);
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001255 write(2, sol, eol - sol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001256
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001257 sol = eol;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001258 cur_idx = t->hreq.hdr_idx.v[cur_idx].next;
Willy Tarreau2a324282006-12-05 00:05:46 +01001259 cur_hdr++;
1260 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001261#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001262
Willy Tarreau06619262006-12-17 08:37:22 +01001263 goto process_data;
1264
1265 return_bad_req: /* let's centralize all bad requests */
1266 t->hreq.hdr_state = HTTP_PA_ERROR;
1267 t->logs.status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01001268 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreau06619262006-12-17 08:37:22 +01001269 return_prx_cond:
1270 if (!(t->flags & SN_ERR_MASK))
1271 t->flags |= SN_ERR_PRXCOND;
1272 if (!(t->flags & SN_FINST_MASK))
1273 t->flags |= SN_FINST_R;
1274 return 1;
1275
Willy Tarreaubaaee002006-06-26 02:48:02 +02001276 }
1277 else if (c == CL_STDATA) {
1278 process_data:
1279 /* FIXME: this error handling is partly buggy because we always report
1280 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
1281 * or HEADER phase. BTW, it's not logical to expire the client while
1282 * we're waiting for the server to connect.
1283 */
1284 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001285 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001286 tv_eternity(&req->rex);
1287 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001288 fd_delete(t->cli_fd);
1289 t->cli_state = CL_STCLOSE;
1290 if (!(t->flags & SN_ERR_MASK))
1291 t->flags |= SN_ERR_CLICL;
1292 if (!(t->flags & SN_FINST_MASK)) {
1293 if (t->pend_pos)
1294 t->flags |= SN_FINST_Q;
1295 else if (s == SV_STCONN)
1296 t->flags |= SN_FINST_C;
1297 else
1298 t->flags |= SN_FINST_D;
1299 }
1300 return 1;
1301 }
1302 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001303 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001304 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001305 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001306 shutdown(t->cli_fd, SHUT_RD);
1307 t->cli_state = CL_STSHUTR;
1308 return 1;
1309 }
1310 /* last server read and buffer empty */
1311 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001312 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001313 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001314 shutdown(t->cli_fd, SHUT_WR);
1315 /* We must ensure that the read part is still alive when switching
1316 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001317 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001318 if (t->fe->clitimeout)
1319 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001320 t->cli_state = CL_STSHUTW;
1321 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1322 return 1;
1323 }
1324 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001325 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001326 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001327 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001328 shutdown(t->cli_fd, SHUT_RD);
1329 t->cli_state = CL_STSHUTR;
1330 if (!(t->flags & SN_ERR_MASK))
1331 t->flags |= SN_ERR_CLITO;
1332 if (!(t->flags & SN_FINST_MASK)) {
1333 if (t->pend_pos)
1334 t->flags |= SN_FINST_Q;
1335 else if (s == SV_STCONN)
1336 t->flags |= SN_FINST_C;
1337 else
1338 t->flags |= SN_FINST_D;
1339 }
1340 return 1;
1341 }
1342 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001343 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001344 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001345 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001346 shutdown(t->cli_fd, SHUT_WR);
1347 /* We must ensure that the read part is still alive when switching
1348 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001349 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001350 if (t->fe->clitimeout)
1351 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001352
1353 t->cli_state = CL_STSHUTW;
1354 if (!(t->flags & SN_ERR_MASK))
1355 t->flags |= SN_ERR_CLITO;
1356 if (!(t->flags & SN_FINST_MASK)) {
1357 if (t->pend_pos)
1358 t->flags |= SN_FINST_Q;
1359 else if (s == SV_STCONN)
1360 t->flags |= SN_FINST_C;
1361 else
1362 t->flags |= SN_FINST_D;
1363 }
1364 return 1;
1365 }
1366
1367 if (req->l >= req->rlim - req->data) {
1368 /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02001369 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001370 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001371 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001372 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001373 }
1374 } else {
1375 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001376 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1377 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001378 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001379 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001380 /* If the client has no timeout, or if the server not ready yet, and we
1381 * know for sure that it can expire, then it's cleaner to disable the
1382 * timeout on the client side so that too low values cannot make the
1383 * sessions abort too early.
1384 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001385 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001386 else
Willy Tarreau73de9892006-11-30 11:40:23 +01001387 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001388 }
1389 }
1390
1391 if ((rep->l == 0) ||
1392 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001393 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1394 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001395 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001396 }
1397 } else {
1398 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001399 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1400 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001401 if (t->fe->clitimeout) {
1402 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001403 /* FIXME: to prevent the client from expiring read timeouts during writes,
1404 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001405 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001406 }
1407 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001408 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001409 }
1410 }
1411 return 0; /* other cases change nothing */
1412 }
1413 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001414 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001415 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001416 fd_delete(t->cli_fd);
1417 t->cli_state = CL_STCLOSE;
1418 if (!(t->flags & SN_ERR_MASK))
1419 t->flags |= SN_ERR_CLICL;
1420 if (!(t->flags & SN_FINST_MASK)) {
1421 if (t->pend_pos)
1422 t->flags |= SN_FINST_Q;
1423 else if (s == SV_STCONN)
1424 t->flags |= SN_FINST_C;
1425 else
1426 t->flags |= SN_FINST_D;
1427 }
1428 return 1;
1429 }
1430 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
1431 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001432 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001433 fd_delete(t->cli_fd);
1434 t->cli_state = CL_STCLOSE;
1435 return 1;
1436 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001437 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
1438 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001439 fd_delete(t->cli_fd);
1440 t->cli_state = CL_STCLOSE;
1441 if (!(t->flags & SN_ERR_MASK))
1442 t->flags |= SN_ERR_CLITO;
1443 if (!(t->flags & SN_FINST_MASK)) {
1444 if (t->pend_pos)
1445 t->flags |= SN_FINST_Q;
1446 else if (s == SV_STCONN)
1447 t->flags |= SN_FINST_C;
1448 else
1449 t->flags |= SN_FINST_D;
1450 }
1451 return 1;
1452 }
1453
1454 if (t->flags & SN_SELF_GEN) {
1455 produce_content(t);
1456 if (rep->l == 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001457 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001458 fd_delete(t->cli_fd);
1459 t->cli_state = CL_STCLOSE;
1460 return 1;
1461 }
1462 }
1463
1464 if ((rep->l == 0)
1465 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001466 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1467 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001468 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001469 }
1470 } else {
1471 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001472 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1473 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001474 if (t->fe->clitimeout) {
1475 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001476 /* FIXME: to prevent the client from expiring read timeouts during writes,
1477 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001478 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001479 }
1480 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001481 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001482 }
1483 }
1484 return 0;
1485 }
1486 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001487 if (req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001488 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001489 fd_delete(t->cli_fd);
1490 t->cli_state = CL_STCLOSE;
1491 if (!(t->flags & SN_ERR_MASK))
1492 t->flags |= SN_ERR_CLICL;
1493 if (!(t->flags & SN_FINST_MASK)) {
1494 if (t->pend_pos)
1495 t->flags |= SN_FINST_Q;
1496 else if (s == SV_STCONN)
1497 t->flags |= SN_FINST_C;
1498 else
1499 t->flags |= SN_FINST_D;
1500 }
1501 return 1;
1502 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001503 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001504 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001505 fd_delete(t->cli_fd);
1506 t->cli_state = CL_STCLOSE;
1507 return 1;
1508 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001509 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
1510 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001511 fd_delete(t->cli_fd);
1512 t->cli_state = CL_STCLOSE;
1513 if (!(t->flags & SN_ERR_MASK))
1514 t->flags |= SN_ERR_CLITO;
1515 if (!(t->flags & SN_FINST_MASK)) {
1516 if (t->pend_pos)
1517 t->flags |= SN_FINST_Q;
1518 else if (s == SV_STCONN)
1519 t->flags |= SN_FINST_C;
1520 else
1521 t->flags |= SN_FINST_D;
1522 }
1523 return 1;
1524 }
1525 else if (req->l >= req->rlim - req->data) {
1526 /* no room to read more data */
1527
1528 /* FIXME-20050705: is it possible for a client to maintain a session
1529 * after the timeout by sending more data after it receives a close ?
1530 */
1531
Willy Tarreau2a429502006-10-15 14:52:29 +02001532 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001533 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001534 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001535 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001536 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1537 }
1538 } else {
1539 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001540 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1541 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001542 if (t->fe->clitimeout)
1543 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001544 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001545 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001546 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1547 }
1548 }
1549 return 0;
1550 }
1551 else { /* CL_STCLOSE: nothing to do */
1552 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1553 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01001554 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 +02001555 write(1, trash, len);
1556 }
1557 return 0;
1558 }
1559 return 0;
1560}
1561
1562
1563/*
1564 * manages the server FSM and its socket. It returns 1 if a state has changed
1565 * (and a resync may be needed), 0 else.
1566 */
1567int process_srv(struct session *t)
1568{
1569 int s = t->srv_state;
1570 int c = t->cli_state;
1571 struct buffer *req = t->req;
1572 struct buffer *rep = t->rep;
1573 appsess *asession_temp = NULL;
1574 appsess local_asession;
1575 int conn_err;
1576
1577#ifdef DEBUG_FULL
1578 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
1579#endif
1580 //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 +02001581 //MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
1582 //MY_FD_ISSET(t->srv_fd, StaticReadEvent), MY_FD_ISSET(t->srv_fd, StaticWriteEvent)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001583 //);
1584 if (s == SV_STIDLE) {
1585 if (c == CL_STHEADERS)
1586 return 0; /* stay in idle, waiting for data to reach the client side */
1587 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
1588 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001589 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001590 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001591 if (t->pend_pos)
1592 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1593 /* note that this must not return any error because it would be able to
1594 * overwrite the client_retnclose() output.
1595 */
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001596 if (t->flags & SN_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01001597 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001598 else
Willy Tarreau0f772532006-12-23 20:51:41 +01001599 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001600
1601 return 1;
1602 }
1603 else {
Willy Tarreaub8750a82006-09-03 09:56:00 +02001604 if (t->flags & SN_CLTARPIT) {
1605 /* This connection is being tarpitted. The CLIENT side has
1606 * already set the connect expiration date to the right
1607 * timeout. We just have to check that it has not expired.
1608 */
1609 if (tv_cmp2_ms(&req->cex, &now) > 0)
1610 return 0;
1611
1612 /* We will set the queue timer to the time spent, just for
1613 * logging purposes. We fake a 500 server error, so that the
1614 * attacker will not suspect his connection has been tarpitted.
1615 * It will not cause trouble to the logs because we can exclude
1616 * the tarpitted connections by filtering on the 'PT' status flags.
1617 */
1618 tv_eternity(&req->cex);
1619 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1620 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01001621 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02001622 return 1;
1623 }
1624
Willy Tarreaubaaee002006-06-26 02:48:02 +02001625 /* Right now, we will need to create a connection to the server.
1626 * We might already have tried, and got a connection pending, in
1627 * which case we will not do anything till it's pending. It's up
1628 * to any other session to release it and wake us up again.
1629 */
1630 if (t->pend_pos) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001631 if (tv_cmp2_ms(&req->cex, &now) > 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001632 return 0;
1633 else {
1634 /* we've been waiting too long here */
Willy Tarreaud7971282006-07-29 18:36:34 +02001635 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001636 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1637 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01001638 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001639 if (t->srv)
1640 t->srv->failed_conns++;
Willy Tarreau73de9892006-11-30 11:40:23 +01001641 t->fe->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001642 return 1;
1643 }
1644 }
1645
1646 do {
1647 /* first, get a connection */
1648 if (srv_redispatch_connect(t))
1649 return t->srv_state != SV_STIDLE;
1650
1651 /* try to (re-)connect to the server, and fail if we expire the
1652 * number of retries.
1653 */
1654 if (srv_retryable_connect(t)) {
1655 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1656 return t->srv_state != SV_STIDLE;
1657 }
1658
1659 } while (1);
1660 }
1661 }
1662 else if (s == SV_STCONN) { /* connection in progress */
1663 if (c == CL_STCLOSE || c == CL_STSHUTW ||
1664 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001665 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001666 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001667 fd_delete(t->srv_fd);
1668 if (t->srv)
1669 t->srv->cur_sess--;
1670
1671 /* note that this must not return any error because it would be able to
1672 * overwrite the client_retnclose() output.
1673 */
Willy Tarreau0f772532006-12-23 20:51:41 +01001674 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001675 return 1;
1676 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001677 if (!(req->flags & BF_WRITE_STATUS) && tv_cmp2_ms(&req->cex, &now) > 0) {
1678 //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 +02001679 return 0; /* nothing changed */
1680 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001681 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001682 /* timeout, asynchronous connect error or first write error */
1683 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
1684
1685 fd_delete(t->srv_fd);
1686 if (t->srv)
1687 t->srv->cur_sess--;
1688
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001689 if (!(req->flags & BF_WRITE_STATUS))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001690 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
1691 else
1692 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
1693
1694 /* ensure that we have enough retries left */
1695 if (srv_count_retry_down(t, conn_err))
1696 return 1;
1697
Willy Tarreau830ff452006-12-17 19:31:23 +01001698 if (t->srv && t->conn_retries == 0 && t->be->beprm->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001699 /* We're on our last chance, and the REDISP option was specified.
1700 * We will ignore cookie and force to balance or use the dispatcher.
1701 */
1702 /* let's try to offer this slot to anybody */
Willy Tarreau830ff452006-12-17 19:31:23 +01001703 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001704 task_wakeup(&rq, t->srv->queue_mgt);
1705
1706 if (t->srv)
1707 t->srv->failed_conns++;
Willy Tarreau830ff452006-12-17 19:31:23 +01001708 t->be->beprm->failed_conns++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001709
1710 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
1711 t->srv = NULL; /* it's left to the dispatcher to choose a server */
1712 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
1713 t->flags &= ~SN_CK_MASK;
1714 t->flags |= SN_CK_DOWN;
1715 }
1716
1717 /* first, get a connection */
1718 if (srv_redispatch_connect(t))
1719 return t->srv_state != SV_STIDLE;
1720 }
1721
Willy Tarreaubaaee002006-06-26 02:48:02 +02001722 do {
1723 /* Now we will try to either reconnect to the same server or
1724 * connect to another server. If the connection gets queued
1725 * because all servers are saturated, then we will go back to
1726 * the SV_STIDLE state.
1727 */
1728 if (srv_retryable_connect(t)) {
1729 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1730 return t->srv_state != SV_STCONN;
1731 }
1732
1733 /* we need to redispatch the connection to another server */
1734 if (srv_redispatch_connect(t))
1735 return t->srv_state != SV_STCONN;
1736 } while (1);
1737 }
1738 else { /* no error or write 0 */
1739 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
1740
1741 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
1742 if (req->l == 0) /* nothing to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02001743 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001744 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001745 } else /* need the right to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02001746 MY_FD_SET(t->srv_fd, StaticWriteEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001747 if (t->be->beprm->srvtimeout) {
1748 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001749 /* FIXME: to prevent the server from expiring read timeouts during writes,
1750 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001751 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001752 }
1753 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001754 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001755 }
1756
Willy Tarreau830ff452006-12-17 19:31:23 +01001757 if (t->be->beprm->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreau2a429502006-10-15 14:52:29 +02001758 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001759 if (t->be->beprm->srvtimeout)
1760 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001761 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001762 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001763
1764 t->srv_state = SV_STDATA;
1765 if (t->srv)
1766 t->srv->cum_sess++;
1767 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
1768
1769 /* if the user wants to log as soon as possible, without counting
1770 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001771 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001772 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
1773 sess_log(t);
1774 }
1775 }
1776 else {
1777 t->srv_state = SV_STHEADERS;
1778 if (t->srv)
1779 t->srv->cum_sess++;
1780 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
1781 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001782 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001783 return 1;
1784 }
1785 }
1786 else if (s == SV_STHEADERS) { /* receiving server headers */
1787 /* now parse the partial (or complete) headers */
1788 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
1789 char *ptr;
1790 int delete_header;
1791
1792 ptr = rep->lr;
1793
1794 /* look for the end of the current header */
1795 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
1796 ptr++;
1797
1798 if (ptr == rep->h) {
1799 int line, len;
1800
1801 /* we can only get here after an end of headers */
1802
1803 /* first, we'll block if security checks have caught nasty things */
1804 if (t->flags & SN_CACHEABLE) {
1805 if ((t->flags & SN_CACHE_COOK) &&
1806 (t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001807 (t->be->beprm->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001808
1809 /* we're in presence of a cacheable response containing
1810 * a set-cookie header. We'll block it as requested by
1811 * the 'checkcache' option, and send an alert.
1812 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001813 tv_eternity(&rep->rex);
1814 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001815 fd_delete(t->srv_fd);
1816 if (t->srv) {
1817 t->srv->cur_sess--;
1818 t->srv->failed_secu++;
1819 }
Willy Tarreau73de9892006-11-30 11:40:23 +01001820 t->be->failed_secu++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001821 t->srv_state = SV_STCLOSE;
1822 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01001823 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001824 if (!(t->flags & SN_ERR_MASK))
1825 t->flags |= SN_ERR_PRXCOND;
1826 if (!(t->flags & SN_FINST_MASK))
1827 t->flags |= SN_FINST_H;
1828
Willy Tarreau830ff452006-12-17 19:31:23 +01001829 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->be->beprm->id, t->srv->id);
1830 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 +02001831
1832 /* We used to have a free connection slot. Since we'll never use it,
1833 * we have to inform the server that it may be used by another session.
1834 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001835 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001836 task_wakeup(&rq, t->srv->queue_mgt);
1837
1838 return 1;
1839 }
1840 }
1841
1842 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
1843 if (t->flags & SN_SVDENY) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001844 tv_eternity(&rep->rex);
1845 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001846 fd_delete(t->srv_fd);
1847 if (t->srv) {
1848 t->srv->cur_sess--;
1849 t->srv->failed_secu++;
1850 }
Willy Tarreau73de9892006-11-30 11:40:23 +01001851 t->be->failed_secu++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001852 t->srv_state = SV_STCLOSE;
1853 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01001854 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001855 if (!(t->flags & SN_ERR_MASK))
1856 t->flags |= SN_ERR_PRXCOND;
1857 if (!(t->flags & SN_FINST_MASK))
1858 t->flags |= SN_FINST_H;
1859 /* We used to have a free connection slot. Since we'll never use it,
1860 * we have to inform the server that it may be used by another session.
1861 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001862 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001863 task_wakeup(&rq, t->srv->queue_mgt);
1864
1865 return 1;
1866 }
1867
1868 /* we'll have something else to do here : add new headers ... */
1869
Willy Tarreau830ff452006-12-17 19:31:23 +01001870 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_INS) &&
1871 (!(t->be->beprm->options & PR_O_COOK_POST) || (t->hreq.meth == HTTP_METH_POST))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001872 /* the server is known, it's not the one the client requested, we have to
1873 * insert a set-cookie here, except if we want to insert only on POST
1874 * requests and this one isn't. Note that servers which don't have cookies
1875 * (eg: some backup servers) will return a full cookie removal request.
1876 */
1877 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
Willy Tarreau830ff452006-12-17 19:31:23 +01001878 t->be->beprm->cookie_name,
Willy Tarreaubaaee002006-06-26 02:48:02 +02001879 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
1880
1881 t->flags |= SN_SCK_INSERTED;
1882
1883 /* Here, we will tell an eventual cache on the client side that we don't
1884 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
1885 * Some caches understand the correct form: 'no-cache="set-cookie"', but
1886 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
1887 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001888 if (t->be->beprm->options & PR_O_COOK_NOC)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001889 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
1890 len += sprintf(trash + len, "Cache-control: private\r\n");
1891
1892 if (rep->data + rep->l < rep->h)
1893 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
1894 *(int *)0 = 0;
1895 buffer_replace2(rep, rep->h, rep->h, trash, len);
1896 }
1897
1898 /* headers to be added */
Willy Tarreau830ff452006-12-17 19:31:23 +01001899 /* FIXME: we should add headers from BE then from FE */
1900 for (line = 0; line < t->be->fiprm->nb_rspadd; line++) {
1901 len = sprintf(trash, "%s\r\n", t->be->fiprm->rsp_add[line]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001902 buffer_replace2(rep, rep->h, rep->h, trash, len);
1903 }
1904
1905 /* add a "connection: close" line if needed */
Willy Tarreaue01954f2006-12-30 23:43:54 +01001906 if ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001907 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
1908
1909 t->srv_state = SV_STDATA;
1910 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
1911 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
1912
1913 /* client connection already closed or option 'httpclose' required :
1914 * we close the server's outgoing connection right now.
1915 */
1916 if ((req->l == 0) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001917 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->beprm->options & PR_O_FORCE_CLO)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001918 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001919 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001920
1921 /* We must ensure that the read part is still alive when switching
1922 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001923 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001924 if (t->be->beprm->srvtimeout)
1925 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001926
1927 shutdown(t->srv_fd, SHUT_WR);
1928 t->srv_state = SV_STSHUTW;
1929 }
1930
1931 /* if the user wants to log as soon as possible, without counting
1932 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001933 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001934 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
1935 t->logs.bytes = rep->h - rep->data;
1936 sess_log(t);
1937 }
1938 break;
1939 }
1940
1941 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1942 if (ptr > rep->r - 2) {
1943 /* this is a partial header, let's wait for more to come */
1944 rep->lr = ptr;
1945 break;
1946 }
1947
1948 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
1949 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
1950
1951 /* now we know that *ptr is either \r or \n,
1952 * and that there are at least 1 char after it.
1953 */
1954 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
1955 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
1956 else
1957 rep->lr = ptr + 2; /* \r\n or \n\r */
1958
1959 /*
1960 * now we know that we have a full header ; we can do whatever
1961 * we want with these pointers :
1962 * rep->h = beginning of header
1963 * ptr = end of header (first \r or \n)
1964 * rep->lr = beginning of next line (next rep->h)
1965 * rep->r = end of data (not used at this stage)
1966 */
1967
1968
1969 if (t->logs.status == -1) {
1970 t->logs.logwait &= ~LW_RESP;
1971 t->logs.status = atoi(rep->h + 9);
1972 switch (t->logs.status) {
1973 case 200:
1974 case 203:
1975 case 206:
1976 case 300:
1977 case 301:
1978 case 410:
1979 /* RFC2616 @13.4:
1980 * "A response received with a status code of
1981 * 200, 203, 206, 300, 301 or 410 MAY be stored
1982 * by a cache (...) unless a cache-control
1983 * directive prohibits caching."
1984 *
1985 * RFC2616 @9.5: POST method :
1986 * "Responses to this method are not cacheable,
1987 * unless the response includes appropriate
1988 * Cache-Control or Expires header fields."
1989 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001990 if (!(t->hreq.meth == HTTP_METH_POST) && (t->be->beprm->options & PR_O_CHK_CACHE))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001991 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
1992 break;
1993 default:
1994 break;
1995 }
1996 }
1997 else if (t->logs.logwait & LW_RSPHDR) {
1998 struct cap_hdr *h;
1999 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01002000 for (h = t->fe->fiprm->rsp_cap; h; h = h->next) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002001 if ((h->namelen + 2 <= ptr - rep->h) &&
2002 (rep->h[h->namelen] == ':') &&
2003 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
2004
2005 if (t->rsp_cap[h->index] == NULL)
2006 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
2007
2008 len = ptr - (rep->h + h->namelen + 2);
2009 if (len > h->len)
2010 len = h->len;
2011
2012 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
2013 t->rsp_cap[h->index][len]=0;
2014 }
2015 }
2016
2017 }
2018
2019 delete_header = 0;
2020
Willy Tarreau58f10d72006-12-04 02:26:12 +01002021 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
2022 debug_hdr("srvhdr", t, rep->h, ptr);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002023
2024 /* remove "connection: " if needed */
Willy Tarreaue01954f2006-12-30 23:43:54 +01002025 if (!delete_header &&
2026 ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) &&
2027 (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002028 delete_header = 1;
2029 }
2030
2031 /* try headers regexps */
Willy Tarreau830ff452006-12-17 19:31:23 +01002032 if (!delete_header && t->be->fiprm->rsp_exp != NULL
Willy Tarreaubaaee002006-06-26 02:48:02 +02002033 && !(t->flags & SN_SVDENY)) {
2034 struct hdr_exp *exp;
2035 char term;
2036
2037 term = *ptr;
2038 *ptr = '\0';
Willy Tarreau830ff452006-12-17 19:31:23 +01002039 exp = t->be->fiprm->rsp_exp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002040 do {
2041 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2042 switch (exp->action) {
2043 case ACT_ALLOW:
2044 if (!(t->flags & SN_SVDENY))
2045 t->flags |= SN_SVALLOW;
2046 break;
2047 case ACT_REPLACE:
2048 if (!(t->flags & SN_SVDENY)) {
2049 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
2050 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2051 }
2052 break;
2053 case ACT_REMOVE:
2054 if (!(t->flags & SN_SVDENY))
2055 delete_header = 1;
2056 break;
2057 case ACT_DENY:
2058 if (!(t->flags & SN_SVALLOW))
2059 t->flags |= SN_SVDENY;
2060 break;
2061 case ACT_PASS: /* we simply don't deny this one */
2062 break;
2063 }
2064 break;
2065 }
2066 } while ((exp = exp->next) != NULL);
2067 *ptr = term; /* restore the string terminator */
2068 }
2069
2070 /* check for cache-control: or pragma: headers */
2071 if (!delete_header && (t->flags & SN_CACHEABLE)) {
2072 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
2073 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2074 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
2075 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
2076 if (rep->h + 23 == ptr || rep->h[23] == ',')
2077 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2078 else {
2079 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
2080 && (rep->h[35] == '"' || rep->h[35] == ','))
2081 t->flags &= ~SN_CACHE_COOK;
2082 }
2083 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
2084 (rep->h + 22 == ptr || rep->h[22] == ','))
2085 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
2086 (rep->h + 23 == ptr || rep->h[23] == ','))) {
2087 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2088 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
2089 (rep->h + 24 == ptr || rep->h[24] == ',')) {
2090 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2091 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
2092 (rep->h + 25 == ptr || rep->h[25] == ',')) {
2093 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2094 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
2095 (rep->h + 21 == ptr || rep->h[21] == ',')) {
2096 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
2097 }
2098 }
2099 }
2100
2101 /* check for server cookies */
2102 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002103 && (t->be->beprm->cookie_name != NULL ||
2104 t->be->fiprm->capture_name != NULL ||
2105 t->be->beprm->appsession_name !=NULL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002106 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2107 char *p1, *p2, *p3, *p4;
2108
2109 t->flags |= SN_SCK_ANY;
2110
2111 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2112
2113 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
2114 while (p1 < ptr && (isspace((int)*p1)))
2115 p1++;
2116
2117 if (p1 == ptr || *p1 == ';') /* end of cookie */
2118 break;
2119
2120 /* p1 is at the beginning of the cookie name */
2121 p2 = p1;
2122
2123 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2124 p2++;
2125
2126 if (p2 == ptr || *p2 == ';') /* next cookie */
2127 break;
2128
2129 p3 = p2 + 1; /* skips the '=' sign */
2130 if (p3 == ptr)
2131 break;
2132
2133 p4 = p3;
2134 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
2135 p4++;
2136
2137 /* here, we have the cookie name between p1 and p2,
2138 * and its value between p3 and p4.
2139 * we can process it.
2140 */
2141
2142 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01002143 if (t->be->fiprm->capture_name != NULL &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002144 t->logs.srv_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002145 (p4 - p1 >= t->be->fiprm->capture_namelen) &&
2146 memcmp(p1, t->be->fiprm->capture_name, t->be->fiprm->capture_namelen) == 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002147 int log_len = p4 - p1;
2148
2149 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
2150 Alert("HTTP logging : out of memory.\n");
2151 }
2152
Willy Tarreau830ff452006-12-17 19:31:23 +01002153 if (log_len > t->be->fiprm->capture_len)
2154 log_len = t->be->fiprm->capture_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002155 memcpy(t->logs.srv_cookie, p1, log_len);
2156 t->logs.srv_cookie[log_len] = 0;
2157 }
2158
Willy Tarreau830ff452006-12-17 19:31:23 +01002159 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
2160 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002161 /* Cool... it's the right one */
2162 t->flags |= SN_SCK_SEEN;
2163
2164 /* If the cookie is in insert mode on a known server, we'll delete
2165 * this occurrence because we'll insert another one later.
2166 * We'll delete it too if the "indirect" option is set and we're in
2167 * a direct access. */
Willy Tarreau830ff452006-12-17 19:31:23 +01002168 if (((t->srv) && (t->be->beprm->options & PR_O_COOK_INS)) ||
2169 ((t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_IND))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002170 /* this header must be deleted */
2171 delete_header = 1;
2172 t->flags |= SN_SCK_DELETED;
2173 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002174 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_RW)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002175 /* replace bytes p3->p4 with the cookie name associated
2176 * with this server since we know it.
2177 */
2178 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2179 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2180 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002181 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_PFX)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002182 /* insert the cookie name associated with this server
2183 * before existing cookie, and insert a delimitor between them..
2184 */
2185 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
2186 p3[t->srv->cklen] = COOKIE_DELIM;
2187 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2188 }
2189 break;
2190 }
2191
2192 /* first, let's see if the cookie is our appcookie*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002193 if ((t->be->beprm->appsession_name != NULL) &&
2194 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002195
2196 /* Cool... it's the right one */
2197
2198 size_t server_id_len = strlen(t->srv->id) + 1;
2199 asession_temp = &local_asession;
2200
2201 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
2202 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002203 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002204 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002205 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
2206 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002207 asession_temp->serverid = NULL;
2208
2209 /* only do insert, if lookup fails */
Willy Tarreau73de9892006-11-30 11:40:23 +01002210 if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002211 if ((asession_temp = pool_alloc(appsess)) == NULL) {
2212 Alert("Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002213 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002214 return 0;
2215 }
2216 asession_temp->sessid = local_asession.sessid;
2217 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01002218 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002219 }/* end if (chtbl_lookup()) */
2220 else {
2221 /* free wasted memory */
2222 pool_free_to(apools.sessid, local_asession.sessid);
2223 } /* end else from if (chtbl_lookup()) */
2224
2225 if (asession_temp->serverid == NULL) {
2226 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
2227 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002228 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002229 }
2230 asession_temp->serverid[0] = '\0';
2231 }
2232
2233 if (asession_temp->serverid[0] == '\0')
2234 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
2235
Willy Tarreau830ff452006-12-17 19:31:23 +01002236 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002237
2238#if defined(DEBUG_HASH)
Willy Tarreau830ff452006-12-17 19:31:23 +01002239 print_table(&(t->be->beprm->htbl_proxy));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002240#endif
2241 break;
2242 }/* end if ((t->proxy->appsession_name != NULL) ... */
2243 else {
2244 // fprintf(stderr,"Ignoring unknown cookie : ");
2245 // write(2, p1, p2-p1);
2246 // fprintf(stderr," = ");
2247 // write(2, p3, p4-p3);
2248 // fprintf(stderr,"\n");
2249 }
2250 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2251 } /* we're now at the end of the cookie value */
2252 } /* end of cookie processing */
2253
2254 /* check for any set-cookie in case we check for cacheability */
2255 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002256 (t->be->beprm->options & PR_O_CHK_CACHE) &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002257 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2258 t->flags |= SN_SCK_ANY;
2259 }
2260
2261 /* let's look if we have to delete this header */
2262 if (delete_header && !(t->flags & SN_SVDENY))
2263 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2264
2265 rep->h = rep->lr;
2266 } /* while (rep->lr < rep->r) */
2267
2268 /* end of header processing (even if incomplete) */
2269
Willy Tarreau2a429502006-10-15 14:52:29 +02002270 if ((rep->l < rep->rlim - rep->data) && ! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002271 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
Willy Tarreaud7971282006-07-29 18:36:34 +02002272 * full. We cannot loop here since stream_sock_read will disable it only if
Willy Tarreaubaaee002006-06-26 02:48:02 +02002273 * rep->l == rlim-data
2274 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002275 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002276 if (t->be->beprm->srvtimeout)
2277 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002278 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002279 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002280 }
2281
2282 /* read error, write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002283 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002284 tv_eternity(&rep->rex);
2285 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002286 fd_delete(t->srv_fd);
2287 if (t->srv) {
2288 t->srv->cur_sess--;
2289 t->srv->failed_resp++;
2290 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002291 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002292
2293 t->srv_state = SV_STCLOSE;
2294 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01002295 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002296 if (!(t->flags & SN_ERR_MASK))
2297 t->flags |= SN_ERR_SRVCL;
2298 if (!(t->flags & SN_FINST_MASK))
2299 t->flags |= SN_FINST_H;
2300 /* We used to have a free connection slot. Since we'll never use it,
2301 * we have to inform the server that it may be used by another session.
2302 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002303 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002304 task_wakeup(&rq, t->srv->queue_mgt);
2305
2306 return 1;
2307 }
2308 /* end of client write or end of server read.
2309 * since we are in header mode, if there's no space left for headers, we
2310 * won't be able to free more later, so the session will never terminate.
2311 */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002312 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 +02002313 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002314 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002315 shutdown(t->srv_fd, SHUT_RD);
2316 t->srv_state = SV_STSHUTR;
2317 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2318 return 1;
2319 }
2320 /* read timeout : return a 504 to the client.
2321 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002322 else if (MY_FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002323 tv_eternity(&rep->rex);
2324 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002325 fd_delete(t->srv_fd);
2326 if (t->srv) {
2327 t->srv->cur_sess--;
2328 t->srv->failed_resp++;
2329 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002330 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002331 t->srv_state = SV_STCLOSE;
2332 t->logs.status = 504;
Willy Tarreau80587432006-12-24 17:47:20 +01002333 client_return(t, error_message(t, HTTP_ERR_504));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002334 if (!(t->flags & SN_ERR_MASK))
2335 t->flags |= SN_ERR_SRVTO;
2336 if (!(t->flags & SN_FINST_MASK))
2337 t->flags |= SN_FINST_H;
2338 /* We used to have a free connection slot. Since we'll never use it,
2339 * we have to inform the server that it may be used by another session.
2340 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002341 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002342 task_wakeup(&rq, t->srv->queue_mgt);
2343
2344 return 1;
2345 }
2346 /* last client read and buffer empty */
2347 /* FIXME!!! here, we don't want to switch to SHUTW if the
2348 * client shuts read too early, because we may still have
2349 * some work to do on the headers.
2350 * The side-effect is that if the client completely closes its
2351 * connection during SV_STHEADER, the connection to the server
2352 * is kept until a response comes back or the timeout is reached.
2353 */
2354 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002355 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002356 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002357
2358 /* We must ensure that the read part is still alive when switching
2359 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002360 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002361 if (t->be->beprm->srvtimeout)
2362 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002363
2364 shutdown(t->srv_fd, SHUT_WR);
2365 t->srv_state = SV_STSHUTW;
2366 return 1;
2367 }
2368 /* write timeout */
2369 /* FIXME!!! here, we don't want to switch to SHUTW if the
2370 * client shuts read too early, because we may still have
2371 * some work to do on the headers.
2372 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002373 else if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&req->wex, &now) <= 0) {
2374 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002375 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002376 shutdown(t->srv_fd, SHUT_WR);
2377 /* We must ensure that the read part is still alive when switching
2378 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002379 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002380 if (t->be->beprm->srvtimeout)
2381 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002382
2383 /* We must ensure that the read part is still alive when switching
2384 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002385 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002386 if (t->be->beprm->srvtimeout)
2387 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002388
2389 t->srv_state = SV_STSHUTW;
2390 if (!(t->flags & SN_ERR_MASK))
2391 t->flags |= SN_ERR_SRVTO;
2392 if (!(t->flags & SN_FINST_MASK))
2393 t->flags |= SN_FINST_H;
2394 return 1;
2395 }
2396
2397 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002398 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2399 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002400 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002401 }
2402 }
2403 else { /* client buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002404 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2405 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002406 if (t->be->beprm->srvtimeout) {
2407 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002408 /* FIXME: to prevent the server from expiring read timeouts during writes,
2409 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002410 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002411 }
2412 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002413 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002414 }
2415 }
2416
2417 /* be nice with the client side which would like to send a complete header
2418 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2419 * would read all remaining data at once ! The client should not write past rep->lr
2420 * when the server is in header state.
2421 */
2422 //return header_processed;
2423 return t->srv_state != SV_STHEADERS;
2424 }
2425 else if (s == SV_STDATA) {
2426 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002427 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002428 tv_eternity(&rep->rex);
2429 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002430 fd_delete(t->srv_fd);
2431 if (t->srv) {
2432 t->srv->cur_sess--;
2433 t->srv->failed_resp++;
2434 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002435 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002436 t->srv_state = SV_STCLOSE;
2437 if (!(t->flags & SN_ERR_MASK))
2438 t->flags |= SN_ERR_SRVCL;
2439 if (!(t->flags & SN_FINST_MASK))
2440 t->flags |= SN_FINST_D;
2441 /* We used to have a free connection slot. Since we'll never use it,
2442 * we have to inform the server that it may be used by another session.
2443 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002444 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002445 task_wakeup(&rq, t->srv->queue_mgt);
2446
2447 return 1;
2448 }
2449 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002450 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002451 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002452 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002453 shutdown(t->srv_fd, SHUT_RD);
2454 t->srv_state = SV_STSHUTR;
2455 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2456 return 1;
2457 }
2458 /* end of client read and no more data to send */
2459 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002460 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002461 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002462 shutdown(t->srv_fd, SHUT_WR);
2463 /* We must ensure that the read part is still alive when switching
2464 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002465 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002466 if (t->be->beprm->srvtimeout)
2467 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002468
2469 t->srv_state = SV_STSHUTW;
2470 return 1;
2471 }
2472 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002473 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002474 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002475 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002476 shutdown(t->srv_fd, SHUT_RD);
2477 t->srv_state = SV_STSHUTR;
2478 if (!(t->flags & SN_ERR_MASK))
2479 t->flags |= SN_ERR_SRVTO;
2480 if (!(t->flags & SN_FINST_MASK))
2481 t->flags |= SN_FINST_D;
2482 return 1;
2483 }
2484 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002485 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002486 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002487 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002488 shutdown(t->srv_fd, SHUT_WR);
2489 /* We must ensure that the read part is still alive when switching
2490 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002491 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002492 if (t->be->beprm->srvtimeout)
2493 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002494 t->srv_state = SV_STSHUTW;
2495 if (!(t->flags & SN_ERR_MASK))
2496 t->flags |= SN_ERR_SRVTO;
2497 if (!(t->flags & SN_FINST_MASK))
2498 t->flags |= SN_FINST_D;
2499 return 1;
2500 }
2501
2502 /* recompute request time-outs */
2503 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002504 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2505 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002506 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002507 }
2508 }
2509 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau2a429502006-10-15 14:52:29 +02002510 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2511 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002512 if (t->be->beprm->srvtimeout) {
2513 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002514 /* FIXME: to prevent the server from expiring read timeouts during writes,
2515 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002516 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002517 }
2518 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002519 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002520 }
2521 }
2522
2523 /* recompute response time-outs */
2524 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002525 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2526 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002527 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002528 }
2529 }
2530 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002531 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2532 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002533 if (t->be->beprm->srvtimeout)
2534 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002535 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002536 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002537 }
2538 }
2539
2540 return 0; /* other cases change nothing */
2541 }
2542 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002543 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002544 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002545 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002546 fd_delete(t->srv_fd);
2547 if (t->srv) {
2548 t->srv->cur_sess--;
2549 t->srv->failed_resp++;
2550 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002551 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002552 //close(t->srv_fd);
2553 t->srv_state = SV_STCLOSE;
2554 if (!(t->flags & SN_ERR_MASK))
2555 t->flags |= SN_ERR_SRVCL;
2556 if (!(t->flags & SN_FINST_MASK))
2557 t->flags |= SN_FINST_D;
2558 /* We used to have a free connection slot. Since we'll never use it,
2559 * we have to inform the server that it may be used by another session.
2560 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002561 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002562 task_wakeup(&rq, t->srv->queue_mgt);
2563
2564 return 1;
2565 }
2566 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002567 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002568 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002569 fd_delete(t->srv_fd);
2570 if (t->srv)
2571 t->srv->cur_sess--;
2572 //close(t->srv_fd);
2573 t->srv_state = SV_STCLOSE;
2574 /* We used to have a free connection slot. Since we'll never use it,
2575 * we have to inform the server that it may be used by another session.
2576 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002577 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002578 task_wakeup(&rq, t->srv->queue_mgt);
2579
2580 return 1;
2581 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002582 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002583 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002584 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002585 fd_delete(t->srv_fd);
2586 if (t->srv)
2587 t->srv->cur_sess--;
2588 //close(t->srv_fd);
2589 t->srv_state = SV_STCLOSE;
2590 if (!(t->flags & SN_ERR_MASK))
2591 t->flags |= SN_ERR_SRVTO;
2592 if (!(t->flags & SN_FINST_MASK))
2593 t->flags |= SN_FINST_D;
2594 /* We used to have a free connection slot. Since we'll never use it,
2595 * we have to inform the server that it may be used by another session.
2596 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002597 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002598 task_wakeup(&rq, t->srv->queue_mgt);
2599
2600 return 1;
2601 }
2602 else if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002603 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2604 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002605 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002606 }
2607 }
2608 else { /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002609 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2610 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002611 if (t->be->beprm->srvtimeout) {
2612 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002613 /* FIXME: to prevent the server from expiring read timeouts during writes,
2614 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002615 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002616 }
2617 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002618 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002619 }
2620 }
2621 return 0;
2622 }
2623 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002624 if (rep->flags & BF_READ_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002625 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002626 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002627 fd_delete(t->srv_fd);
2628 if (t->srv) {
2629 t->srv->cur_sess--;
2630 t->srv->failed_resp++;
2631 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002632 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002633 //close(t->srv_fd);
2634 t->srv_state = SV_STCLOSE;
2635 if (!(t->flags & SN_ERR_MASK))
2636 t->flags |= SN_ERR_SRVCL;
2637 if (!(t->flags & SN_FINST_MASK))
2638 t->flags |= SN_FINST_D;
2639 /* We used to have a free connection slot. Since we'll never use it,
2640 * we have to inform the server that it may be used by another session.
2641 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002642 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002643 task_wakeup(&rq, t->srv->queue_mgt);
2644
2645 return 1;
2646 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002647 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002648 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002649 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002650 fd_delete(t->srv_fd);
2651 if (t->srv)
2652 t->srv->cur_sess--;
2653 //close(t->srv_fd);
2654 t->srv_state = SV_STCLOSE;
2655 /* We used to have a free connection slot. Since we'll never use it,
2656 * we have to inform the server that it may be used by another session.
2657 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002658 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002659 task_wakeup(&rq, t->srv->queue_mgt);
2660
2661 return 1;
2662 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002663 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002664 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002665 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002666 fd_delete(t->srv_fd);
2667 if (t->srv)
2668 t->srv->cur_sess--;
2669 //close(t->srv_fd);
2670 t->srv_state = SV_STCLOSE;
2671 if (!(t->flags & SN_ERR_MASK))
2672 t->flags |= SN_ERR_SRVTO;
2673 if (!(t->flags & SN_FINST_MASK))
2674 t->flags |= SN_FINST_D;
2675 /* We used to have a free connection slot. Since we'll never use it,
2676 * we have to inform the server that it may be used by another session.
2677 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002678 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002679 task_wakeup(&rq, t->srv->queue_mgt);
2680
2681 return 1;
2682 }
2683 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002684 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2685 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002686 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002687 }
2688 }
2689 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002690 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2691 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002692 if (t->be->beprm->srvtimeout)
2693 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002694 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002695 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002696 }
2697 }
2698 return 0;
2699 }
2700 else { /* SV_STCLOSE : nothing to do */
2701 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2702 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01002703 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 +02002704 write(1, trash, len);
2705 }
2706 return 0;
2707 }
2708 return 0;
2709}
2710
2711
2712/*
2713 * Produces data for the session <s> depending on its source. Expects to be
2714 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
2715 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
2716 * session, which it uses to keep on being called when there is free space in
2717 * the buffer, of simply by letting an empty buffer upon return. It returns 1
2718 * if it changes the session state from CL_STSHUTR, otherwise 0.
2719 */
2720int produce_content(struct session *s)
2721{
2722 struct buffer *rep = s->rep;
2723 struct proxy *px;
2724 struct server *sv;
Willy Tarreau0f772532006-12-23 20:51:41 +01002725 struct chunk msg;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002726
2727 if (s->data_source == DATA_SRC_NONE) {
2728 s->flags &= ~SN_SELF_GEN;
2729 return 1;
2730 }
2731 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreau0f772532006-12-23 20:51:41 +01002732 msg.len = 0;
2733 msg.str = trash;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002734
2735 if (s->data_state == DATA_ST_INIT) { /* the function had not been called yet */
2736 unsigned int up;
2737
2738 s->flags |= SN_SELF_GEN; // more data will follow
2739
2740 /* send the start of the HTTP response */
Willy Tarreau0f772532006-12-23 20:51:41 +01002741 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002742 "HTTP/1.0 200 OK\r\n"
2743 "Cache-Control: no-cache\r\n"
2744 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +02002745 "Content-Type: text/html\r\n"
Willy Tarreau2b5652f2006-12-31 17:46:05 +01002746 "\r\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002747
2748 s->logs.status = 200;
Willy Tarreau0f772532006-12-23 20:51:41 +01002749 client_retnclose(s, &msg); // send the start of the response.
2750 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002751
2752 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
2753 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
2754 if (!(s->flags & SN_FINST_MASK))
2755 s->flags |= SN_FINST_R;
2756
2757 /* WARNING! This must fit in the first buffer !!! */
Willy Tarreau0f772532006-12-23 20:51:41 +01002758 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002759 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
2760 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
2761 "<style type=\"text/css\"><!--\n"
2762 "body {"
2763 " font-family: helvetica, arial;"
2764 " font-size: 12px;"
2765 " font-weight: normal;"
2766 " color: black;"
2767 " background: white;"
2768 "}\n"
2769 "td {"
2770 " font-size: 12px;"
2771 " align: center;"
2772 "}\n"
2773 "h1 {"
2774 " font-size: xx-large;"
2775 " margin-bottom: 0.5em;"
2776 "}\n"
2777 "h2 {"
2778 " font-family: helvetica, arial;"
2779 " font-size: x-large;"
2780 " font-weight: bold;"
2781 " font-style: italic;"
2782 " color: #6020a0;"
2783 " margin-top: 0em;"
2784 " margin-bottom: 0em;"
2785 "}\n"
2786 "h3 {"
2787 " font-family: helvetica, arial;"
2788 " font-size: 16px;"
2789 " font-weight: bold;"
2790 " color: #b00040;"
2791 " background: #e8e8d0;"
2792 " margin-top: 0em;"
2793 " margin-bottom: 0em;"
2794 "}\n"
2795 "li {"
2796 " margin-top: 0.25em;"
2797 " margin-right: 2em;"
2798 "}\n"
2799 ".hr {"
2800 " margin-top: 0.25em;"
2801 " border-color: black;"
2802 " border-bottom-style: solid;"
2803 "}\n"
2804 "table.tbl { border-collapse: collapse; border-width: 1px; border-style: solid; border-color: gray;}\n"
2805 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; border-color: gray; }\n"
2806 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray; }\n"
2807 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
2808 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
2809 "-->"
2810 "</style></head>");
2811
Willy Tarreau0f772532006-12-23 20:51:41 +01002812 if (buffer_write(rep, trash, msg.len) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002813 return 0;
Willy Tarreau0f772532006-12-23 20:51:41 +01002814 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002815
2816 up = (now.tv_sec - start_date.tv_sec);
2817
2818 /* WARNING! this has to fit the first packet too */
Willy Tarreau0f772532006-12-23 20:51:41 +01002819 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002820 "<body><h1>" PRODUCT_NAME "</h1>\n"
2821 "<h2>Statistics Report for pid %d</h2>\n"
2822 "<hr width=\"100%%\" class=\"hr\">\n"
2823 "<h3>&gt; General process information</h3>\n"
2824 "<table border=0><tr><td align=\"left\">\n"
2825 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
2826 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
2827 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
2828 "<b>maxsock = </b> %d<br>\n"
2829 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
2830 "</td><td width=\"10%%\">\n"
2831 "</td><td align=\"right\">\n"
2832 "<table class=\"lgd\">"
2833 "<tr><td bgcolor=\"#C0FFC0\">&nbsp;</td><td style=\"border-style: none;\">active UP </td>"
2834 "<td bgcolor=\"#B0D0FF\">&nbsp;</td><td style=\"border-style: none;\">backup UP </td></tr>"
2835 "<tr><td bgcolor=\"#FFFFA0\"></td><td style=\"border-style: none;\">active UP, going down </td>"
2836 "<td bgcolor=\"#C060FF\"></td><td style=\"border-style: none;\">backup UP, going down </td></tr>"
2837 "<tr><td bgcolor=\"#FFD020\"></td><td style=\"border-style: none;\">active DOWN, going up </td>"
2838 "<td bgcolor=\"#FF80FF\"></td><td style=\"border-style: none;\">backup DOWN, going up </td></tr>"
2839 "<tr><td bgcolor=\"#FF9090\"></td><td style=\"border-style: none;\">active or backup DOWN &nbsp;</td>"
2840 "<td bgcolor=\"#E0E0E0\"></td><td style=\"border-style: none;\">not checked </td></tr>"
2841 "</table>\n"
2842 "</tr></table>\n"
2843 "",
2844 pid, pid, global.nbproc,
2845 up / 86400, (up % 86400) / 3600,
2846 (up % 3600) / 60, (up % 60),
2847 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
2848 global.rlimit_memmax ? " MB" : "",
2849 global.rlimit_nofile,
2850 global.maxsock,
2851 global.maxconn,
2852 actconn
2853 );
2854
Willy Tarreau0f772532006-12-23 20:51:41 +01002855 if (buffer_write(rep, trash, msg.len) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002856 return 0;
Willy Tarreau0f772532006-12-23 20:51:41 +01002857 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002858
2859 s->data_state = DATA_ST_DATA;
2860 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
2861
2862 px = s->data_ctx.stats.px = proxy;
2863 s->data_ctx.stats.px_st = DATA_ST_INIT;
2864 }
2865
2866 while (s->data_ctx.stats.px) {
2867 int dispatch_sess, dispatch_cum;
2868 int failed_checks, down_trans;
2869 int failed_secu, failed_conns, failed_resp;
2870
2871 if (s->data_ctx.stats.px_st == DATA_ST_INIT) {
2872 /* we are on a new proxy */
2873 px = s->data_ctx.stats.px;
2874
2875 /* skip the disabled proxies */
2876 if (px->state == PR_STSTOPPED)
2877 goto next_proxy;
2878
Willy Tarreau830ff452006-12-17 19:31:23 +01002879 if (s->be->fiprm->uri_auth && s->be->fiprm->uri_auth->scope) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002880 /* we have a limited scope, we have to check the proxy name */
2881 struct stat_scope *scope;
2882 int len;
2883
2884 len = strlen(px->id);
Willy Tarreau830ff452006-12-17 19:31:23 +01002885 scope = s->be->fiprm->uri_auth->scope;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002886
2887 while (scope) {
2888 /* match exact proxy name */
2889 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
2890 break;
2891
2892 /* match '.' which means 'self' proxy */
Willy Tarreau73de9892006-11-30 11:40:23 +01002893 if (!strcmp(scope->px_id, ".") && px == s->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002894 break;
2895 scope = scope->next;
2896 }
2897
2898 /* proxy name not found */
2899 if (scope == NULL)
2900 goto next_proxy;
2901 }
2902
Willy Tarreau0f772532006-12-23 20:51:41 +01002903 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002904 "<h3>&gt; Proxy instance %s : "
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002905 "%d front conns (max=%d), %d back, "
2906 "%d queued (%d unassigned), %d total front conns, %d back</h3>\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +02002907 "",
2908 px->id,
Willy Tarreauf1221aa2006-12-17 22:14:12 +01002909 px->feconn, px->maxconn, px->beconn,
2910 px->totpend, px->nbpend, px->cum_feconn, px->cum_beconn);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002911
Willy Tarreau0f772532006-12-23 20:51:41 +01002912 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002913 "<table cols=\"16\" class=\"tbl\">\n"
2914 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
2915 "<th colspan=5>Server</th>"
2916 "<th colspan=2>Queue</th>"
2917 "<th colspan=4>Sessions</th>"
2918 "<th colspan=5>Errors</th></tr>\n"
2919 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
2920 "<th>Name</th><th>Weight</th><th>Status</th><th>Act.</th><th>Bck.</th>"
2921 "<th>Curr.</th><th>Max.</th>"
2922 "<th>Curr.</th><th>Max.</th><th>Limit</th><th>Cumul.</th>"
2923 "<th>Conn.</th><th>Resp.</th><th>Sec.</th><th>Check</th><th>Down</th></tr>\n");
2924
Willy Tarreau0f772532006-12-23 20:51:41 +01002925 if (buffer_write(rep, trash, msg.len) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002926 return 0;
Willy Tarreau0f772532006-12-23 20:51:41 +01002927 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002928
2929 s->data_ctx.stats.sv = px->srv;
2930 s->data_ctx.stats.px_st = DATA_ST_DATA;
2931 }
2932
2933 px = s->data_ctx.stats.px;
2934
2935 /* stats.sv has been initialized above */
2936 while (s->data_ctx.stats.sv != NULL) {
2937 static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
2938 static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
2939 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
2940 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
2941
2942 sv = s->data_ctx.stats.sv;
2943
2944 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
2945 if (!(sv->state & SRV_CHECKED))
2946 sv_state = 4;
2947 else if (sv->state & SRV_RUNNING)
2948 if (sv->health == sv->rise + sv->fall - 1)
2949 sv_state = 3; /* UP */
2950 else
2951 sv_state = 2; /* going down */
2952 else
2953 if (sv->health)
2954 sv_state = 1; /* going up */
2955 else
2956 sv_state = 0; /* DOWN */
2957
2958 /* name, weight */
Willy Tarreau0f772532006-12-23 20:51:41 +01002959 msg.len += snprintf(trash, sizeof(trash),
Willy Tarreaubaaee002006-06-26 02:48:02 +02002960 "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
2961 (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
2962 sv->id, sv->uweight+1);
2963 /* status */
Willy Tarreau0f772532006-12-23 20:51:41 +01002964 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len, srv_hlt_st[sv_state],
Willy Tarreaubaaee002006-06-26 02:48:02 +02002965 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
2966 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
2967
2968 /* act, bck */
Willy Tarreau0f772532006-12-23 20:51:41 +01002969 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002970 "</td><td>%s</td><td>%s</td>",
2971 (sv->state & SRV_BACKUP) ? "-" : "Y",
2972 (sv->state & SRV_BACKUP) ? "Y" : "-");
2973
2974 /* queue : current, max */
Willy Tarreau0f772532006-12-23 20:51:41 +01002975 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002976 "<td align=right>%d</td><td align=right>%d</td>",
2977 sv->nbpend, sv->nbpend_max);
2978
2979 /* sessions : current, max, limit, cumul */
Willy Tarreau0f772532006-12-23 20:51:41 +01002980 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002981 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>",
2982 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess);
2983
2984 /* errors : connect, response, security */
Willy Tarreau0f772532006-12-23 20:51:41 +01002985 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002986 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
2987 sv->failed_conns, sv->failed_resp, sv->failed_secu);
2988
2989 /* check failures : unique, fatal */
2990 if (sv->state & SRV_CHECKED)
Willy Tarreau0f772532006-12-23 20:51:41 +01002991 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002992 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
2993 sv->failed_checks, sv->down_trans);
2994 else
Willy Tarreau0f772532006-12-23 20:51:41 +01002995 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02002996 "<td align=right>-</td><td align=right>-</td></tr>\n");
2997
Willy Tarreau0f772532006-12-23 20:51:41 +01002998 if (buffer_write(rep, trash, msg.len) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002999 return 0;
Willy Tarreau0f772532006-12-23 20:51:41 +01003000 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003001
3002 s->data_ctx.stats.sv = sv->next;
3003 } /* while sv */
3004
3005 /* now we are past the last server, we'll dump information about the dispatcher */
3006
3007 /* We have to count down from the proxy to the servers to tell how
3008 * many sessions are on the dispatcher, and how many checks have
3009 * failed. We cannot count this during the servers dump because it
3010 * might be interrupted multiple times.
3011 */
Willy Tarreauf1221aa2006-12-17 22:14:12 +01003012 dispatch_sess = px->beconn;
3013 dispatch_cum = px->cum_beconn;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003014 failed_secu = px->failed_secu;
3015 failed_conns = px->failed_conns;
3016 failed_resp = px->failed_resp;
3017 failed_checks = down_trans = 0;
3018
3019 sv = px->srv;
3020 while (sv) {
3021 dispatch_sess -= sv->cur_sess;
3022 dispatch_cum -= sv->cum_sess;
3023 failed_conns -= sv->failed_conns;
3024 failed_resp -= sv->failed_resp;
3025 failed_secu -= sv->failed_secu;
3026 if (sv->state & SRV_CHECKED) {
3027 failed_checks += sv->failed_checks;
3028 down_trans += sv->down_trans;
3029 }
3030 sv = sv->next;
3031 }
3032
3033 /* name, weight, status, act, bck */
Willy Tarreau0f772532006-12-23 20:51:41 +01003034 msg.len += snprintf(trash + msg.len, sizeof(trash),
Willy Tarreaubaaee002006-06-26 02:48:02 +02003035 "<tr align=center bgcolor=\"#e8e8d0\">"
3036 "<td>Dispatcher</td><td>-</td>"
3037 "<td>%s</td><td>-</td><td>-</td>",
3038 px->state == PR_STRUN ? "UP" : "DOWN");
3039
3040 /* queue : current, max */
Willy Tarreau0f772532006-12-23 20:51:41 +01003041 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02003042 "<td align=right>%d</td><td align=right>%d</td>",
3043 px->nbpend, px->nbpend_max);
3044
3045 /* sessions : current, max, limit, cumul. */
Willy Tarreau0f772532006-12-23 20:51:41 +01003046 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreauf1221aa2006-12-17 22:14:12 +01003047 "<td align=right>%d</td><td align=right>%d</td><td align=right>-</td><td align=right>%d</td>",
3048 dispatch_sess, px->beconn_max, dispatch_cum);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003049
3050 /* errors : connect, response, security */
Willy Tarreau0f772532006-12-23 20:51:41 +01003051 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02003052 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3053 failed_conns, failed_resp, failed_secu);
3054
3055 /* check failures : unique, fatal */
Willy Tarreau0f772532006-12-23 20:51:41 +01003056 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02003057 "<td align=right>-</td><td align=right>-</td></tr>\n");
3058
3059
3060 /* now the summary for the whole proxy */
3061 /* name, weight, status, act, bck */
Willy Tarreau0f772532006-12-23 20:51:41 +01003062 msg.len += snprintf(trash + msg.len, sizeof(trash),
Willy Tarreaubaaee002006-06-26 02:48:02 +02003063 "<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
3064 "<td><b>Total</b></td><td>-</td>"
3065 "<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
3066 (px->state == PR_STRUN && ((px->srv == NULL) || px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
3067 px->srv_act, px->srv_bck);
3068
3069 /* queue : current, max */
Willy Tarreau0f772532006-12-23 20:51:41 +01003070 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02003071 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
3072 px->totpend, px->nbpend_max);
3073
3074 /* sessions : current, max, limit, cumul */
Willy Tarreau0f772532006-12-23 20:51:41 +01003075 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreauf1221aa2006-12-17 22:14:12 +01003076 "<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>",
3077 px->beconn, px->beconn_max, px->cum_beconn);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003078
3079 /* errors : connect, response, security */
Willy Tarreau0f772532006-12-23 20:51:41 +01003080 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02003081 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
3082 px->failed_conns, px->failed_resp, px->failed_secu);
3083
3084 /* check failures : unique, fatal */
Willy Tarreau0f772532006-12-23 20:51:41 +01003085 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len,
Willy Tarreaubaaee002006-06-26 02:48:02 +02003086 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3087 failed_checks, down_trans);
3088
Willy Tarreau0f772532006-12-23 20:51:41 +01003089 msg.len += snprintf(trash + msg.len, sizeof(trash) - msg.len, "</table><p>\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003090
Willy Tarreau0f772532006-12-23 20:51:41 +01003091 if (buffer_write(rep, trash, msg.len) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003092 return 0;
Willy Tarreau0f772532006-12-23 20:51:41 +01003093 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003094
3095 s->data_ctx.stats.px_st = DATA_ST_INIT;
3096 next_proxy:
3097 s->data_ctx.stats.px = px->next;
3098 } /* proxy loop */
3099 /* here, we just have reached the sv == NULL and px == NULL */
3100 s->flags &= ~SN_SELF_GEN;
3101 return 1;
3102 }
3103 else {
3104 /* unknown data source */
3105 s->logs.status = 500;
Willy Tarreau80587432006-12-24 17:47:20 +01003106 client_retnclose(s, error_message(s, HTTP_ERR_500));
Willy Tarreaubaaee002006-06-26 02:48:02 +02003107 if (!(s->flags & SN_ERR_MASK))
3108 s->flags |= SN_ERR_PRXCOND;
3109 if (!(s->flags & SN_FINST_MASK))
3110 s->flags |= SN_FINST_R;
3111 s->flags &= SN_SELF_GEN;
3112 return 1;
3113 }
3114}
3115
3116
Willy Tarreau58f10d72006-12-04 02:26:12 +01003117
3118/*
3119 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>
3120 */
3121
3122void apply_filters_to_session(struct session *t, struct buffer *req, struct hdr_exp *exp)
3123{
3124 /* iterate through the filters in the outer loop */
3125 while (exp && !(t->flags & (SN_CLDENY|SN_CLTARPIT))) {
3126 char term;
3127 char *cur_ptr, *cur_end, *cur_next;
3128 int cur_idx, old_idx, abort_filt;
3129
3130
3131 /*
3132 * The interleaving of transformations and verdicts
3133 * makes it difficult to decide to continue or stop
3134 * the evaluation.
3135 */
3136
3137 if ((t->flags & SN_CLALLOW) &&
3138 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
3139 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
3140 exp = exp->next;
3141 continue;
3142 }
3143
3144 /* Iterate through the headers in the inner loop.
3145 * we start with the start line.
3146 */
3147 old_idx = cur_idx = 0;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003148 cur_next = req->data + t->hreq.sor;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003149 abort_filt = 0;
3150
Willy Tarreau45e73e32006-12-17 00:05:15 +01003151 while (!abort_filt && (cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
3152 struct hdr_idx_elem *cur_hdr = &t->hreq.hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003153 cur_ptr = cur_next;
3154 cur_end = cur_ptr + cur_hdr->len;
3155 cur_next = cur_end + cur_hdr->cr + 1;
3156
3157 /* Now we have one header between cur_ptr and cur_end,
3158 * and the next header starts at cur_next.
3159 */
3160
3161 /* The annoying part is that pattern matching needs
3162 * that we modify the contents to null-terminate all
3163 * strings before testing them.
3164 */
3165
3166 term = *cur_end;
3167 *cur_end = '\0';
3168
3169 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3170 switch (exp->action) {
Willy Tarreaua496b602006-12-17 23:15:24 +01003171 case ACT_SETBE:
3172 /* It is not possible to jump a second time.
3173 * FIXME: should we return an HTTP/500 here so that
3174 * the admin knows there's a problem ?
3175 */
3176 if (t->be != t->fe)
3177 break;
3178
3179 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3180 struct proxy *target = (struct proxy *) exp->replace;
3181
3182 /* Swithing Proxy */
3183 *cur_end = term;
3184 cur_end = NULL;
3185
3186 /* right now, the backend switch is not too much complicated
3187 * because we have associated req_cap and rsp_cap to the
3188 * frontend, and the beconn will be updated later.
3189 */
3190
3191 t->rep->rto = t->req->wto = target->beprm->srvtimeout;
3192 t->req->cto = target->beprm->contimeout;
3193
3194 t->be = target;
3195
3196 //t->logs.logwait |= LW_REQ | (target->to_log & (LW_REQHDR | LW_COOKIE));
Willy Tarreau97de6242006-12-27 17:18:38 +01003197 /* FIXME: should we use the backend's log options or not ?
3198 * It would seem far too complicated to configure a service with
3199 * logs defined both in the frontend and the backend.
3200 */
3201 //t->logs.logwait |= (target->to_log | target->beprm->to_log);
3202
Willy Tarreaua496b602006-12-17 23:15:24 +01003203 abort_filt = 1;
3204 }
3205 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003206 case ACT_ALLOW:
3207 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3208 t->flags |= SN_CLALLOW;
3209 abort_filt = 1;
3210 }
3211 break;
3212 case ACT_REPLACE:
3213 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3214 int len, delta;
3215 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3216 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
Willy Tarreaue15d9132006-12-14 22:26:42 +01003217 /* FIXME: if the user adds a newline in the replacement, the
3218 * index will not be recalculated for now, and the new line
3219 * will not be counted for a new header.
3220 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003221 cur_end += delta;
3222 cur_next += delta;
3223 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003224 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003225 }
3226 break;
3227 case ACT_REMOVE:
3228 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3229 int delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3230 cur_next += delta;
3231
3232 /* FIXME: this should be a separate function */
Willy Tarreau45e73e32006-12-17 00:05:15 +01003233 t->hreq.eoh += delta;
3234 t->hreq.hdr_idx.v[old_idx].next = cur_hdr->next;
3235 t->hreq.hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003236 cur_hdr->len = 0;
3237
3238 cur_end = NULL; /* null-term has been rewritten */
3239 }
3240 break;
3241 case ACT_DENY:
3242 if (!(t->flags & (SN_CLALLOW | SN_CLTARPIT))) {
3243 t->flags |= SN_CLDENY;
3244 abort_filt = 1;
3245 }
3246 break;
3247 case ACT_TARPIT:
3248 if (!(t->flags & (SN_CLALLOW | SN_CLDENY))) {
3249 t->flags |= SN_CLTARPIT;
3250 abort_filt = 1;
3251 }
3252 break;
3253 //case ACT_PASS: /* FIXME: broken as of now. We should mark the header as "ignored". */
3254 // break;
3255 }
3256 }
3257 if (cur_end)
3258 *cur_end = term; /* restore the string terminator */
3259
3260 /* keep the link from this header to next one */
3261 old_idx = cur_idx;
3262 }
3263 exp = exp->next;
3264 }
3265}
3266
3267
3268
3269/*
3270 * Manager client-side cookie
3271 */
3272void manage_client_side_cookies(struct session *t, struct buffer *req)
3273{
3274 char *p1, *p2, *p3, *p4;
3275 char *del_colon, *del_cookie, *colon;
3276 int app_cookies;
3277
3278 appsess *asession_temp = NULL;
3279 appsess local_asession;
3280
3281 char *cur_ptr, *cur_end, *cur_next;
3282 int cur_idx, old_idx, abort_filt;
3283
Willy Tarreau830ff452006-12-17 19:31:23 +01003284 if (t->be->beprm->cookie_name == NULL &&
3285 t->be->beprm->appsession_name ==NULL &&
3286 t->be->fiprm->capture_name != NULL)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003287 return;
3288
Willy Tarreau2a324282006-12-05 00:05:46 +01003289 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003290 * we start with the start line.
3291 */
3292 old_idx = cur_idx = 0;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003293 cur_next = req->data + t->hreq.sor;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003294 abort_filt = 0;
3295
Willy Tarreau45e73e32006-12-17 00:05:15 +01003296 while ((cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003297 struct hdr_idx_elem *cur_hdr;
3298
Willy Tarreau45e73e32006-12-17 00:05:15 +01003299 cur_hdr = &t->hreq.hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003300 cur_ptr = cur_next;
3301 cur_end = cur_ptr + cur_hdr->len;
3302 cur_next = cur_end + cur_hdr->cr + 1;
3303
3304 /* We have one full header between cur_ptr and cur_end, and the
3305 * next header starts at cur_next. We're only interested in
3306 * "Cookie:" headers.
3307 */
3308
3309 if ((cur_end - cur_ptr <= 7) ||
3310 (strncasecmp(cur_ptr, "Cookie:", 7) != 0)) {
3311 old_idx = cur_idx;
3312 continue;
3313 }
3314
3315 /* Now look for cookies. Conforming to RFC2109, we have to support
3316 * attributes whose name begin with a '$', and associate them with
3317 * the right cookie, if we want to delete this cookie.
3318 * So there are 3 cases for each cookie read :
3319 * 1) it's a special attribute, beginning with a '$' : ignore it.
3320 * 2) it's a server id cookie that we *MAY* want to delete : save
3321 * some pointers on it (last semi-colon, beginning of cookie...)
3322 * 3) it's an application cookie : we *MAY* have to delete a previous
3323 * "special" cookie.
3324 * At the end of loop, if a "special" cookie remains, we may have to
3325 * remove it. If no application cookie persists in the header, we
3326 * *MUST* delete it
3327 */
3328
3329
3330 p1 = cur_ptr + 7; /* first char after 'Cookie:' */
3331 if (isspace((int)*p1)) /* try to get the first space with it */
3332 p1++;
3333
3334 colon = p1;
3335 /* del_cookie == NULL => nothing to be deleted */
3336 del_colon = del_cookie = NULL;
3337 app_cookies = 0;
3338
3339 while (p1 < cur_end) {
3340 /* skip spaces and colons, but keep an eye on these ones */
3341 while (p1 < cur_end) {
3342 if (*p1 == ';' || *p1 == ',')
3343 colon = p1;
3344 else if (!isspace((int)*p1))
3345 break;
3346 p1++;
3347 }
3348
3349 if (p1 == cur_end)
3350 break;
3351
3352 /* p1 is at the beginning of the cookie name */
3353 p2 = p1;
3354 while (p2 < cur_end && *p2 != '=')
3355 p2++;
3356
3357 if (p2 == cur_end)
3358 break;
3359
3360 p3 = p2 + 1; /* skips the '=' sign */
3361 if (p3 == cur_end)
3362 break;
3363
3364 p4 = p3;
3365 while (p4 < cur_end && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
3366 p4++;
3367
3368 /* here, we have the cookie name between p1 and p2,
3369 * and its value between p3 and p4.
3370 * we can process it :
3371 *
3372 * Cookie: NAME=VALUE;
3373 * | || || |
3374 * | || || +--> p4
3375 * | || |+-------> p3
3376 * | || +--------> p2
3377 * | |+------------> p1
3378 * | +-------------> colon
3379 * +--------------------> cur_ptr
3380 */
3381
3382 if (*p1 == '$') {
3383 /* skip this one */
3384 }
3385 else {
3386 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01003387 if (t->fe->fiprm->capture_name != NULL &&
Willy Tarreau58f10d72006-12-04 02:26:12 +01003388 t->logs.cli_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01003389 (p4 - p1 >= t->fe->fiprm->capture_namelen) &&
3390 memcmp(p1, t->fe->fiprm->capture_name, t->fe->fiprm->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003391 int log_len = p4 - p1;
3392
3393 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3394 Alert("HTTP logging : out of memory.\n");
3395 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003396 if (log_len > t->fe->fiprm->capture_len)
3397 log_len = t->fe->fiprm->capture_len;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003398 memcpy(t->logs.cli_cookie, p1, log_len);
3399 t->logs.cli_cookie[log_len] = 0;
3400 }
3401 }
3402
Willy Tarreau830ff452006-12-17 19:31:23 +01003403 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
3404 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003405 /* Cool... it's the right one */
Willy Tarreau830ff452006-12-17 19:31:23 +01003406 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003407 char *delim;
3408
3409 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3410 * have the server ID betweek p3 and delim, and the original cookie between
3411 * delim+1 and p4. Otherwise, delim==p4 :
3412 *
3413 * Cookie: NAME=SRV~VALUE;
3414 * | || || | |
3415 * | || || | +--> p4
3416 * | || || +--------> delim
3417 * | || |+-----------> p3
3418 * | || +------------> p2
3419 * | |+----------------> p1
3420 * | +-----------------> colon
3421 * +------------------------> cur_ptr
3422 */
3423
Willy Tarreau830ff452006-12-17 19:31:23 +01003424 if (t->be->beprm->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003425 for (delim = p3; delim < p4; delim++)
3426 if (*delim == COOKIE_DELIM)
3427 break;
3428 }
3429 else
3430 delim = p4;
3431
3432
3433 /* Here, we'll look for the first running server which supports the cookie.
3434 * This allows to share a same cookie between several servers, for example
3435 * to dedicate backup servers to specific servers only.
3436 * However, to prevent clients from sticking to cookie-less backup server
3437 * when they have incidentely learned an empty cookie, we simply ignore
3438 * empty cookies and mark them as invalid.
3439 */
3440 if (delim == p3)
3441 srv = NULL;
3442
3443 while (srv) {
3444 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003445 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003446 /* we found the server and it's usable */
3447 t->flags &= ~SN_CK_MASK;
3448 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3449 t->srv = srv;
3450 break;
3451 } else {
3452 /* we found a server, but it's down */
3453 t->flags &= ~SN_CK_MASK;
3454 t->flags |= SN_CK_DOWN;
3455 }
3456 }
3457 srv = srv->next;
3458 }
3459
3460 if (!srv && !(t->flags & SN_CK_DOWN)) {
3461 /* no server matched this cookie */
3462 t->flags &= ~SN_CK_MASK;
3463 t->flags |= SN_CK_INVALID;
3464 }
3465
3466 /* depending on the cookie mode, we may have to either :
3467 * - delete the complete cookie if we're in insert+indirect mode, so that
3468 * the server never sees it ;
3469 * - remove the server id from the cookie value, and tag the cookie as an
3470 * application cookie so that it does not get accidentely removed later,
3471 * if we're in cookie prefix mode
3472 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003473 if ((t->be->beprm->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003474 int delta; /* negative */
3475
3476 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
3477 p4 += delta;
3478 cur_end += delta;
3479 cur_next += delta;
3480 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003481 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003482
3483 del_cookie = del_colon = NULL;
3484 app_cookies++; /* protect the header from deletion */
3485 }
3486 else if (del_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01003487 (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 +01003488 del_cookie = p1;
3489 del_colon = colon;
3490 }
3491 } else {
3492 /* now we know that we must keep this cookie since it's
3493 * not ours. But if we wanted to delete our cookie
3494 * earlier, we cannot remove the complete header, but we
3495 * can remove the previous block itself.
3496 */
3497 app_cookies++;
3498
3499 if (del_cookie != NULL) {
3500 int delta; /* negative */
3501
3502 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
3503 p4 += delta;
3504 cur_end += delta;
3505 cur_next += delta;
3506 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003507 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003508 del_cookie = del_colon = NULL;
3509 }
3510 }
3511
Willy Tarreau830ff452006-12-17 19:31:23 +01003512 if ((t->be->beprm->appsession_name != NULL) &&
3513 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003514 /* first, let's see if the cookie is our appcookie*/
3515
3516 /* Cool... it's the right one */
3517
3518 asession_temp = &local_asession;
3519
3520 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3521 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3522 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3523 return;
3524 }
3525
Willy Tarreau830ff452006-12-17 19:31:23 +01003526 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
3527 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003528 asession_temp->serverid = NULL;
3529
3530 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01003531 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003532 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3533 /* free previously allocated memory */
3534 pool_free_to(apools.sessid, local_asession.sessid);
3535 Alert("Not enough memory process_cli():asession:calloc().\n");
3536 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3537 return;
3538 }
3539
3540 asession_temp->sessid = local_asession.sessid;
3541 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01003542 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003543 } else {
3544 /* free previously allocated memory */
3545 pool_free_to(apools.sessid, local_asession.sessid);
3546 }
3547
3548 if (asession_temp->serverid == NULL) {
3549 Alert("Found Application Session without matching server.\n");
3550 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003551 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003552 while (srv) {
3553 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003554 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003555 /* we found the server and it's usable */
3556 t->flags &= ~SN_CK_MASK;
3557 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3558 t->srv = srv;
3559 break;
3560 } else {
3561 t->flags &= ~SN_CK_MASK;
3562 t->flags |= SN_CK_DOWN;
3563 }
3564 }
3565 srv = srv->next;
3566 }/* end while(srv) */
3567 }/* end else if server == NULL */
3568
Willy Tarreau830ff452006-12-17 19:31:23 +01003569 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003570 }/* end if ((t->proxy->appsession_name != NULL) ... */
3571 }
3572
3573 /* we'll have to look for another cookie ... */
3574 p1 = p4;
3575 } /* while (p1 < cur_end) */
3576
3577 /* There's no more cookie on this line.
3578 * We may have marked the last one(s) for deletion.
3579 * We must do this now in two ways :
3580 * - if there is no app cookie, we simply delete the header ;
3581 * - if there are app cookies, we must delete the end of the
3582 * string properly, including the colon/semi-colon before
3583 * the cookie name.
3584 */
3585 if (del_cookie != NULL) {
3586 int delta;
3587 if (app_cookies) {
3588 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
3589 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003590 cur_hdr->len += delta;
3591 } else {
3592 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003593
3594 /* FIXME: this should be a separate function */
Willy Tarreau45e73e32006-12-17 00:05:15 +01003595 t->hreq.hdr_idx.v[old_idx].next = cur_hdr->next;
3596 t->hreq.hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003597 cur_hdr->len = 0;
3598 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01003599 cur_next += delta;
3600 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003601 }
3602
3603 /* keep the link from this header to next one */
3604 old_idx = cur_idx;
3605 } /* end of cookie processing on this header */
3606}
3607
3608
3609
3610/*
3611 * Try to retrieve a known appsession in the URI, then the associated server.
3612 * If the server is found, it's assigned to the session.
3613 */
3614
3615void get_srv_from_appsession(struct session *t, const char *begin, const char *end)
3616{
3617 appsess *asession_temp = NULL;
3618 appsess local_asession;
3619 char *request_line;
3620
Willy Tarreau830ff452006-12-17 19:31:23 +01003621 if (t->be->beprm->appsession_name == NULL ||
Willy Tarreau921d7c02006-12-17 13:50:27 +01003622 (t->hreq.meth != HTTP_METH_GET && t->hreq.meth != HTTP_METH_POST) ||
Willy Tarreau58f10d72006-12-04 02:26:12 +01003623 (request_line = memchr(begin, ';', end - begin)) == NULL ||
Willy Tarreau830ff452006-12-17 19:31:23 +01003624 ((1 + t->be->beprm->appsession_name_len + 1 + t->be->beprm->appsession_len) > (end - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01003625 return;
3626
3627 /* skip ';' */
3628 request_line++;
3629
3630 /* look if we have a jsessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01003631 if (strncasecmp(request_line, t->be->beprm->appsession_name, t->be->beprm->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003632 return;
3633
3634 /* skip jsessionid= */
Willy Tarreau830ff452006-12-17 19:31:23 +01003635 request_line += t->be->beprm->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003636
3637 /* First try if we already have an appsession */
3638 asession_temp = &local_asession;
3639
3640 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3641 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3642 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3643 return;
3644 }
3645
3646 /* Copy the sessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01003647 memcpy(asession_temp->sessid, request_line, t->be->beprm->appsession_len);
3648 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003649 asession_temp->serverid = NULL;
3650
3651 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01003652 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *)&asession_temp)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003653 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3654 /* free previously allocated memory */
3655 pool_free_to(apools.sessid, local_asession.sessid);
3656 Alert("Not enough memory process_cli():asession:calloc().\n");
3657 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3658 return;
3659 }
3660 asession_temp->sessid = local_asession.sessid;
3661 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01003662 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003663 }
3664 else {
3665 /* free previously allocated memory */
3666 pool_free_to(apools.sessid, local_asession.sessid);
3667 }
3668
Willy Tarreau830ff452006-12-17 19:31:23 +01003669 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003670 asession_temp->request_count++;
3671
3672#if defined(DEBUG_HASH)
3673 print_table(&(t->proxy->htbl_proxy));
3674#endif
3675 if (asession_temp->serverid == NULL) {
3676 Alert("Found Application Session without matching server.\n");
3677 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003678 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003679 while (srv) {
3680 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003681 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003682 /* we found the server and it's usable */
3683 t->flags &= ~SN_CK_MASK;
3684 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3685 t->srv = srv;
3686 break;
3687 } else {
3688 t->flags &= ~SN_CK_MASK;
3689 t->flags |= SN_CK_DOWN;
3690 }
3691 }
3692 srv = srv->next;
3693 }
3694 }
3695}
3696
3697
Willy Tarreaub2513902006-12-17 14:52:38 +01003698
3699/*
3700 * In a GET request, check if the requested URI matches the stats uri for the
3701 * current backend, and if an authorization has been passed and is valid.
3702 *
Willy Tarreau830ff452006-12-17 19:31:23 +01003703 * 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 +01003704 * is valid. An HTTP/401 response may be sent, or produce_content() can be
3705 * called to start sending data.
3706 *
3707 * Returns 1 if the session's state changes, otherwise 0.
3708 */
3709int stats_check_uri_auth(struct session *t, struct proxy *backend)
3710{
3711 struct uri_auth *uri_auth = backend->uri_auth;
3712 struct user_auth *user;
3713 int authenticated, cur_idx;
3714 char *h;
3715
3716 if (t->hreq.start.len < uri_auth->uri_len + 4) /* +4 for "GET " */
3717 return 0;
3718
3719 if (memcmp(t->hreq.start.str + 4, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
3720 return 0;
3721
3722 /* we are in front of a interceptable URI. Let's check
3723 * if there's an authentication and if it's valid.
3724 */
3725 user = uri_auth->users;
3726 if (!user) {
3727 /* no user auth required, it's OK */
3728 authenticated = 1;
3729 } else {
3730 authenticated = 0;
3731
3732 /* a user list is defined, we have to check.
3733 * skip 21 chars for "Authorization: Basic ".
3734 */
3735
3736 /* FIXME: this should move to an earlier place */
3737 cur_idx = 0;
3738 h = t->req->data + t->hreq.sor;
3739 while ((cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
3740 int len = t->hreq.hdr_idx.v[cur_idx].len;
3741 if (len > 14 &&
3742 !strncasecmp("Authorization:", h, 14)) {
3743 t->hreq.auth_hdr.str = h;
3744 t->hreq.auth_hdr.len = len;
3745 break;
3746 }
3747 h += len + t->hreq.hdr_idx.v[cur_idx].cr + 1;
3748 }
3749
3750 if (t->hreq.auth_hdr.len < 21 ||
3751 memcmp(t->hreq.auth_hdr.str + 14, " Basic ", 7))
3752 user = NULL;
3753
3754 while (user) {
3755 if ((t->hreq.auth_hdr.len == user->user_len + 14 + 7)
3756 && !memcmp(t->hreq.auth_hdr.str + 14 + 7,
3757 user->user_pwd, user->user_len)) {
3758 authenticated = 1;
3759 break;
3760 }
3761 user = user->next;
3762 }
3763 }
3764
3765 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01003766 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01003767
3768 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01003769 msg.str = trash;
3770 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreaub2513902006-12-17 14:52:38 +01003771 t->logs.status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01003772 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01003773 if (!(t->flags & SN_ERR_MASK))
3774 t->flags |= SN_ERR_PRXCOND;
3775 if (!(t->flags & SN_FINST_MASK))
3776 t->flags |= SN_FINST_R;
3777 return 1;
3778 }
3779
3780 /* The request is valid, the user is authenticate. Let's start sending
3781 * data.
3782 */
3783 t->cli_state = CL_STSHUTR;
3784 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
3785 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
3786 t->data_source = DATA_SRC_STATS;
3787 t->data_state = DATA_ST_INIT;
3788 produce_content(t);
3789 return 1;
3790}
3791
3792
3793
Willy Tarreaubaaee002006-06-26 02:48:02 +02003794/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01003795 * Print a debug line with a header
3796 */
3797void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
3798{
3799 int len, max;
3800 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
3801 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
3802 max = end - start;
3803 UBOUND(max, sizeof(trash) - len - 1);
3804 len += strlcpy2(trash + len, start, max + 1);
3805 trash[len++] = '\n';
3806 write(1, trash, len);
3807}
3808
3809
3810/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02003811 * Local variables:
3812 * c-indent-level: 8
3813 * c-basic-offset: 8
3814 * End:
3815 */