blob: b051467d94a611005777a325f63034af605e850f [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * HTTP protocol analyzer
3 *
4 * Copyright 2000-2006 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <syslog.h>
20
21#include <sys/socket.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24
Willy Tarreau2dd0d472006-06-29 17:53:05 +020025#include <common/appsession.h>
26#include <common/compat.h>
27#include <common/config.h>
Willy Tarreaua4cd1f52006-12-16 19:57:26 +010028#include <common/debug.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020029#include <common/memory.h>
30#include <common/mini-clist.h>
31#include <common/standard.h>
32#include <common/time.h>
33#include <common/uri_auth.h>
34#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020035
36#include <types/capture.h>
37#include <types/client.h>
38#include <types/global.h>
39#include <types/httperr.h>
40#include <types/polling.h>
41#include <types/proxy.h>
42#include <types/server.h>
43
44#include <proto/backend.h>
45#include <proto/buffers.h>
46#include <proto/fd.h>
47#include <proto/log.h>
Willy Tarreau58f10d72006-12-04 02:26:12 +010048#include <proto/hdr_idx.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020049#include <proto/proto_http.h>
50#include <proto/queue.h>
51#include <proto/session.h>
52#include <proto/task.h>
53
Willy Tarreau6d1a9882007-01-07 02:03:04 +010054#ifdef CONFIG_HAP_TCPSPLICE
55#include <libtcpsplice.h>
56#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020057
Willy Tarreau58f10d72006-12-04 02:26:12 +010058#define DEBUG_PARSE_NO_SPEEDUP
59#undef DEBUG_PARSE_NO_SPEEDUP
60
Willy Tarreau976f1ee2006-12-17 10:06:03 +010061/* This is used to perform a quick jump as an alternative to a break/continue
62 * instruction. The first argument is the label for normal operation, and the
63 * second one is the break/continue instruction in the no_speedup mode.
64 */
65
66#ifdef DEBUG_PARSE_NO_SPEEDUP
67#define QUICK_JUMP(x,y) y
68#else
69#define QUICK_JUMP(x,y) goto x
70#endif
71
Willy Tarreau1c47f852006-07-09 08:22:27 +020072/* This is used by remote monitoring */
Willy Tarreau0f772532006-12-23 20:51:41 +010073const char HTTP_200[] =
Willy Tarreau1c47f852006-07-09 08:22:27 +020074 "HTTP/1.0 200 OK\r\n"
75 "Cache-Control: no-cache\r\n"
76 "Connection: close\r\n"
77 "Content-Type: text/html\r\n"
78 "\r\n"
79 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
80
Willy Tarreau0f772532006-12-23 20:51:41 +010081const struct chunk http_200_chunk = {
82 .str = (char *)&HTTP_200,
83 .len = sizeof(HTTP_200)-1
84};
85
86const char *HTTP_302 =
87 "HTTP/1.0 302 Found\r\n"
88 "Cache-Control: no-cache\r\n"
89 "Connection: close\r\n"
90 "Location: "; /* not terminated since it will be concatenated with the URL */
91
92/* same as 302 except that the browser MUST retry with the GET method */
93const char *HTTP_303 =
94 "HTTP/1.0 303 See Other\r\n"
95 "Cache-Control: no-cache\r\n"
96 "Connection: close\r\n"
97 "Location: "; /* not terminated since it will be concatenated with the URL */
98
Willy Tarreaubaaee002006-06-26 02:48:02 +020099/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
100const char *HTTP_401_fmt =
101 "HTTP/1.0 401 Unauthorized\r\n"
102 "Cache-Control: no-cache\r\n"
103 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +0200104 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +0200105 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
106 "\r\n"
107 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
108
Willy Tarreau0f772532006-12-23 20:51:41 +0100109
110const int http_err_codes[HTTP_ERR_SIZE] = {
111 [HTTP_ERR_400] = 400,
112 [HTTP_ERR_403] = 403,
113 [HTTP_ERR_408] = 408,
114 [HTTP_ERR_500] = 500,
115 [HTTP_ERR_502] = 502,
116 [HTTP_ERR_503] = 503,
117 [HTTP_ERR_504] = 504,
118};
119
Willy Tarreau80587432006-12-24 17:47:20 +0100120static const char *http_err_msgs[HTTP_ERR_SIZE] = {
Willy Tarreau0f772532006-12-23 20:51:41 +0100121 [HTTP_ERR_400] =
Willy Tarreau80587432006-12-24 17:47:20 +0100122 "HTTP/1.0 400 Bad request\r\n"
Willy Tarreau0f772532006-12-23 20:51:41 +0100123 "Cache-Control: no-cache\r\n"
124 "Connection: close\r\n"
125 "Content-Type: text/html\r\n"
126 "\r\n"
127 "<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
128
129 [HTTP_ERR_403] =
130 "HTTP/1.0 403 Forbidden\r\n"
131 "Cache-Control: no-cache\r\n"
132 "Connection: close\r\n"
133 "Content-Type: text/html\r\n"
134 "\r\n"
135 "<html><body><h1>403 Forbidden</h1>\nRequest forbidden by administrative rules.\n</body></html>\n",
136
137 [HTTP_ERR_408] =
138 "HTTP/1.0 408 Request Time-out\r\n"
139 "Cache-Control: no-cache\r\n"
140 "Connection: close\r\n"
141 "Content-Type: text/html\r\n"
142 "\r\n"
143 "<html><body><h1>408 Request Time-out</h1>\nYour browser didn't send a complete request in time.\n</body></html>\n",
144
145 [HTTP_ERR_500] =
146 "HTTP/1.0 500 Server Error\r\n"
147 "Cache-Control: no-cache\r\n"
148 "Connection: close\r\n"
149 "Content-Type: text/html\r\n"
150 "\r\n"
151 "<html><body><h1>500 Server Error</h1>\nAn internal server error occured.\n</body></html>\n",
152
153 [HTTP_ERR_502] =
154 "HTTP/1.0 502 Bad Gateway\r\n"
155 "Cache-Control: no-cache\r\n"
156 "Connection: close\r\n"
157 "Content-Type: text/html\r\n"
158 "\r\n"
159 "<html><body><h1>502 Bad Gateway</h1>\nThe server returned an invalid or incomplete response.\n</body></html>\n",
160
161 [HTTP_ERR_503] =
162 "HTTP/1.0 503 Service Unavailable\r\n"
163 "Cache-Control: no-cache\r\n"
164 "Connection: close\r\n"
165 "Content-Type: text/html\r\n"
166 "\r\n"
167 "<html><body><h1>503 Service Unavailable</h1>\nNo server is available to handle this request.\n</body></html>\n",
168
169 [HTTP_ERR_504] =
170 "HTTP/1.0 504 Gateway Time-out\r\n"
171 "Cache-Control: no-cache\r\n"
172 "Connection: close\r\n"
173 "Content-Type: text/html\r\n"
174 "\r\n"
175 "<html><body><h1>504 Gateway Time-out</h1>\nThe server didn't respond in time.\n</body></html>\n",
176
177};
178
Willy Tarreau80587432006-12-24 17:47:20 +0100179/* We must put the messages here since GCC cannot initialize consts depending
180 * on strlen().
181 */
182struct chunk http_err_chunks[HTTP_ERR_SIZE];
183
184void init_proto_http()
185{
186 int msg;
187 for (msg = 0; msg < HTTP_ERR_SIZE; msg++) {
188 if (!http_err_msgs[msg]) {
189 Alert("Internal error: no message defined for HTTP return code %d. Aborting.\n", msg);
190 abort();
191 }
192
193 http_err_chunks[msg].str = (char *)http_err_msgs[msg];
194 http_err_chunks[msg].len = strlen(http_err_msgs[msg]);
195 }
196}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200197
Willy Tarreau53b6c742006-12-17 13:37:46 +0100198/*
199 * We have 26 list of methods (1 per first letter), each of which can have
200 * up to 3 entries (2 valid, 1 null).
201 */
202struct http_method_desc {
203 http_meth_t meth;
204 int len;
205 const char text[8];
206};
207
208static struct http_method_desc http_methods[26][3] = {
209 ['C' - 'A'] = {
210 [0] = { .meth = HTTP_METH_CONNECT , .len=7, .text="CONNECT" },
211 },
212 ['D' - 'A'] = {
213 [0] = { .meth = HTTP_METH_DELETE , .len=6, .text="DELETE" },
214 },
215 ['G' - 'A'] = {
216 [0] = { .meth = HTTP_METH_GET , .len=3, .text="GET" },
217 },
218 ['H' - 'A'] = {
219 [0] = { .meth = HTTP_METH_HEAD , .len=4, .text="HEAD" },
220 },
221 ['P' - 'A'] = {
222 [0] = { .meth = HTTP_METH_POST , .len=4, .text="POST" },
223 [1] = { .meth = HTTP_METH_PUT , .len=3, .text="PUT" },
224 },
225 ['T' - 'A'] = {
226 [0] = { .meth = HTTP_METH_TRACE , .len=5, .text="TRACE" },
227 },
228 /* rest is empty like this :
229 * [1] = { .meth = HTTP_METH_NONE , .len=0, .text="" },
230 */
231};
232
Willy Tarreaubaaee002006-06-26 02:48:02 +0200233#ifdef DEBUG_FULL
234static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
235static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
236#endif
237
238
239/*
240 * returns a message to the client ; the connection is shut down for read,
241 * and the request is cleared so that no server connection can be initiated.
242 * The client must be in a valid state for this (HEADER, DATA ...).
Willy Tarreau0f772532006-12-23 20:51:41 +0100243 * Nothing is performed on the server side. The message is contained in a
244 * "chunk". If it is null, then an empty message is used.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200245 * The reply buffer doesn't need to be empty before this.
246 */
Willy Tarreau0f772532006-12-23 20:51:41 +0100247void client_retnclose(struct session *s, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200248{
Willy Tarreau2a429502006-10-15 14:52:29 +0200249 MY_FD_CLR(s->cli_fd, StaticReadEvent);
250 MY_FD_SET(s->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +0200251 tv_eternity(&s->req->rex);
Willy Tarreau73de9892006-11-30 11:40:23 +0100252 if (s->fe->clitimeout)
253 tv_delayfrom(&s->rep->wex, &now, s->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200254 else
Willy Tarreaud7971282006-07-29 18:36:34 +0200255 tv_eternity(&s->rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200256 shutdown(s->cli_fd, SHUT_RD);
257 s->cli_state = CL_STSHUTR;
258 buffer_flush(s->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100259 if (msg->len)
260 buffer_write(s->rep, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200261 s->req->l = 0;
262}
263
264
265/*
266 * returns a message into the rep buffer, and flushes the req buffer.
Willy Tarreau0f772532006-12-23 20:51:41 +0100267 * The reply buffer doesn't need to be empty before this. The message
268 * is contained in a "chunk". If it is null, then an empty message is
269 * used.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200270 */
Willy Tarreau0f772532006-12-23 20:51:41 +0100271void client_return(struct session *s, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200272{
273 buffer_flush(s->rep);
Willy Tarreau0f772532006-12-23 20:51:41 +0100274 if (msg->len)
275 buffer_write(s->rep, msg->str, msg->len);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200276 s->req->l = 0;
277}
278
279
280/* This function turns the server state into the SV_STCLOSE, and sets
Willy Tarreau0f772532006-12-23 20:51:41 +0100281 * indicators accordingly. Note that if <status> is 0, or if the message
282 * pointer is NULL, then no message is returned.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200283 */
284void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreau0f772532006-12-23 20:51:41 +0100285 int status, const struct chunk *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200286{
287 t->srv_state = SV_STCLOSE;
Willy Tarreau0f772532006-12-23 20:51:41 +0100288 if (status > 0 && msg) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200289 t->logs.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100290 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreau0f772532006-12-23 20:51:41 +0100291 client_return(t, msg);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200292 }
293 if (!(t->flags & SN_ERR_MASK))
294 t->flags |= err;
295 if (!(t->flags & SN_FINST_MASK))
296 t->flags |= finst;
297}
298
Willy Tarreau80587432006-12-24 17:47:20 +0100299/* This function returns the appropriate error location for the given session
300 * and message.
301 */
302
303struct chunk *error_message(struct session *s, int msgnum)
304{
305 if (s->be->beprm->errmsg[msgnum].str)
306 return &s->be->beprm->errmsg[msgnum];
307 else if (s->fe->errmsg[msgnum].str)
308 return &s->fe->errmsg[msgnum];
309 else
310 return &http_err_chunks[msgnum];
311}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200312
Willy Tarreau53b6c742006-12-17 13:37:46 +0100313/*
314 * returns HTTP_METH_NONE if there is nothing valid to read (empty or non-text
315 * string), HTTP_METH_OTHER for unknown methods, or the identified method.
316 */
317static http_meth_t find_http_meth(const char *str, const int len)
318{
319 unsigned char m;
320 struct http_method_desc *h;
321
322 m = ((unsigned)*str - 'A');
323
324 if (m < 26) {
325 int l;
326 for (h = http_methods[m]; (l = (h->len)) > 0; h++) {
327 if (len <= l)
328 continue;
329
330 if (str[l] != ' ' && str[l] != '\t')
331 continue;
332
333 if (memcmp(str, h->text, l) == 0) {
334 return h->meth;
335 }
336 };
337 return HTTP_METH_OTHER;
338 }
339 return HTTP_METH_NONE;
340
341}
342
343
Willy Tarreaubaaee002006-06-26 02:48:02 +0200344/* Processes the client and server jobs of a session task, then
345 * puts it back to the wait queue in a clean state, or
346 * cleans up its resources if it must be deleted. Returns
347 * the time the task accepts to wait, or TIME_ETERNITY for
348 * infinity.
349 */
350int process_session(struct task *t)
351{
352 struct session *s = t->context;
353 int fsm_resync = 0;
354
355 do {
356 fsm_resync = 0;
357 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
358 fsm_resync |= process_cli(s);
359 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
360 fsm_resync |= process_srv(s);
361 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
362 } while (fsm_resync);
363
364 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
365 struct timeval min1, min2;
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200366 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
367 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200368
Willy Tarreaud7971282006-07-29 18:36:34 +0200369 tv_min(&min1, &s->req->rex, &s->req->wex);
370 tv_min(&min2, &s->rep->rex, &s->rep->wex);
371 tv_min(&min1, &min1, &s->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200372 tv_min(&t->expire, &min1, &min2);
373
374 /* restore t to its place in the task list */
375 task_queue(t);
376
377#ifdef DEBUG_FULL
378 /* DEBUG code : this should never ever happen, otherwise it indicates
379 * that a task still has something to do and will provoke a quick loop.
380 */
381 if (tv_remain2(&now, &t->expire) <= 0)
382 exit(100);
383#endif
384
385 return tv_remain2(&now, &t->expire); /* nothing more to do */
386 }
387
Willy Tarreauf1221aa2006-12-17 22:14:12 +0100388 s->fe->feconn--;
389 if (s->flags & SN_BE_ASSIGNED)
390 s->be->beprm->beconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200391 actconn--;
392
393 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
394 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100395 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
Willy Tarreau830ff452006-12-17 19:31:23 +0100396 s->uniq_id, s->be->beprm->id,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100397 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200398 write(1, trash, len);
399 }
400
401 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
Willy Tarreau35d66b02007-01-02 00:28:21 +0100402 if (s->req != NULL)
403 s->logs.bytes_in = s->req->total;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200404 if (s->rep != NULL)
Willy Tarreau35d66b02007-01-02 00:28:21 +0100405 s->logs.bytes_out = s->rep->total;
406
407 s->fe->bytes_in += s->logs.bytes_in;
408 s->fe->bytes_out += s->logs.bytes_out;
409 if (s->be->beprm != s->fe) {
410 s->be->beprm->bytes_in += s->logs.bytes_in;
411 s->be->beprm->bytes_out += s->logs.bytes_out;
412 }
413 if (s->srv) {
414 s->srv->bytes_in += s->logs.bytes_in;
415 s->srv->bytes_out += s->logs.bytes_out;
416 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200417
418 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200419 if (s->logs.logwait &&
420 !(s->flags & SN_MONITOR) &&
Willy Tarreau73de9892006-11-30 11:40:23 +0100421 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total))
Willy Tarreaubaaee002006-06-26 02:48:02 +0200422 sess_log(s);
423
424 /* the task MUST not be in the run queue anymore */
425 task_delete(t);
426 session_free(s);
427 task_free(t);
428 return TIME_ETERNITY; /* rest in peace for eternity */
429}
430
431
432/*
433 * FIXME: This should move to the HTTP_flow_analyzer code
434 */
435
436/*
437 * manages the client FSM and its socket. BTW, it also tries to handle the
438 * cookie. It returns 1 if a state has changed (and a resync may be needed),
439 * 0 else.
440 */
441int process_cli(struct session *t)
442{
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100443 struct http_req *hreq = &t->hreq;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200444 int s = t->srv_state;
445 int c = t->cli_state;
446 struct buffer *req = t->req;
447 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100448 int delete_header = 0;
449
Willy Tarreaub2513902006-12-17 14:52:38 +0100450 int cur_hdr;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200451
Willy Tarreau45e73e32006-12-17 00:05:15 +0100452 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 +0200453 cli_stnames[c], srv_stnames[s],
Willy Tarreau2a429502006-10-15 14:52:29 +0200454 MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
Willy Tarreaud7971282006-07-29 18:36:34 +0200455 req->rex.tv_sec, req->rex.tv_usec,
456 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau45e73e32006-12-17 00:05:15 +0100457
Willy Tarreaubaaee002006-06-26 02:48:02 +0200458 if (c == CL_STHEADERS) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100459 /*
460 * Now parse the partial (or complete) lines.
461 * We will check the request syntax, and also join multi-line
462 * headers. An index of all the lines will be elaborated while
463 * parsing.
464 *
465 * For the parsing, we use a 10 states FSM.
466 *
467 * RFC2616 requires that both LF and CRLF are recognized as
468 * line breaks, but that any other combination is an error.
469 * To avoid duplicating all the states above to check for CR,
470 * we use a special bit HTTP_PA_LF_EXP that we 'OR' with the
471 * state we will switch to if the LF is seen, so that we know
472 * whether there's a pending CR or not. We can check it
473 * globally since all CR followed by anything but LF are
474 * errors. Each state is entered with the first character is
475 * has to process at req->lr. We also have HTTP_PA_CR_SKIP
476 * indicating that a CR has been seen on current line and
477 * skipped.
478 *
479 * Here is the information we currently have :
Willy Tarreau45e73e32006-12-17 00:05:15 +0100480 * req->data + req->sor = beginning of request
481 * req->data + req->eoh = end of (parsed) headers
Willy Tarreau58f10d72006-12-04 02:26:12 +0100482 * req->lr = first non-visited byte
483 * req->r = end of data
484 */
485
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100486 char *sol, *eol; /* Start Of Line, End Of Line */
Willy Tarreau830ff452006-12-17 19:31:23 +0100487 struct proxy *cur_proxy;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100488
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100489 eol = sol = req->data + hreq->req.eoh;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100490
Willy Tarreau58f10d72006-12-04 02:26:12 +0100491 while (req->lr < req->r) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100492 int parse;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200493
Willy Tarreau45e73e32006-12-17 00:05:15 +0100494 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",
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100495 hreq->req.hdr_state, hreq->hdr_idx.used, hreq->hdr_idx.tail, hreq->hdr_idx.last,
496 sol - req->data, req->lr - req->data, req->r - req->data, hreq->req.eoh);
Willy Tarreau45e73e32006-12-17 00:05:15 +0100497
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100498 if (hreq->req.hdr_state & HTTP_PA_LF_EXP) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100499 if (*req->lr != '\n') {
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100500 hreq->req.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100501 break;
502 }
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100503 hreq->req.hdr_state &= ~HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100504 }
505
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100506 parse = hreq->req.hdr_state & ~HTTP_PA_CR_SKIP;;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100507
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100508 if (parse == HTTP_PA_HDR_LF) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100509 parse_hdr_lf:
510 /* The LF validating last header, but it
511 * may also be an LWS, in which case we will
512 * need more data to know if we can close this
513 * header or not. However, we must check right
514 * now if this LF/CRLF closes an empty line, in
515 * which case it means the end of the request.
516 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100517 eol = req->lr;
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100518 if (hreq->req.hdr_state & HTTP_PA_CR_SKIP)
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100519 eol--; /* Get back to the CR */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100520
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100521 if (eol == sol) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100522 /* We have found the end of the headers.
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100523 * sol points to the ending LF/CRLF,
Willy Tarreau58f10d72006-12-04 02:26:12 +0100524 * and req->lr points to the first byte
525 * after the LF, so it is easy to append
526 * anything there.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200527 */
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100528 hreq->req.hdr_state = HTTP_PA_LFLF;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100529 QUICK_JUMP(parse_lflf, continue);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100530 }
531
532 if (req->lr + 1 >= req->r) /* LF, ?? */
533 break;
534 req->lr++;
535
536 /* Right now, we *know* that there is one char
537 * available at req->lr.
538 */
539
540 if (*req->lr == ' ' || *req->lr == '\t') {
541 /* We have an LWS, we will replace the
542 * CR and LF with spaces as RFC2616
543 * allows it. <lr> now points to the
544 * first space char of the LWS part.
545 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100546 for (;eol < req->lr; eol++)
547 *eol = ' ';
Willy Tarreau58f10d72006-12-04 02:26:12 +0100548
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100549 hreq->req.hdr_state = HTTP_PA_HDR_LWS;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100550 QUICK_JUMP(parse_hdr_lws, continue);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100551 }
552
553 /**********************************************
554 * We now have one complete header between *
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100555 * sol and eol, with a possible CR at eol, *
Willy Tarreau58f10d72006-12-04 02:26:12 +0100556 * everything ending before req->lr. Some very*
557 * early processing can be applied. *
558 **********************************************/
559
560 /*
561 * FIXME: insert a REQHEADER hook here.
562 * For instance, we could check the header's
563 * syntax such as forbidding the leading space
564 * in the first header (Apache also has the same problem)
565 */
566
567
568 /* 1: we might have to print this header */
569 if ((global.mode & MODE_DEBUG) &&
570 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100571 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100572
573
574 /* 2: maybe we have to copy this header for the logs ? */
575 if (t->logs.logwait & LW_REQHDR) {
576 /* FIXME: we must *search* the value after the ':' and not
577 * consider that it's necessary after one single space.*/
578 struct cap_hdr *h;
579 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +0100580 for (h = t->fe->fiprm->req_cap; h; h = h->next) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100581 if ((h->namelen + 2 <= eol - sol) &&
582 (sol[h->namelen] == ':') &&
583 (strncasecmp(sol, h->name, h->namelen) == 0)) {
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100584 if (hreq->req.cap[h->index] == NULL)
585 hreq->req.cap[h->index] =
Willy Tarreau45e73e32006-12-17 00:05:15 +0100586 pool_alloc_from(h->pool, h->len + 1);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100587
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100588 if (hreq->req.cap[h->index] == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100589 Alert("HTTP capture : out of memory.\n");
590 continue;
591 }
592
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100593 len = eol - (sol + h->namelen + 2);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100594 if (len > h->len)
595 len = h->len;
596
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100597 memcpy(hreq->req.cap[h->index], sol + h->namelen + 2, len);
598 hreq->req.cap[h->index][len]=0;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100599 }
600 }
601 }
602
603
604 /* 3: We might need to remove "connection:" */
Willy Tarreaue01954f2006-12-30 23:43:54 +0100605 if (!delete_header &&
606 ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) &&
607 (strncasecmp(sol, "Connection:", 11) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100608 delete_header = 1;
609 }
610
611
Willy Tarreau58f10d72006-12-04 02:26:12 +0100612 /* OK, that's enough processing for the first step.
613 * Now either we index this header or we remove it.
614 */
615
616 if (!delete_header) {
617 /* we insert it into the index */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100618 if (hdr_idx_add(eol - sol, req->lr - eol - 1,
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100619 &hreq->hdr_idx, hreq->hdr_idx.tail) < 0) {
620 hreq->req.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100621 break;
622 }
623 } else {
624 /* we remove it */
625 delete_header = 0;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100626 buffer_replace2(req, sol, req->lr, NULL, 0);
627 /* WARNING: eol is not valid anymore, since the
Willy Tarreau58f10d72006-12-04 02:26:12 +0100628 * header may have been deleted or truncated ! */
629 }
630
631 /* In any case, we set the next header pointer
632 * to the next line.
633 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100634 sol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100635
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100636#ifdef DEBUG_PARSE_NO_SPEEDUP
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100637 hreq->req.hdr_state = HTTP_PA_HEADER;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100638 continue;
639#else
Willy Tarreau58f10d72006-12-04 02:26:12 +0100640 /*
641 * We know that at least one character remains.
642 * It is interesting to directly branch to the
643 * matching state.
644 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100645 eol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100646 if (IS_CTL(*req->lr)) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100647 if (*eol == '\r') {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100648 req->lr++;
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100649 hreq->req.hdr_state = HTTP_PA_LFLF | HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100650 continue;
651 }
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100652 else if (*eol == '\n') {
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100653 hreq->req.hdr_state = HTTP_PA_LFLF;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100654 goto parse_lflf;
655 }
656 else {
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100657 hreq->req.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100658 break;
659 }
660 }
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100661 hreq->req.hdr_state = HTTP_PA_HEADER;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100662 goto parse_inside_hdr;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100663#endif
664
665 } else if (parse == HTTP_PA_STRT_LF) {
666 parse_strt_lf:
667 /* The LF validating the request line */
668
669 eol = req->lr;
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100670 if (hreq->req.hdr_state & HTTP_PA_CR_SKIP)
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100671 eol--; /* Get back to the CR */
672
673 /* We have the complete start line between
674 * sol and eol (excluded). lr points to
675 * the LF.
676 */
677
678 /* FIXME: insert a REQUESTURI hook here. */
679
680
681 /* 1: we might have to print this header */
682 if ((global.mode & MODE_DEBUG) &&
683 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
684 debug_hdr("clireq", t, sol, eol);
685
686 /* 2: maybe we have to copy the original REQURI for the logs ? */
687 if (t->logs.logwait & LW_REQ) {
688 /* we have a complete HTTP request that we must log */
689 if ((t->logs.uri = pool_alloc(requri)) != NULL) {
690 int urilen = eol - sol;
691
692 if (urilen >= REQURI_LEN)
693 urilen = REQURI_LEN - 1;
694 memcpy(t->logs.uri, sol, urilen);
695 t->logs.uri[urilen] = 0;
696
697 if (!(t->logs.logwait &= ~LW_REQ))
698 sess_log(t);
699 } else {
700 Alert("HTTP logging : out of memory.\n");
701 }
702 }
703
704 /* 3: reference this line as the start line */
705 if (hdr_idx_add(eol - sol, req->lr - eol,
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100706 &hreq->hdr_idx, hreq->hdr_idx.tail) < 0) {
707 hreq->req.hdr_state = HTTP_PA_ERROR;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100708 break;
709 }
710
711 req->lr++;
712 sol = req->lr;
713 /* in fact, a state is missing here, we should
714 * be able to distinguish between an empty line
715 * and a header.
716 */
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100717 hreq->req.hdr_state = HTTP_PA_HEADER;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100718#ifdef DEBUG_PARSE_NO_SPEEDUP
Willy Tarreau58f10d72006-12-04 02:26:12 +0100719 continue;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100720#else
721 if (req->lr < req->r)
722 goto parse_inside_hdr;
723 else
724 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100725#endif
726
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100727 } else if (parse == HTTP_PA_HEADER) {
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100728 char *ptr;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100729 /* Inside a non-empty header */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100730
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100731 parse_inside_hdr:
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100732 delete_header = 0;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100733
734 ptr = req->lr;
735
736#ifdef GCC_FINALLY_PRODUCES_EFFICIENT_WHILE_LOOPS
737 /* This code is disabled right now because
738 * eventhough it seems straightforward, the
739 * object code produced by GCC is so much
740 * suboptimal that about 10% of the time
741 * spend parsing header is there.
742 */
743 while (ptr < req->r && !IS_CTL(*ptr))
744 ptr++;
745 req->lr = ptr;
746 if (ptr == req->r)
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100747 break;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100748#else
749 /* Just by using this loop instead of the previous one,
750 * the global performance increases by about 2% ! The
751 * code is also smaller by about 50 bytes.
752 */
753 goto reqhdr_loop_chk;
754 reqhdr_loop:
755 ptr++;
756 reqhdr_loop_chk:
757 if (ptr == req->r) {
758 req->lr = ptr;
759 break;
760 }
761 if (*ptr != 0x7F && (unsigned)*ptr >= 0x20)
762 goto reqhdr_loop;
763 req->lr = ptr;
764#endif
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100765
766 /* we have a CTL char */
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100767 if (*ptr == '\r') {
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100768 hreq->req.hdr_state = HTTP_PA_HDR_LF | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100769 req->lr++;
770 continue;
771 }
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100772 else if (*ptr == '\n') {
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100773 hreq->req.hdr_state = HTTP_PA_HDR_LF;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100774 QUICK_JUMP(parse_hdr_lf, continue);
775 }
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100776 hreq->req.hdr_state = HTTP_PA_ERROR;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100777 break;
778
779 } else if (parse == HTTP_PA_EMPTY) {
780 /* leading empty lines */
781
782 if (*req->lr == '\n') {
783 req->lr ++;
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100784 hreq->req.hdr_state = HTTP_PA_EMPTY;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100785 continue;
786 }
787 else if (*req->lr == '\r') {
788 req->lr ++;
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100789 hreq->req.hdr_state = HTTP_PA_EMPTY | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100790 continue;
791 }
792
793 FSM_PRINTF(stderr, "PA_EMPTY[0]: h=%d, lr=%d, r=%d\n",
794 sol - req->data, req->lr - req->data, req->r - req->data);
795
796#if PARSE_PRESERVE_EMPTY_LINES
797 /* only skip empty leading lines, don't remove them */
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100798 hreq->hdr_idx.v[0].len = req->lr - sol;
799 hreq->sor = hreq->hdr_idx.v[0].len;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100800#else
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100801 /* remove empty leading lines, as recommended by
802 * RFC2616. This takes a lot of time because we
803 * must move all the buffer backwards, but this
804 * is rarely needed. The method above will be
805 * cleaner when we'll be able to start sending
806 * the request from any place in the buffer.
807 */
808 buffer_replace2(req, sol, req->lr, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100809#endif
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100810 sol = req->lr;
811 FSM_PRINTF(stderr, "PA_EMPTY[1]: h=%d, lr=%d, r=%d\n",
812 sol - req->data, req->lr - req->data, req->r - req->data);
813
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100814 hreq->req.hdr_state = HTTP_PA_START;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100815 /* we know that we still have one char available */
816 QUICK_JUMP(parse_start, continue);
817
818 } else if (parse == HTTP_PA_START) {
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100819 char *ptr;
820 /* Inside the start line */
821
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100822 parse_start:
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100823 ptr = req->lr;
824
825#ifdef GCC_FINALLY_PRODUCES_EFFICIENT_WHILE_LOOPS
826 /* This code is disabled right now because
827 * eventhough it seems straightforward, the
828 * object code produced by GCC is so much
829 * suboptimal that about 10% of the time
830 * spend parsing header is there.
831 */
832 while (ptr < req->r && !IS_CTL(*ptr))
833 ptr++;
834 req->lr = ptr;
835 if (ptr == req->r)
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100836 break;
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100837#else
838 /* Just by using this loop instead of the previous one,
839 * the global performance increases by about 2% ! The
840 * code is also smaller by about 50 bytes.
841 */
842 goto reqstrt_loop_chk;
843 reqstrt_loop:
844 ptr++;
845 reqstrt_loop_chk:
846 if (ptr == req->r) {
847 req->lr = ptr;
848 break;
849 }
850 if (*ptr != 0x7F && (unsigned)*ptr >= 0x20)
851 goto reqstrt_loop;
852 req->lr = ptr;
853#endif
854
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100855 /* we have a CTL char */
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100856 if (*ptr == '\r') {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100857 req->lr++;
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100858 hreq->req.hdr_state = HTTP_PA_STRT_LF | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100859 continue;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100860 }
Willy Tarreau230fd0b2006-12-17 12:05:00 +0100861 else if (*ptr == '\n') {
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100862 hreq->req.hdr_state = HTTP_PA_STRT_LF;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100863 /* we know that we still have one char available */
864 QUICK_JUMP(parse_strt_lf, continue);
865 }
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100866 hreq->req.hdr_state = HTTP_PA_ERROR;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100867 break;
868
Willy Tarreau58f10d72006-12-04 02:26:12 +0100869
870 } else if (parse == HTTP_PA_LFLF) {
871 parse_lflf:
872 req->lr ++;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100873 /* sol points to either CR or CRLF, and
Willy Tarreau58f10d72006-12-04 02:26:12 +0100874 * req->lr points to 1 char after LF.
875 */
876
877 /*
878 * FIXME: insert a hook here for the end of the headers
879 */
880 break;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100881
882 } else if (parse == HTTP_PA_HDR_LWS) {
883 parse_hdr_lws:
884 /* Inside an LWS. We just replace tabs with
885 * spaces and fall back to the HEADER state
886 * at the first non-space character
887 */
888
889 while (req->lr < req->r) {
890 if (*req->lr == '\t')
891 *req->lr = ' ';
892 else if (*req->lr != ' ') {
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100893 hreq->req.hdr_state = HTTP_PA_HEADER;
Willy Tarreau976f1ee2006-12-17 10:06:03 +0100894 QUICK_JUMP(parse_inside_hdr, break);
895 }
896 req->lr++;
897 }
898 continue;
899
Willy Tarreau58f10d72006-12-04 02:26:12 +0100900 } else if (parse == HTTP_PA_ERROR) {
901 break;
902 }
903
904 } /* end of the "while(req->lr < req->r)" loop */
905
Willy Tarreau45e73e32006-12-17 00:05:15 +0100906 /* update the end of headers */
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100907 hreq->req.eoh = sol - req->data;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100908
909 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",
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100910 hreq->req.hdr_state, hreq->hdr_idx.used, hreq->hdr_idx.tail, hreq->hdr_idx.last,
911 sol - req->data, req->lr - req->data, req->r - req->data, hreq->req.eoh);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100912
913 /*
914 * Now, let's catch bad requests.
915 */
916
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100917 if (hreq->req.hdr_state == HTTP_PA_ERROR)
Willy Tarreau06619262006-12-17 08:37:22 +0100918 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100919
920 /*
921 * Now we quickly check if we have found a full request.
922 * If not so, we check the FD and buffer states before leaving.
923 * A full request is indicated by the fact that we have seen
924 * the double LF/CRLF, so the state is HTTP_PA_LFLF.
925 *
926 */
927
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100928 if (hreq->req.hdr_state != HTTP_PA_LFLF) { /* Request not complete yet */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100929
930 /* 1: Since we are in header mode, if there's no space
931 * left for headers, we won't be able to free more
932 * later, so the session will never terminate. We
933 * must terminate it now.
934 */
935 if (req->l >= req->rlim - req->data) {
Willy Tarreau0f7562b2007-01-07 15:46:13 +0100936 /* FIXME: check if hreq.req.hdr_state & mask < HTTP_PA_HEADER,
Willy Tarreau58f10d72006-12-04 02:26:12 +0100937 * and return Status 414 Request URI too long instead.
938 */
Willy Tarreau06619262006-12-17 08:37:22 +0100939 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100940 }
941
942 /* 2: have we encountered a read error or a close ? */
943 else if (req->flags & (BF_READ_ERROR | BF_READ_NULL)) {
944 /* read error, or last read : give up. */
945 tv_eternity(&req->rex);
946 fd_delete(t->cli_fd);
947 t->cli_state = CL_STCLOSE;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +0100948 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100949 if (!(t->flags & SN_ERR_MASK))
950 t->flags |= SN_ERR_CLICL;
951 if (!(t->flags & SN_FINST_MASK))
952 t->flags |= SN_FINST_R;
953 return 1;
954 }
955
956 /* 3: has the read timeout expired ? */
957 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
958 /* read timeout : give up with an error message. */
959 t->logs.status = 408;
Willy Tarreau80587432006-12-24 17:47:20 +0100960 client_retnclose(t, error_message(t, HTTP_ERR_408));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +0100961 t->fe->failed_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100962 if (!(t->flags & SN_ERR_MASK))
963 t->flags |= SN_ERR_CLITO;
964 if (!(t->flags & SN_FINST_MASK))
965 t->flags |= SN_FINST_R;
966 return 1;
967 }
968
969 /* 4: do we need to re-enable the read socket ? */
970 else if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
971 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
972 * full. We cannot loop here since stream_sock_read will disable it only if
973 * req->l == rlim-data
974 */
975 MY_FD_SET(t->cli_fd, StaticReadEvent);
976 if (t->fe->clitimeout)
977 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
978 else
979 tv_eternity(&req->rex);
980 }
981 return t->cli_state != CL_STHEADERS;
982 }
983
984
985 /****************************************************************
986 * More interesting part now : we know that we have a complete *
987 * request which at least looks like HTTP. We have an indicator *
988 * of each header's length, so we can parse them quickly. *
989 ****************************************************************/
990
991
992 /*
Willy Tarreau06619262006-12-17 08:37:22 +0100993 * 1: check if the URI matches the monitor_uri.
994 * We have to do this for every request which gets in, because
995 * the monitor-uri is defined by the frontend. To speed-up the
996 * test, we include the leading and trailing spaces in the
997 * comparison. This is generally not a problem because the
998 * monitor-uri is primarily used by external checkers which
999 * send pre-formatted requests too.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001000 */
1001
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001002 hreq->start.str = req->data + hreq->req.sor; /* start of the REQURI */
1003 hreq->start.len = hreq->hdr_idx.v[hreq->hdr_idx.v[0].next].len; /* end of the REQURI */
1004 hreq->meth = find_http_meth(hreq->start.str, hreq->start.len);
Willy Tarreau06619262006-12-17 08:37:22 +01001005
1006 if ((t->fe->monitor_uri_len != 0) &&
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001007 (hreq->start.len >= t->fe->monitor_uri_len)) {
1008 char *p = hreq->start.str;
Willy Tarreau06619262006-12-17 08:37:22 +01001009 int idx = 0;
1010
1011 /* skip the method so that we accept any method */
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001012 while (idx < hreq->start.len && p[idx] != ' ')
Willy Tarreau06619262006-12-17 08:37:22 +01001013 idx++;
1014 p += idx;
1015
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001016 if (hreq->start.len - idx >= t->fe->monitor_uri_len &&
Willy Tarreau06619262006-12-17 08:37:22 +01001017 !memcmp(p, t->fe->monitor_uri, t->fe->monitor_uri_len)) {
1018 /*
1019 * We have found the monitor URI
1020 */
1021 t->flags |= SN_MONITOR;
1022 t->logs.status = 200;
Willy Tarreau0f772532006-12-23 20:51:41 +01001023 client_retnclose(t, &http_200_chunk);
Willy Tarreau06619262006-12-17 08:37:22 +01001024 goto return_prx_cond;
1025 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001026 }
1027
1028
1029 /*
1030 * 2: we will have to evaluate the filters.
1031 * As opposed to version 1.2, now they will be evaluated in the
1032 * filters order and not in the header order. This means that
1033 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +01001034 *
1035 * We can now check whether we want to switch to another
1036 * backend, in which case we will re-check the backend's
1037 * filters and various options. In order to support 3-level
1038 * switching, here's how we should proceed :
1039 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001040 * a) run be->fiprm.
1041 * if (switch) then switch ->be to the new backend.
1042 * b) run be->fiprm if (be != fe).
Willy Tarreau06619262006-12-17 08:37:22 +01001043 * There cannot be any switch from there, so ->be cannot be
1044 * changed anymore.
1045 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001046 * => filters always apply to ->be, then ->be may change.
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001047 *
Willy Tarreau830ff452006-12-17 19:31:23 +01001048 * The response path will be able to apply either ->be, or
1049 * ->be then ->fe filters in order to match the reverse of
1050 * the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +01001051 */
1052
Willy Tarreau06619262006-12-17 08:37:22 +01001053 do {
Willy Tarreau830ff452006-12-17 19:31:23 +01001054 struct proxy *rule_set = t->be->fiprm;
1055 cur_proxy = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +01001056
Willy Tarreau06619262006-12-17 08:37:22 +01001057 /* try headers filters */
Willy Tarreau53b6c742006-12-17 13:37:46 +01001058 if (rule_set->req_exp != NULL) {
Willy Tarreau06619262006-12-17 08:37:22 +01001059 apply_filters_to_session(t, req, rule_set->req_exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001060
Willy Tarreau53b6c742006-12-17 13:37:46 +01001061 /* the start line might have been modified */
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001062 hreq->start.len = hreq->hdr_idx.v[hreq->hdr_idx.v[0].next].len;
1063 hreq->meth = find_http_meth(hreq->start.str, hreq->start.len);
Willy Tarreau53b6c742006-12-17 13:37:46 +01001064 }
1065
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001066 if (!(t->flags & SN_BE_ASSIGNED) && (t->be != cur_proxy)) {
1067 /* to ensure correct connection accounting on
1068 * the backend, we count the connection for the
1069 * one managing the queue.
1070 */
1071 t->be->beprm->beconn++;
1072 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1073 t->be->beprm->beconn_max = t->be->beprm->beconn;
1074 t->be->beprm->cum_beconn++;
1075 t->flags |= SN_BE_ASSIGNED;
1076 }
1077
Willy Tarreau06619262006-12-17 08:37:22 +01001078 /* has the request been denied ? */
1079 if (t->flags & SN_CLDENY) {
1080 /* no need to go further */
1081 t->logs.status = 403;
1082 /* let's log the request time */
1083 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreau80587432006-12-24 17:47:20 +01001084 client_retnclose(t, error_message(t, HTTP_ERR_403));
Willy Tarreau06619262006-12-17 08:37:22 +01001085 goto return_prx_cond;
1086 }
1087
1088 /* add request headers from the rule sets in the same order */
1089 for (cur_hdr = 0; cur_hdr < rule_set->nb_reqadd; cur_hdr++) {
1090 int len;
1091
1092 len = sprintf(trash, "%s\r\n", rule_set->req_add[cur_hdr]);
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001093 len = buffer_replace2(req, req->data + hreq->req.eoh,
1094 req->data + hreq->req.eoh, trash, len);
1095 hreq->req.eoh += len;
Willy Tarreau06619262006-12-17 08:37:22 +01001096
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001097 if (hdr_idx_add(len - 2, 1, &hreq->hdr_idx, hreq->hdr_idx.tail) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01001098 goto return_bad_req;
1099 }
Willy Tarreaub2513902006-12-17 14:52:38 +01001100
Willy Tarreau0214c3a2007-01-07 13:47:30 +01001101 if (rule_set->uri_auth != NULL &&
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001102 (hreq->meth == HTTP_METH_GET || hreq->meth == HTTP_METH_HEAD)) {
Willy Tarreaub2513902006-12-17 14:52:38 +01001103 /* we have to check the URI and auth for this request */
1104 if (stats_check_uri_auth(t, rule_set))
1105 return 1;
1106 }
1107
Willy Tarreau5fdfb912007-01-01 23:11:07 +01001108 if (!(t->flags & SN_BE_ASSIGNED) && cur_proxy->defbe.be) {
1109 /* No backend was set, but there was a default
1110 * backend set in the frontend, so we use it and
1111 * loop again.
1112 */
1113 t->be = cur_proxy->defbe.be;
1114 t->be->beprm->beconn++;
1115 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1116 t->be->beprm->beconn_max = t->be->beprm->beconn;
1117 t->be->beprm->cum_beconn++;
1118 t->flags |= SN_BE_ASSIGNED;
1119 }
1120 } while (t->be != cur_proxy); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +01001121
Willy Tarreau58f10d72006-12-04 02:26:12 +01001122
Willy Tarreauf1221aa2006-12-17 22:14:12 +01001123 if (!(t->flags & SN_BE_ASSIGNED)) {
1124 /* To ensure correct connection accounting on
1125 * the backend, we count the connection for the
1126 * one managing the queue.
1127 */
1128 t->be->beprm->beconn++;
1129 if (t->be->beprm->beconn > t->be->beprm->beconn_max)
1130 t->be->beprm->beconn_max = t->be->beprm->beconn;
1131 t->be->beprm->cum_beconn++;
1132 t->flags |= SN_BE_ASSIGNED;
1133 }
1134
1135
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001136 /*
1137 * Right now, we know that we have processed the entire headers
Willy Tarreau2a324282006-12-05 00:05:46 +01001138 * and that unwanted requests have been filtered out. We can do
Willy Tarreau230fd0b2006-12-17 12:05:00 +01001139 * whatever we want with the remaining request. Also, now we
Willy Tarreau830ff452006-12-17 19:31:23 +01001140 * may have separate values for ->fe, ->be.
Willy Tarreau2a324282006-12-05 00:05:46 +01001141 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01001142
Willy Tarreau58f10d72006-12-04 02:26:12 +01001143
Willy Tarreau58f10d72006-12-04 02:26:12 +01001144
Willy Tarreau58f10d72006-12-04 02:26:12 +01001145
Willy Tarreau2a324282006-12-05 00:05:46 +01001146 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001147 * 3: the appsession cookie was looked up very early in 1.2,
Willy Tarreau06619262006-12-17 08:37:22 +01001148 * so let's do the same now.
1149 */
1150
1151 /* It needs to look into the URI */
Willy Tarreau830ff452006-12-17 19:31:23 +01001152 if (t->be->beprm->appsession_name) {
Willy Tarreau06619262006-12-17 08:37:22 +01001153 get_srv_from_appsession(t,
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001154 hreq->start.str,
1155 hreq->start.str + hreq->start.len);
Willy Tarreau06619262006-12-17 08:37:22 +01001156 }
1157
1158
1159 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001160 * 4: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +01001161 * Note that doing so might move headers in the request, but
1162 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +01001163 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +01001164 */
1165 if (!(t->flags & (SN_CLDENY|SN_CLTARPIT)))
1166 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +01001167
Willy Tarreau58f10d72006-12-04 02:26:12 +01001168
Willy Tarreau2a324282006-12-05 00:05:46 +01001169 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001170 * 5: add X-Forwarded-For : Should depend on the backend only.
Willy Tarreau2a324282006-12-05 00:05:46 +01001171 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001172 if (t->be->beprm->options & PR_O_FWDFOR) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001173 if (t->cli_addr.ss_family == AF_INET) {
1174 int len;
1175 unsigned char *pn;
1176 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
1177 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
1178 pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001179 len = buffer_replace2(req, req->data + hreq->req.eoh,
1180 req->data + hreq->req.eoh, trash, len);
1181 hreq->req.eoh += len;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001182
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001183 if (hdr_idx_add(len - 2, 1, &hreq->hdr_idx, hreq->hdr_idx.tail) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01001184 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001185 }
1186 else if (t->cli_addr.ss_family == AF_INET6) {
1187 int len;
1188 char pn[INET6_ADDRSTRLEN];
1189 inet_ntop(AF_INET6,
1190 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
1191 pn, sizeof(pn));
1192 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001193 len = buffer_replace2(req, req->data + hreq->req.eoh,
1194 req->data + hreq->req.eoh, trash, len);
1195 hreq->req.eoh += len;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001196
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001197 if (hdr_idx_add(len - 2, 1, &hreq->hdr_idx, hreq->hdr_idx.tail) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01001198 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +01001199 }
1200 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001201
Willy Tarreaubaaee002006-06-26 02:48:02 +02001202
Willy Tarreau2a324282006-12-05 00:05:46 +01001203 /*
Willy Tarreaub2513902006-12-17 14:52:38 +01001204 * 6: add "Connection:"
Willy Tarreau2a324282006-12-05 00:05:46 +01001205 */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001206
Willy Tarreaub2513902006-12-17 14:52:38 +01001207 /* add a "connection: close" line if needed.
1208 * FIXME: this should depend on both the frontend and the backend.
1209 * Header removals should be performed when the filters are run.
1210 */
Willy Tarreaue01954f2006-12-30 23:43:54 +01001211 if ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) {
Willy Tarreau45e73e32006-12-17 00:05:15 +01001212 int len;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001213 len = buffer_replace2(req, req->data + hreq->req.eoh,
1214 req->data + hreq->req.eoh, "Connection: close\r\n", 19);
1215 hreq->req.eoh += len;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001216
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001217 if (hdr_idx_add(17, 1, &hreq->hdr_idx, hreq->hdr_idx.tail) < 0)
Willy Tarreau06619262006-12-17 08:37:22 +01001218 goto return_bad_req;
Willy Tarreaue15d9132006-12-14 22:26:42 +01001219 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001220
Willy Tarreaubaaee002006-06-26 02:48:02 +02001221
Willy Tarreaue15d9132006-12-14 22:26:42 +01001222
1223
Willy Tarreau06619262006-12-17 08:37:22 +01001224
Willy Tarreaue15d9132006-12-14 22:26:42 +01001225
Willy Tarreau2a324282006-12-05 00:05:46 +01001226 /*************************************************************
1227 * OK, that's finished for the headers. We have done what we *
1228 * could. Let's switch to the DATA state. *
1229 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02001230
Willy Tarreau2a324282006-12-05 00:05:46 +01001231 t->cli_state = CL_STDATA;
1232 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001233
Willy Tarreau2a324282006-12-05 00:05:46 +01001234 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001235
Willy Tarreaubaaee002006-06-26 02:48:02 +02001236
Willy Tarreau2a324282006-12-05 00:05:46 +01001237 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001238 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout)) {
Willy Tarreau2a324282006-12-05 00:05:46 +01001239 /* If the client has no timeout, or if the server is not ready yet,
1240 * and we know for sure that it can expire, then it's cleaner to
1241 * disable the timeout on the client side so that too low values
1242 * cannot make the sessions abort too early.
1243 *
1244 * FIXME-20050705: the server needs a way to re-enable this time-out
1245 * when it switches its state, otherwise a client can stay connected
1246 * indefinitely. This now seems to be OK.
1247 */
1248 tv_eternity(&req->rex);
1249 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001250
Willy Tarreaub8750a82006-09-03 09:56:00 +02001251
Willy Tarreau2a324282006-12-05 00:05:46 +01001252 /* When a connection is tarpitted, we use the queue timeout for the
1253 * tarpit delay, which currently happens to be the server's connect
1254 * timeout. If unset, then set it to zero because we really want it
1255 * to expire at one moment.
1256 */
1257 if (t->flags & SN_CLTARPIT) {
1258 t->req->l = 0;
1259 /* flush the request so that we can drop the connection early
1260 * if the client closes first.
1261 */
1262 tv_delayfrom(&req->cex, &now,
Willy Tarreau830ff452006-12-17 19:31:23 +01001263 t->be->beprm->contimeout ? t->be->beprm->contimeout : 0);
Willy Tarreau2a324282006-12-05 00:05:46 +01001264 }
Willy Tarreaub8750a82006-09-03 09:56:00 +02001265
Willy Tarreau2a324282006-12-05 00:05:46 +01001266#if DEBUG_HTTP_PARSER
1267 /* example: dump each line */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001268
Willy Tarreau2a324282006-12-05 00:05:46 +01001269 fprintf(stderr, "t->flags=0x%08x\n", t->flags & (SN_CLALLOW|SN_CLDENY|SN_CLTARPIT));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001270
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001271 fprintf(stderr, "sol=%d\n", sol - req->data);
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001272 sol = req->data + hreq->sor;
Willy Tarreau2a324282006-12-05 00:05:46 +01001273 cur_hdr = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001274
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001275 cur_idx = hreq->hdr_idx.v[0].next;
Willy Tarreau2a324282006-12-05 00:05:46 +01001276 cur_hdr = 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001277
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001278 while (cur_hdr < hreq->hdr_idx.used) {
1279 eol = sol + hreq->hdr_idx.v[cur_idx].len + hreq->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreau2a324282006-12-05 00:05:46 +01001280 fprintf(stderr, "lr=%d r=%d hdr=%d idx=%d adr=%d..%d len=%d cr=%d data:\n",
1281 req->lr - req->data, req->r - req->data,
1282 cur_hdr, cur_idx,
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001283 sol - req->data,
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001284 sol - req->data + hreq->hdr_idx.v[cur_idx].len + hreq->hdr_idx.v[cur_idx].cr,
1285 hreq->hdr_idx.v[cur_idx].len,
1286 hreq->hdr_idx.v[cur_idx].cr);
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001287 write(2, sol, eol - sol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001288
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001289 sol = eol;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001290 cur_idx = hreq->hdr_idx.v[cur_idx].next;
Willy Tarreau2a324282006-12-05 00:05:46 +01001291 cur_hdr++;
1292 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001293#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001294
Willy Tarreau06619262006-12-17 08:37:22 +01001295 goto process_data;
1296
1297 return_bad_req: /* let's centralize all bad requests */
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001298 hreq->req.hdr_state = HTTP_PA_ERROR;
Willy Tarreau06619262006-12-17 08:37:22 +01001299 t->logs.status = 400;
Willy Tarreau80587432006-12-24 17:47:20 +01001300 client_retnclose(t, error_message(t, HTTP_ERR_400));
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001301 t->fe->failed_req++;
Willy Tarreau06619262006-12-17 08:37:22 +01001302 return_prx_cond:
1303 if (!(t->flags & SN_ERR_MASK))
1304 t->flags |= SN_ERR_PRXCOND;
1305 if (!(t->flags & SN_FINST_MASK))
1306 t->flags |= SN_FINST_R;
1307 return 1;
1308
Willy Tarreaubaaee002006-06-26 02:48:02 +02001309 }
1310 else if (c == CL_STDATA) {
1311 process_data:
1312 /* FIXME: this error handling is partly buggy because we always report
1313 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
1314 * or HEADER phase. BTW, it's not logical to expire the client while
1315 * we're waiting for the server to connect.
1316 */
1317 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001318 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001319 tv_eternity(&req->rex);
1320 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001321 fd_delete(t->cli_fd);
1322 t->cli_state = CL_STCLOSE;
1323 if (!(t->flags & SN_ERR_MASK))
1324 t->flags |= SN_ERR_CLICL;
1325 if (!(t->flags & SN_FINST_MASK)) {
1326 if (t->pend_pos)
1327 t->flags |= SN_FINST_Q;
1328 else if (s == SV_STCONN)
1329 t->flags |= SN_FINST_C;
1330 else
1331 t->flags |= SN_FINST_D;
1332 }
1333 return 1;
1334 }
1335 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001336 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001337 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001338 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001339 shutdown(t->cli_fd, SHUT_RD);
1340 t->cli_state = CL_STSHUTR;
1341 return 1;
1342 }
1343 /* last server read and buffer empty */
1344 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001345 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001346 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001347 shutdown(t->cli_fd, SHUT_WR);
1348 /* We must ensure that the read part is still alive when switching
1349 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001350 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001351 if (t->fe->clitimeout)
1352 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001353 t->cli_state = CL_STSHUTW;
1354 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1355 return 1;
1356 }
1357 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001358 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001359 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001360 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001361 shutdown(t->cli_fd, SHUT_RD);
1362 t->cli_state = CL_STSHUTR;
1363 if (!(t->flags & SN_ERR_MASK))
1364 t->flags |= SN_ERR_CLITO;
1365 if (!(t->flags & SN_FINST_MASK)) {
1366 if (t->pend_pos)
1367 t->flags |= SN_FINST_Q;
1368 else if (s == SV_STCONN)
1369 t->flags |= SN_FINST_C;
1370 else
1371 t->flags |= SN_FINST_D;
1372 }
1373 return 1;
1374 }
1375 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001376 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001377 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001378 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001379 shutdown(t->cli_fd, SHUT_WR);
1380 /* We must ensure that the read part is still alive when switching
1381 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001382 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001383 if (t->fe->clitimeout)
1384 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001385
1386 t->cli_state = CL_STSHUTW;
1387 if (!(t->flags & SN_ERR_MASK))
1388 t->flags |= SN_ERR_CLITO;
1389 if (!(t->flags & SN_FINST_MASK)) {
1390 if (t->pend_pos)
1391 t->flags |= SN_FINST_Q;
1392 else if (s == SV_STCONN)
1393 t->flags |= SN_FINST_C;
1394 else
1395 t->flags |= SN_FINST_D;
1396 }
1397 return 1;
1398 }
1399
1400 if (req->l >= req->rlim - req->data) {
1401 /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02001402 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001403 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001404 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001405 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001406 }
1407 } else {
1408 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001409 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1410 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001411 if (!t->fe->clitimeout ||
Willy Tarreau830ff452006-12-17 19:31:23 +01001412 (t->srv_state < SV_STDATA && t->be->beprm->srvtimeout))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001413 /* If the client has no timeout, or if the server not ready yet, and we
1414 * know for sure that it can expire, then it's cleaner to disable the
1415 * timeout on the client side so that too low values cannot make the
1416 * sessions abort too early.
1417 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001418 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001419 else
Willy Tarreau73de9892006-11-30 11:40:23 +01001420 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001421 }
1422 }
1423
1424 if ((rep->l == 0) ||
1425 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001426 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1427 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001428 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001429 }
1430 } else {
1431 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001432 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1433 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001434 if (t->fe->clitimeout) {
1435 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001436 /* FIXME: to prevent the client from expiring read timeouts during writes,
1437 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001438 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001439 }
1440 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001441 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001442 }
1443 }
1444 return 0; /* other cases change nothing */
1445 }
1446 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001447 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001448 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001449 fd_delete(t->cli_fd);
1450 t->cli_state = CL_STCLOSE;
1451 if (!(t->flags & SN_ERR_MASK))
1452 t->flags |= SN_ERR_CLICL;
1453 if (!(t->flags & SN_FINST_MASK)) {
1454 if (t->pend_pos)
1455 t->flags |= SN_FINST_Q;
1456 else if (s == SV_STCONN)
1457 t->flags |= SN_FINST_C;
1458 else
1459 t->flags |= SN_FINST_D;
1460 }
1461 return 1;
1462 }
1463 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
1464 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001465 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001466 fd_delete(t->cli_fd);
1467 t->cli_state = CL_STCLOSE;
1468 return 1;
1469 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001470 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
1471 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001472 fd_delete(t->cli_fd);
1473 t->cli_state = CL_STCLOSE;
1474 if (!(t->flags & SN_ERR_MASK))
1475 t->flags |= SN_ERR_CLITO;
1476 if (!(t->flags & SN_FINST_MASK)) {
1477 if (t->pend_pos)
1478 t->flags |= SN_FINST_Q;
1479 else if (s == SV_STCONN)
1480 t->flags |= SN_FINST_C;
1481 else
1482 t->flags |= SN_FINST_D;
1483 }
1484 return 1;
1485 }
1486
1487 if (t->flags & SN_SELF_GEN) {
1488 produce_content(t);
1489 if (rep->l == 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001490 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001491 fd_delete(t->cli_fd);
1492 t->cli_state = CL_STCLOSE;
1493 return 1;
1494 }
1495 }
1496
1497 if ((rep->l == 0)
1498 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001499 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1500 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001501 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001502 }
1503 } else {
1504 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001505 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1506 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001507 if (t->fe->clitimeout) {
1508 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001509 /* FIXME: to prevent the client from expiring read timeouts during writes,
1510 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001511 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001512 }
1513 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001514 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001515 }
1516 }
1517 return 0;
1518 }
1519 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001520 if (req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001521 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001522 fd_delete(t->cli_fd);
1523 t->cli_state = CL_STCLOSE;
1524 if (!(t->flags & SN_ERR_MASK))
1525 t->flags |= SN_ERR_CLICL;
1526 if (!(t->flags & SN_FINST_MASK)) {
1527 if (t->pend_pos)
1528 t->flags |= SN_FINST_Q;
1529 else if (s == SV_STCONN)
1530 t->flags |= SN_FINST_C;
1531 else
1532 t->flags |= SN_FINST_D;
1533 }
1534 return 1;
1535 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001536 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001537 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001538 fd_delete(t->cli_fd);
1539 t->cli_state = CL_STCLOSE;
1540 return 1;
1541 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001542 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
1543 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001544 fd_delete(t->cli_fd);
1545 t->cli_state = CL_STCLOSE;
1546 if (!(t->flags & SN_ERR_MASK))
1547 t->flags |= SN_ERR_CLITO;
1548 if (!(t->flags & SN_FINST_MASK)) {
1549 if (t->pend_pos)
1550 t->flags |= SN_FINST_Q;
1551 else if (s == SV_STCONN)
1552 t->flags |= SN_FINST_C;
1553 else
1554 t->flags |= SN_FINST_D;
1555 }
1556 return 1;
1557 }
1558 else if (req->l >= req->rlim - req->data) {
1559 /* no room to read more data */
1560
1561 /* FIXME-20050705: is it possible for a client to maintain a session
1562 * after the timeout by sending more data after it receives a close ?
1563 */
1564
Willy Tarreau2a429502006-10-15 14:52:29 +02001565 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001566 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001567 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001568 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001569 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1570 }
1571 } else {
1572 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001573 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1574 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001575 if (t->fe->clitimeout)
1576 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001577 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001578 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001579 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1580 }
1581 }
1582 return 0;
1583 }
1584 else { /* CL_STCLOSE: nothing to do */
1585 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1586 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01001587 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 +02001588 write(1, trash, len);
1589 }
1590 return 0;
1591 }
1592 return 0;
1593}
1594
1595
1596/*
1597 * manages the server FSM and its socket. It returns 1 if a state has changed
1598 * (and a resync may be needed), 0 else.
1599 */
1600int process_srv(struct session *t)
1601{
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001602 struct http_req *hreq = &t->hreq;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001603 int s = t->srv_state;
1604 int c = t->cli_state;
1605 struct buffer *req = t->req;
1606 struct buffer *rep = t->rep;
1607 appsess *asession_temp = NULL;
1608 appsess local_asession;
1609 int conn_err;
1610
1611#ifdef DEBUG_FULL
1612 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
1613#endif
1614 //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 +02001615 //MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
1616 //MY_FD_ISSET(t->srv_fd, StaticReadEvent), MY_FD_ISSET(t->srv_fd, StaticWriteEvent)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001617 //);
1618 if (s == SV_STIDLE) {
1619 if (c == CL_STHEADERS)
1620 return 0; /* stay in idle, waiting for data to reach the client side */
1621 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
1622 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001623 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001624 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001625 if (t->pend_pos)
1626 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1627 /* note that this must not return any error because it would be able to
1628 * overwrite the client_retnclose() output.
1629 */
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001630 if (t->flags & SN_CLTARPIT)
Willy Tarreau0f772532006-12-23 20:51:41 +01001631 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001632 else
Willy Tarreau0f772532006-12-23 20:51:41 +01001633 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 +02001634
1635 return 1;
1636 }
1637 else {
Willy Tarreaub8750a82006-09-03 09:56:00 +02001638 if (t->flags & SN_CLTARPIT) {
1639 /* This connection is being tarpitted. The CLIENT side has
1640 * already set the connect expiration date to the right
1641 * timeout. We just have to check that it has not expired.
1642 */
1643 if (tv_cmp2_ms(&req->cex, &now) > 0)
1644 return 0;
1645
1646 /* We will set the queue timer to the time spent, just for
1647 * logging purposes. We fake a 500 server error, so that the
1648 * attacker will not suspect his connection has been tarpitted.
1649 * It will not cause trouble to the logs because we can exclude
1650 * the tarpitted connections by filtering on the 'PT' status flags.
1651 */
1652 tv_eternity(&req->cex);
1653 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1654 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau80587432006-12-24 17:47:20 +01001655 500, error_message(t, HTTP_ERR_500));
Willy Tarreaub8750a82006-09-03 09:56:00 +02001656 return 1;
1657 }
1658
Willy Tarreaubaaee002006-06-26 02:48:02 +02001659 /* Right now, we will need to create a connection to the server.
1660 * We might already have tried, and got a connection pending, in
1661 * which case we will not do anything till it's pending. It's up
1662 * to any other session to release it and wake us up again.
1663 */
1664 if (t->pend_pos) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001665 if (tv_cmp2_ms(&req->cex, &now) > 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001666 return 0;
1667 else {
1668 /* we've been waiting too long here */
Willy Tarreaud7971282006-07-29 18:36:34 +02001669 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001670 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1671 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau80587432006-12-24 17:47:20 +01001672 503, error_message(t, HTTP_ERR_503));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001673 if (t->srv)
1674 t->srv->failed_conns++;
Willy Tarreau73de9892006-11-30 11:40:23 +01001675 t->fe->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001676 return 1;
1677 }
1678 }
1679
1680 do {
1681 /* first, get a connection */
1682 if (srv_redispatch_connect(t))
1683 return t->srv_state != SV_STIDLE;
1684
1685 /* try to (re-)connect to the server, and fail if we expire the
1686 * number of retries.
1687 */
1688 if (srv_retryable_connect(t)) {
1689 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1690 return t->srv_state != SV_STIDLE;
1691 }
1692
1693 } while (1);
1694 }
1695 }
1696 else if (s == SV_STCONN) { /* connection in progress */
1697 if (c == CL_STCLOSE || c == CL_STSHUTW ||
1698 (c == CL_STSHUTR &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001699 (t->req->l == 0 || t->be->beprm->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001700 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001701 fd_delete(t->srv_fd);
1702 if (t->srv)
1703 t->srv->cur_sess--;
1704
1705 /* note that this must not return any error because it would be able to
1706 * overwrite the client_retnclose() output.
1707 */
Willy Tarreau0f772532006-12-23 20:51:41 +01001708 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001709 return 1;
1710 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001711 if (!(req->flags & BF_WRITE_STATUS) && tv_cmp2_ms(&req->cex, &now) > 0) {
1712 //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 +02001713 return 0; /* nothing changed */
1714 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001715 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001716 /* timeout, asynchronous connect error or first write error */
1717 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
1718
1719 fd_delete(t->srv_fd);
1720 if (t->srv)
1721 t->srv->cur_sess--;
1722
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001723 if (!(req->flags & BF_WRITE_STATUS))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001724 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
1725 else
1726 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
1727
1728 /* ensure that we have enough retries left */
1729 if (srv_count_retry_down(t, conn_err))
1730 return 1;
1731
Willy Tarreau830ff452006-12-17 19:31:23 +01001732 if (t->srv && t->conn_retries == 0 && t->be->beprm->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001733 /* We're on our last chance, and the REDISP option was specified.
1734 * We will ignore cookie and force to balance or use the dispatcher.
1735 */
1736 /* let's try to offer this slot to anybody */
Willy Tarreau830ff452006-12-17 19:31:23 +01001737 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001738 task_wakeup(&rq, t->srv->queue_mgt);
1739
1740 if (t->srv)
1741 t->srv->failed_conns++;
Willy Tarreau830ff452006-12-17 19:31:23 +01001742 t->be->beprm->failed_conns++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001743
1744 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
1745 t->srv = NULL; /* it's left to the dispatcher to choose a server */
1746 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
1747 t->flags &= ~SN_CK_MASK;
1748 t->flags |= SN_CK_DOWN;
1749 }
1750
1751 /* first, get a connection */
1752 if (srv_redispatch_connect(t))
1753 return t->srv_state != SV_STIDLE;
1754 }
1755
Willy Tarreaubaaee002006-06-26 02:48:02 +02001756 do {
1757 /* Now we will try to either reconnect to the same server or
1758 * connect to another server. If the connection gets queued
1759 * because all servers are saturated, then we will go back to
1760 * the SV_STIDLE state.
1761 */
1762 if (srv_retryable_connect(t)) {
1763 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1764 return t->srv_state != SV_STCONN;
1765 }
1766
1767 /* we need to redispatch the connection to another server */
1768 if (srv_redispatch_connect(t))
1769 return t->srv_state != SV_STCONN;
1770 } while (1);
1771 }
1772 else { /* no error or write 0 */
1773 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
1774
1775 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
1776 if (req->l == 0) /* nothing to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02001777 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001778 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001779 } else /* need the right to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02001780 MY_FD_SET(t->srv_fd, StaticWriteEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001781 if (t->be->beprm->srvtimeout) {
1782 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001783 /* FIXME: to prevent the server from expiring read timeouts during writes,
1784 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001785 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001786 }
1787 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001788 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001789 }
1790
Willy Tarreau830ff452006-12-17 19:31:23 +01001791 if (t->be->beprm->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreau2a429502006-10-15 14:52:29 +02001792 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001793 if (t->be->beprm->srvtimeout)
1794 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001795 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001796 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001797
1798 t->srv_state = SV_STDATA;
1799 if (t->srv)
1800 t->srv->cum_sess++;
1801 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
1802
1803 /* if the user wants to log as soon as possible, without counting
1804 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001805 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001806 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
1807 sess_log(t);
1808 }
Willy Tarreau6d1a9882007-01-07 02:03:04 +01001809#ifdef CONFIG_HAP_TCPSPLICE
1810 if ((t->fe->options & t->be->beprm->options) & PR_O_TCPSPLICE) {
1811 /* TCP splicing supported by both FE and BE */
1812 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
1813 }
1814#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001815 }
1816 else {
1817 t->srv_state = SV_STHEADERS;
1818 if (t->srv)
1819 t->srv->cum_sess++;
1820 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
1821 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001822 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001823 return 1;
1824 }
1825 }
1826 else if (s == SV_STHEADERS) { /* receiving server headers */
1827 /* now parse the partial (or complete) headers */
1828 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
1829 char *ptr;
1830 int delete_header;
1831
1832 ptr = rep->lr;
1833
1834 /* look for the end of the current header */
1835 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
1836 ptr++;
1837
1838 if (ptr == rep->h) {
1839 int line, len;
1840
1841 /* we can only get here after an end of headers */
1842
1843 /* first, we'll block if security checks have caught nasty things */
1844 if (t->flags & SN_CACHEABLE) {
1845 if ((t->flags & SN_CACHE_COOK) &&
1846 (t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001847 (t->be->beprm->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001848
1849 /* we're in presence of a cacheable response containing
1850 * a set-cookie header. We'll block it as requested by
1851 * the 'checkcache' option, and send an alert.
1852 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001853 tv_eternity(&rep->rex);
1854 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001855 fd_delete(t->srv_fd);
1856 if (t->srv) {
1857 t->srv->cur_sess--;
1858 t->srv->failed_secu++;
1859 }
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001860 t->be->beprm->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001861 t->srv_state = SV_STCLOSE;
1862 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01001863 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001864 if (!(t->flags & SN_ERR_MASK))
1865 t->flags |= SN_ERR_PRXCOND;
1866 if (!(t->flags & SN_FINST_MASK))
1867 t->flags |= SN_FINST_H;
1868
Willy Tarreau830ff452006-12-17 19:31:23 +01001869 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->be->beprm->id, t->srv->id);
1870 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 +02001871
1872 /* We used to have a free connection slot. Since we'll never use it,
1873 * we have to inform the server that it may be used by another session.
1874 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001875 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001876 task_wakeup(&rq, t->srv->queue_mgt);
1877
1878 return 1;
1879 }
1880 }
1881
1882 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
1883 if (t->flags & SN_SVDENY) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001884 tv_eternity(&rep->rex);
1885 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001886 fd_delete(t->srv_fd);
1887 if (t->srv) {
1888 t->srv->cur_sess--;
1889 t->srv->failed_secu++;
1890 }
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01001891 t->be->beprm->denied_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001892 t->srv_state = SV_STCLOSE;
1893 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01001894 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001895 if (!(t->flags & SN_ERR_MASK))
1896 t->flags |= SN_ERR_PRXCOND;
1897 if (!(t->flags & SN_FINST_MASK))
1898 t->flags |= SN_FINST_H;
1899 /* We used to have a free connection slot. Since we'll never use it,
1900 * we have to inform the server that it may be used by another session.
1901 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001902 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001903 task_wakeup(&rq, t->srv->queue_mgt);
1904
1905 return 1;
1906 }
1907
1908 /* we'll have something else to do here : add new headers ... */
1909
Willy Tarreau830ff452006-12-17 19:31:23 +01001910 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_INS) &&
Willy Tarreau0f7562b2007-01-07 15:46:13 +01001911 (!(t->be->beprm->options & PR_O_COOK_POST) || (hreq->meth == HTTP_METH_POST))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001912 /* the server is known, it's not the one the client requested, we have to
1913 * insert a set-cookie here, except if we want to insert only on POST
1914 * requests and this one isn't. Note that servers which don't have cookies
1915 * (eg: some backup servers) will return a full cookie removal request.
1916 */
1917 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
Willy Tarreau830ff452006-12-17 19:31:23 +01001918 t->be->beprm->cookie_name,
Willy Tarreaubaaee002006-06-26 02:48:02 +02001919 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
1920
1921 t->flags |= SN_SCK_INSERTED;
1922
1923 /* Here, we will tell an eventual cache on the client side that we don't
1924 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
1925 * Some caches understand the correct form: 'no-cache="set-cookie"', but
1926 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
1927 */
Willy Tarreau830ff452006-12-17 19:31:23 +01001928 if (t->be->beprm->options & PR_O_COOK_NOC)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001929 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
1930 len += sprintf(trash + len, "Cache-control: private\r\n");
1931
1932 if (rep->data + rep->l < rep->h)
1933 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
1934 *(int *)0 = 0;
1935 buffer_replace2(rep, rep->h, rep->h, trash, len);
1936 }
1937
1938 /* headers to be added */
Willy Tarreau830ff452006-12-17 19:31:23 +01001939 /* FIXME: we should add headers from BE then from FE */
1940 for (line = 0; line < t->be->fiprm->nb_rspadd; line++) {
1941 len = sprintf(trash, "%s\r\n", t->be->fiprm->rsp_add[line]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001942 buffer_replace2(rep, rep->h, rep->h, trash, len);
1943 }
1944
1945 /* add a "connection: close" line if needed */
Willy Tarreaue01954f2006-12-30 23:43:54 +01001946 if ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001947 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
1948
1949 t->srv_state = SV_STDATA;
1950 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
1951 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
1952
1953 /* client connection already closed or option 'httpclose' required :
1954 * we close the server's outgoing connection right now.
1955 */
1956 if ((req->l == 0) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01001957 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->beprm->options & PR_O_FORCE_CLO)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001958 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001959 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001960
1961 /* We must ensure that the read part is still alive when switching
1962 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001963 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01001964 if (t->be->beprm->srvtimeout)
1965 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001966
1967 shutdown(t->srv_fd, SHUT_WR);
1968 t->srv_state = SV_STSHUTW;
1969 }
1970
Willy Tarreau6d1a9882007-01-07 02:03:04 +01001971#ifdef CONFIG_HAP_TCPSPLICE
1972 if ((t->fe->options & t->be->beprm->options) & PR_O_TCPSPLICE) {
1973 /* TCP splicing supported by both FE and BE */
1974 tcp_splice_splicefd(t->cli_fd, t->srv_fd, 0);
1975 }
1976#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001977 /* if the user wants to log as soon as possible, without counting
1978 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001979 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001980 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
Willy Tarreau35d66b02007-01-02 00:28:21 +01001981 t->logs.bytes_in = rep->h - rep->data;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001982 sess_log(t);
1983 }
1984 break;
1985 }
1986
1987 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1988 if (ptr > rep->r - 2) {
1989 /* this is a partial header, let's wait for more to come */
1990 rep->lr = ptr;
1991 break;
1992 }
1993
1994 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
1995 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
1996
1997 /* now we know that *ptr is either \r or \n,
1998 * and that there are at least 1 char after it.
1999 */
2000 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
2001 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
2002 else
2003 rep->lr = ptr + 2; /* \r\n or \n\r */
2004
2005 /*
2006 * now we know that we have a full header ; we can do whatever
2007 * we want with these pointers :
2008 * rep->h = beginning of header
2009 * ptr = end of header (first \r or \n)
2010 * rep->lr = beginning of next line (next rep->h)
2011 * rep->r = end of data (not used at this stage)
2012 */
2013
2014
2015 if (t->logs.status == -1) {
2016 t->logs.logwait &= ~LW_RESP;
2017 t->logs.status = atoi(rep->h + 9);
2018 switch (t->logs.status) {
2019 case 200:
2020 case 203:
2021 case 206:
2022 case 300:
2023 case 301:
2024 case 410:
2025 /* RFC2616 @13.4:
2026 * "A response received with a status code of
2027 * 200, 203, 206, 300, 301 or 410 MAY be stored
2028 * by a cache (...) unless a cache-control
2029 * directive prohibits caching."
2030 *
2031 * RFC2616 @9.5: POST method :
2032 * "Responses to this method are not cacheable,
2033 * unless the response includes appropriate
2034 * Cache-Control or Expires header fields."
2035 */
Willy Tarreau0f7562b2007-01-07 15:46:13 +01002036 if (!(hreq->meth == HTTP_METH_POST) && (t->be->beprm->options & PR_O_CHK_CACHE))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002037 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
2038 break;
2039 default:
2040 break;
2041 }
2042 }
2043 else if (t->logs.logwait & LW_RSPHDR) {
2044 struct cap_hdr *h;
2045 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01002046 for (h = t->fe->fiprm->rsp_cap; h; h = h->next) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002047 if ((h->namelen + 2 <= ptr - rep->h) &&
2048 (rep->h[h->namelen] == ':') &&
2049 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
2050
2051 if (t->rsp_cap[h->index] == NULL)
2052 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
2053
2054 len = ptr - (rep->h + h->namelen + 2);
2055 if (len > h->len)
2056 len = h->len;
2057
2058 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
2059 t->rsp_cap[h->index][len]=0;
2060 }
2061 }
2062
2063 }
2064
2065 delete_header = 0;
2066
Willy Tarreau58f10d72006-12-04 02:26:12 +01002067 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
2068 debug_hdr("srvhdr", t, rep->h, ptr);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002069
2070 /* remove "connection: " if needed */
Willy Tarreaue01954f2006-12-30 23:43:54 +01002071 if (!delete_header &&
2072 ((t->fe->options | t->be->beprm->options) & PR_O_HTTP_CLOSE) &&
2073 (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002074 delete_header = 1;
2075 }
2076
2077 /* try headers regexps */
Willy Tarreau830ff452006-12-17 19:31:23 +01002078 if (!delete_header && t->be->fiprm->rsp_exp != NULL
Willy Tarreaubaaee002006-06-26 02:48:02 +02002079 && !(t->flags & SN_SVDENY)) {
2080 struct hdr_exp *exp;
2081 char term;
2082
2083 term = *ptr;
2084 *ptr = '\0';
Willy Tarreau830ff452006-12-17 19:31:23 +01002085 exp = t->be->fiprm->rsp_exp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002086 do {
2087 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
2088 switch (exp->action) {
2089 case ACT_ALLOW:
2090 if (!(t->flags & SN_SVDENY))
2091 t->flags |= SN_SVALLOW;
2092 break;
2093 case ACT_REPLACE:
2094 if (!(t->flags & SN_SVDENY)) {
2095 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
2096 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
2097 }
2098 break;
2099 case ACT_REMOVE:
2100 if (!(t->flags & SN_SVDENY))
2101 delete_header = 1;
2102 break;
2103 case ACT_DENY:
2104 if (!(t->flags & SN_SVALLOW))
2105 t->flags |= SN_SVDENY;
2106 break;
2107 case ACT_PASS: /* we simply don't deny this one */
2108 break;
2109 }
2110 break;
2111 }
2112 } while ((exp = exp->next) != NULL);
2113 *ptr = term; /* restore the string terminator */
2114 }
2115
2116 /* check for cache-control: or pragma: headers */
2117 if (!delete_header && (t->flags & SN_CACHEABLE)) {
2118 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
2119 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2120 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
2121 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
2122 if (rep->h + 23 == ptr || rep->h[23] == ',')
2123 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2124 else {
2125 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
2126 && (rep->h[35] == '"' || rep->h[35] == ','))
2127 t->flags &= ~SN_CACHE_COOK;
2128 }
2129 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
2130 (rep->h + 22 == ptr || rep->h[22] == ','))
2131 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
2132 (rep->h + 23 == ptr || rep->h[23] == ','))) {
2133 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2134 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
2135 (rep->h + 24 == ptr || rep->h[24] == ',')) {
2136 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2137 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
2138 (rep->h + 25 == ptr || rep->h[25] == ',')) {
2139 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
2140 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
2141 (rep->h + 21 == ptr || rep->h[21] == ',')) {
2142 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
2143 }
2144 }
2145 }
2146
2147 /* check for server cookies */
2148 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002149 && (t->be->beprm->cookie_name != NULL ||
2150 t->be->fiprm->capture_name != NULL ||
2151 t->be->beprm->appsession_name !=NULL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002152 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2153 char *p1, *p2, *p3, *p4;
2154
2155 t->flags |= SN_SCK_ANY;
2156
2157 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
2158
2159 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
2160 while (p1 < ptr && (isspace((int)*p1)))
2161 p1++;
2162
2163 if (p1 == ptr || *p1 == ';') /* end of cookie */
2164 break;
2165
2166 /* p1 is at the beginning of the cookie name */
2167 p2 = p1;
2168
2169 while (p2 < ptr && *p2 != '=' && *p2 != ';')
2170 p2++;
2171
2172 if (p2 == ptr || *p2 == ';') /* next cookie */
2173 break;
2174
2175 p3 = p2 + 1; /* skips the '=' sign */
2176 if (p3 == ptr)
2177 break;
2178
2179 p4 = p3;
2180 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
2181 p4++;
2182
2183 /* here, we have the cookie name between p1 and p2,
2184 * and its value between p3 and p4.
2185 * we can process it.
2186 */
2187
2188 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01002189 if (t->be->fiprm->capture_name != NULL &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002190 t->logs.srv_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002191 (p4 - p1 >= t->be->fiprm->capture_namelen) &&
2192 memcmp(p1, t->be->fiprm->capture_name, t->be->fiprm->capture_namelen) == 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002193 int log_len = p4 - p1;
2194
2195 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
2196 Alert("HTTP logging : out of memory.\n");
2197 }
2198
Willy Tarreau830ff452006-12-17 19:31:23 +01002199 if (log_len > t->be->fiprm->capture_len)
2200 log_len = t->be->fiprm->capture_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002201 memcpy(t->logs.srv_cookie, p1, log_len);
2202 t->logs.srv_cookie[log_len] = 0;
2203 }
2204
Willy Tarreau830ff452006-12-17 19:31:23 +01002205 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
2206 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002207 /* Cool... it's the right one */
2208 t->flags |= SN_SCK_SEEN;
2209
2210 /* If the cookie is in insert mode on a known server, we'll delete
2211 * this occurrence because we'll insert another one later.
2212 * We'll delete it too if the "indirect" option is set and we're in
2213 * a direct access. */
Willy Tarreau830ff452006-12-17 19:31:23 +01002214 if (((t->srv) && (t->be->beprm->options & PR_O_COOK_INS)) ||
2215 ((t->flags & SN_DIRECT) && (t->be->beprm->options & PR_O_COOK_IND))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002216 /* this header must be deleted */
2217 delete_header = 1;
2218 t->flags |= SN_SCK_DELETED;
2219 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002220 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_RW)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002221 /* replace bytes p3->p4 with the cookie name associated
2222 * with this server since we know it.
2223 */
2224 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
2225 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2226 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002227 else if ((t->srv) && (t->be->beprm->options & PR_O_COOK_PFX)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002228 /* insert the cookie name associated with this server
2229 * before existing cookie, and insert a delimitor between them..
2230 */
2231 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
2232 p3[t->srv->cklen] = COOKIE_DELIM;
2233 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
2234 }
2235 break;
2236 }
2237
2238 /* first, let's see if the cookie is our appcookie*/
Willy Tarreau830ff452006-12-17 19:31:23 +01002239 if ((t->be->beprm->appsession_name != NULL) &&
2240 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002241
2242 /* Cool... it's the right one */
2243
2244 size_t server_id_len = strlen(t->srv->id) + 1;
2245 asession_temp = &local_asession;
2246
2247 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
2248 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002249 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002250 }
Willy Tarreau830ff452006-12-17 19:31:23 +01002251 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
2252 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002253 asession_temp->serverid = NULL;
2254
2255 /* only do insert, if lookup fails */
Willy Tarreau73de9892006-11-30 11:40:23 +01002256 if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002257 if ((asession_temp = pool_alloc(appsess)) == NULL) {
2258 Alert("Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002259 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002260 return 0;
2261 }
2262 asession_temp->sessid = local_asession.sessid;
2263 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01002264 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002265 }/* end if (chtbl_lookup()) */
2266 else {
2267 /* free wasted memory */
2268 pool_free_to(apools.sessid, local_asession.sessid);
2269 } /* end else from if (chtbl_lookup()) */
2270
2271 if (asession_temp->serverid == NULL) {
2272 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
2273 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002274 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002275 }
2276 asession_temp->serverid[0] = '\0';
2277 }
2278
2279 if (asession_temp->serverid[0] == '\0')
2280 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
2281
Willy Tarreau830ff452006-12-17 19:31:23 +01002282 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002283
2284#if defined(DEBUG_HASH)
Willy Tarreau830ff452006-12-17 19:31:23 +01002285 print_table(&(t->be->beprm->htbl_proxy));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002286#endif
2287 break;
2288 }/* end if ((t->proxy->appsession_name != NULL) ... */
2289 else {
2290 // fprintf(stderr,"Ignoring unknown cookie : ");
2291 // write(2, p1, p2-p1);
2292 // fprintf(stderr," = ");
2293 // write(2, p3, p4-p3);
2294 // fprintf(stderr,"\n");
2295 }
2296 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2297 } /* we're now at the end of the cookie value */
2298 } /* end of cookie processing */
2299
2300 /* check for any set-cookie in case we check for cacheability */
2301 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
Willy Tarreau830ff452006-12-17 19:31:23 +01002302 (t->be->beprm->options & PR_O_CHK_CACHE) &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002303 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2304 t->flags |= SN_SCK_ANY;
2305 }
2306
2307 /* let's look if we have to delete this header */
2308 if (delete_header && !(t->flags & SN_SVDENY))
2309 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2310
2311 rep->h = rep->lr;
2312 } /* while (rep->lr < rep->r) */
2313
2314 /* end of header processing (even if incomplete) */
2315
Willy Tarreau2a429502006-10-15 14:52:29 +02002316 if ((rep->l < rep->rlim - rep->data) && ! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002317 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
Willy Tarreaud7971282006-07-29 18:36:34 +02002318 * full. We cannot loop here since stream_sock_read will disable it only if
Willy Tarreaubaaee002006-06-26 02:48:02 +02002319 * rep->l == rlim-data
2320 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002321 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002322 if (t->be->beprm->srvtimeout)
2323 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002324 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002325 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002326 }
2327
2328 /* read error, write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002329 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002330 tv_eternity(&rep->rex);
2331 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002332 fd_delete(t->srv_fd);
2333 if (t->srv) {
2334 t->srv->cur_sess--;
2335 t->srv->failed_resp++;
2336 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002337 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002338
2339 t->srv_state = SV_STCLOSE;
2340 t->logs.status = 502;
Willy Tarreau80587432006-12-24 17:47:20 +01002341 client_return(t, error_message(t, HTTP_ERR_502));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002342 if (!(t->flags & SN_ERR_MASK))
2343 t->flags |= SN_ERR_SRVCL;
2344 if (!(t->flags & SN_FINST_MASK))
2345 t->flags |= SN_FINST_H;
2346 /* We used to have a free connection slot. Since we'll never use it,
2347 * we have to inform the server that it may be used by another session.
2348 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002349 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002350 task_wakeup(&rq, t->srv->queue_mgt);
2351
2352 return 1;
2353 }
2354 /* end of client write or end of server read.
2355 * since we are in header mode, if there's no space left for headers, we
2356 * won't be able to free more later, so the session will never terminate.
2357 */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002358 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 +02002359 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002360 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002361 shutdown(t->srv_fd, SHUT_RD);
2362 t->srv_state = SV_STSHUTR;
2363 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2364 return 1;
2365 }
2366 /* read timeout : return a 504 to the client.
2367 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002368 else if (MY_FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002369 tv_eternity(&rep->rex);
2370 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002371 fd_delete(t->srv_fd);
2372 if (t->srv) {
2373 t->srv->cur_sess--;
2374 t->srv->failed_resp++;
2375 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002376 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002377 t->srv_state = SV_STCLOSE;
2378 t->logs.status = 504;
Willy Tarreau80587432006-12-24 17:47:20 +01002379 client_return(t, error_message(t, HTTP_ERR_504));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002380 if (!(t->flags & SN_ERR_MASK))
2381 t->flags |= SN_ERR_SRVTO;
2382 if (!(t->flags & SN_FINST_MASK))
2383 t->flags |= SN_FINST_H;
2384 /* We used to have a free connection slot. Since we'll never use it,
2385 * we have to inform the server that it may be used by another session.
2386 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002387 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002388 task_wakeup(&rq, t->srv->queue_mgt);
2389
2390 return 1;
2391 }
2392 /* last client read and buffer empty */
2393 /* FIXME!!! here, we don't want to switch to SHUTW if the
2394 * client shuts read too early, because we may still have
2395 * some work to do on the headers.
2396 * The side-effect is that if the client completely closes its
2397 * connection during SV_STHEADER, the connection to the server
2398 * is kept until a response comes back or the timeout is reached.
2399 */
2400 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002401 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002402 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002403
2404 /* We must ensure that the read part is still alive when switching
2405 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002406 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002407 if (t->be->beprm->srvtimeout)
2408 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002409
2410 shutdown(t->srv_fd, SHUT_WR);
2411 t->srv_state = SV_STSHUTW;
2412 return 1;
2413 }
2414 /* write timeout */
2415 /* FIXME!!! here, we don't want to switch to SHUTW if the
2416 * client shuts read too early, because we may still have
2417 * some work to do on the headers.
2418 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002419 else if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&req->wex, &now) <= 0) {
2420 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002421 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002422 shutdown(t->srv_fd, SHUT_WR);
2423 /* We must ensure that the read part is still alive when switching
2424 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002425 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002426 if (t->be->beprm->srvtimeout)
2427 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002428
2429 /* We must ensure that the read part is still alive when switching
2430 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002431 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002432 if (t->be->beprm->srvtimeout)
2433 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002434
2435 t->srv_state = SV_STSHUTW;
2436 if (!(t->flags & SN_ERR_MASK))
2437 t->flags |= SN_ERR_SRVTO;
2438 if (!(t->flags & SN_FINST_MASK))
2439 t->flags |= SN_FINST_H;
2440 return 1;
2441 }
2442
2443 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002444 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2445 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002446 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002447 }
2448 }
2449 else { /* client buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002450 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2451 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002452 if (t->be->beprm->srvtimeout) {
2453 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002454 /* FIXME: to prevent the server from expiring read timeouts during writes,
2455 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002456 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002457 }
2458 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002459 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002460 }
2461 }
2462
2463 /* be nice with the client side which would like to send a complete header
2464 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2465 * would read all remaining data at once ! The client should not write past rep->lr
2466 * when the server is in header state.
2467 */
2468 //return header_processed;
2469 return t->srv_state != SV_STHEADERS;
2470 }
2471 else if (s == SV_STDATA) {
2472 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002473 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002474 tv_eternity(&rep->rex);
2475 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002476 fd_delete(t->srv_fd);
2477 if (t->srv) {
2478 t->srv->cur_sess--;
2479 t->srv->failed_resp++;
2480 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002481 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002482 t->srv_state = SV_STCLOSE;
2483 if (!(t->flags & SN_ERR_MASK))
2484 t->flags |= SN_ERR_SRVCL;
2485 if (!(t->flags & SN_FINST_MASK))
2486 t->flags |= SN_FINST_D;
2487 /* We used to have a free connection slot. Since we'll never use it,
2488 * we have to inform the server that it may be used by another session.
2489 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002490 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002491 task_wakeup(&rq, t->srv->queue_mgt);
2492
2493 return 1;
2494 }
2495 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002496 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002497 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002498 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002499 shutdown(t->srv_fd, SHUT_RD);
2500 t->srv_state = SV_STSHUTR;
2501 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2502 return 1;
2503 }
2504 /* end of client read and no more data to send */
2505 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002506 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002507 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002508 shutdown(t->srv_fd, SHUT_WR);
2509 /* We must ensure that the read part is still alive when switching
2510 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002511 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002512 if (t->be->beprm->srvtimeout)
2513 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002514
2515 t->srv_state = SV_STSHUTW;
2516 return 1;
2517 }
2518 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002519 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002520 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002521 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002522 shutdown(t->srv_fd, SHUT_RD);
2523 t->srv_state = SV_STSHUTR;
2524 if (!(t->flags & SN_ERR_MASK))
2525 t->flags |= SN_ERR_SRVTO;
2526 if (!(t->flags & SN_FINST_MASK))
2527 t->flags |= SN_FINST_D;
2528 return 1;
2529 }
2530 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002531 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002532 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002533 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002534 shutdown(t->srv_fd, SHUT_WR);
2535 /* We must ensure that the read part is still alive when switching
2536 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002537 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002538 if (t->be->beprm->srvtimeout)
2539 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002540 t->srv_state = SV_STSHUTW;
2541 if (!(t->flags & SN_ERR_MASK))
2542 t->flags |= SN_ERR_SRVTO;
2543 if (!(t->flags & SN_FINST_MASK))
2544 t->flags |= SN_FINST_D;
2545 return 1;
2546 }
2547
2548 /* recompute request time-outs */
2549 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002550 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2551 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002552 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002553 }
2554 }
2555 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau2a429502006-10-15 14:52:29 +02002556 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2557 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002558 if (t->be->beprm->srvtimeout) {
2559 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002560 /* FIXME: to prevent the server from expiring read timeouts during writes,
2561 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002562 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002563 }
2564 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002565 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002566 }
2567 }
2568
2569 /* recompute response time-outs */
2570 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002571 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2572 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002573 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002574 }
2575 }
2576 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002577 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2578 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002579 if (t->be->beprm->srvtimeout)
2580 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002581 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002582 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002583 }
2584 }
2585
2586 return 0; /* other cases change nothing */
2587 }
2588 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002589 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002590 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002591 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002592 fd_delete(t->srv_fd);
2593 if (t->srv) {
2594 t->srv->cur_sess--;
2595 t->srv->failed_resp++;
2596 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002597 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002598 //close(t->srv_fd);
2599 t->srv_state = SV_STCLOSE;
2600 if (!(t->flags & SN_ERR_MASK))
2601 t->flags |= SN_ERR_SRVCL;
2602 if (!(t->flags & SN_FINST_MASK))
2603 t->flags |= SN_FINST_D;
2604 /* We used to have a free connection slot. Since we'll never use it,
2605 * we have to inform the server that it may be used by another session.
2606 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002607 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002608 task_wakeup(&rq, t->srv->queue_mgt);
2609
2610 return 1;
2611 }
2612 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002613 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002614 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002615 fd_delete(t->srv_fd);
2616 if (t->srv)
2617 t->srv->cur_sess--;
2618 //close(t->srv_fd);
2619 t->srv_state = SV_STCLOSE;
2620 /* We used to have a free connection slot. Since we'll never use it,
2621 * we have to inform the server that it may be used by another session.
2622 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002623 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002624 task_wakeup(&rq, t->srv->queue_mgt);
2625
2626 return 1;
2627 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002628 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002629 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002630 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002631 fd_delete(t->srv_fd);
2632 if (t->srv)
2633 t->srv->cur_sess--;
2634 //close(t->srv_fd);
2635 t->srv_state = SV_STCLOSE;
2636 if (!(t->flags & SN_ERR_MASK))
2637 t->flags |= SN_ERR_SRVTO;
2638 if (!(t->flags & SN_FINST_MASK))
2639 t->flags |= SN_FINST_D;
2640 /* We used to have a free connection slot. Since we'll never use it,
2641 * we have to inform the server that it may be used by another session.
2642 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002643 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002644 task_wakeup(&rq, t->srv->queue_mgt);
2645
2646 return 1;
2647 }
2648 else if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002649 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2650 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002651 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002652 }
2653 }
2654 else { /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002655 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2656 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau830ff452006-12-17 19:31:23 +01002657 if (t->be->beprm->srvtimeout) {
2658 tv_delayfrom(&req->wex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002659 /* FIXME: to prevent the server from expiring read timeouts during writes,
2660 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002661 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002662 }
2663 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002664 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002665 }
2666 }
2667 return 0;
2668 }
2669 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002670 if (rep->flags & BF_READ_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002671 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002672 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002673 fd_delete(t->srv_fd);
2674 if (t->srv) {
2675 t->srv->cur_sess--;
2676 t->srv->failed_resp++;
2677 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002678 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002679 //close(t->srv_fd);
2680 t->srv_state = SV_STCLOSE;
2681 if (!(t->flags & SN_ERR_MASK))
2682 t->flags |= SN_ERR_SRVCL;
2683 if (!(t->flags & SN_FINST_MASK))
2684 t->flags |= SN_FINST_D;
2685 /* We used to have a free connection slot. Since we'll never use it,
2686 * we have to inform the server that it may be used by another session.
2687 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002688 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002689 task_wakeup(&rq, t->srv->queue_mgt);
2690
2691 return 1;
2692 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002693 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002694 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002695 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002696 fd_delete(t->srv_fd);
2697 if (t->srv)
2698 t->srv->cur_sess--;
2699 //close(t->srv_fd);
2700 t->srv_state = SV_STCLOSE;
2701 /* We used to have a free connection slot. Since we'll never use it,
2702 * we have to inform the server that it may be used by another session.
2703 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002704 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002705 task_wakeup(&rq, t->srv->queue_mgt);
2706
2707 return 1;
2708 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002709 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002710 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002711 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002712 fd_delete(t->srv_fd);
2713 if (t->srv)
2714 t->srv->cur_sess--;
2715 //close(t->srv_fd);
2716 t->srv_state = SV_STCLOSE;
2717 if (!(t->flags & SN_ERR_MASK))
2718 t->flags |= SN_ERR_SRVTO;
2719 if (!(t->flags & SN_FINST_MASK))
2720 t->flags |= SN_FINST_D;
2721 /* We used to have a free connection slot. Since we'll never use it,
2722 * we have to inform the server that it may be used by another session.
2723 */
Willy Tarreau830ff452006-12-17 19:31:23 +01002724 if (may_dequeue_tasks(t->srv, t->be->beprm))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002725 task_wakeup(&rq, t->srv->queue_mgt);
2726
2727 return 1;
2728 }
2729 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002730 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2731 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002732 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002733 }
2734 }
2735 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002736 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2737 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau830ff452006-12-17 19:31:23 +01002738 if (t->be->beprm->srvtimeout)
2739 tv_delayfrom(&rep->rex, &now, t->be->beprm->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002740 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002741 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002742 }
2743 }
2744 return 0;
2745 }
2746 else { /* SV_STCLOSE : nothing to do */
2747 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2748 int len;
Willy Tarreau830ff452006-12-17 19:31:23 +01002749 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 +02002750 write(1, trash, len);
2751 }
2752 return 0;
2753 }
2754 return 0;
2755}
2756
2757
2758/*
2759 * Produces data for the session <s> depending on its source. Expects to be
2760 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
2761 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
2762 * session, which it uses to keep on being called when there is free space in
2763 * the buffer, of simply by letting an empty buffer upon return. It returns 1
2764 * if it changes the session state from CL_STSHUTR, otherwise 0.
2765 */
2766int produce_content(struct session *s)
2767{
Willy Tarreaubaaee002006-06-26 02:48:02 +02002768 if (s->data_source == DATA_SRC_NONE) {
2769 s->flags &= ~SN_SELF_GEN;
2770 return 1;
2771 }
2772 else if (s->data_source == DATA_SRC_STATS) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002773 /* dump server statistics */
2774 return produce_content_stats(s);
2775 }
2776 else {
2777 /* unknown data source */
2778 s->logs.status = 500;
2779 client_retnclose(s, error_message(s, HTTP_ERR_500));
2780 if (!(s->flags & SN_ERR_MASK))
2781 s->flags |= SN_ERR_PRXCOND;
2782 if (!(s->flags & SN_FINST_MASK))
2783 s->flags |= SN_FINST_R;
2784 s->flags &= ~SN_SELF_GEN;
2785 return 1;
2786 }
2787}
2788
2789
2790/*
2791 * Produces statistics data for the session <s>. Expects to be called with
2792 * s->cli_state == CL_STSHUTR. It stops by itself by unsetting the SN_SELF_GEN
2793 * flag from the session, which it uses to keep on being called when there is
2794 * free space in the buffer, of simply by letting an empty buffer upon return.
2795 * It returns 1 if it changes the session state from CL_STSHUTR, otherwise 0.
2796 */
2797int produce_content_stats(struct session *s)
2798{
2799 struct buffer *rep = s->rep;
2800 struct proxy *px;
2801 struct chunk msg;
2802 unsigned int up;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002803
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002804 msg.len = 0;
2805 msg.str = trash;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002806
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002807 switch (s->data_state) {
2808 case DATA_ST_INIT:
2809 /* the function had not been called yet */
2810 s->flags |= SN_SELF_GEN; // more data will follow
Willy Tarreaubaaee002006-06-26 02:48:02 +02002811
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002812 chunk_printf(&msg, sizeof(trash),
2813 "HTTP/1.0 200 OK\r\n"
2814 "Cache-Control: no-cache\r\n"
2815 "Connection: close\r\n"
2816 "Content-Type: text/html\r\n"
2817 "\r\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002818
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002819 s->logs.status = 200;
2820 client_retnclose(s, &msg); // send the start of the response.
2821 msg.len = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002822
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002823 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
2824 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
2825 if (!(s->flags & SN_FINST_MASK))
2826 s->flags |= SN_FINST_R;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002827
Willy Tarreau0214c3a2007-01-07 13:47:30 +01002828 if (s->hreq.meth == HTTP_METH_HEAD) {
2829 /* that's all we return in case of HEAD request */
2830 s->data_state = DATA_ST_FIN;
2831 s->flags &= ~SN_SELF_GEN;
2832 return 1;
2833 }
2834
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002835 s->data_state = DATA_ST_HEAD; /* let's start producing data */
2836 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002837
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002838 case DATA_ST_HEAD:
2839 /* WARNING! This must fit in the first buffer !!! */
2840 chunk_printf(&msg, sizeof(trash),
2841 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
2842 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
2843 "<style type=\"text/css\"><!--\n"
2844 "body {"
2845 " font-family: helvetica, arial;"
2846 " font-size: 12px;"
2847 " font-weight: normal;"
2848 " color: black;"
2849 " background: white;"
2850 "}\n"
2851 "th,td {"
2852 " font-size: 0.8em;"
2853 " align: center;"
2854 "}"
2855 "h1 {"
2856 " font-size: xx-large;"
2857 " margin-bottom: 0.5em;"
2858 "}\n"
2859 "h2 {"
2860 " font-family: helvetica, arial;"
2861 " font-size: x-large;"
2862 " font-weight: bold;"
2863 " font-style: italic;"
2864 " color: #6020a0;"
2865 " margin-top: 0em;"
2866 " margin-bottom: 0em;"
2867 "}\n"
2868 "h3 {"
2869 " font-family: helvetica, arial;"
2870 " font-size: 16px;"
2871 " font-weight: bold;"
2872 " color: #b00040;"
2873 " background: #e8e8d0;"
2874 " margin-top: 0em;"
2875 " margin-bottom: 0em;"
2876 "}\n"
2877 "li {"
2878 " margin-top: 0.25em;"
2879 " margin-right: 2em;"
2880 "}\n"
2881 ".hr {margin-top: 0.25em;"
2882 " border-color: black;"
2883 " border-bottom-style: solid;"
2884 "}\n"
2885 ".pxname {background: #b00040;color: #ffff40;font-weight: bold;}\n"
2886 ".titre {background: #20D0D0;color: #000000;font-weight: bold;}\n"
2887 ".total {background: #20D0D0;color: #ffff80;}\n"
2888 ".frontend {background: #e8e8d0;}\n"
2889 ".backend {background: #e8e8d0;}\n"
2890 ".active0 {background: #ff9090;}\n"
2891 ".active1 {background: #ffd020;}\n"
2892 ".active2 {background: #ffffa0;}\n"
2893 ".active3 {background: #c0ffc0;}\n"
2894 ".active4 {background: #e0e0e0;}\n"
2895 ".backup0 {background: #ff9090;}\n"
2896 ".backup1 {background: #ff80ff;}\n"
2897 ".backup2 {background: #c060ff;}\n"
2898 ".backup3 {background: #b0d0ff;}\n"
2899 ".backup4 {background: #e0e0e0;}\n"
2900 "table.tbl { border-collapse: collapse; border-style: none;}\n"
Willy Tarreau35d66b02007-01-02 00:28:21 +01002901 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; padding: 2px 3px; border-color: gray;}\n"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002902 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}\n"
2903 "table.tbl th.empty { border-style: none; empty-cells: hide;}\n"
2904 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
2905 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
2906 "table.lgd td.noborder { border-style: none; padding: 2px; white-space: nowrap;}\n"
2907 "-->"
2908 "</style></head>");
2909
2910 if (buffer_write_chunk(rep, &msg) != 0)
2911 return 0;
2912
2913 s->data_state = DATA_ST_INFO;
2914 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002915
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002916 case DATA_ST_INFO:
2917 up = (now.tv_sec - start_date.tv_sec);
2918
2919 /* WARNING! this has to fit the first packet too.
2920 * We are around 3.5 kB, add adding entries will
2921 * become tricky if we want to support 4kB buffers !
2922 */
2923 chunk_printf(&msg, sizeof(trash),
2924 "<body><h1><a href=\"" PRODUCT_URL "\" style=\"text-decoration: none;\">"
2925 PRODUCT_NAME "</a></h1>\n"
2926 "<h2>Statistics Report for pid %d</h2>\n"
2927 "<hr width=\"100%%\" class=\"hr\">\n"
2928 "<h3>&gt; General process information</h3>\n"
2929 "<table border=0 cols=3><tr><td align=\"left\" nowrap width=\"1%%\">\n"
2930 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
2931 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
2932 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
2933 "<b>maxsock = </b> %d<br>\n"
2934 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
2935 "</td><td align=\"center\" nowrap>\n"
2936 "<table class=\"lgd\"><tr>"
2937 "<td class=\"active3\">&nbsp;</td><td class=\"noborder\">active UP </td>"
2938 "<td class=\"backup3\">&nbsp;</td><td class=\"noborder\">backup UP </td>"
2939 "</tr><tr>"
2940 "<td class=\"active2\"></td><td class=\"noborder\">active UP, going down </td>"
2941 "<td class=\"backup2\"></td><td class=\"noborder\">backup UP, going down </td>"
2942 "</tr><tr>"
2943 "<td class=\"active1\"></td><td class=\"noborder\">active DOWN, going up </td>"
2944 "<td class=\"backup1\"></td><td class=\"noborder\">backup DOWN, going up </td>"
2945 "</tr><tr>"
2946 "<td class=\"active0\"></td><td class=\"noborder\">active or backup DOWN &nbsp;</td>"
2947 "<td class=\"active4\"></td><td class=\"noborder\">not checked </td>"
2948 "</tr></table>\n"
2949 "</td>"
2950 "<td align=\"left\" nowrap width=\"1%%\">"
2951 "<b>External ressources:</b><ul style=\"margin-top: 0.25em;\">"
2952 "<li><a href=\"" PRODUCT_URL "\">Primary site</a><br>"
2953 "<li><a href=\"" PRODUCT_URL_UPD "\">Updates (v" PRODUCT_BRANCH ")</a><br>"
2954 "<li><a href=\"" PRODUCT_URL_DOC "\">Online manual</a><br>"
2955 "</ul>"
2956 "</td>"
2957 "</tr></table>\n"
2958 "",
2959 pid, pid, global.nbproc,
2960 up / 86400, (up % 86400) / 3600,
2961 (up % 3600) / 60, (up % 60),
2962 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
2963 global.rlimit_memmax ? " MB" : "",
2964 global.rlimit_nofile,
2965 global.maxsock,
2966 global.maxconn,
2967 actconn
2968 );
Willy Tarreaubaaee002006-06-26 02:48:02 +02002969
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002970 if (buffer_write_chunk(rep, &msg) != 0)
2971 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002972
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002973 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002974
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002975 s->data_ctx.stats.px = proxy;
2976 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
2977 s->data_state = DATA_ST_LIST;
2978 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002979
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002980 case DATA_ST_LIST:
2981 /* dump proxies */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002982 while (s->data_ctx.stats.px) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002983 px = s->data_ctx.stats.px;
2984 /* skip the disabled proxies and non-networked ones */
2985 if (px->state != PR_STSTOPPED && (px->cap & (PR_CAP_FE | PR_CAP_BE)))
2986 if (produce_content_stats_proxy(s, px) == 0)
2987 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002988
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002989 s->data_ctx.stats.px = px->next;
2990 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
2991 }
2992 /* here, we just have reached the last proxy */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002993
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002994 s->data_state = DATA_ST_END;
2995 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02002996
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002997 case DATA_ST_END:
Willy Tarreau0214c3a2007-01-07 13:47:30 +01002998 chunk_printf(&msg, sizeof(trash), "</body></html>\n");
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01002999 if (buffer_write_chunk(rep, &msg) != 0)
3000 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003001
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003002 s->data_state = DATA_ST_FIN;
3003 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003004
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003005 case DATA_ST_FIN:
3006 s->flags &= ~SN_SELF_GEN;
3007 return 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003008
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003009 default:
3010 /* unknown state ! */
3011 s->logs.status = 500;
3012 client_retnclose(s, error_message(s, HTTP_ERR_500));
3013 if (!(s->flags & SN_ERR_MASK))
3014 s->flags |= SN_ERR_PRXCOND;
3015 if (!(s->flags & SN_FINST_MASK))
3016 s->flags |= SN_FINST_R;
3017 s->flags &= ~SN_SELF_GEN;
3018 return 1;
3019 }
3020}
Willy Tarreaubaaee002006-06-26 02:48:02 +02003021
Willy Tarreaubaaee002006-06-26 02:48:02 +02003022
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003023/*
3024 * Dumps statistics for a proxy.
3025 * Returns 0 if it had to stop dumping data because of lack of buffer space,
3026 * ot non-zero if everything completed.
3027 */
3028int produce_content_stats_proxy(struct session *s, struct proxy *px)
3029{
3030 struct buffer *rep = s->rep;
3031 struct server *sv;
3032 struct chunk msg;
3033
3034 msg.len = 0;
3035 msg.str = trash;
3036
3037 switch (s->data_ctx.stats.px_st) {
3038 case DATA_ST_PX_INIT:
3039 /* we are on a new proxy */
3040
3041 if (s->be->fiprm->uri_auth && s->be->fiprm->uri_auth->scope) {
3042 /* we have a limited scope, we have to check the proxy name */
3043 struct stat_scope *scope;
3044 int len;
3045
3046 len = strlen(px->id);
3047 scope = s->be->fiprm->uri_auth->scope;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003048
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003049 while (scope) {
3050 /* match exact proxy name */
3051 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
3052 break;
3053
3054 /* match '.' which means 'self' proxy */
3055 if (!strcmp(scope->px_id, ".") && px == s->fe)
3056 break;
3057 scope = scope->next;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003058 }
3059
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003060 /* proxy name not found : don't dump anything */
3061 if (scope == NULL)
3062 return 1;
3063 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003064
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003065 s->data_ctx.stats.px_st = DATA_ST_PX_TH;
3066 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003067
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003068 case DATA_ST_PX_TH:
3069 /* print a new table */
3070 chunk_printf(&msg, sizeof(trash),
3071 "<table cols=\"20\" class=\"tbl\" width=\"100%%\">\n"
3072 "<tr align=\"center\" class=\"titre\">"
3073 "<th colspan=2 class=\"pxname\">%s</th>"
3074 "<th colspan=18 class=\"empty\"></th>"
3075 "</tr>\n"
3076 "<tr align=\"center\" class=\"titre\">"
3077 "<th rowspan=2></th>"
3078 "<th colspan=2>Queue</th><th colspan=4>Sessions</th>"
3079 "<th colspan=2>Bytes</th><th colspan=2>Denied</th>"
3080 "<th colspan=3>Errors</th><th colspan=6>Server</th>"
3081 "</tr>\n"
3082 "<tr align=\"center\" class=\"titre\">"
Willy Tarreau35d66b02007-01-02 00:28:21 +01003083 "<th>Cur</th><th>Max</th><th>Cur</th><th>Max</th>"
3084 "<th>Limit</th><th>Cumul</th><th>In</th><th>Out</th>"
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003085 "<th>Req</th><th>Resp</th><th>Req</th><th>Conn</th>"
3086 "<th>Resp</th><th>Status</th><th>Weight</th><th>Act</th>"
3087 "<th>Bck</th><th>Check</th><th>Down</th></tr>\n"
3088 "",
3089 px->id);
3090
3091 if (buffer_write_chunk(rep, &msg) != 0)
3092 return 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003093
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003094 s->data_ctx.stats.px_st = DATA_ST_PX_FE;
3095 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003096
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003097 case DATA_ST_PX_FE:
3098 /* print the frontend */
3099 if (px->cap & PR_CAP_FE) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003100 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003101 /* name, queue */
3102 "<tr align=center class=\"frontend\"><td>Frontend</td><td colspan=2></td>"
3103 /* sessions : current, max, limit, cumul. */
3104 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
3105 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003106 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003107 /* denied: req, resp */
3108 "<td align=right>%d</td><td align=right>%d</td>"
3109 /* errors : request, connect, response */
3110 "<td align=right>%d</td><td align=right></td><td align=right></td>"
3111 /* server status : reflect backend status */
3112 "<td align=center>%s</td>"
3113 /* rest of server: nothing */
3114 "<td align=center colspan=5></td></tr>"
3115 "",
3116 px->feconn, px->feconn_max, px->maxconn, px->cum_feconn,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003117 px->bytes_in, px->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003118 px->denied_req, px->denied_resp,
3119 px->failed_req,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003120 px->state == PR_STRUN ? "OPEN" :
3121 px->state == PR_STIDLE ? "FULL" : "STOP");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003122
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003123 if (buffer_write_chunk(rep, &msg) != 0)
3124 return 0;
3125 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02003126
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003127 s->data_ctx.stats.sv = px->srv; /* may be NULL */
3128 s->data_ctx.stats.px_st = DATA_ST_PX_SV;
3129 /* fall through */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003130
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003131 case DATA_ST_PX_SV:
3132 /* stats.sv has been initialized above */
3133 while (s->data_ctx.stats.sv != NULL) {
3134 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
3135 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP, 4=unchecked */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003136
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003137 sv = s->data_ctx.stats.sv;
Willy Tarreaubaaee002006-06-26 02:48:02 +02003138
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003139 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
3140 if (!(sv->state & SRV_CHECKED))
3141 sv_state = 4;
3142 else if (sv->state & SRV_RUNNING)
3143 if (sv->health == sv->rise + sv->fall - 1)
3144 sv_state = 3; /* UP */
3145 else
3146 sv_state = 2; /* going down */
3147 else
3148 if (sv->health)
3149 sv_state = 1; /* going up */
3150 else
3151 sv_state = 0; /* DOWN */
3152
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003153 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003154 /* name */
3155 "<tr align=\"center\" class=\"%s%d\"><td>%s</td>"
3156 /* queue : current, max */
3157 "<td align=right>%d</td><td align=right>%d</td>"
3158 /* sessions : current, max, limit, cumul */
3159 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>"
3160 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003161 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003162 /* denied: req, resp */
3163 "<td align=right></td><td align=right>%d</td>"
3164 /* errors : request, connect, response */
3165 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
3166 "",
Willy Tarreau368e96a2007-01-07 00:16:15 +01003167 (sv->state & SRV_BACKUP) ? "backup" : "active",
Willy Tarreau128e9542007-01-01 22:01:43 +01003168 sv_state, sv->id,
3169 sv->nbpend, sv->nbpend_max,
3170 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003171 sv->bytes_in, sv->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003172 sv->failed_secu,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003173 sv->failed_conns, sv->failed_resp);
Willy Tarreau128e9542007-01-01 22:01:43 +01003174
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003175 /* status */
3176 chunk_printf(&msg, sizeof(trash), "<td nowrap>");
3177 chunk_printf(&msg, sizeof(trash),
3178 srv_hlt_st[sv_state],
3179 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
3180 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
3181
Willy Tarreau128e9542007-01-01 22:01:43 +01003182 chunk_printf(&msg, sizeof(trash),
3183 /* weight */
3184 "</td><td>%d</td>"
3185 /* act, bck */
3186 "<td>%s</td><td>%s</td>"
3187 "",
3188 sv->uweight+1,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003189 (sv->state & SRV_BACKUP) ? "-" : "Y",
3190 (sv->state & SRV_BACKUP) ? "Y" : "-");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003191
3192 /* check failures : unique, fatal */
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003193 if (sv->state & SRV_CHECKED)
3194 chunk_printf(&msg, sizeof(trash),
3195 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
3196 sv->failed_checks, sv->down_trans);
3197 else
3198 chunk_printf(&msg, sizeof(trash),
3199 "<td colspan=2></td></tr>\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02003200
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003201 if (buffer_write_chunk(rep, &msg) != 0)
3202 return 0;
3203
3204 s->data_ctx.stats.sv = sv->next;
3205 } /* while sv */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003206
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003207 s->data_ctx.stats.px_st = DATA_ST_PX_BE;
3208 /* fall through */
3209
3210 case DATA_ST_PX_BE:
3211 /* print the backend */
3212 if (px->cap & PR_CAP_BE) {
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003213 chunk_printf(&msg, sizeof(trash),
Willy Tarreau128e9542007-01-01 22:01:43 +01003214 /* name */
3215 "<tr align=center class=\"backend\"><td>Backend</td>"
3216 /* queue : current, max */
3217 "<td align=right>%d</td><td align=right>%d</td>"
3218 /* sessions : current, max, limit, cumul. */
3219 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
3220 /* bytes : in, out */
Willy Tarreau35d66b02007-01-02 00:28:21 +01003221 "<td align=right>%lld</td><td align=right>%lld</td>"
Willy Tarreau128e9542007-01-01 22:01:43 +01003222 /* denied: req, resp */
3223 "<td align=right>%d</td><td align=right>%d</td>"
3224 /* errors : request, connect, response */
3225 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
3226 /* server status : reflect backend status (up/down) : we display UP
3227 * if the backend has known working servers or if it has no server at
3228 * all (eg: for stats). Tthen we display the total weight, number of
3229 * active and backups. */
3230 "<td align=center>%s</td><td align=center>%d</td>"
3231 "<td align=center>%d</td><td align=center>%d</td>"
3232 /* rest of server: nothing */
3233 "<td align=center colspan=2></td></tr>"
3234 "",
3235 px->nbpend /* or px->totpend ? */, px->nbpend_max,
3236 px->beconn, px->beconn_max, px->fullconn, px->cum_beconn,
Willy Tarreau35d66b02007-01-02 00:28:21 +01003237 px->bytes_in, px->bytes_out,
Willy Tarreau128e9542007-01-01 22:01:43 +01003238 px->denied_req, px->denied_resp,
3239 px->failed_conns, px->failed_resp,
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003240 (px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN",
3241 px->srv_map_sz, px->srv_act, px->srv_bck);
Willy Tarreaubaaee002006-06-26 02:48:02 +02003242
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003243 if (buffer_write_chunk(rep, &msg) != 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02003244 return 0;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003245 }
3246
3247 s->data_ctx.stats.px_st = DATA_ST_PX_END;
3248 /* fall through */
3249
3250 case DATA_ST_PX_END:
3251 chunk_printf(&msg, sizeof(trash), "</table><p>\n");
3252
3253 if (buffer_write_chunk(rep, &msg) != 0)
3254 return 0;
3255
3256 s->data_ctx.stats.px_st = DATA_ST_PX_FIN;
3257 /* fall through */
3258
3259 case DATA_ST_PX_FIN:
Willy Tarreaubaaee002006-06-26 02:48:02 +02003260 return 1;
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003261
3262 default:
3263 /* unknown state, we should put an abort() here ! */
Willy Tarreaubaaee002006-06-26 02:48:02 +02003264 return 1;
3265 }
3266}
3267
3268
Willy Tarreau58f10d72006-12-04 02:26:12 +01003269
3270/*
3271 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>
3272 */
3273
3274void apply_filters_to_session(struct session *t, struct buffer *req, struct hdr_exp *exp)
3275{
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003276 struct http_req *hreq = &t->hreq;
3277
Willy Tarreau58f10d72006-12-04 02:26:12 +01003278 /* iterate through the filters in the outer loop */
3279 while (exp && !(t->flags & (SN_CLDENY|SN_CLTARPIT))) {
3280 char term;
3281 char *cur_ptr, *cur_end, *cur_next;
3282 int cur_idx, old_idx, abort_filt;
3283
3284
3285 /*
3286 * The interleaving of transformations and verdicts
3287 * makes it difficult to decide to continue or stop
3288 * the evaluation.
3289 */
3290
3291 if ((t->flags & SN_CLALLOW) &&
3292 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
3293 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
3294 exp = exp->next;
3295 continue;
3296 }
3297
3298 /* Iterate through the headers in the inner loop.
3299 * we start with the start line.
3300 */
3301 old_idx = cur_idx = 0;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003302 cur_next = req->data + hreq->req.sor;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003303 abort_filt = 0;
3304
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003305 while (!abort_filt && (cur_idx = hreq->hdr_idx.v[cur_idx].next)) {
3306 struct hdr_idx_elem *cur_hdr = &hreq->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003307 cur_ptr = cur_next;
3308 cur_end = cur_ptr + cur_hdr->len;
3309 cur_next = cur_end + cur_hdr->cr + 1;
3310
3311 /* Now we have one header between cur_ptr and cur_end,
3312 * and the next header starts at cur_next.
3313 */
3314
3315 /* The annoying part is that pattern matching needs
3316 * that we modify the contents to null-terminate all
3317 * strings before testing them.
3318 */
3319
3320 term = *cur_end;
3321 *cur_end = '\0';
3322
3323 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
3324 switch (exp->action) {
Willy Tarreaua496b602006-12-17 23:15:24 +01003325 case ACT_SETBE:
3326 /* It is not possible to jump a second time.
3327 * FIXME: should we return an HTTP/500 here so that
3328 * the admin knows there's a problem ?
3329 */
3330 if (t->be != t->fe)
3331 break;
3332
3333 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3334 struct proxy *target = (struct proxy *) exp->replace;
3335
3336 /* Swithing Proxy */
3337 *cur_end = term;
3338 cur_end = NULL;
3339
3340 /* right now, the backend switch is not too much complicated
3341 * because we have associated req_cap and rsp_cap to the
3342 * frontend, and the beconn will be updated later.
3343 */
3344
3345 t->rep->rto = t->req->wto = target->beprm->srvtimeout;
3346 t->req->cto = target->beprm->contimeout;
3347
3348 t->be = target;
3349
3350 //t->logs.logwait |= LW_REQ | (target->to_log & (LW_REQHDR | LW_COOKIE));
Willy Tarreau97de6242006-12-27 17:18:38 +01003351 /* FIXME: should we use the backend's log options or not ?
3352 * It would seem far too complicated to configure a service with
3353 * logs defined both in the frontend and the backend.
3354 */
3355 //t->logs.logwait |= (target->to_log | target->beprm->to_log);
3356
Willy Tarreaua496b602006-12-17 23:15:24 +01003357 abort_filt = 1;
3358 }
3359 break;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003360 case ACT_ALLOW:
3361 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3362 t->flags |= SN_CLALLOW;
3363 abort_filt = 1;
3364 }
3365 break;
3366 case ACT_REPLACE:
3367 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3368 int len, delta;
3369 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
3370 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
Willy Tarreaue15d9132006-12-14 22:26:42 +01003371 /* FIXME: if the user adds a newline in the replacement, the
3372 * index will not be recalculated for now, and the new line
3373 * will not be counted for a new header.
3374 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01003375 cur_end += delta;
3376 cur_next += delta;
3377 cur_hdr->len += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003378 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003379 }
3380 break;
3381 case ACT_REMOVE:
3382 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
3383 int delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3384 cur_next += delta;
3385
3386 /* FIXME: this should be a separate function */
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003387 hreq->req.eoh += delta;
3388 hreq->hdr_idx.v[old_idx].next = cur_hdr->next;
3389 hreq->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003390 cur_hdr->len = 0;
3391
3392 cur_end = NULL; /* null-term has been rewritten */
3393 }
3394 break;
3395 case ACT_DENY:
3396 if (!(t->flags & (SN_CLALLOW | SN_CLTARPIT))) {
3397 t->flags |= SN_CLDENY;
3398 abort_filt = 1;
3399 }
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003400 t->be->beprm->denied_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003401 break;
3402 case ACT_TARPIT:
3403 if (!(t->flags & (SN_CLALLOW | SN_CLDENY))) {
3404 t->flags |= SN_CLTARPIT;
3405 abort_filt = 1;
3406 }
Willy Tarreauc0dde7a2007-01-01 21:38:07 +01003407 t->be->beprm->denied_req++;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003408 break;
3409 //case ACT_PASS: /* FIXME: broken as of now. We should mark the header as "ignored". */
3410 // break;
3411 }
3412 }
3413 if (cur_end)
3414 *cur_end = term; /* restore the string terminator */
3415
3416 /* keep the link from this header to next one */
3417 old_idx = cur_idx;
3418 }
3419 exp = exp->next;
3420 }
3421}
3422
3423
3424
3425/*
3426 * Manager client-side cookie
3427 */
3428void manage_client_side_cookies(struct session *t, struct buffer *req)
3429{
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003430 struct http_req *hreq = &t->hreq;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003431 char *p1, *p2, *p3, *p4;
3432 char *del_colon, *del_cookie, *colon;
3433 int app_cookies;
3434
3435 appsess *asession_temp = NULL;
3436 appsess local_asession;
3437
3438 char *cur_ptr, *cur_end, *cur_next;
3439 int cur_idx, old_idx, abort_filt;
3440
Willy Tarreau830ff452006-12-17 19:31:23 +01003441 if (t->be->beprm->cookie_name == NULL &&
3442 t->be->beprm->appsession_name ==NULL &&
3443 t->be->fiprm->capture_name != NULL)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003444 return;
3445
Willy Tarreau2a324282006-12-05 00:05:46 +01003446 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003447 * we start with the start line.
3448 */
3449 old_idx = cur_idx = 0;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003450 cur_next = req->data + hreq->req.sor;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003451 abort_filt = 0;
3452
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003453 while ((cur_idx = hreq->hdr_idx.v[cur_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003454 struct hdr_idx_elem *cur_hdr;
3455
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003456 cur_hdr = &hreq->hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003457 cur_ptr = cur_next;
3458 cur_end = cur_ptr + cur_hdr->len;
3459 cur_next = cur_end + cur_hdr->cr + 1;
3460
3461 /* We have one full header between cur_ptr and cur_end, and the
3462 * next header starts at cur_next. We're only interested in
3463 * "Cookie:" headers.
3464 */
3465
3466 if ((cur_end - cur_ptr <= 7) ||
3467 (strncasecmp(cur_ptr, "Cookie:", 7) != 0)) {
3468 old_idx = cur_idx;
3469 continue;
3470 }
3471
3472 /* Now look for cookies. Conforming to RFC2109, we have to support
3473 * attributes whose name begin with a '$', and associate them with
3474 * the right cookie, if we want to delete this cookie.
3475 * So there are 3 cases for each cookie read :
3476 * 1) it's a special attribute, beginning with a '$' : ignore it.
3477 * 2) it's a server id cookie that we *MAY* want to delete : save
3478 * some pointers on it (last semi-colon, beginning of cookie...)
3479 * 3) it's an application cookie : we *MAY* have to delete a previous
3480 * "special" cookie.
3481 * At the end of loop, if a "special" cookie remains, we may have to
3482 * remove it. If no application cookie persists in the header, we
3483 * *MUST* delete it
3484 */
3485
3486
3487 p1 = cur_ptr + 7; /* first char after 'Cookie:' */
3488 if (isspace((int)*p1)) /* try to get the first space with it */
3489 p1++;
3490
3491 colon = p1;
3492 /* del_cookie == NULL => nothing to be deleted */
3493 del_colon = del_cookie = NULL;
3494 app_cookies = 0;
3495
3496 while (p1 < cur_end) {
3497 /* skip spaces and colons, but keep an eye on these ones */
3498 while (p1 < cur_end) {
3499 if (*p1 == ';' || *p1 == ',')
3500 colon = p1;
3501 else if (!isspace((int)*p1))
3502 break;
3503 p1++;
3504 }
3505
3506 if (p1 == cur_end)
3507 break;
3508
3509 /* p1 is at the beginning of the cookie name */
3510 p2 = p1;
3511 while (p2 < cur_end && *p2 != '=')
3512 p2++;
3513
3514 if (p2 == cur_end)
3515 break;
3516
3517 p3 = p2 + 1; /* skips the '=' sign */
3518 if (p3 == cur_end)
3519 break;
3520
3521 p4 = p3;
3522 while (p4 < cur_end && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
3523 p4++;
3524
3525 /* here, we have the cookie name between p1 and p2,
3526 * and its value between p3 and p4.
3527 * we can process it :
3528 *
3529 * Cookie: NAME=VALUE;
3530 * | || || |
3531 * | || || +--> p4
3532 * | || |+-------> p3
3533 * | || +--------> p2
3534 * | |+------------> p1
3535 * | +-------------> colon
3536 * +--------------------> cur_ptr
3537 */
3538
3539 if (*p1 == '$') {
3540 /* skip this one */
3541 }
3542 else {
3543 /* first, let's see if we want to capture it */
Willy Tarreau830ff452006-12-17 19:31:23 +01003544 if (t->fe->fiprm->capture_name != NULL &&
Willy Tarreau58f10d72006-12-04 02:26:12 +01003545 t->logs.cli_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01003546 (p4 - p1 >= t->fe->fiprm->capture_namelen) &&
3547 memcmp(p1, t->fe->fiprm->capture_name, t->fe->fiprm->capture_namelen) == 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003548 int log_len = p4 - p1;
3549
3550 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3551 Alert("HTTP logging : out of memory.\n");
3552 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003553 if (log_len > t->fe->fiprm->capture_len)
3554 log_len = t->fe->fiprm->capture_len;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003555 memcpy(t->logs.cli_cookie, p1, log_len);
3556 t->logs.cli_cookie[log_len] = 0;
3557 }
3558 }
3559
Willy Tarreau830ff452006-12-17 19:31:23 +01003560 if ((p2 - p1 == t->be->beprm->cookie_len) && (t->be->beprm->cookie_name != NULL) &&
3561 (memcmp(p1, t->be->beprm->cookie_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003562 /* Cool... it's the right one */
Willy Tarreau830ff452006-12-17 19:31:23 +01003563 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003564 char *delim;
3565
3566 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3567 * have the server ID betweek p3 and delim, and the original cookie between
3568 * delim+1 and p4. Otherwise, delim==p4 :
3569 *
3570 * Cookie: NAME=SRV~VALUE;
3571 * | || || | |
3572 * | || || | +--> p4
3573 * | || || +--------> delim
3574 * | || |+-----------> p3
3575 * | || +------------> p2
3576 * | |+----------------> p1
3577 * | +-----------------> colon
3578 * +------------------------> cur_ptr
3579 */
3580
Willy Tarreau830ff452006-12-17 19:31:23 +01003581 if (t->be->beprm->options & PR_O_COOK_PFX) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003582 for (delim = p3; delim < p4; delim++)
3583 if (*delim == COOKIE_DELIM)
3584 break;
3585 }
3586 else
3587 delim = p4;
3588
3589
3590 /* Here, we'll look for the first running server which supports the cookie.
3591 * This allows to share a same cookie between several servers, for example
3592 * to dedicate backup servers to specific servers only.
3593 * However, to prevent clients from sticking to cookie-less backup server
3594 * when they have incidentely learned an empty cookie, we simply ignore
3595 * empty cookies and mark them as invalid.
3596 */
3597 if (delim == p3)
3598 srv = NULL;
3599
3600 while (srv) {
3601 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003602 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003603 /* we found the server and it's usable */
3604 t->flags &= ~SN_CK_MASK;
3605 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3606 t->srv = srv;
3607 break;
3608 } else {
3609 /* we found a server, but it's down */
3610 t->flags &= ~SN_CK_MASK;
3611 t->flags |= SN_CK_DOWN;
3612 }
3613 }
3614 srv = srv->next;
3615 }
3616
3617 if (!srv && !(t->flags & SN_CK_DOWN)) {
3618 /* no server matched this cookie */
3619 t->flags &= ~SN_CK_MASK;
3620 t->flags |= SN_CK_INVALID;
3621 }
3622
3623 /* depending on the cookie mode, we may have to either :
3624 * - delete the complete cookie if we're in insert+indirect mode, so that
3625 * the server never sees it ;
3626 * - remove the server id from the cookie value, and tag the cookie as an
3627 * application cookie so that it does not get accidentely removed later,
3628 * if we're in cookie prefix mode
3629 */
Willy Tarreau830ff452006-12-17 19:31:23 +01003630 if ((t->be->beprm->options & PR_O_COOK_PFX) && (delim != p4)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003631 int delta; /* negative */
3632
3633 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
3634 p4 += delta;
3635 cur_end += delta;
3636 cur_next += delta;
3637 cur_hdr->len += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003638 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003639
3640 del_cookie = del_colon = NULL;
3641 app_cookies++; /* protect the header from deletion */
3642 }
3643 else if (del_cookie == NULL &&
Willy Tarreau830ff452006-12-17 19:31:23 +01003644 (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 +01003645 del_cookie = p1;
3646 del_colon = colon;
3647 }
3648 } else {
3649 /* now we know that we must keep this cookie since it's
3650 * not ours. But if we wanted to delete our cookie
3651 * earlier, we cannot remove the complete header, but we
3652 * can remove the previous block itself.
3653 */
3654 app_cookies++;
3655
3656 if (del_cookie != NULL) {
3657 int delta; /* negative */
3658
3659 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
3660 p4 += delta;
3661 cur_end += delta;
3662 cur_next += delta;
3663 cur_hdr->len += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003664 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003665 del_cookie = del_colon = NULL;
3666 }
3667 }
3668
Willy Tarreau830ff452006-12-17 19:31:23 +01003669 if ((t->be->beprm->appsession_name != NULL) &&
3670 (memcmp(p1, t->be->beprm->appsession_name, p2 - p1) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003671 /* first, let's see if the cookie is our appcookie*/
3672
3673 /* Cool... it's the right one */
3674
3675 asession_temp = &local_asession;
3676
3677 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3678 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3679 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3680 return;
3681 }
3682
Willy Tarreau830ff452006-12-17 19:31:23 +01003683 memcpy(asession_temp->sessid, p3, t->be->beprm->appsession_len);
3684 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003685 asession_temp->serverid = NULL;
3686
3687 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01003688 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003689 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3690 /* free previously allocated memory */
3691 pool_free_to(apools.sessid, local_asession.sessid);
3692 Alert("Not enough memory process_cli():asession:calloc().\n");
3693 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3694 return;
3695 }
3696
3697 asession_temp->sessid = local_asession.sessid;
3698 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01003699 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003700 } else {
3701 /* free previously allocated memory */
3702 pool_free_to(apools.sessid, local_asession.sessid);
3703 }
3704
3705 if (asession_temp->serverid == NULL) {
3706 Alert("Found Application Session without matching server.\n");
3707 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003708 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003709 while (srv) {
3710 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003711 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003712 /* we found the server and it's usable */
3713 t->flags &= ~SN_CK_MASK;
3714 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3715 t->srv = srv;
3716 break;
3717 } else {
3718 t->flags &= ~SN_CK_MASK;
3719 t->flags |= SN_CK_DOWN;
3720 }
3721 }
3722 srv = srv->next;
3723 }/* end while(srv) */
3724 }/* end else if server == NULL */
3725
Willy Tarreau830ff452006-12-17 19:31:23 +01003726 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003727 }/* end if ((t->proxy->appsession_name != NULL) ... */
3728 }
3729
3730 /* we'll have to look for another cookie ... */
3731 p1 = p4;
3732 } /* while (p1 < cur_end) */
3733
3734 /* There's no more cookie on this line.
3735 * We may have marked the last one(s) for deletion.
3736 * We must do this now in two ways :
3737 * - if there is no app cookie, we simply delete the header ;
3738 * - if there are app cookies, we must delete the end of the
3739 * string properly, including the colon/semi-colon before
3740 * the cookie name.
3741 */
3742 if (del_cookie != NULL) {
3743 int delta;
3744 if (app_cookies) {
3745 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
3746 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003747 cur_hdr->len += delta;
3748 } else {
3749 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003750
3751 /* FIXME: this should be a separate function */
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003752 hreq->hdr_idx.v[old_idx].next = cur_hdr->next;
3753 hreq->hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003754 cur_hdr->len = 0;
3755 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01003756 cur_next += delta;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003757 hreq->req.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003758 }
3759
3760 /* keep the link from this header to next one */
3761 old_idx = cur_idx;
3762 } /* end of cookie processing on this header */
3763}
3764
3765
3766
3767/*
3768 * Try to retrieve a known appsession in the URI, then the associated server.
3769 * If the server is found, it's assigned to the session.
3770 */
3771
3772void get_srv_from_appsession(struct session *t, const char *begin, const char *end)
3773{
3774 appsess *asession_temp = NULL;
3775 appsess local_asession;
3776 char *request_line;
3777
Willy Tarreau830ff452006-12-17 19:31:23 +01003778 if (t->be->beprm->appsession_name == NULL ||
Willy Tarreau921d7c02006-12-17 13:50:27 +01003779 (t->hreq.meth != HTTP_METH_GET && t->hreq.meth != HTTP_METH_POST) ||
Willy Tarreau58f10d72006-12-04 02:26:12 +01003780 (request_line = memchr(begin, ';', end - begin)) == NULL ||
Willy Tarreau830ff452006-12-17 19:31:23 +01003781 ((1 + t->be->beprm->appsession_name_len + 1 + t->be->beprm->appsession_len) > (end - request_line)))
Willy Tarreau58f10d72006-12-04 02:26:12 +01003782 return;
3783
3784 /* skip ';' */
3785 request_line++;
3786
3787 /* look if we have a jsessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01003788 if (strncasecmp(request_line, t->be->beprm->appsession_name, t->be->beprm->appsession_name_len) != 0)
Willy Tarreau58f10d72006-12-04 02:26:12 +01003789 return;
3790
3791 /* skip jsessionid= */
Willy Tarreau830ff452006-12-17 19:31:23 +01003792 request_line += t->be->beprm->appsession_name_len + 1;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003793
3794 /* First try if we already have an appsession */
3795 asession_temp = &local_asession;
3796
3797 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3798 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3799 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3800 return;
3801 }
3802
3803 /* Copy the sessionid */
Willy Tarreau830ff452006-12-17 19:31:23 +01003804 memcpy(asession_temp->sessid, request_line, t->be->beprm->appsession_len);
3805 asession_temp->sessid[t->be->beprm->appsession_len] = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003806 asession_temp->serverid = NULL;
3807
3808 /* only do insert, if lookup fails */
Willy Tarreau830ff452006-12-17 19:31:23 +01003809 if (chtbl_lookup(&(t->be->beprm->htbl_proxy), (void *)&asession_temp)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003810 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3811 /* free previously allocated memory */
3812 pool_free_to(apools.sessid, local_asession.sessid);
3813 Alert("Not enough memory process_cli():asession:calloc().\n");
3814 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3815 return;
3816 }
3817 asession_temp->sessid = local_asession.sessid;
3818 asession_temp->serverid = local_asession.serverid;
Willy Tarreau830ff452006-12-17 19:31:23 +01003819 chtbl_insert(&(t->be->beprm->htbl_proxy), (void *) asession_temp);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003820 }
3821 else {
3822 /* free previously allocated memory */
3823 pool_free_to(apools.sessid, local_asession.sessid);
3824 }
3825
Willy Tarreau830ff452006-12-17 19:31:23 +01003826 tv_delayfrom(&asession_temp->expire, &now, t->be->beprm->appsession_timeout);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003827 asession_temp->request_count++;
3828
3829#if defined(DEBUG_HASH)
3830 print_table(&(t->proxy->htbl_proxy));
3831#endif
3832 if (asession_temp->serverid == NULL) {
3833 Alert("Found Application Session without matching server.\n");
3834 } else {
Willy Tarreau830ff452006-12-17 19:31:23 +01003835 struct server *srv = t->be->beprm->srv;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003836 while (srv) {
3837 if (strcmp(srv->id, asession_temp->serverid) == 0) {
Willy Tarreau830ff452006-12-17 19:31:23 +01003838 if (srv->state & SRV_RUNNING || t->be->beprm->options & PR_O_PERSIST) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003839 /* we found the server and it's usable */
3840 t->flags &= ~SN_CK_MASK;
3841 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3842 t->srv = srv;
3843 break;
3844 } else {
3845 t->flags &= ~SN_CK_MASK;
3846 t->flags |= SN_CK_DOWN;
3847 }
3848 }
3849 srv = srv->next;
3850 }
3851 }
3852}
3853
3854
Willy Tarreaub2513902006-12-17 14:52:38 +01003855
3856/*
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003857 * In a GET or HEAD request, check if the requested URI matches the stats uri
3858 * for the current backend, and if an authorization has been passed and is valid.
Willy Tarreaub2513902006-12-17 14:52:38 +01003859 *
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003860 * It is assumed that the request is either a HEAD or GET and that the
3861 * t->be->fiprm->uri_auth field is valid. An HTTP/401 response may be sent, or
3862 * produce_content() can be called to start sending data.
Willy Tarreaub2513902006-12-17 14:52:38 +01003863 *
3864 * Returns 1 if the session's state changes, otherwise 0.
3865 */
3866int stats_check_uri_auth(struct session *t, struct proxy *backend)
3867{
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003868 struct http_req *hreq = &t->hreq;
Willy Tarreaub2513902006-12-17 14:52:38 +01003869 struct uri_auth *uri_auth = backend->uri_auth;
3870 struct user_auth *user;
3871 int authenticated, cur_idx;
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003872 char *h, *e;
Willy Tarreaub2513902006-12-17 14:52:38 +01003873
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003874 /* FIXME: this will soon be easier */
3875 /* skip the method */
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003876 h = hreq->start.str;
3877 e = h + hreq->start.len - uri_auth->uri_len;
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003878
3879 while (h < e && *h != ' ' && *h != '\t')
3880 h++;
3881
3882 /* find the URI */
3883 while (h < e && (*h == ' ' || *h == '\t'))
3884 h++;
3885
3886 if (h >= e)
Willy Tarreaub2513902006-12-17 14:52:38 +01003887 return 0;
3888
Willy Tarreau0214c3a2007-01-07 13:47:30 +01003889 /* the URI is in h */
3890 if (memcmp(h, uri_auth->uri_prefix, uri_auth->uri_len) != 0)
Willy Tarreaub2513902006-12-17 14:52:38 +01003891 return 0;
3892
3893 /* we are in front of a interceptable URI. Let's check
3894 * if there's an authentication and if it's valid.
3895 */
3896 user = uri_auth->users;
3897 if (!user) {
3898 /* no user auth required, it's OK */
3899 authenticated = 1;
3900 } else {
3901 authenticated = 0;
3902
3903 /* a user list is defined, we have to check.
3904 * skip 21 chars for "Authorization: Basic ".
3905 */
3906
3907 /* FIXME: this should move to an earlier place */
3908 cur_idx = 0;
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003909 h = t->req->data + hreq->req.sor;
3910 while ((cur_idx = hreq->hdr_idx.v[cur_idx].next)) {
3911 int len = hreq->hdr_idx.v[cur_idx].len;
Willy Tarreaub2513902006-12-17 14:52:38 +01003912 if (len > 14 &&
3913 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003914 hreq->auth_hdr.str = h;
3915 hreq->auth_hdr.len = len;
Willy Tarreaub2513902006-12-17 14:52:38 +01003916 break;
3917 }
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003918 h += len + hreq->hdr_idx.v[cur_idx].cr + 1;
Willy Tarreaub2513902006-12-17 14:52:38 +01003919 }
3920
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003921 if (hreq->auth_hdr.len < 21 ||
3922 memcmp(hreq->auth_hdr.str + 14, " Basic ", 7))
Willy Tarreaub2513902006-12-17 14:52:38 +01003923 user = NULL;
3924
3925 while (user) {
Willy Tarreau0f7562b2007-01-07 15:46:13 +01003926 if ((hreq->auth_hdr.len == user->user_len + 14 + 7)
3927 && !memcmp(hreq->auth_hdr.str + 14 + 7,
Willy Tarreaub2513902006-12-17 14:52:38 +01003928 user->user_pwd, user->user_len)) {
3929 authenticated = 1;
3930 break;
3931 }
3932 user = user->next;
3933 }
3934 }
3935
3936 if (!authenticated) {
Willy Tarreau0f772532006-12-23 20:51:41 +01003937 struct chunk msg;
Willy Tarreaub2513902006-12-17 14:52:38 +01003938
3939 /* no need to go further */
Willy Tarreau0f772532006-12-23 20:51:41 +01003940 msg.str = trash;
3941 msg.len = sprintf(trash, HTTP_401_fmt, uri_auth->auth_realm);
Willy Tarreaub2513902006-12-17 14:52:38 +01003942 t->logs.status = 401;
Willy Tarreau0f772532006-12-23 20:51:41 +01003943 client_retnclose(t, &msg);
Willy Tarreaub2513902006-12-17 14:52:38 +01003944 if (!(t->flags & SN_ERR_MASK))
3945 t->flags |= SN_ERR_PRXCOND;
3946 if (!(t->flags & SN_FINST_MASK))
3947 t->flags |= SN_FINST_R;
3948 return 1;
3949 }
3950
3951 /* The request is valid, the user is authenticate. Let's start sending
3952 * data.
3953 */
3954 t->cli_state = CL_STSHUTR;
3955 t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */
3956 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
3957 t->data_source = DATA_SRC_STATS;
3958 t->data_state = DATA_ST_INIT;
3959 produce_content(t);
3960 return 1;
3961}
3962
3963
3964
Willy Tarreaubaaee002006-06-26 02:48:02 +02003965/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01003966 * Print a debug line with a header
3967 */
3968void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
3969{
3970 int len, max;
3971 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
3972 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
3973 max = end - start;
3974 UBOUND(max, sizeof(trash) - len - 1);
3975 len += strlcpy2(trash + len, start, max + 1);
3976 trash[len++] = '\n';
3977 write(1, trash, len);
3978}
3979
3980
3981/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02003982 * Local variables:
3983 * c-indent-level: 8
3984 * c-basic-offset: 8
3985 * End:
3986 */