blob: 171f44076433015f5cd1d747ca0e9a5ea3ddfb5f [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * HTTP protocol analyzer
3 *
4 * Copyright 2000-2006 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <syslog.h>
20
21#include <sys/socket.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24
Willy Tarreau2dd0d472006-06-29 17:53:05 +020025#include <common/appsession.h>
26#include <common/compat.h>
27#include <common/config.h>
Willy Tarreaua4cd1f52006-12-16 19:57:26 +010028#include <common/debug.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020029#include <common/memory.h>
30#include <common/mini-clist.h>
31#include <common/standard.h>
32#include <common/time.h>
33#include <common/uri_auth.h>
34#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020035
36#include <types/capture.h>
37#include <types/client.h>
38#include <types/global.h>
39#include <types/httperr.h>
40#include <types/polling.h>
41#include <types/proxy.h>
42#include <types/server.h>
43
44#include <proto/backend.h>
45#include <proto/buffers.h>
46#include <proto/fd.h>
47#include <proto/log.h>
Willy Tarreau58f10d72006-12-04 02:26:12 +010048#include <proto/hdr_idx.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020049#include <proto/proto_http.h>
50#include <proto/queue.h>
51#include <proto/session.h>
52#include <proto/task.h>
53
54
Willy Tarreau58f10d72006-12-04 02:26:12 +010055#define DEBUG_PARSE_NO_SPEEDUP
56#undef DEBUG_PARSE_NO_SPEEDUP
57
Willy Tarreau1c47f852006-07-09 08:22:27 +020058/* This is used by remote monitoring */
59const char *HTTP_200 =
60 "HTTP/1.0 200 OK\r\n"
61 "Cache-Control: no-cache\r\n"
62 "Connection: close\r\n"
63 "Content-Type: text/html\r\n"
64 "\r\n"
65 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
66
Willy Tarreaubaaee002006-06-26 02:48:02 +020067/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
68const char *HTTP_401_fmt =
69 "HTTP/1.0 401 Unauthorized\r\n"
70 "Cache-Control: no-cache\r\n"
71 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +020072 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +020073 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
74 "\r\n"
75 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
76
77
78#ifdef DEBUG_FULL
79static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
80static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
81#endif
82
83
84/*
85 * returns a message to the client ; the connection is shut down for read,
86 * and the request is cleared so that no server connection can be initiated.
87 * The client must be in a valid state for this (HEADER, DATA ...).
88 * Nothing is performed on the server side.
89 * The reply buffer doesn't need to be empty before this.
90 */
91void client_retnclose(struct session *s, int len, const char *msg)
92{
Willy Tarreau2a429502006-10-15 14:52:29 +020093 MY_FD_CLR(s->cli_fd, StaticReadEvent);
94 MY_FD_SET(s->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +020095 tv_eternity(&s->req->rex);
Willy Tarreau73de9892006-11-30 11:40:23 +010096 if (s->fe->clitimeout)
97 tv_delayfrom(&s->rep->wex, &now, s->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +020098 else
Willy Tarreaud7971282006-07-29 18:36:34 +020099 tv_eternity(&s->rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200100 shutdown(s->cli_fd, SHUT_RD);
101 s->cli_state = CL_STSHUTR;
102 buffer_flush(s->rep);
103 buffer_write(s->rep, msg, len);
104 s->req->l = 0;
105}
106
107
108/*
109 * returns a message into the rep buffer, and flushes the req buffer.
110 * The reply buffer doesn't need to be empty before this.
111 */
112void client_return(struct session *s, int len, const char *msg)
113{
114 buffer_flush(s->rep);
115 buffer_write(s->rep, msg, len);
116 s->req->l = 0;
117}
118
119
120/* This function turns the server state into the SV_STCLOSE, and sets
121 * indicators accordingly. Note that if <status> is 0, no message is
122 * returned.
123 */
124void srv_close_with_err(struct session *t, int err, int finst,
Willy Tarreaub17916e2006-10-15 15:17:57 +0200125 int status, int msglen, const char *msg)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200126{
127 t->srv_state = SV_STCLOSE;
128 if (status > 0) {
129 t->logs.status = status;
Willy Tarreau73de9892006-11-30 11:40:23 +0100130 if (t->fe->mode == PR_MODE_HTTP)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200131 client_return(t, msglen, msg);
132 }
133 if (!(t->flags & SN_ERR_MASK))
134 t->flags |= err;
135 if (!(t->flags & SN_FINST_MASK))
136 t->flags |= finst;
137}
138
139
140/* Processes the client and server jobs of a session task, then
141 * puts it back to the wait queue in a clean state, or
142 * cleans up its resources if it must be deleted. Returns
143 * the time the task accepts to wait, or TIME_ETERNITY for
144 * infinity.
145 */
146int process_session(struct task *t)
147{
148 struct session *s = t->context;
149 int fsm_resync = 0;
150
151 do {
152 fsm_resync = 0;
153 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
154 fsm_resync |= process_cli(s);
155 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
156 fsm_resync |= process_srv(s);
157 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
158 } while (fsm_resync);
159
160 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
161 struct timeval min1, min2;
Willy Tarreau0f9f5052006-07-29 17:39:25 +0200162 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
163 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200164
Willy Tarreaud7971282006-07-29 18:36:34 +0200165 tv_min(&min1, &s->req->rex, &s->req->wex);
166 tv_min(&min2, &s->rep->rex, &s->rep->wex);
167 tv_min(&min1, &min1, &s->req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200168 tv_min(&t->expire, &min1, &min2);
169
170 /* restore t to its place in the task list */
171 task_queue(t);
172
173#ifdef DEBUG_FULL
174 /* DEBUG code : this should never ever happen, otherwise it indicates
175 * that a task still has something to do and will provoke a quick loop.
176 */
177 if (tv_remain2(&now, &t->expire) <= 0)
178 exit(100);
179#endif
180
181 return tv_remain2(&now, &t->expire); /* nothing more to do */
182 }
183
Willy Tarreau73de9892006-11-30 11:40:23 +0100184 s->fe->nbconn--;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200185 actconn--;
186
187 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
188 int len;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100189 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
190 s->uniq_id, s->be->id,
191 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200192 write(1, trash, len);
193 }
194
195 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
196 if (s->rep != NULL)
197 s->logs.bytes = s->rep->total;
198
199 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200200 if (s->logs.logwait &&
201 !(s->flags & SN_MONITOR) &&
Willy Tarreau73de9892006-11-30 11:40:23 +0100202 (!(s->fe->options & PR_O_NULLNOLOG) || s->req->total))
Willy Tarreaubaaee002006-06-26 02:48:02 +0200203 sess_log(s);
204
205 /* the task MUST not be in the run queue anymore */
206 task_delete(t);
207 session_free(s);
208 task_free(t);
209 return TIME_ETERNITY; /* rest in peace for eternity */
210}
211
212
213/*
214 * FIXME: This should move to the HTTP_flow_analyzer code
215 */
216
217/*
218 * manages the client FSM and its socket. BTW, it also tries to handle the
219 * cookie. It returns 1 if a state has changed (and a resync may be needed),
220 * 0 else.
221 */
222int process_cli(struct session *t)
223{
224 int s = t->srv_state;
225 int c = t->cli_state;
226 struct buffer *req = t->req;
227 struct buffer *rep = t->rep;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100228 int delete_header = 0;
229
230 int cur_hdr, cur_idx;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200231
Willy Tarreau45e73e32006-12-17 00:05:15 +0100232 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 +0200233 cli_stnames[c], srv_stnames[s],
Willy Tarreau2a429502006-10-15 14:52:29 +0200234 MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
Willy Tarreaud7971282006-07-29 18:36:34 +0200235 req->rex.tv_sec, req->rex.tv_usec,
236 rep->wex.tv_sec, rep->wex.tv_usec);
Willy Tarreau45e73e32006-12-17 00:05:15 +0100237
Willy Tarreaubaaee002006-06-26 02:48:02 +0200238 if (c == CL_STHEADERS) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100239 /*
240 * Now parse the partial (or complete) lines.
241 * We will check the request syntax, and also join multi-line
242 * headers. An index of all the lines will be elaborated while
243 * parsing.
244 *
245 * For the parsing, we use a 10 states FSM.
246 *
247 * RFC2616 requires that both LF and CRLF are recognized as
248 * line breaks, but that any other combination is an error.
249 * To avoid duplicating all the states above to check for CR,
250 * we use a special bit HTTP_PA_LF_EXP that we 'OR' with the
251 * state we will switch to if the LF is seen, so that we know
252 * whether there's a pending CR or not. We can check it
253 * globally since all CR followed by anything but LF are
254 * errors. Each state is entered with the first character is
255 * has to process at req->lr. We also have HTTP_PA_CR_SKIP
256 * indicating that a CR has been seen on current line and
257 * skipped.
258 *
259 * Here is the information we currently have :
Willy Tarreau45e73e32006-12-17 00:05:15 +0100260 * req->data + req->sor = beginning of request
261 * req->data + req->eoh = end of (parsed) headers
Willy Tarreau58f10d72006-12-04 02:26:12 +0100262 * req->lr = first non-visited byte
263 * req->r = end of data
264 */
265
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100266 char *sol, *eol; /* Start Of Line, End Of Line */
Willy Tarreau06619262006-12-17 08:37:22 +0100267 struct proxy *rule_set;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100268
Willy Tarreau45e73e32006-12-17 00:05:15 +0100269 eol = sol = req->data + t->hreq.eoh;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100270
Willy Tarreau58f10d72006-12-04 02:26:12 +0100271 while (req->lr < req->r) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100272 int parse;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200273
Willy Tarreau45e73e32006-12-17 00:05:15 +0100274 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",
275 t->hreq.hdr_state, t->hreq.hdr_idx.used, t->hreq.hdr_idx.tail, t->hreq.hdr_idx.last,
276 sol - req->data, req->lr - req->data, req->r - req->data, t->hreq.eoh);
277
278 if (t->hreq.hdr_state & HTTP_PA_LF_EXP) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100279 if (*req->lr != '\n') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100280 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100281 break;
282 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100283 t->hreq.hdr_state &= ~HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100284 }
285
Willy Tarreau45e73e32006-12-17 00:05:15 +0100286 parse = t->hreq.hdr_state & ~HTTP_PA_CR_SKIP;;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100287
288 if (parse == HTTP_PA_EMPTY) {
289 /* leading empty lines */
290
291 if (*req->lr == '\n') {
292 req->lr ++;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100293 t->hreq.hdr_state = HTTP_PA_EMPTY;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100294 continue;
295 }
296 else if (*req->lr == '\r') {
297 req->lr ++;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100298 t->hreq.hdr_state = HTTP_PA_EMPTY | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100299 continue;
300 }
301
Willy Tarreau45e73e32006-12-17 00:05:15 +0100302 FSM_PRINTF(stderr, "PA_EMPTY[0]: h=%d, lr=%d, r=%d\n",
303 sol - req->data, req->lr - req->data, req->r - req->data);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100304#if PARSE_PRESERVE_EMPTY_LINES
305 /* only skip empty leading lines, don't remove them */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100306 t->hreq.hdr_idx.v[0].len = req->lr - sol;
307 t->hreq.sor = t->hreq.hdr_idx.v[0].len;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100308#else
309 /* remove empty leading lines, as recommended by
310 * RFC2616. This takes a lot of time because we
311 * must move all the buffer backwards, but this
312 * is rarely needed. The method above will be
313 * cleaner when we'll be able to start sending
314 * the request from any place in the buffer.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200315 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100316 buffer_replace2(req, sol, req->lr, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100317#endif
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100318 sol = req->lr;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100319 FSM_PRINTF(stderr, "PA_EMPTY[1]: h=%d, lr=%d, r=%d\n",
320 sol - req->data, req->lr - req->data, req->r - req->data);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100321
Willy Tarreau45e73e32006-12-17 00:05:15 +0100322 t->hreq.hdr_state = HTTP_PA_START;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100323#ifndef DEBUG_PARSE_NO_SPEEDUP
324 /* we know that we still have one char available */
325 goto parse_start;
326#else
327 continue;
328#endif
329
330 } else if (parse == HTTP_PA_START) {
331 parse_start:
332 /* Start line */
333 while (req->lr < req->r && !IS_CTL(*req->lr))
334 req->lr++;
335 if (req->lr == req->r)
336 break;
337 /* we have a CTL char */
338 if (*req->lr == '\r') {
339 req->lr++;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100340 t->hreq.hdr_state = HTTP_PA_STRT_LF | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100341 continue;
342 }
343 else if (*req->lr == '\n') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100344 t->hreq.hdr_state = HTTP_PA_STRT_LF;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100345#ifndef DEBUG_PARSE_NO_SPEEDUP
346 /* we know that we still have one char available */
347 goto parse_strt_lf;
348#else
349 continue;
350#endif
351 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100352 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100353 break;
354
355 } else if (parse == HTTP_PA_STRT_LF) {
356 parse_strt_lf:
357 /* The LF validating the request line */
358
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100359 eol = req->lr;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100360 if (t->hreq.hdr_state & HTTP_PA_CR_SKIP)
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100361 eol--; /* Get back to the CR */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100362
363 /* We have the complete start line between
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100364 * sol and eol (excluded). lr points to
Willy Tarreau58f10d72006-12-04 02:26:12 +0100365 * the LF.
366 */
367
368 /* FIXME: insert a REQUESTURI hook here. */
369
370
371 /* 1: we might have to print this header */
372 if ((global.mode & MODE_DEBUG) &&
373 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100374 debug_hdr("clireq", t, sol, eol);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100375
Willy Tarreau58f10d72006-12-04 02:26:12 +0100376 /* 2: maybe we have to copy the original REQURI for the logs ? */
377 if (t->logs.logwait & LW_REQ) {
378 /* we have a complete HTTP request that we must log */
379 if ((t->logs.uri = pool_alloc(requri)) != NULL) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100380 int urilen = eol - sol;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100381
382 if (urilen >= REQURI_LEN)
383 urilen = REQURI_LEN - 1;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100384 memcpy(t->logs.uri, sol, urilen);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100385 t->logs.uri[urilen] = 0;
386
387 if (!(t->logs.logwait &= ~LW_REQ))
388 sess_log(t);
389 } else {
390 Alert("HTTP logging : out of memory.\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +0200391 }
Willy Tarreau58f10d72006-12-04 02:26:12 +0100392 }
393
394 /* 3: reference this line as the start line */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100395 if (hdr_idx_add(eol - sol, req->lr - eol,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100396 &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0) {
397 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100398 break;
399 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200400
Willy Tarreau58f10d72006-12-04 02:26:12 +0100401 req->lr++;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100402 sol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100403 /* in fact, a state is missing here, we should
404 * be able to distinguish between an empty line
405 * and a header.
406 */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100407 t->hreq.hdr_state = HTTP_PA_HEADER;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100408 continue;
409
410 } else if (parse == HTTP_PA_HEADER) {
411 parse_inside_hdr:
412 /* Inside a non-empty header */
413
414 delete_header = 0;
415 while (req->lr < req->r && !IS_CTL(*req->lr))
416 req->lr++;
417 if (req->lr == req->r)
418 break;
419
420 /* we have a CTL char */
421 if (*req->lr == '\r') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100422 t->hreq.hdr_state = HTTP_PA_HDR_LF | HTTP_PA_CR_SKIP | HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100423 req->lr++;
424 continue;
425 }
426 else if (*req->lr == '\n') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100427 t->hreq.hdr_state = HTTP_PA_HDR_LF;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100428#ifndef DEBUG_PARSE_NO_SPEEDUP
429 goto parse_hdr_lf;
430#else
431 continue;
432#endif
433 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100434 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100435 break;
436
437 } else if (parse == HTTP_PA_HDR_LF) {
438 parse_hdr_lf:
439 /* The LF validating last header, but it
440 * may also be an LWS, in which case we will
441 * need more data to know if we can close this
442 * header or not. However, we must check right
443 * now if this LF/CRLF closes an empty line, in
444 * which case it means the end of the request.
445 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100446 eol = req->lr;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100447 if (t->hreq.hdr_state & HTTP_PA_CR_SKIP)
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100448 eol--; /* Get back to the CR */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100449
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100450 if (eol == sol) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100451 /* We have found the end of the headers.
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100452 * sol points to the ending LF/CRLF,
Willy Tarreau58f10d72006-12-04 02:26:12 +0100453 * and req->lr points to the first byte
454 * after the LF, so it is easy to append
455 * anything there.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200456 */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100457 t->hreq.hdr_state = HTTP_PA_LFLF;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100458#ifndef DEBUG_PARSE_NO_SPEEDUP
459 goto parse_lflf;
460#else
461 continue;
462#endif
463 //req->lr++;
464 //break;
465 }
466
467 if (req->lr + 1 >= req->r) /* LF, ?? */
468 break;
469 req->lr++;
470
471 /* Right now, we *know* that there is one char
472 * available at req->lr.
473 */
474
475 if (*req->lr == ' ' || *req->lr == '\t') {
476 /* We have an LWS, we will replace the
477 * CR and LF with spaces as RFC2616
478 * allows it. <lr> now points to the
479 * first space char of the LWS part.
480 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100481 for (;eol < req->lr; eol++)
482 *eol = ' ';
Willy Tarreau58f10d72006-12-04 02:26:12 +0100483
Willy Tarreau45e73e32006-12-17 00:05:15 +0100484 t->hreq.hdr_state = HTTP_PA_HDR_LWS;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100485#ifndef DEBUG_PARSE_NO_SPEEDUP
486 goto parse_hdr_lws;
487#else
Willy Tarreaubaaee002006-06-26 02:48:02 +0200488 continue;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100489#endif
490 }
491
492 /**********************************************
493 * We now have one complete header between *
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100494 * sol and eol, with a possible CR at eol, *
Willy Tarreau58f10d72006-12-04 02:26:12 +0100495 * everything ending before req->lr. Some very*
496 * early processing can be applied. *
497 **********************************************/
498
499 /*
500 * FIXME: insert a REQHEADER hook here.
501 * For instance, we could check the header's
502 * syntax such as forbidding the leading space
503 * in the first header (Apache also has the same problem)
504 */
505
506
507 /* 1: we might have to print this header */
508 if ((global.mode & MODE_DEBUG) &&
509 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100510 debug_hdr("clihdr", t, sol, eol);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100511
512
513 /* 2: maybe we have to copy this header for the logs ? */
514 if (t->logs.logwait & LW_REQHDR) {
515 /* FIXME: we must *search* the value after the ':' and not
516 * consider that it's necessary after one single space.*/
517 struct cap_hdr *h;
518 int len;
519 for (h = t->fi->req_cap; h; h = h->next) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100520 if ((h->namelen + 2 <= eol - sol) &&
521 (sol[h->namelen] == ':') &&
522 (strncasecmp(sol, h->name, h->namelen) == 0)) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100523 if (t->hreq.cap[h->index] == NULL)
524 t->hreq.cap[h->index] =
525 pool_alloc_from(h->pool, h->len + 1);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100526
Willy Tarreau45e73e32006-12-17 00:05:15 +0100527 if (t->hreq.cap[h->index] == NULL) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100528 Alert("HTTP capture : out of memory.\n");
529 continue;
530 }
531
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100532 len = eol - (sol + h->namelen + 2);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100533 if (len > h->len)
534 len = h->len;
535
Willy Tarreau45e73e32006-12-17 00:05:15 +0100536 memcpy(t->hreq.cap[h->index], sol + h->namelen + 2, len);
537 t->hreq.cap[h->index][len]=0;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100538 }
539 }
540 }
541
542
543 /* 3: We might need to remove "connection:" */
544 if (!delete_header && (t->fe->options & PR_O_HTTP_CLOSE)
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100545 && (strncasecmp(sol, "Connection:", 11) == 0)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100546 delete_header = 1;
547 }
548
549
Willy Tarreau58f10d72006-12-04 02:26:12 +0100550 /* OK, that's enough processing for the first step.
551 * Now either we index this header or we remove it.
552 */
553
554 if (!delete_header) {
555 /* we insert it into the index */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100556 if (hdr_idx_add(eol - sol, req->lr - eol - 1,
Willy Tarreau45e73e32006-12-17 00:05:15 +0100557 &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0) {
558 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100559 break;
560 }
561 } else {
562 /* we remove it */
563 delete_header = 0;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100564 buffer_replace2(req, sol, req->lr, NULL, 0);
565 /* WARNING: eol is not valid anymore, since the
Willy Tarreau58f10d72006-12-04 02:26:12 +0100566 * header may have been deleted or truncated ! */
567 }
568
569 /* In any case, we set the next header pointer
570 * to the next line.
571 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100572 sol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100573
574#ifndef DEBUG_PARSE_NO_SPEEDUP
575 /*
576 * We know that at least one character remains.
577 * It is interesting to directly branch to the
578 * matching state.
579 */
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100580 eol = req->lr;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100581 if (IS_CTL(*req->lr)) {
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100582 if (*eol == '\r') {
Willy Tarreau58f10d72006-12-04 02:26:12 +0100583 req->lr++;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100584 t->hreq.hdr_state = HTTP_PA_LFLF | HTTP_PA_LF_EXP;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100585 continue;
586 }
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100587 else if (*eol == '\n') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100588 t->hreq.hdr_state = HTTP_PA_LFLF;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100589 goto parse_lflf;
590 }
591 else {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100592 t->hreq.hdr_state = HTTP_PA_ERROR;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100593 break;
594 }
595 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100596 t->hreq.hdr_state = HTTP_PA_HEADER;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100597 goto parse_inside_hdr;
598#else
Willy Tarreau45e73e32006-12-17 00:05:15 +0100599 t->hreq.hdr_state = HTTP_PA_HEADER;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100600 continue;
601#endif
602
603 } else if (parse == HTTP_PA_HDR_LWS) {
604 parse_hdr_lws:
605 /* Inside an LWS. We just replace tabs with
606 * spaces and fall back to the HEADER state
607 * at the first non-space character
608 */
609
610 while (req->lr < req->r) {
611 if (*req->lr == '\t')
612 *req->lr = ' ';
613 else if (*req->lr != ' ') {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100614 t->hreq.hdr_state = HTTP_PA_HEADER;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100615#ifndef DEBUG_PARSE_NO_SPEEDUP
616 goto parse_inside_hdr;
617#else
618 break;
619#endif
620 }
621 req->lr++;
622 }
623 continue;
624
625 } else if (parse == HTTP_PA_LFLF) {
626 parse_lflf:
627 req->lr ++;
Willy Tarreaua4cd1f52006-12-16 19:57:26 +0100628 /* sol points to either CR or CRLF, and
Willy Tarreau58f10d72006-12-04 02:26:12 +0100629 * req->lr points to 1 char after LF.
630 */
631
632 /*
633 * FIXME: insert a hook here for the end of the headers
634 */
635 break;
636 } else if (parse == HTTP_PA_ERROR) {
637 break;
638 }
639
640 } /* end of the "while(req->lr < req->r)" loop */
641
Willy Tarreau45e73e32006-12-17 00:05:15 +0100642 /* update the end of headers */
643 t->hreq.eoh = sol - req->data;
644
645 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",
646 t->hreq.hdr_state, t->hreq.hdr_idx.used, t->hreq.hdr_idx.tail, t->hreq.hdr_idx.last,
647 sol - req->data, req->lr - req->data, req->r - req->data, t->hreq.eoh);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100648
649 /*
650 * Now, let's catch bad requests.
651 */
652
Willy Tarreau06619262006-12-17 08:37:22 +0100653 if (t->hreq.hdr_state == HTTP_PA_ERROR)
654 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100655
656 /*
657 * Now we quickly check if we have found a full request.
658 * If not so, we check the FD and buffer states before leaving.
659 * A full request is indicated by the fact that we have seen
660 * the double LF/CRLF, so the state is HTTP_PA_LFLF.
661 *
662 */
663
Willy Tarreau45e73e32006-12-17 00:05:15 +0100664 if (t->hreq.hdr_state != HTTP_PA_LFLF) { /* Request not complete yet */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100665
666 /* 1: Since we are in header mode, if there's no space
667 * left for headers, we won't be able to free more
668 * later, so the session will never terminate. We
669 * must terminate it now.
670 */
671 if (req->l >= req->rlim - req->data) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100672 /* FIXME: check if hreq.hdr_state & mask < HTTP_PA_HEADER,
Willy Tarreau58f10d72006-12-04 02:26:12 +0100673 * and return Status 414 Request URI too long instead.
674 */
Willy Tarreau06619262006-12-17 08:37:22 +0100675 goto return_bad_req;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100676 }
677
678 /* 2: have we encountered a read error or a close ? */
679 else if (req->flags & (BF_READ_ERROR | BF_READ_NULL)) {
680 /* read error, or last read : give up. */
681 tv_eternity(&req->rex);
682 fd_delete(t->cli_fd);
683 t->cli_state = CL_STCLOSE;
684 if (!(t->flags & SN_ERR_MASK))
685 t->flags |= SN_ERR_CLICL;
686 if (!(t->flags & SN_FINST_MASK))
687 t->flags |= SN_FINST_R;
688 return 1;
689 }
690
691 /* 3: has the read timeout expired ? */
692 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
693 /* read timeout : give up with an error message. */
694 t->logs.status = 408;
695 client_retnclose(t, t->fe->errmsg.len408, t->fe->errmsg.msg408);
696 if (!(t->flags & SN_ERR_MASK))
697 t->flags |= SN_ERR_CLITO;
698 if (!(t->flags & SN_FINST_MASK))
699 t->flags |= SN_FINST_R;
700 return 1;
701 }
702
703 /* 4: do we need to re-enable the read socket ? */
704 else if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
705 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
706 * full. We cannot loop here since stream_sock_read will disable it only if
707 * req->l == rlim-data
708 */
709 MY_FD_SET(t->cli_fd, StaticReadEvent);
710 if (t->fe->clitimeout)
711 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
712 else
713 tv_eternity(&req->rex);
714 }
715 return t->cli_state != CL_STHEADERS;
716 }
717
718
719 /****************************************************************
720 * More interesting part now : we know that we have a complete *
721 * request which at least looks like HTTP. We have an indicator *
722 * of each header's length, so we can parse them quickly. *
723 ****************************************************************/
724
725
726 /*
Willy Tarreau06619262006-12-17 08:37:22 +0100727 * 1: check if the URI matches the monitor_uri.
728 * We have to do this for every request which gets in, because
729 * the monitor-uri is defined by the frontend. To speed-up the
730 * test, we include the leading and trailing spaces in the
731 * comparison. This is generally not a problem because the
732 * monitor-uri is primarily used by external checkers which
733 * send pre-formatted requests too.
Willy Tarreau58f10d72006-12-04 02:26:12 +0100734 */
735
Willy Tarreau06619262006-12-17 08:37:22 +0100736 t->hreq.start.str = req->data + t->hreq.sor; /* start of the REQURI */
737 t->hreq.start.len = t->hreq.hdr_idx.v[t->hreq.hdr_idx.v[0].next].len; /* end of the REQURI */
738
739 if ((t->fe->monitor_uri_len != 0) &&
740 (t->hreq.start.len >= t->fe->monitor_uri_len)) {
741 char *p = t->hreq.start.str;
742 int idx = 0;
743
744 /* skip the method so that we accept any method */
745 while (idx < t->hreq.start.len && p[idx] != ' ')
746 idx++;
747 p += idx;
748
749 if (t->hreq.start.len - idx >= t->fe->monitor_uri_len &&
750 !memcmp(p, t->fe->monitor_uri, t->fe->monitor_uri_len)) {
751 /*
752 * We have found the monitor URI
753 */
754 t->flags |= SN_MONITOR;
755 t->logs.status = 200;
756 client_retnclose(t, strlen(HTTP_200), HTTP_200);
757 goto return_prx_cond;
758 }
Willy Tarreau58f10d72006-12-04 02:26:12 +0100759 }
760
761
762 /*
763 * 2: we will have to evaluate the filters.
764 * As opposed to version 1.2, now they will be evaluated in the
765 * filters order and not in the header order. This means that
766 * each filter has to be validated among all headers.
Willy Tarreau06619262006-12-17 08:37:22 +0100767 *
768 * We can now check whether we want to switch to another
769 * backend, in which case we will re-check the backend's
770 * filters and various options. In order to support 3-level
771 * switching, here's how we should proceed :
772 *
773 * a) run fe->filters.
774 * if (switch) then switch ->fi and ->be to the new backend.
775 * b) run fi->filters.
776 * If there's another switch, then switch ->be to the new be.
777 * c) run be->filters
778 * There cannot be any switch from there, so ->be cannot be
779 * changed anymore.
780 *
781 * The response path will be able to apply either ->be, or
782 * ->be then ->fi, or ->be then ->fi then ->fe filters in order
783 * to match the reverse of the forward sequence.
Willy Tarreau58f10d72006-12-04 02:26:12 +0100784 */
785
Willy Tarreau06619262006-12-17 08:37:22 +0100786 do {
787 if (t->fi == t->fe)
788 rule_set = t->fe;
789 else if (t->be == t->fi)
790 rule_set = t->fi;
791 else
792 rule_set = t->be;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100793
Willy Tarreau06619262006-12-17 08:37:22 +0100794 /* try headers filters */
795 if (rule_set->req_exp != NULL)
796 apply_filters_to_session(t, req, rule_set->req_exp);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100797
Willy Tarreau06619262006-12-17 08:37:22 +0100798 /* has the request been denied ? */
799 if (t->flags & SN_CLDENY) {
800 /* no need to go further */
801 t->logs.status = 403;
802 /* let's log the request time */
803 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
804 client_retnclose(t, t->fe->errmsg.len403, t->fe->errmsg.msg403);
805 goto return_prx_cond;
806 }
807
808 /* add request headers from the rule sets in the same order */
809 for (cur_hdr = 0; cur_hdr < rule_set->nb_reqadd; cur_hdr++) {
810 int len;
811
812 len = sprintf(trash, "%s\r\n", rule_set->req_add[cur_hdr]);
813 len = buffer_replace2(req, req->data + t->hreq.eoh,
814 req->data + t->hreq.eoh, trash, len);
815 t->hreq.eoh += len;
816
817 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
818 goto return_bad_req;
819 }
820 } while (rule_set != t->be); /* we loop only if t->be has changed */
Willy Tarreau2a324282006-12-05 00:05:46 +0100821
Willy Tarreau58f10d72006-12-04 02:26:12 +0100822
Willy Tarreau2a324282006-12-05 00:05:46 +0100823 /* Right now, we know that we have processed the entire headers
824 * and that unwanted requests have been filtered out. We can do
825 * whatever we want with the remaining request.
826 */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100827
Willy Tarreau58f10d72006-12-04 02:26:12 +0100828
Willy Tarreau2a324282006-12-05 00:05:46 +0100829 /*
830 * 3: save a pointer to the first line as the request, and
831 * check the method (needed for cookies).
832 */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100833
Willy Tarreau06619262006-12-17 08:37:22 +0100834 t->hreq.start.str = req->data + t->hreq.sor; /* start of the REQURI */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100835 t->hreq.start.len = t->hreq.hdr_idx.v[t->hreq.hdr_idx.v[0].next].len; /* end of the REQURI */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100836
Willy Tarreau06619262006-12-17 08:37:22 +0100837 if ((t->hreq.start.len >= 5) &&
838 (t->hreq.start.str[4] == ' ' || t->hreq.start.str[4] == '\t') &&
839 (!memcmp(t->hreq.start.str, "POST", 4))) {
Willy Tarreau2a324282006-12-05 00:05:46 +0100840 /* this is a POST request, which is not cacheable by default */
841 t->flags |= SN_POST;
842 }
843
Willy Tarreau58f10d72006-12-04 02:26:12 +0100844
Willy Tarreau2a324282006-12-05 00:05:46 +0100845 /*
Willy Tarreau06619262006-12-17 08:37:22 +0100846 * 4: the appsession cookie was looked up very early in 1.2,
847 * so let's do the same now.
848 */
849
850 /* It needs to look into the URI */
851 if (t->be->appsession_name) {
852 get_srv_from_appsession(t,
853 t->hreq.start.str,
854 t->hreq.start.str + t->hreq.start.len);
855 }
856
857
858 /*
859 * 5: Now we can work with the cookies.
Willy Tarreau2a324282006-12-05 00:05:46 +0100860 * Note that doing so might move headers in the request, but
861 * the fields will stay coherent and the URI will not move.
Willy Tarreau06619262006-12-17 08:37:22 +0100862 * This should only be performed in the backend.
Willy Tarreau2a324282006-12-05 00:05:46 +0100863 */
864 if (!(t->flags & (SN_CLDENY|SN_CLTARPIT)))
865 manage_client_side_cookies(t, req);
Willy Tarreau58f10d72006-12-04 02:26:12 +0100866
Willy Tarreau58f10d72006-12-04 02:26:12 +0100867
Willy Tarreau2a324282006-12-05 00:05:46 +0100868 /*
869 * FIXME:
870 * we could run the whole list of headers right here to extract
Willy Tarreau06619262006-12-17 08:37:22 +0100871 * commonly used headers.
Willy Tarreau2a324282006-12-05 00:05:46 +0100872 */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100873
Willy Tarreau2a324282006-12-05 00:05:46 +0100874 /*
875 * 6: check if the user tries to access a protected URI.
876 */
Willy Tarreau06619262006-12-17 08:37:22 +0100877 if (t->be->uri_auth != NULL
878 && t->hreq.start.len >= t->be->uri_auth->uri_len + 4) { /* +4 for "GET /" */
Willy Tarreau45e73e32006-12-17 00:05:15 +0100879 if (!memcmp(t->hreq.start.str + 4,
Willy Tarreau06619262006-12-17 08:37:22 +0100880 t->be->uri_auth->uri_prefix, t->be->uri_auth->uri_len)
Willy Tarreau45e73e32006-12-17 00:05:15 +0100881 && !memcmp(t->hreq.start.str, "GET ", 4)) {
Willy Tarreau2a324282006-12-05 00:05:46 +0100882 struct user_auth *user;
883 int authenticated;
884 char *h;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100885
Willy Tarreau2a324282006-12-05 00:05:46 +0100886 /* we are in front of a interceptable URI. Let's check
887 * if there's an authentication and if it's valid.
888 */
Willy Tarreau06619262006-12-17 08:37:22 +0100889 user = t->be->uri_auth->users;
Willy Tarreau2a324282006-12-05 00:05:46 +0100890 if (!user) {
891 /* no user auth required, it's OK */
892 authenticated = 1;
893 } else {
894 authenticated = 0;
Willy Tarreau58f10d72006-12-04 02:26:12 +0100895
Willy Tarreau2a324282006-12-05 00:05:46 +0100896 /* a user list is defined, we have to check.
897 * skip 21 chars for "Authorization: Basic ".
898 */
Willy Tarreau58f10d72006-12-04 02:26:12 +0100899
Willy Tarreau2a324282006-12-05 00:05:46 +0100900 /* FIXME: this should move to an earlier place */
901 cur_idx = 0;
Willy Tarreau45e73e32006-12-17 00:05:15 +0100902 h = req->data + t->hreq.sor;
903 while ((cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
904 int len = t->hreq.hdr_idx.v[cur_idx].len;
Willy Tarreau2a324282006-12-05 00:05:46 +0100905 if (len > 14 &&
906 !strncasecmp("Authorization:", h, 14)) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100907 t->hreq.auth_hdr.str = h;
908 t->hreq.auth_hdr.len = len;
Willy Tarreau2a324282006-12-05 00:05:46 +0100909 break;
910 }
Willy Tarreau45e73e32006-12-17 00:05:15 +0100911 h += len + t->hreq.hdr_idx.v[cur_idx].cr + 1;
Willy Tarreau2a324282006-12-05 00:05:46 +0100912 }
Willy Tarreau58f10d72006-12-04 02:26:12 +0100913
914
Willy Tarreau45e73e32006-12-17 00:05:15 +0100915 if (t->hreq.auth_hdr.len < 21 ||
916 memcmp(t->hreq.auth_hdr.str + 14, " Basic ", 7))
Willy Tarreau2a324282006-12-05 00:05:46 +0100917 user = NULL;
918
919 while (user) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100920 if ((t->hreq.auth_hdr.len == user->user_len + 14 + 7)
921 && !memcmp(t->hreq.auth_hdr.str + 14 + 7,
922 user->user_pwd, user->user_len)) {
Willy Tarreau2a324282006-12-05 00:05:46 +0100923 authenticated = 1;
924 break;
925 }
926 user = user->next;
927 }
928 }
Willy Tarreau58f10d72006-12-04 02:26:12 +0100929
Willy Tarreau2a324282006-12-05 00:05:46 +0100930 if (!authenticated) {
931 int msglen;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200932
Willy Tarreaubaaee002006-06-26 02:48:02 +0200933 /* no need to go further */
Willy Tarreau2a324282006-12-05 00:05:46 +0100934
Willy Tarreau06619262006-12-17 08:37:22 +0100935 msglen = sprintf(trash, HTTP_401_fmt, t->be->uri_auth->auth_realm);
Willy Tarreau2a324282006-12-05 00:05:46 +0100936 t->logs.status = 401;
937 client_retnclose(t, msglen, trash);
Willy Tarreau06619262006-12-17 08:37:22 +0100938 goto return_prx_cond;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200939 }
940
Willy Tarreau2a324282006-12-05 00:05:46 +0100941 t->cli_state = CL_STSHUTR;
942 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
943 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
944 t->data_source = DATA_SRC_STATS;
945 t->data_state = DATA_ST_INIT;
946 produce_content(t);
947 return 1;
948 }
949 }
Willy Tarreau1c47f852006-07-09 08:22:27 +0200950
Willy Tarreaubaaee002006-06-26 02:48:02 +0200951
Willy Tarreau2a324282006-12-05 00:05:46 +0100952 /*
Willy Tarreau06619262006-12-17 08:37:22 +0100953 * 7: add X-Forwarded-For : Should depend on the backend only.
Willy Tarreau2a324282006-12-05 00:05:46 +0100954 */
955 if (t->be->options & PR_O_FWDFOR) {
956 if (t->cli_addr.ss_family == AF_INET) {
957 int len;
958 unsigned char *pn;
959 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
960 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
961 pn[0], pn[1], pn[2], pn[3]);
Willy Tarreau45e73e32006-12-17 00:05:15 +0100962 len = buffer_replace2(req, req->data + t->hreq.eoh,
963 req->data + t->hreq.eoh, trash, len);
964 t->hreq.eoh += len;
965
Willy Tarreau06619262006-12-17 08:37:22 +0100966 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
967 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +0100968 }
969 else if (t->cli_addr.ss_family == AF_INET6) {
970 int len;
971 char pn[INET6_ADDRSTRLEN];
972 inet_ntop(AF_INET6,
973 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
974 pn, sizeof(pn));
975 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
Willy Tarreau45e73e32006-12-17 00:05:15 +0100976 len = buffer_replace2(req, req->data + t->hreq.eoh,
977 req->data + t->hreq.eoh, trash, len);
978 t->hreq.eoh += len;
979
Willy Tarreau06619262006-12-17 08:37:22 +0100980 if (hdr_idx_add(len - 2, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
981 goto return_bad_req;
Willy Tarreau2a324282006-12-05 00:05:46 +0100982 }
983 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200984
Willy Tarreaubaaee002006-06-26 02:48:02 +0200985
Willy Tarreau2a324282006-12-05 00:05:46 +0100986 /*
Willy Tarreau06619262006-12-17 08:37:22 +0100987 * 8: add "Connection:"
Willy Tarreau2a324282006-12-05 00:05:46 +0100988 */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200989
Willy Tarreau2a324282006-12-05 00:05:46 +0100990 /* add a "connection: close" line if needed */
Willy Tarreaue15d9132006-12-14 22:26:42 +0100991 if (t->fe->options & PR_O_HTTP_CLOSE) {
Willy Tarreau45e73e32006-12-17 00:05:15 +0100992 int len;
993 len = buffer_replace2(req, req->data + t->hreq.eoh,
994 req->data + t->hreq.eoh, "Connection: close\r\n", 19);
995 t->hreq.eoh += len;
996
Willy Tarreau06619262006-12-17 08:37:22 +0100997 if (hdr_idx_add(17, 1, &t->hreq.hdr_idx, t->hreq.hdr_idx.tail) < 0)
998 goto return_bad_req;
Willy Tarreaue15d9132006-12-14 22:26:42 +0100999 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001000
Willy Tarreaubaaee002006-06-26 02:48:02 +02001001
Willy Tarreaue15d9132006-12-14 22:26:42 +01001002
1003
Willy Tarreau06619262006-12-17 08:37:22 +01001004
Willy Tarreaue15d9132006-12-14 22:26:42 +01001005
Willy Tarreau2a324282006-12-05 00:05:46 +01001006 /*************************************************************
1007 * OK, that's finished for the headers. We have done what we *
1008 * could. Let's switch to the DATA state. *
1009 ************************************************************/
Willy Tarreaubaaee002006-06-26 02:48:02 +02001010
Willy Tarreau2a324282006-12-05 00:05:46 +01001011 t->cli_state = CL_STDATA;
1012 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001013
Willy Tarreau2a324282006-12-05 00:05:46 +01001014 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001015
Willy Tarreaubaaee002006-06-26 02:48:02 +02001016
Willy Tarreau2a324282006-12-05 00:05:46 +01001017 if (!t->fe->clitimeout ||
1018 (t->srv_state < SV_STDATA && t->be->srvtimeout)) {
1019 /* If the client has no timeout, or if the server is not ready yet,
1020 * and we know for sure that it can expire, then it's cleaner to
1021 * disable the timeout on the client side so that too low values
1022 * cannot make the sessions abort too early.
1023 *
1024 * FIXME-20050705: the server needs a way to re-enable this time-out
1025 * when it switches its state, otherwise a client can stay connected
1026 * indefinitely. This now seems to be OK.
1027 */
1028 tv_eternity(&req->rex);
1029 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001030
Willy Tarreaub8750a82006-09-03 09:56:00 +02001031
Willy Tarreau2a324282006-12-05 00:05:46 +01001032 /* When a connection is tarpitted, we use the queue timeout for the
1033 * tarpit delay, which currently happens to be the server's connect
1034 * timeout. If unset, then set it to zero because we really want it
1035 * to expire at one moment.
1036 */
1037 if (t->flags & SN_CLTARPIT) {
1038 t->req->l = 0;
1039 /* flush the request so that we can drop the connection early
1040 * if the client closes first.
1041 */
1042 tv_delayfrom(&req->cex, &now,
1043 t->be->contimeout ? t->be->contimeout : 0);
1044 }
Willy Tarreaub8750a82006-09-03 09:56:00 +02001045
Willy Tarreau2a324282006-12-05 00:05:46 +01001046#if DEBUG_HTTP_PARSER
1047 /* example: dump each line */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001048
Willy Tarreau2a324282006-12-05 00:05:46 +01001049 fprintf(stderr, "t->flags=0x%08x\n", t->flags & (SN_CLALLOW|SN_CLDENY|SN_CLTARPIT));
Willy Tarreaubaaee002006-06-26 02:48:02 +02001050
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001051 fprintf(stderr, "sol=%d\n", sol - req->data);
Willy Tarreau45e73e32006-12-17 00:05:15 +01001052 sol = req->data + t->hreq.sor;
Willy Tarreau2a324282006-12-05 00:05:46 +01001053 cur_hdr = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001054
Willy Tarreau45e73e32006-12-17 00:05:15 +01001055 cur_idx = t->hreq.hdr_idx.v[0].next;
Willy Tarreau2a324282006-12-05 00:05:46 +01001056 cur_hdr = 1;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001057
Willy Tarreau45e73e32006-12-17 00:05:15 +01001058 while (cur_hdr < t->hreq.hdr_idx.used) {
1059 eol = sol + t->hreq.hdr_idx.v[cur_idx].len + t->hreq.hdr_idx.v[cur_idx].cr + 1;
Willy Tarreau2a324282006-12-05 00:05:46 +01001060 fprintf(stderr, "lr=%d r=%d hdr=%d idx=%d adr=%d..%d len=%d cr=%d data:\n",
1061 req->lr - req->data, req->r - req->data,
1062 cur_hdr, cur_idx,
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001063 sol - req->data,
Willy Tarreau45e73e32006-12-17 00:05:15 +01001064 sol - req->data + t->hreq.hdr_idx.v[cur_idx].len + t->hreq.hdr_idx.v[cur_idx].cr,
1065 t->hreq.hdr_idx.v[cur_idx].len,
1066 t->hreq.hdr_idx.v[cur_idx].cr);
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001067 write(2, sol, eol - sol);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001068
Willy Tarreaua4cd1f52006-12-16 19:57:26 +01001069 sol = eol;
Willy Tarreau45e73e32006-12-17 00:05:15 +01001070 cur_idx = t->hreq.hdr_idx.v[cur_idx].next;
Willy Tarreau2a324282006-12-05 00:05:46 +01001071 cur_hdr++;
1072 }
Willy Tarreau58f10d72006-12-04 02:26:12 +01001073#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +02001074
Willy Tarreau06619262006-12-17 08:37:22 +01001075 goto process_data;
1076
1077 return_bad_req: /* let's centralize all bad requests */
1078 t->hreq.hdr_state = HTTP_PA_ERROR;
1079 t->logs.status = 400;
1080 client_retnclose(t, t->fe->errmsg.len400, t->fe->errmsg.msg400);
1081 return_prx_cond:
1082 if (!(t->flags & SN_ERR_MASK))
1083 t->flags |= SN_ERR_PRXCOND;
1084 if (!(t->flags & SN_FINST_MASK))
1085 t->flags |= SN_FINST_R;
1086 return 1;
1087
Willy Tarreaubaaee002006-06-26 02:48:02 +02001088 }
1089 else if (c == CL_STDATA) {
1090 process_data:
1091 /* FIXME: this error handling is partly buggy because we always report
1092 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
1093 * or HEADER phase. BTW, it's not logical to expire the client while
1094 * we're waiting for the server to connect.
1095 */
1096 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001097 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001098 tv_eternity(&req->rex);
1099 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001100 fd_delete(t->cli_fd);
1101 t->cli_state = CL_STCLOSE;
1102 if (!(t->flags & SN_ERR_MASK))
1103 t->flags |= SN_ERR_CLICL;
1104 if (!(t->flags & SN_FINST_MASK)) {
1105 if (t->pend_pos)
1106 t->flags |= SN_FINST_Q;
1107 else if (s == SV_STCONN)
1108 t->flags |= SN_FINST_C;
1109 else
1110 t->flags |= SN_FINST_D;
1111 }
1112 return 1;
1113 }
1114 /* last read, or end of server write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001115 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001116 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001117 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001118 shutdown(t->cli_fd, SHUT_RD);
1119 t->cli_state = CL_STSHUTR;
1120 return 1;
1121 }
1122 /* last server read and buffer empty */
1123 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001124 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001125 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001126 shutdown(t->cli_fd, SHUT_WR);
1127 /* We must ensure that the read part is still alive when switching
1128 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001129 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001130 if (t->fe->clitimeout)
1131 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001132 t->cli_state = CL_STSHUTW;
1133 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1134 return 1;
1135 }
1136 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001137 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001138 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001139 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001140 shutdown(t->cli_fd, SHUT_RD);
1141 t->cli_state = CL_STSHUTR;
1142 if (!(t->flags & SN_ERR_MASK))
1143 t->flags |= SN_ERR_CLITO;
1144 if (!(t->flags & SN_FINST_MASK)) {
1145 if (t->pend_pos)
1146 t->flags |= SN_FINST_Q;
1147 else if (s == SV_STCONN)
1148 t->flags |= SN_FINST_C;
1149 else
1150 t->flags |= SN_FINST_D;
1151 }
1152 return 1;
1153 }
1154 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02001155 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001156 MY_FD_CLR(t->cli_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001157 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001158 shutdown(t->cli_fd, SHUT_WR);
1159 /* We must ensure that the read part is still alive when switching
1160 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001161 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001162 if (t->fe->clitimeout)
1163 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001164
1165 t->cli_state = CL_STSHUTW;
1166 if (!(t->flags & SN_ERR_MASK))
1167 t->flags |= SN_ERR_CLITO;
1168 if (!(t->flags & SN_FINST_MASK)) {
1169 if (t->pend_pos)
1170 t->flags |= SN_FINST_Q;
1171 else if (s == SV_STCONN)
1172 t->flags |= SN_FINST_C;
1173 else
1174 t->flags |= SN_FINST_D;
1175 }
1176 return 1;
1177 }
1178
1179 if (req->l >= req->rlim - req->data) {
1180 /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02001181 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001182 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001183 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001184 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001185 }
1186 } else {
1187 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001188 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1189 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001190 if (!t->fe->clitimeout ||
1191 (t->srv_state < SV_STDATA && t->be->srvtimeout))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001192 /* If the client has no timeout, or if the server not ready yet, and we
1193 * know for sure that it can expire, then it's cleaner to disable the
1194 * timeout on the client side so that too low values cannot make the
1195 * sessions abort too early.
1196 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001197 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001198 else
Willy Tarreau73de9892006-11-30 11:40:23 +01001199 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001200 }
1201 }
1202
1203 if ((rep->l == 0) ||
1204 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001205 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1206 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001207 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001208 }
1209 } else {
1210 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001211 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1212 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001213 if (t->fe->clitimeout) {
1214 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001215 /* FIXME: to prevent the client from expiring read timeouts during writes,
1216 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001217 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001218 }
1219 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001220 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001221 }
1222 }
1223 return 0; /* other cases change nothing */
1224 }
1225 else if (c == CL_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001226 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001227 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001228 fd_delete(t->cli_fd);
1229 t->cli_state = CL_STCLOSE;
1230 if (!(t->flags & SN_ERR_MASK))
1231 t->flags |= SN_ERR_CLICL;
1232 if (!(t->flags & SN_FINST_MASK)) {
1233 if (t->pend_pos)
1234 t->flags |= SN_FINST_Q;
1235 else if (s == SV_STCONN)
1236 t->flags |= SN_FINST_C;
1237 else
1238 t->flags |= SN_FINST_D;
1239 }
1240 return 1;
1241 }
1242 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
1243 && !(t->flags & SN_SELF_GEN)) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001244 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001245 fd_delete(t->cli_fd);
1246 t->cli_state = CL_STCLOSE;
1247 return 1;
1248 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001249 else if (tv_cmp2_ms(&rep->wex, &now) <= 0) {
1250 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001251 fd_delete(t->cli_fd);
1252 t->cli_state = CL_STCLOSE;
1253 if (!(t->flags & SN_ERR_MASK))
1254 t->flags |= SN_ERR_CLITO;
1255 if (!(t->flags & SN_FINST_MASK)) {
1256 if (t->pend_pos)
1257 t->flags |= SN_FINST_Q;
1258 else if (s == SV_STCONN)
1259 t->flags |= SN_FINST_C;
1260 else
1261 t->flags |= SN_FINST_D;
1262 }
1263 return 1;
1264 }
1265
1266 if (t->flags & SN_SELF_GEN) {
1267 produce_content(t);
1268 if (rep->l == 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001269 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001270 fd_delete(t->cli_fd);
1271 t->cli_state = CL_STCLOSE;
1272 return 1;
1273 }
1274 }
1275
1276 if ((rep->l == 0)
1277 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001278 if (MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1279 MY_FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02001280 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001281 }
1282 } else {
1283 /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02001284 if (! MY_FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1285 MY_FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01001286 if (t->fe->clitimeout) {
1287 tv_delayfrom(&rep->wex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001288 /* FIXME: to prevent the client from expiring read timeouts during writes,
1289 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001290 req->rex = rep->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001291 }
1292 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001293 tv_eternity(&rep->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001294 }
1295 }
1296 return 0;
1297 }
1298 else if (c == CL_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001299 if (req->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001300 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001301 fd_delete(t->cli_fd);
1302 t->cli_state = CL_STCLOSE;
1303 if (!(t->flags & SN_ERR_MASK))
1304 t->flags |= SN_ERR_CLICL;
1305 if (!(t->flags & SN_FINST_MASK)) {
1306 if (t->pend_pos)
1307 t->flags |= SN_FINST_Q;
1308 else if (s == SV_STCONN)
1309 t->flags |= SN_FINST_C;
1310 else
1311 t->flags |= SN_FINST_D;
1312 }
1313 return 1;
1314 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001315 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001316 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001317 fd_delete(t->cli_fd);
1318 t->cli_state = CL_STCLOSE;
1319 return 1;
1320 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001321 else if (tv_cmp2_ms(&req->rex, &now) <= 0) {
1322 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001323 fd_delete(t->cli_fd);
1324 t->cli_state = CL_STCLOSE;
1325 if (!(t->flags & SN_ERR_MASK))
1326 t->flags |= SN_ERR_CLITO;
1327 if (!(t->flags & SN_FINST_MASK)) {
1328 if (t->pend_pos)
1329 t->flags |= SN_FINST_Q;
1330 else if (s == SV_STCONN)
1331 t->flags |= SN_FINST_C;
1332 else
1333 t->flags |= SN_FINST_D;
1334 }
1335 return 1;
1336 }
1337 else if (req->l >= req->rlim - req->data) {
1338 /* no room to read more data */
1339
1340 /* FIXME-20050705: is it possible for a client to maintain a session
1341 * after the timeout by sending more data after it receives a close ?
1342 */
1343
Willy Tarreau2a429502006-10-15 14:52:29 +02001344 if (MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001345 /* stop reading until we get some space */
Willy Tarreau2a429502006-10-15 14:52:29 +02001346 MY_FD_CLR(t->cli_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001347 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001348 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1349 }
1350 } else {
1351 /* there's still some space in the buffer */
Willy Tarreau2a429502006-10-15 14:52:29 +02001352 if (! MY_FD_ISSET(t->cli_fd, StaticReadEvent)) {
1353 MY_FD_SET(t->cli_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001354 if (t->fe->clitimeout)
1355 tv_delayfrom(&req->rex, &now, t->fe->clitimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001356 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001357 tv_eternity(&req->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001358 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1359 }
1360 }
1361 return 0;
1362 }
1363 else { /* CL_STCLOSE: nothing to do */
1364 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1365 int len;
Willy Tarreau73de9892006-11-30 11:40:23 +01001366 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001367 write(1, trash, len);
1368 }
1369 return 0;
1370 }
1371 return 0;
1372}
1373
1374
1375/*
1376 * manages the server FSM and its socket. It returns 1 if a state has changed
1377 * (and a resync may be needed), 0 else.
1378 */
1379int process_srv(struct session *t)
1380{
1381 int s = t->srv_state;
1382 int c = t->cli_state;
1383 struct buffer *req = t->req;
1384 struct buffer *rep = t->rep;
1385 appsess *asession_temp = NULL;
1386 appsess local_asession;
1387 int conn_err;
1388
1389#ifdef DEBUG_FULL
1390 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
1391#endif
1392 //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 +02001393 //MY_FD_ISSET(t->cli_fd, StaticReadEvent), MY_FD_ISSET(t->cli_fd, StaticWriteEvent),
1394 //MY_FD_ISSET(t->srv_fd, StaticReadEvent), MY_FD_ISSET(t->srv_fd, StaticWriteEvent)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001395 //);
1396 if (s == SV_STIDLE) {
1397 if (c == CL_STHEADERS)
1398 return 0; /* stay in idle, waiting for data to reach the client side */
1399 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
1400 (c == CL_STSHUTR &&
Willy Tarreau73de9892006-11-30 11:40:23 +01001401 (t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001402 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001403 if (t->pend_pos)
1404 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1405 /* note that this must not return any error because it would be able to
1406 * overwrite the client_retnclose() output.
1407 */
Willy Tarreau08fa2e32006-09-03 10:47:37 +02001408 if (t->flags & SN_CLTARPIT)
1409 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, 0, NULL);
1410 else
1411 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C, 0, 0, NULL);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001412
1413 return 1;
1414 }
1415 else {
Willy Tarreaub8750a82006-09-03 09:56:00 +02001416 if (t->flags & SN_CLTARPIT) {
1417 /* This connection is being tarpitted. The CLIENT side has
1418 * already set the connect expiration date to the right
1419 * timeout. We just have to check that it has not expired.
1420 */
1421 if (tv_cmp2_ms(&req->cex, &now) > 0)
1422 return 0;
1423
1424 /* We will set the queue timer to the time spent, just for
1425 * logging purposes. We fake a 500 server error, so that the
1426 * attacker will not suspect his connection has been tarpitted.
1427 * It will not cause trouble to the logs because we can exclude
1428 * the tarpitted connections by filtering on the 'PT' status flags.
1429 */
1430 tv_eternity(&req->cex);
1431 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1432 srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
Willy Tarreau73de9892006-11-30 11:40:23 +01001433 500, t->fe->errmsg.len500, t->fe->errmsg.msg500);
Willy Tarreaub8750a82006-09-03 09:56:00 +02001434 return 1;
1435 }
1436
Willy Tarreaubaaee002006-06-26 02:48:02 +02001437 /* Right now, we will need to create a connection to the server.
1438 * We might already have tried, and got a connection pending, in
1439 * which case we will not do anything till it's pending. It's up
1440 * to any other session to release it and wake us up again.
1441 */
1442 if (t->pend_pos) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001443 if (tv_cmp2_ms(&req->cex, &now) > 0)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001444 return 0;
1445 else {
1446 /* we've been waiting too long here */
Willy Tarreaud7971282006-07-29 18:36:34 +02001447 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001448 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1449 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
Willy Tarreau73de9892006-11-30 11:40:23 +01001450 503, t->fe->errmsg.len503, t->fe->errmsg.msg503);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001451 if (t->srv)
1452 t->srv->failed_conns++;
Willy Tarreau73de9892006-11-30 11:40:23 +01001453 t->fe->failed_conns++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001454 return 1;
1455 }
1456 }
1457
1458 do {
1459 /* first, get a connection */
1460 if (srv_redispatch_connect(t))
1461 return t->srv_state != SV_STIDLE;
1462
1463 /* try to (re-)connect to the server, and fail if we expire the
1464 * number of retries.
1465 */
1466 if (srv_retryable_connect(t)) {
1467 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1468 return t->srv_state != SV_STIDLE;
1469 }
1470
1471 } while (1);
1472 }
1473 }
1474 else if (s == SV_STCONN) { /* connection in progress */
1475 if (c == CL_STCLOSE || c == CL_STSHUTW ||
1476 (c == CL_STSHUTR &&
Willy Tarreau73de9892006-11-30 11:40:23 +01001477 (t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreaud7971282006-07-29 18:36:34 +02001478 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001479 fd_delete(t->srv_fd);
1480 if (t->srv)
1481 t->srv->cur_sess--;
1482
1483 /* note that this must not return any error because it would be able to
1484 * overwrite the client_retnclose() output.
1485 */
1486 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, 0, NULL);
1487 return 1;
1488 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001489 if (!(req->flags & BF_WRITE_STATUS) && tv_cmp2_ms(&req->cex, &now) > 0) {
1490 //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 +02001491 return 0; /* nothing changed */
1492 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001493 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001494 /* timeout, asynchronous connect error or first write error */
1495 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
1496
1497 fd_delete(t->srv_fd);
1498 if (t->srv)
1499 t->srv->cur_sess--;
1500
Willy Tarreau0f9f5052006-07-29 17:39:25 +02001501 if (!(req->flags & BF_WRITE_STATUS))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001502 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
1503 else
1504 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
1505
1506 /* ensure that we have enough retries left */
1507 if (srv_count_retry_down(t, conn_err))
1508 return 1;
1509
Willy Tarreau73de9892006-11-30 11:40:23 +01001510 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001511 /* We're on our last chance, and the REDISP option was specified.
1512 * We will ignore cookie and force to balance or use the dispatcher.
1513 */
1514 /* let's try to offer this slot to anybody */
Willy Tarreau73de9892006-11-30 11:40:23 +01001515 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001516 task_wakeup(&rq, t->srv->queue_mgt);
1517
1518 if (t->srv)
1519 t->srv->failed_conns++;
Willy Tarreau73de9892006-11-30 11:40:23 +01001520 t->be->failed_conns++;
Willy Tarreau0bbc3cf2006-10-15 14:26:02 +02001521
1522 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
1523 t->srv = NULL; /* it's left to the dispatcher to choose a server */
1524 if ((t->flags & SN_CK_MASK) == SN_CK_VALID) {
1525 t->flags &= ~SN_CK_MASK;
1526 t->flags |= SN_CK_DOWN;
1527 }
1528
1529 /* first, get a connection */
1530 if (srv_redispatch_connect(t))
1531 return t->srv_state != SV_STIDLE;
1532 }
1533
Willy Tarreaubaaee002006-06-26 02:48:02 +02001534 do {
1535 /* Now we will try to either reconnect to the same server or
1536 * connect to another server. If the connection gets queued
1537 * because all servers are saturated, then we will go back to
1538 * the SV_STIDLE state.
1539 */
1540 if (srv_retryable_connect(t)) {
1541 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1542 return t->srv_state != SV_STCONN;
1543 }
1544
1545 /* we need to redispatch the connection to another server */
1546 if (srv_redispatch_connect(t))
1547 return t->srv_state != SV_STCONN;
1548 } while (1);
1549 }
1550 else { /* no error or write 0 */
1551 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
1552
1553 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
1554 if (req->l == 0) /* nothing to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02001555 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001556 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001557 } else /* need the right to write */ {
Willy Tarreau2a429502006-10-15 14:52:29 +02001558 MY_FD_SET(t->srv_fd, StaticWriteEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001559 if (t->be->srvtimeout) {
1560 tv_delayfrom(&req->wex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001561 /* FIXME: to prevent the server from expiring read timeouts during writes,
1562 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02001563 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001564 }
1565 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001566 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001567 }
1568
Willy Tarreau73de9892006-11-30 11:40:23 +01001569 if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
Willy Tarreau2a429502006-10-15 14:52:29 +02001570 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001571 if (t->be->srvtimeout)
1572 tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001573 else
Willy Tarreaud7971282006-07-29 18:36:34 +02001574 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001575
1576 t->srv_state = SV_STDATA;
1577 if (t->srv)
1578 t->srv->cum_sess++;
1579 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
1580
1581 /* if the user wants to log as soon as possible, without counting
1582 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001583 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001584 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
1585 sess_log(t);
1586 }
1587 }
1588 else {
1589 t->srv_state = SV_STHEADERS;
1590 if (t->srv)
1591 t->srv->cum_sess++;
1592 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
1593 }
Willy Tarreaud7971282006-07-29 18:36:34 +02001594 tv_eternity(&req->cex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001595 return 1;
1596 }
1597 }
1598 else if (s == SV_STHEADERS) { /* receiving server headers */
1599 /* now parse the partial (or complete) headers */
1600 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
1601 char *ptr;
1602 int delete_header;
1603
1604 ptr = rep->lr;
1605
1606 /* look for the end of the current header */
1607 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
1608 ptr++;
1609
1610 if (ptr == rep->h) {
1611 int line, len;
1612
1613 /* we can only get here after an end of headers */
1614
1615 /* first, we'll block if security checks have caught nasty things */
1616 if (t->flags & SN_CACHEABLE) {
1617 if ((t->flags & SN_CACHE_COOK) &&
1618 (t->flags & SN_SCK_ANY) &&
Willy Tarreau73de9892006-11-30 11:40:23 +01001619 (t->be->options & PR_O_CHK_CACHE)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001620
1621 /* we're in presence of a cacheable response containing
1622 * a set-cookie header. We'll block it as requested by
1623 * the 'checkcache' option, and send an alert.
1624 */
Willy Tarreaud7971282006-07-29 18:36:34 +02001625 tv_eternity(&rep->rex);
1626 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001627 fd_delete(t->srv_fd);
1628 if (t->srv) {
1629 t->srv->cur_sess--;
1630 t->srv->failed_secu++;
1631 }
Willy Tarreau73de9892006-11-30 11:40:23 +01001632 t->be->failed_secu++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001633 t->srv_state = SV_STCLOSE;
1634 t->logs.status = 502;
Willy Tarreau73de9892006-11-30 11:40:23 +01001635 client_return(t, t->fe->errmsg.len502, t->fe->errmsg.msg502);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001636 if (!(t->flags & SN_ERR_MASK))
1637 t->flags |= SN_ERR_PRXCOND;
1638 if (!(t->flags & SN_FINST_MASK))
1639 t->flags |= SN_FINST_H;
1640
Willy Tarreau73de9892006-11-30 11:40:23 +01001641 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->be->id, t->srv->id);
1642 send_log(t->be, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->be->id, t->srv->id);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001643
1644 /* We used to have a free connection slot. Since we'll never use it,
1645 * we have to inform the server that it may be used by another session.
1646 */
Willy Tarreau73de9892006-11-30 11:40:23 +01001647 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001648 task_wakeup(&rq, t->srv->queue_mgt);
1649
1650 return 1;
1651 }
1652 }
1653
1654 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
1655 if (t->flags & SN_SVDENY) {
Willy Tarreaud7971282006-07-29 18:36:34 +02001656 tv_eternity(&rep->rex);
1657 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001658 fd_delete(t->srv_fd);
1659 if (t->srv) {
1660 t->srv->cur_sess--;
1661 t->srv->failed_secu++;
1662 }
Willy Tarreau73de9892006-11-30 11:40:23 +01001663 t->be->failed_secu++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001664 t->srv_state = SV_STCLOSE;
1665 t->logs.status = 502;
Willy Tarreau73de9892006-11-30 11:40:23 +01001666 client_return(t, t->fe->errmsg.len502, t->fe->errmsg.msg502);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001667 if (!(t->flags & SN_ERR_MASK))
1668 t->flags |= SN_ERR_PRXCOND;
1669 if (!(t->flags & SN_FINST_MASK))
1670 t->flags |= SN_FINST_H;
1671 /* We used to have a free connection slot. Since we'll never use it,
1672 * we have to inform the server that it may be used by another session.
1673 */
Willy Tarreau73de9892006-11-30 11:40:23 +01001674 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001675 task_wakeup(&rq, t->srv->queue_mgt);
1676
1677 return 1;
1678 }
1679
1680 /* we'll have something else to do here : add new headers ... */
1681
Willy Tarreau73de9892006-11-30 11:40:23 +01001682 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_INS) &&
1683 (!(t->be->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001684 /* the server is known, it's not the one the client requested, we have to
1685 * insert a set-cookie here, except if we want to insert only on POST
1686 * requests and this one isn't. Note that servers which don't have cookies
1687 * (eg: some backup servers) will return a full cookie removal request.
1688 */
1689 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
Willy Tarreau73de9892006-11-30 11:40:23 +01001690 t->be->cookie_name,
Willy Tarreaubaaee002006-06-26 02:48:02 +02001691 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
1692
1693 t->flags |= SN_SCK_INSERTED;
1694
1695 /* Here, we will tell an eventual cache on the client side that we don't
1696 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
1697 * Some caches understand the correct form: 'no-cache="set-cookie"', but
1698 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
1699 */
Willy Tarreau73de9892006-11-30 11:40:23 +01001700 if (t->be->options & PR_O_COOK_NOC)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001701 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
1702 len += sprintf(trash + len, "Cache-control: private\r\n");
1703
1704 if (rep->data + rep->l < rep->h)
1705 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
1706 *(int *)0 = 0;
1707 buffer_replace2(rep, rep->h, rep->h, trash, len);
1708 }
1709
1710 /* headers to be added */
Willy Tarreau73de9892006-11-30 11:40:23 +01001711 for (line = 0; line < t->fi->nb_rspadd; line++) {
1712 len = sprintf(trash, "%s\r\n", t->fi->rsp_add[line]);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001713 buffer_replace2(rep, rep->h, rep->h, trash, len);
1714 }
1715
1716 /* add a "connection: close" line if needed */
Willy Tarreau73de9892006-11-30 11:40:23 +01001717 if (t->fe->options & PR_O_HTTP_CLOSE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001718 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
1719
1720 t->srv_state = SV_STDATA;
1721 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
1722 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
1723
1724 /* client connection already closed or option 'httpclose' required :
1725 * we close the server's outgoing connection right now.
1726 */
1727 if ((req->l == 0) &&
Willy Tarreau73de9892006-11-30 11:40:23 +01001728 (c == CL_STSHUTR || c == CL_STCLOSE || t->be->options & PR_O_FORCE_CLO)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02001729 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02001730 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001731
1732 /* We must ensure that the read part is still alive when switching
1733 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02001734 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01001735 if (t->be->srvtimeout)
1736 tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001737
1738 shutdown(t->srv_fd, SHUT_WR);
1739 t->srv_state = SV_STSHUTW;
1740 }
1741
1742 /* if the user wants to log as soon as possible, without counting
1743 bytes from the server, then this is the right moment. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001744 if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001745 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
1746 t->logs.bytes = rep->h - rep->data;
1747 sess_log(t);
1748 }
1749 break;
1750 }
1751
1752 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1753 if (ptr > rep->r - 2) {
1754 /* this is a partial header, let's wait for more to come */
1755 rep->lr = ptr;
1756 break;
1757 }
1758
1759 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
1760 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
1761
1762 /* now we know that *ptr is either \r or \n,
1763 * and that there are at least 1 char after it.
1764 */
1765 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
1766 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
1767 else
1768 rep->lr = ptr + 2; /* \r\n or \n\r */
1769
1770 /*
1771 * now we know that we have a full header ; we can do whatever
1772 * we want with these pointers :
1773 * rep->h = beginning of header
1774 * ptr = end of header (first \r or \n)
1775 * rep->lr = beginning of next line (next rep->h)
1776 * rep->r = end of data (not used at this stage)
1777 */
1778
1779
1780 if (t->logs.status == -1) {
1781 t->logs.logwait &= ~LW_RESP;
1782 t->logs.status = atoi(rep->h + 9);
1783 switch (t->logs.status) {
1784 case 200:
1785 case 203:
1786 case 206:
1787 case 300:
1788 case 301:
1789 case 410:
1790 /* RFC2616 @13.4:
1791 * "A response received with a status code of
1792 * 200, 203, 206, 300, 301 or 410 MAY be stored
1793 * by a cache (...) unless a cache-control
1794 * directive prohibits caching."
1795 *
1796 * RFC2616 @9.5: POST method :
1797 * "Responses to this method are not cacheable,
1798 * unless the response includes appropriate
1799 * Cache-Control or Expires header fields."
1800 */
Willy Tarreau73de9892006-11-30 11:40:23 +01001801 if (!(t->flags & SN_POST) && (t->be->options & PR_O_CHK_CACHE))
Willy Tarreaubaaee002006-06-26 02:48:02 +02001802 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
1803 break;
1804 default:
1805 break;
1806 }
1807 }
1808 else if (t->logs.logwait & LW_RSPHDR) {
1809 struct cap_hdr *h;
1810 int len;
Willy Tarreau73de9892006-11-30 11:40:23 +01001811 for (h = t->fi->rsp_cap; h; h = h->next) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001812 if ((h->namelen + 2 <= ptr - rep->h) &&
1813 (rep->h[h->namelen] == ':') &&
1814 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
1815
1816 if (t->rsp_cap[h->index] == NULL)
1817 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
1818
1819 len = ptr - (rep->h + h->namelen + 2);
1820 if (len > h->len)
1821 len = h->len;
1822
1823 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
1824 t->rsp_cap[h->index][len]=0;
1825 }
1826 }
1827
1828 }
1829
1830 delete_header = 0;
1831
Willy Tarreau58f10d72006-12-04 02:26:12 +01001832 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))
1833 debug_hdr("srvhdr", t, rep->h, ptr);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001834
1835 /* remove "connection: " if needed */
Willy Tarreau73de9892006-11-30 11:40:23 +01001836 if (!delete_header && (t->fe->options & PR_O_HTTP_CLOSE)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001837 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
1838 delete_header = 1;
1839 }
1840
1841 /* try headers regexps */
Willy Tarreau73de9892006-11-30 11:40:23 +01001842 if (!delete_header && t->fi->rsp_exp != NULL
Willy Tarreaubaaee002006-06-26 02:48:02 +02001843 && !(t->flags & SN_SVDENY)) {
1844 struct hdr_exp *exp;
1845 char term;
1846
1847 term = *ptr;
1848 *ptr = '\0';
Willy Tarreau73de9892006-11-30 11:40:23 +01001849 exp = t->fi->rsp_exp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001850 do {
1851 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
1852 switch (exp->action) {
1853 case ACT_ALLOW:
1854 if (!(t->flags & SN_SVDENY))
1855 t->flags |= SN_SVALLOW;
1856 break;
1857 case ACT_REPLACE:
1858 if (!(t->flags & SN_SVDENY)) {
1859 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
1860 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
1861 }
1862 break;
1863 case ACT_REMOVE:
1864 if (!(t->flags & SN_SVDENY))
1865 delete_header = 1;
1866 break;
1867 case ACT_DENY:
1868 if (!(t->flags & SN_SVALLOW))
1869 t->flags |= SN_SVDENY;
1870 break;
1871 case ACT_PASS: /* we simply don't deny this one */
1872 break;
1873 }
1874 break;
1875 }
1876 } while ((exp = exp->next) != NULL);
1877 *ptr = term; /* restore the string terminator */
1878 }
1879
1880 /* check for cache-control: or pragma: headers */
1881 if (!delete_header && (t->flags & SN_CACHEABLE)) {
1882 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
1883 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1884 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
1885 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
1886 if (rep->h + 23 == ptr || rep->h[23] == ',')
1887 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1888 else {
1889 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
1890 && (rep->h[35] == '"' || rep->h[35] == ','))
1891 t->flags &= ~SN_CACHE_COOK;
1892 }
1893 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
1894 (rep->h + 22 == ptr || rep->h[22] == ','))
1895 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
1896 (rep->h + 23 == ptr || rep->h[23] == ','))) {
1897 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1898 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
1899 (rep->h + 24 == ptr || rep->h[24] == ',')) {
1900 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1901 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
1902 (rep->h + 25 == ptr || rep->h[25] == ',')) {
1903 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1904 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
1905 (rep->h + 21 == ptr || rep->h[21] == ',')) {
1906 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
1907 }
1908 }
1909 }
1910
1911 /* check for server cookies */
1912 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
Willy Tarreau73de9892006-11-30 11:40:23 +01001913 && (t->be->cookie_name != NULL || t->fi->capture_name != NULL || t->be->appsession_name !=NULL)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001914 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
1915 char *p1, *p2, *p3, *p4;
1916
1917 t->flags |= SN_SCK_ANY;
1918
1919 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
1920
1921 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
1922 while (p1 < ptr && (isspace((int)*p1)))
1923 p1++;
1924
1925 if (p1 == ptr || *p1 == ';') /* end of cookie */
1926 break;
1927
1928 /* p1 is at the beginning of the cookie name */
1929 p2 = p1;
1930
1931 while (p2 < ptr && *p2 != '=' && *p2 != ';')
1932 p2++;
1933
1934 if (p2 == ptr || *p2 == ';') /* next cookie */
1935 break;
1936
1937 p3 = p2 + 1; /* skips the '=' sign */
1938 if (p3 == ptr)
1939 break;
1940
1941 p4 = p3;
1942 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
1943 p4++;
1944
1945 /* here, we have the cookie name between p1 and p2,
1946 * and its value between p3 and p4.
1947 * we can process it.
1948 */
1949
1950 /* first, let's see if we want to capture it */
Willy Tarreau73de9892006-11-30 11:40:23 +01001951 if (t->fi->capture_name != NULL &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02001952 t->logs.srv_cookie == NULL &&
Willy Tarreau73de9892006-11-30 11:40:23 +01001953 (p4 - p1 >= t->fi->capture_namelen) &&
1954 memcmp(p1, t->fi->capture_name, t->fi->capture_namelen) == 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001955 int log_len = p4 - p1;
1956
1957 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
1958 Alert("HTTP logging : out of memory.\n");
1959 }
1960
Willy Tarreau73de9892006-11-30 11:40:23 +01001961 if (log_len > t->fi->capture_len)
1962 log_len = t->fi->capture_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001963 memcpy(t->logs.srv_cookie, p1, log_len);
1964 t->logs.srv_cookie[log_len] = 0;
1965 }
1966
Willy Tarreau73de9892006-11-30 11:40:23 +01001967 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
1968 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001969 /* Cool... it's the right one */
1970 t->flags |= SN_SCK_SEEN;
1971
1972 /* If the cookie is in insert mode on a known server, we'll delete
1973 * this occurrence because we'll insert another one later.
1974 * We'll delete it too if the "indirect" option is set and we're in
1975 * a direct access. */
Willy Tarreau73de9892006-11-30 11:40:23 +01001976 if (((t->srv) && (t->be->options & PR_O_COOK_INS)) ||
1977 ((t->flags & SN_DIRECT) && (t->be->options & PR_O_COOK_IND))) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001978 /* this header must be deleted */
1979 delete_header = 1;
1980 t->flags |= SN_SCK_DELETED;
1981 }
Willy Tarreau73de9892006-11-30 11:40:23 +01001982 else if ((t->srv) && (t->be->options & PR_O_COOK_RW)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001983 /* replace bytes p3->p4 with the cookie name associated
1984 * with this server since we know it.
1985 */
1986 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
1987 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
1988 }
Willy Tarreau73de9892006-11-30 11:40:23 +01001989 else if ((t->srv) && (t->be->options & PR_O_COOK_PFX)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001990 /* insert the cookie name associated with this server
1991 * before existing cookie, and insert a delimitor between them..
1992 */
1993 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
1994 p3[t->srv->cklen] = COOKIE_DELIM;
1995 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
1996 }
1997 break;
1998 }
1999
2000 /* first, let's see if the cookie is our appcookie*/
Willy Tarreau73de9892006-11-30 11:40:23 +01002001 if ((t->be->appsession_name != NULL) &&
2002 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002003
2004 /* Cool... it's the right one */
2005
2006 size_t server_id_len = strlen(t->srv->id) + 1;
2007 asession_temp = &local_asession;
2008
2009 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
2010 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002011 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002012 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002013 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
2014 asession_temp->sessid[t->be->appsession_len] = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002015 asession_temp->serverid = NULL;
2016
2017 /* only do insert, if lookup fails */
Willy Tarreau73de9892006-11-30 11:40:23 +01002018 if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002019 if ((asession_temp = pool_alloc(appsess)) == NULL) {
2020 Alert("Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002021 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002022 return 0;
2023 }
2024 asession_temp->sessid = local_asession.sessid;
2025 asession_temp->serverid = local_asession.serverid;
Willy Tarreau73de9892006-11-30 11:40:23 +01002026 chtbl_insert(&(t->be->htbl_proxy), (void *) asession_temp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002027 }/* end if (chtbl_lookup()) */
2028 else {
2029 /* free wasted memory */
2030 pool_free_to(apools.sessid, local_asession.sessid);
2031 } /* end else from if (chtbl_lookup()) */
2032
2033 if (asession_temp->serverid == NULL) {
2034 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
2035 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreau73de9892006-11-30 11:40:23 +01002036 send_log(t->be, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
Willy Tarreaubaaee002006-06-26 02:48:02 +02002037 }
2038 asession_temp->serverid[0] = '\0';
2039 }
2040
2041 if (asession_temp->serverid[0] == '\0')
2042 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
2043
Willy Tarreau73de9892006-11-30 11:40:23 +01002044 tv_delayfrom(&asession_temp->expire, &now, t->be->appsession_timeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002045
2046#if defined(DEBUG_HASH)
Willy Tarreau73de9892006-11-30 11:40:23 +01002047 print_table(&(t->be->htbl_proxy));
Willy Tarreaubaaee002006-06-26 02:48:02 +02002048#endif
2049 break;
2050 }/* end if ((t->proxy->appsession_name != NULL) ... */
2051 else {
2052 // fprintf(stderr,"Ignoring unknown cookie : ");
2053 // write(2, p1, p2-p1);
2054 // fprintf(stderr," = ");
2055 // write(2, p3, p4-p3);
2056 // fprintf(stderr,"\n");
2057 }
2058 break; /* we don't want to loop again since there cannot be another cookie on the same line */
2059 } /* we're now at the end of the cookie value */
2060 } /* end of cookie processing */
2061
2062 /* check for any set-cookie in case we check for cacheability */
2063 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
Willy Tarreau73de9892006-11-30 11:40:23 +01002064 (t->be->options & PR_O_CHK_CACHE) &&
Willy Tarreaubaaee002006-06-26 02:48:02 +02002065 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
2066 t->flags |= SN_SCK_ANY;
2067 }
2068
2069 /* let's look if we have to delete this header */
2070 if (delete_header && !(t->flags & SN_SVDENY))
2071 buffer_replace2(rep, rep->h, rep->lr, "", 0);
2072
2073 rep->h = rep->lr;
2074 } /* while (rep->lr < rep->r) */
2075
2076 /* end of header processing (even if incomplete) */
2077
Willy Tarreau2a429502006-10-15 14:52:29 +02002078 if ((rep->l < rep->rlim - rep->data) && ! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002079 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
Willy Tarreaud7971282006-07-29 18:36:34 +02002080 * full. We cannot loop here since stream_sock_read will disable it only if
Willy Tarreaubaaee002006-06-26 02:48:02 +02002081 * rep->l == rlim-data
2082 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002083 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01002084 if (t->be->srvtimeout)
2085 tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002086 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002087 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002088 }
2089
2090 /* read error, write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002091 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002092 tv_eternity(&rep->rex);
2093 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002094 fd_delete(t->srv_fd);
2095 if (t->srv) {
2096 t->srv->cur_sess--;
2097 t->srv->failed_resp++;
2098 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002099 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002100
2101 t->srv_state = SV_STCLOSE;
2102 t->logs.status = 502;
Willy Tarreau73de9892006-11-30 11:40:23 +01002103 client_return(t, t->fe->errmsg.len502, t->fe->errmsg.msg502);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002104 if (!(t->flags & SN_ERR_MASK))
2105 t->flags |= SN_ERR_SRVCL;
2106 if (!(t->flags & SN_FINST_MASK))
2107 t->flags |= SN_FINST_H;
2108 /* We used to have a free connection slot. Since we'll never use it,
2109 * we have to inform the server that it may be used by another session.
2110 */
Willy Tarreau73de9892006-11-30 11:40:23 +01002111 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002112 task_wakeup(&rq, t->srv->queue_mgt);
2113
2114 return 1;
2115 }
2116 /* end of client write or end of server read.
2117 * since we are in header mode, if there's no space left for headers, we
2118 * won't be able to free more later, so the session will never terminate.
2119 */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002120 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 +02002121 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002122 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002123 shutdown(t->srv_fd, SHUT_RD);
2124 t->srv_state = SV_STSHUTR;
2125 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2126 return 1;
2127 }
2128 /* read timeout : return a 504 to the client.
2129 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002130 else if (MY_FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002131 tv_eternity(&rep->rex);
2132 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002133 fd_delete(t->srv_fd);
2134 if (t->srv) {
2135 t->srv->cur_sess--;
2136 t->srv->failed_resp++;
2137 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002138 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002139 t->srv_state = SV_STCLOSE;
2140 t->logs.status = 504;
Willy Tarreau73de9892006-11-30 11:40:23 +01002141 client_return(t, t->fe->errmsg.len504, t->fe->errmsg.msg504);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002142 if (!(t->flags & SN_ERR_MASK))
2143 t->flags |= SN_ERR_SRVTO;
2144 if (!(t->flags & SN_FINST_MASK))
2145 t->flags |= SN_FINST_H;
2146 /* We used to have a free connection slot. Since we'll never use it,
2147 * we have to inform the server that it may be used by another session.
2148 */
Willy Tarreau73de9892006-11-30 11:40:23 +01002149 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002150 task_wakeup(&rq, t->srv->queue_mgt);
2151
2152 return 1;
2153 }
2154 /* last client read and buffer empty */
2155 /* FIXME!!! here, we don't want to switch to SHUTW if the
2156 * client shuts read too early, because we may still have
2157 * some work to do on the headers.
2158 * The side-effect is that if the client completely closes its
2159 * connection during SV_STHEADER, the connection to the server
2160 * is kept until a response comes back or the timeout is reached.
2161 */
2162 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002163 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002164 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002165
2166 /* We must ensure that the read part is still alive when switching
2167 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002168 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01002169 if (t->be->srvtimeout)
2170 tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002171
2172 shutdown(t->srv_fd, SHUT_WR);
2173 t->srv_state = SV_STSHUTW;
2174 return 1;
2175 }
2176 /* write timeout */
2177 /* FIXME!!! here, we don't want to switch to SHUTW if the
2178 * client shuts read too early, because we may still have
2179 * some work to do on the headers.
2180 */
Willy Tarreau2a429502006-10-15 14:52:29 +02002181 else if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&req->wex, &now) <= 0) {
2182 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002183 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002184 shutdown(t->srv_fd, SHUT_WR);
2185 /* We must ensure that the read part is still alive when switching
2186 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002187 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01002188 if (t->be->srvtimeout)
2189 tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002190
2191 /* We must ensure that the read part is still alive when switching
2192 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002193 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01002194 if (t->be->srvtimeout)
2195 tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002196
2197 t->srv_state = SV_STSHUTW;
2198 if (!(t->flags & SN_ERR_MASK))
2199 t->flags |= SN_ERR_SRVTO;
2200 if (!(t->flags & SN_FINST_MASK))
2201 t->flags |= SN_FINST_H;
2202 return 1;
2203 }
2204
2205 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002206 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2207 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002208 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002209 }
2210 }
2211 else { /* client buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002212 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2213 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01002214 if (t->be->srvtimeout) {
2215 tv_delayfrom(&req->wex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002216 /* FIXME: to prevent the server from expiring read timeouts during writes,
2217 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002218 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002219 }
2220 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002221 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002222 }
2223 }
2224
2225 /* be nice with the client side which would like to send a complete header
2226 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2227 * would read all remaining data at once ! The client should not write past rep->lr
2228 * when the server is in header state.
2229 */
2230 //return header_processed;
2231 return t->srv_state != SV_STHEADERS;
2232 }
2233 else if (s == SV_STDATA) {
2234 /* read or write error */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002235 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreaud7971282006-07-29 18:36:34 +02002236 tv_eternity(&rep->rex);
2237 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002238 fd_delete(t->srv_fd);
2239 if (t->srv) {
2240 t->srv->cur_sess--;
2241 t->srv->failed_resp++;
2242 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002243 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002244 t->srv_state = SV_STCLOSE;
2245 if (!(t->flags & SN_ERR_MASK))
2246 t->flags |= SN_ERR_SRVCL;
2247 if (!(t->flags & SN_FINST_MASK))
2248 t->flags |= SN_FINST_D;
2249 /* We used to have a free connection slot. Since we'll never use it,
2250 * we have to inform the server that it may be used by another session.
2251 */
Willy Tarreau73de9892006-11-30 11:40:23 +01002252 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002253 task_wakeup(&rq, t->srv->queue_mgt);
2254
2255 return 1;
2256 }
2257 /* last read, or end of client write */
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002258 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002259 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002260 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002261 shutdown(t->srv_fd, SHUT_RD);
2262 t->srv_state = SV_STSHUTR;
2263 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2264 return 1;
2265 }
2266 /* end of client read and no more data to send */
2267 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002268 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002269 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002270 shutdown(t->srv_fd, SHUT_WR);
2271 /* We must ensure that the read part is still alive when switching
2272 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002273 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01002274 if (t->be->srvtimeout)
2275 tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002276
2277 t->srv_state = SV_STSHUTW;
2278 return 1;
2279 }
2280 /* read timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002281 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002282 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002283 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002284 shutdown(t->srv_fd, SHUT_RD);
2285 t->srv_state = SV_STSHUTR;
2286 if (!(t->flags & SN_ERR_MASK))
2287 t->flags |= SN_ERR_SRVTO;
2288 if (!(t->flags & SN_FINST_MASK))
2289 t->flags |= SN_FINST_D;
2290 return 1;
2291 }
2292 /* write timeout */
Willy Tarreaud7971282006-07-29 18:36:34 +02002293 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002294 MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002295 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002296 shutdown(t->srv_fd, SHUT_WR);
2297 /* We must ensure that the read part is still alive when switching
2298 * to shutw */
Willy Tarreau2a429502006-10-15 14:52:29 +02002299 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01002300 if (t->be->srvtimeout)
2301 tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002302 t->srv_state = SV_STSHUTW;
2303 if (!(t->flags & SN_ERR_MASK))
2304 t->flags |= SN_ERR_SRVTO;
2305 if (!(t->flags & SN_FINST_MASK))
2306 t->flags |= SN_FINST_D;
2307 return 1;
2308 }
2309
2310 /* recompute request time-outs */
2311 if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002312 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2313 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002314 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002315 }
2316 }
2317 else { /* buffer not empty, there are still data to be transferred */
Willy Tarreau2a429502006-10-15 14:52:29 +02002318 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2319 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01002320 if (t->be->srvtimeout) {
2321 tv_delayfrom(&req->wex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002322 /* FIXME: to prevent the server from expiring read timeouts during writes,
2323 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002324 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002325 }
2326 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002327 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002328 }
2329 }
2330
2331 /* recompute response time-outs */
2332 if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002333 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2334 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002335 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002336 }
2337 }
2338 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002339 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2340 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01002341 if (t->be->srvtimeout)
2342 tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002343 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002344 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002345 }
2346 }
2347
2348 return 0; /* other cases change nothing */
2349 }
2350 else if (s == SV_STSHUTR) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002351 if (req->flags & BF_WRITE_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002352 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002353 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002354 fd_delete(t->srv_fd);
2355 if (t->srv) {
2356 t->srv->cur_sess--;
2357 t->srv->failed_resp++;
2358 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002359 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002360 //close(t->srv_fd);
2361 t->srv_state = SV_STCLOSE;
2362 if (!(t->flags & SN_ERR_MASK))
2363 t->flags |= SN_ERR_SRVCL;
2364 if (!(t->flags & SN_FINST_MASK))
2365 t->flags |= SN_FINST_D;
2366 /* We used to have a free connection slot. Since we'll never use it,
2367 * we have to inform the server that it may be used by another session.
2368 */
Willy Tarreau73de9892006-11-30 11:40:23 +01002369 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002370 task_wakeup(&rq, t->srv->queue_mgt);
2371
2372 return 1;
2373 }
2374 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002375 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002376 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002377 fd_delete(t->srv_fd);
2378 if (t->srv)
2379 t->srv->cur_sess--;
2380 //close(t->srv_fd);
2381 t->srv_state = SV_STCLOSE;
2382 /* We used to have a free connection slot. Since we'll never use it,
2383 * we have to inform the server that it may be used by another session.
2384 */
Willy Tarreau73de9892006-11-30 11:40:23 +01002385 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002386 task_wakeup(&rq, t->srv->queue_mgt);
2387
2388 return 1;
2389 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002390 else if (tv_cmp2_ms(&req->wex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002391 //MY_FD_CLR(t->srv_fd, StaticWriteEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002392 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002393 fd_delete(t->srv_fd);
2394 if (t->srv)
2395 t->srv->cur_sess--;
2396 //close(t->srv_fd);
2397 t->srv_state = SV_STCLOSE;
2398 if (!(t->flags & SN_ERR_MASK))
2399 t->flags |= SN_ERR_SRVTO;
2400 if (!(t->flags & SN_FINST_MASK))
2401 t->flags |= SN_FINST_D;
2402 /* We used to have a free connection slot. Since we'll never use it,
2403 * we have to inform the server that it may be used by another session.
2404 */
Willy Tarreau73de9892006-11-30 11:40:23 +01002405 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002406 task_wakeup(&rq, t->srv->queue_mgt);
2407
2408 return 1;
2409 }
2410 else if (req->l == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002411 if (MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2412 MY_FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
Willy Tarreaud7971282006-07-29 18:36:34 +02002413 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002414 }
2415 }
2416 else { /* buffer not empty */
Willy Tarreau2a429502006-10-15 14:52:29 +02002417 if (! MY_FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2418 MY_FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
Willy Tarreau73de9892006-11-30 11:40:23 +01002419 if (t->be->srvtimeout) {
2420 tv_delayfrom(&req->wex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002421 /* FIXME: to prevent the server from expiring read timeouts during writes,
2422 * we refresh it. */
Willy Tarreaud7971282006-07-29 18:36:34 +02002423 rep->rex = req->wex;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002424 }
2425 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002426 tv_eternity(&req->wex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002427 }
2428 }
2429 return 0;
2430 }
2431 else if (s == SV_STSHUTW) {
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002432 if (rep->flags & BF_READ_ERROR) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002433 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002434 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002435 fd_delete(t->srv_fd);
2436 if (t->srv) {
2437 t->srv->cur_sess--;
2438 t->srv->failed_resp++;
2439 }
Willy Tarreau73de9892006-11-30 11:40:23 +01002440 t->be->failed_resp++;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002441 //close(t->srv_fd);
2442 t->srv_state = SV_STCLOSE;
2443 if (!(t->flags & SN_ERR_MASK))
2444 t->flags |= SN_ERR_SRVCL;
2445 if (!(t->flags & SN_FINST_MASK))
2446 t->flags |= SN_FINST_D;
2447 /* We used to have a free connection slot. Since we'll never use it,
2448 * we have to inform the server that it may be used by another session.
2449 */
Willy Tarreau73de9892006-11-30 11:40:23 +01002450 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002451 task_wakeup(&rq, t->srv->queue_mgt);
2452
2453 return 1;
2454 }
Willy Tarreau0f9f5052006-07-29 17:39:25 +02002455 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002456 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002457 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002458 fd_delete(t->srv_fd);
2459 if (t->srv)
2460 t->srv->cur_sess--;
2461 //close(t->srv_fd);
2462 t->srv_state = SV_STCLOSE;
2463 /* We used to have a free connection slot. Since we'll never use it,
2464 * we have to inform the server that it may be used by another session.
2465 */
Willy Tarreau73de9892006-11-30 11:40:23 +01002466 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002467 task_wakeup(&rq, t->srv->queue_mgt);
2468
2469 return 1;
2470 }
Willy Tarreaud7971282006-07-29 18:36:34 +02002471 else if (tv_cmp2_ms(&rep->rex, &now) <= 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +02002472 //MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002473 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002474 fd_delete(t->srv_fd);
2475 if (t->srv)
2476 t->srv->cur_sess--;
2477 //close(t->srv_fd);
2478 t->srv_state = SV_STCLOSE;
2479 if (!(t->flags & SN_ERR_MASK))
2480 t->flags |= SN_ERR_SRVTO;
2481 if (!(t->flags & SN_FINST_MASK))
2482 t->flags |= SN_FINST_D;
2483 /* We used to have a free connection slot. Since we'll never use it,
2484 * we have to inform the server that it may be used by another session.
2485 */
Willy Tarreau73de9892006-11-30 11:40:23 +01002486 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreaubaaee002006-06-26 02:48:02 +02002487 task_wakeup(&rq, t->srv->queue_mgt);
2488
2489 return 1;
2490 }
2491 else if (rep->l == BUFSIZE) { /* no room to read more data */
Willy Tarreau2a429502006-10-15 14:52:29 +02002492 if (MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2493 MY_FD_CLR(t->srv_fd, StaticReadEvent);
Willy Tarreaud7971282006-07-29 18:36:34 +02002494 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002495 }
2496 }
2497 else {
Willy Tarreau2a429502006-10-15 14:52:29 +02002498 if (! MY_FD_ISSET(t->srv_fd, StaticReadEvent)) {
2499 MY_FD_SET(t->srv_fd, StaticReadEvent);
Willy Tarreau73de9892006-11-30 11:40:23 +01002500 if (t->be->srvtimeout)
2501 tv_delayfrom(&rep->rex, &now, t->be->srvtimeout);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002502 else
Willy Tarreaud7971282006-07-29 18:36:34 +02002503 tv_eternity(&rep->rex);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002504 }
2505 }
2506 return 0;
2507 }
2508 else { /* SV_STCLOSE : nothing to do */
2509 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2510 int len;
Willy Tarreau73de9892006-11-30 11:40:23 +01002511 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n", t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002512 write(1, trash, len);
2513 }
2514 return 0;
2515 }
2516 return 0;
2517}
2518
2519
2520/*
2521 * Produces data for the session <s> depending on its source. Expects to be
2522 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
2523 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
2524 * session, which it uses to keep on being called when there is free space in
2525 * the buffer, of simply by letting an empty buffer upon return. It returns 1
2526 * if it changes the session state from CL_STSHUTR, otherwise 0.
2527 */
2528int produce_content(struct session *s)
2529{
2530 struct buffer *rep = s->rep;
2531 struct proxy *px;
2532 struct server *sv;
2533 int msglen;
2534
2535 if (s->data_source == DATA_SRC_NONE) {
2536 s->flags &= ~SN_SELF_GEN;
2537 return 1;
2538 }
2539 else if (s->data_source == DATA_SRC_STATS) {
2540 msglen = 0;
2541
2542 if (s->data_state == DATA_ST_INIT) { /* the function had not been called yet */
2543 unsigned int up;
2544
2545 s->flags |= SN_SELF_GEN; // more data will follow
2546
2547 /* send the start of the HTTP response */
2548 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2549 "HTTP/1.0 200 OK\r\n"
2550 "Cache-Control: no-cache\r\n"
2551 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +02002552 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +02002553 "\r\n\r\n");
2554
2555 s->logs.status = 200;
2556 client_retnclose(s, msglen, trash); // send the start of the response.
2557 msglen = 0;
2558
2559 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
2560 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
2561 if (!(s->flags & SN_FINST_MASK))
2562 s->flags |= SN_FINST_R;
2563
2564 /* WARNING! This must fit in the first buffer !!! */
2565 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2566 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
2567 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
2568 "<style type=\"text/css\"><!--\n"
2569 "body {"
2570 " font-family: helvetica, arial;"
2571 " font-size: 12px;"
2572 " font-weight: normal;"
2573 " color: black;"
2574 " background: white;"
2575 "}\n"
2576 "td {"
2577 " font-size: 12px;"
2578 " align: center;"
2579 "}\n"
2580 "h1 {"
2581 " font-size: xx-large;"
2582 " margin-bottom: 0.5em;"
2583 "}\n"
2584 "h2 {"
2585 " font-family: helvetica, arial;"
2586 " font-size: x-large;"
2587 " font-weight: bold;"
2588 " font-style: italic;"
2589 " color: #6020a0;"
2590 " margin-top: 0em;"
2591 " margin-bottom: 0em;"
2592 "}\n"
2593 "h3 {"
2594 " font-family: helvetica, arial;"
2595 " font-size: 16px;"
2596 " font-weight: bold;"
2597 " color: #b00040;"
2598 " background: #e8e8d0;"
2599 " margin-top: 0em;"
2600 " margin-bottom: 0em;"
2601 "}\n"
2602 "li {"
2603 " margin-top: 0.25em;"
2604 " margin-right: 2em;"
2605 "}\n"
2606 ".hr {"
2607 " margin-top: 0.25em;"
2608 " border-color: black;"
2609 " border-bottom-style: solid;"
2610 "}\n"
2611 "table.tbl { border-collapse: collapse; border-width: 1px; border-style: solid; border-color: gray;}\n"
2612 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; border-color: gray; }\n"
2613 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray; }\n"
2614 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
2615 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
2616 "-->"
2617 "</style></head>");
2618
2619 if (buffer_write(rep, trash, msglen) != 0)
2620 return 0;
2621 msglen = 0;
2622
2623 up = (now.tv_sec - start_date.tv_sec);
2624
2625 /* WARNING! this has to fit the first packet too */
2626 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2627 "<body><h1>" PRODUCT_NAME "</h1>\n"
2628 "<h2>Statistics Report for pid %d</h2>\n"
2629 "<hr width=\"100%%\" class=\"hr\">\n"
2630 "<h3>&gt; General process information</h3>\n"
2631 "<table border=0><tr><td align=\"left\">\n"
2632 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
2633 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
2634 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
2635 "<b>maxsock = </b> %d<br>\n"
2636 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
2637 "</td><td width=\"10%%\">\n"
2638 "</td><td align=\"right\">\n"
2639 "<table class=\"lgd\">"
2640 "<tr><td bgcolor=\"#C0FFC0\">&nbsp;</td><td style=\"border-style: none;\">active UP </td>"
2641 "<td bgcolor=\"#B0D0FF\">&nbsp;</td><td style=\"border-style: none;\">backup UP </td></tr>"
2642 "<tr><td bgcolor=\"#FFFFA0\"></td><td style=\"border-style: none;\">active UP, going down </td>"
2643 "<td bgcolor=\"#C060FF\"></td><td style=\"border-style: none;\">backup UP, going down </td></tr>"
2644 "<tr><td bgcolor=\"#FFD020\"></td><td style=\"border-style: none;\">active DOWN, going up </td>"
2645 "<td bgcolor=\"#FF80FF\"></td><td style=\"border-style: none;\">backup DOWN, going up </td></tr>"
2646 "<tr><td bgcolor=\"#FF9090\"></td><td style=\"border-style: none;\">active or backup DOWN &nbsp;</td>"
2647 "<td bgcolor=\"#E0E0E0\"></td><td style=\"border-style: none;\">not checked </td></tr>"
2648 "</table>\n"
2649 "</tr></table>\n"
2650 "",
2651 pid, pid, global.nbproc,
2652 up / 86400, (up % 86400) / 3600,
2653 (up % 3600) / 60, (up % 60),
2654 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
2655 global.rlimit_memmax ? " MB" : "",
2656 global.rlimit_nofile,
2657 global.maxsock,
2658 global.maxconn,
2659 actconn
2660 );
2661
2662 if (buffer_write(rep, trash, msglen) != 0)
2663 return 0;
2664 msglen = 0;
2665
2666 s->data_state = DATA_ST_DATA;
2667 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
2668
2669 px = s->data_ctx.stats.px = proxy;
2670 s->data_ctx.stats.px_st = DATA_ST_INIT;
2671 }
2672
2673 while (s->data_ctx.stats.px) {
2674 int dispatch_sess, dispatch_cum;
2675 int failed_checks, down_trans;
2676 int failed_secu, failed_conns, failed_resp;
2677
2678 if (s->data_ctx.stats.px_st == DATA_ST_INIT) {
2679 /* we are on a new proxy */
2680 px = s->data_ctx.stats.px;
2681
2682 /* skip the disabled proxies */
2683 if (px->state == PR_STSTOPPED)
2684 goto next_proxy;
2685
Willy Tarreau73de9892006-11-30 11:40:23 +01002686 if (s->fi->uri_auth && s->fi->uri_auth->scope) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02002687 /* we have a limited scope, we have to check the proxy name */
2688 struct stat_scope *scope;
2689 int len;
2690
2691 len = strlen(px->id);
Willy Tarreau73de9892006-11-30 11:40:23 +01002692 scope = s->fi->uri_auth->scope;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002693
2694 while (scope) {
2695 /* match exact proxy name */
2696 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
2697 break;
2698
2699 /* match '.' which means 'self' proxy */
Willy Tarreau73de9892006-11-30 11:40:23 +01002700 if (!strcmp(scope->px_id, ".") && px == s->fe)
Willy Tarreaubaaee002006-06-26 02:48:02 +02002701 break;
2702 scope = scope->next;
2703 }
2704
2705 /* proxy name not found */
2706 if (scope == NULL)
2707 goto next_proxy;
2708 }
2709
2710 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2711 "<h3>&gt; Proxy instance %s : "
2712 "%d conns (maxconn=%d), %d queued (%d unassigned), %d total conns</h3>\n"
2713 "",
2714 px->id,
2715 px->nbconn, px->maxconn, px->totpend, px->nbpend, px->cum_conn);
2716
2717 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2718 "<table cols=\"16\" class=\"tbl\">\n"
2719 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
2720 "<th colspan=5>Server</th>"
2721 "<th colspan=2>Queue</th>"
2722 "<th colspan=4>Sessions</th>"
2723 "<th colspan=5>Errors</th></tr>\n"
2724 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
2725 "<th>Name</th><th>Weight</th><th>Status</th><th>Act.</th><th>Bck.</th>"
2726 "<th>Curr.</th><th>Max.</th>"
2727 "<th>Curr.</th><th>Max.</th><th>Limit</th><th>Cumul.</th>"
2728 "<th>Conn.</th><th>Resp.</th><th>Sec.</th><th>Check</th><th>Down</th></tr>\n");
2729
2730 if (buffer_write(rep, trash, msglen) != 0)
2731 return 0;
2732 msglen = 0;
2733
2734 s->data_ctx.stats.sv = px->srv;
2735 s->data_ctx.stats.px_st = DATA_ST_DATA;
2736 }
2737
2738 px = s->data_ctx.stats.px;
2739
2740 /* stats.sv has been initialized above */
2741 while (s->data_ctx.stats.sv != NULL) {
2742 static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
2743 static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
2744 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
2745 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
2746
2747 sv = s->data_ctx.stats.sv;
2748
2749 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
2750 if (!(sv->state & SRV_CHECKED))
2751 sv_state = 4;
2752 else if (sv->state & SRV_RUNNING)
2753 if (sv->health == sv->rise + sv->fall - 1)
2754 sv_state = 3; /* UP */
2755 else
2756 sv_state = 2; /* going down */
2757 else
2758 if (sv->health)
2759 sv_state = 1; /* going up */
2760 else
2761 sv_state = 0; /* DOWN */
2762
2763 /* name, weight */
2764 msglen += snprintf(trash, sizeof(trash),
2765 "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
2766 (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
2767 sv->id, sv->uweight+1);
2768 /* status */
2769 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, srv_hlt_st[sv_state],
2770 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
2771 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
2772
2773 /* act, bck */
2774 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2775 "</td><td>%s</td><td>%s</td>",
2776 (sv->state & SRV_BACKUP) ? "-" : "Y",
2777 (sv->state & SRV_BACKUP) ? "Y" : "-");
2778
2779 /* queue : current, max */
2780 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2781 "<td align=right>%d</td><td align=right>%d</td>",
2782 sv->nbpend, sv->nbpend_max);
2783
2784 /* sessions : current, max, limit, cumul */
2785 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2786 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>",
2787 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess);
2788
2789 /* errors : connect, response, security */
2790 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2791 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
2792 sv->failed_conns, sv->failed_resp, sv->failed_secu);
2793
2794 /* check failures : unique, fatal */
2795 if (sv->state & SRV_CHECKED)
2796 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2797 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
2798 sv->failed_checks, sv->down_trans);
2799 else
2800 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2801 "<td align=right>-</td><td align=right>-</td></tr>\n");
2802
2803 if (buffer_write(rep, trash, msglen) != 0)
2804 return 0;
2805 msglen = 0;
2806
2807 s->data_ctx.stats.sv = sv->next;
2808 } /* while sv */
2809
2810 /* now we are past the last server, we'll dump information about the dispatcher */
2811
2812 /* We have to count down from the proxy to the servers to tell how
2813 * many sessions are on the dispatcher, and how many checks have
2814 * failed. We cannot count this during the servers dump because it
2815 * might be interrupted multiple times.
2816 */
2817 dispatch_sess = px->nbconn;
2818 dispatch_cum = px->cum_conn;
2819 failed_secu = px->failed_secu;
2820 failed_conns = px->failed_conns;
2821 failed_resp = px->failed_resp;
2822 failed_checks = down_trans = 0;
2823
2824 sv = px->srv;
2825 while (sv) {
2826 dispatch_sess -= sv->cur_sess;
2827 dispatch_cum -= sv->cum_sess;
2828 failed_conns -= sv->failed_conns;
2829 failed_resp -= sv->failed_resp;
2830 failed_secu -= sv->failed_secu;
2831 if (sv->state & SRV_CHECKED) {
2832 failed_checks += sv->failed_checks;
2833 down_trans += sv->down_trans;
2834 }
2835 sv = sv->next;
2836 }
2837
2838 /* name, weight, status, act, bck */
2839 msglen += snprintf(trash + msglen, sizeof(trash),
2840 "<tr align=center bgcolor=\"#e8e8d0\">"
2841 "<td>Dispatcher</td><td>-</td>"
2842 "<td>%s</td><td>-</td><td>-</td>",
2843 px->state == PR_STRUN ? "UP" : "DOWN");
2844
2845 /* queue : current, max */
2846 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2847 "<td align=right>%d</td><td align=right>%d</td>",
2848 px->nbpend, px->nbpend_max);
2849
2850 /* sessions : current, max, limit, cumul. */
2851 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2852 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>",
2853 dispatch_sess, px->nbconn_max, px->maxconn, dispatch_cum);
2854
2855 /* errors : connect, response, security */
2856 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2857 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
2858 failed_conns, failed_resp, failed_secu);
2859
2860 /* check failures : unique, fatal */
2861 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2862 "<td align=right>-</td><td align=right>-</td></tr>\n");
2863
2864
2865 /* now the summary for the whole proxy */
2866 /* name, weight, status, act, bck */
2867 msglen += snprintf(trash + msglen, sizeof(trash),
2868 "<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
2869 "<td><b>Total</b></td><td>-</td>"
2870 "<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
2871 (px->state == PR_STRUN && ((px->srv == NULL) || px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
2872 px->srv_act, px->srv_bck);
2873
2874 /* queue : current, max */
2875 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2876 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
2877 px->totpend, px->nbpend_max);
2878
2879 /* sessions : current, max, limit, cumul */
2880 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2881 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
2882 px->nbconn, px->nbconn_max, px->maxconn, px->cum_conn);
2883
2884 /* errors : connect, response, security */
2885 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2886 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
2887 px->failed_conns, px->failed_resp, px->failed_secu);
2888
2889 /* check failures : unique, fatal */
2890 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2891 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
2892 failed_checks, down_trans);
2893
2894 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, "</table><p>\n");
2895
2896 if (buffer_write(rep, trash, msglen) != 0)
2897 return 0;
2898 msglen = 0;
2899
2900 s->data_ctx.stats.px_st = DATA_ST_INIT;
2901 next_proxy:
2902 s->data_ctx.stats.px = px->next;
2903 } /* proxy loop */
2904 /* here, we just have reached the sv == NULL and px == NULL */
2905 s->flags &= ~SN_SELF_GEN;
2906 return 1;
2907 }
2908 else {
2909 /* unknown data source */
2910 s->logs.status = 500;
Willy Tarreau73de9892006-11-30 11:40:23 +01002911 client_retnclose(s, s->fe->errmsg.len500, s->fe->errmsg.msg500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002912 if (!(s->flags & SN_ERR_MASK))
2913 s->flags |= SN_ERR_PRXCOND;
2914 if (!(s->flags & SN_FINST_MASK))
2915 s->flags |= SN_FINST_R;
2916 s->flags &= SN_SELF_GEN;
2917 return 1;
2918 }
2919}
2920
2921
Willy Tarreau58f10d72006-12-04 02:26:12 +01002922
2923/*
2924 * Apply all the req filters <exp> to all headers in buffer <req> of session <t>
2925 */
2926
2927void apply_filters_to_session(struct session *t, struct buffer *req, struct hdr_exp *exp)
2928{
2929 /* iterate through the filters in the outer loop */
2930 while (exp && !(t->flags & (SN_CLDENY|SN_CLTARPIT))) {
2931 char term;
2932 char *cur_ptr, *cur_end, *cur_next;
2933 int cur_idx, old_idx, abort_filt;
2934
2935
2936 /*
2937 * The interleaving of transformations and verdicts
2938 * makes it difficult to decide to continue or stop
2939 * the evaluation.
2940 */
2941
2942 if ((t->flags & SN_CLALLOW) &&
2943 (exp->action == ACT_ALLOW || exp->action == ACT_DENY ||
2944 exp->action == ACT_TARPIT || exp->action == ACT_PASS)) {
2945 exp = exp->next;
2946 continue;
2947 }
2948
2949 /* Iterate through the headers in the inner loop.
2950 * we start with the start line.
2951 */
2952 old_idx = cur_idx = 0;
Willy Tarreau45e73e32006-12-17 00:05:15 +01002953 cur_next = req->data + t->hreq.sor;
Willy Tarreau58f10d72006-12-04 02:26:12 +01002954 abort_filt = 0;
2955
Willy Tarreau45e73e32006-12-17 00:05:15 +01002956 while (!abort_filt && (cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
2957 struct hdr_idx_elem *cur_hdr = &t->hreq.hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01002958 cur_ptr = cur_next;
2959 cur_end = cur_ptr + cur_hdr->len;
2960 cur_next = cur_end + cur_hdr->cr + 1;
2961
2962 /* Now we have one header between cur_ptr and cur_end,
2963 * and the next header starts at cur_next.
2964 */
2965
2966 /* The annoying part is that pattern matching needs
2967 * that we modify the contents to null-terminate all
2968 * strings before testing them.
2969 */
2970
2971 term = *cur_end;
2972 *cur_end = '\0';
2973
2974 if (regexec(exp->preg, cur_ptr, MAX_MATCH, pmatch, 0) == 0) {
2975 switch (exp->action) {
2976 case ACT_ALLOW:
2977 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
2978 t->flags |= SN_CLALLOW;
2979 abort_filt = 1;
2980 }
2981 break;
2982 case ACT_REPLACE:
2983 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
2984 int len, delta;
2985 len = exp_replace(trash, cur_ptr, exp->replace, pmatch);
2986 delta = buffer_replace2(req, cur_ptr, cur_end, trash, len);
Willy Tarreaue15d9132006-12-14 22:26:42 +01002987 /* FIXME: if the user adds a newline in the replacement, the
2988 * index will not be recalculated for now, and the new line
2989 * will not be counted for a new header.
2990 */
Willy Tarreau58f10d72006-12-04 02:26:12 +01002991 cur_end += delta;
2992 cur_next += delta;
2993 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01002994 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01002995 }
2996 break;
2997 case ACT_REMOVE:
2998 if (!(t->flags & (SN_CLDENY | SN_CLTARPIT))) {
2999 int delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
3000 cur_next += delta;
3001
3002 /* FIXME: this should be a separate function */
Willy Tarreau45e73e32006-12-17 00:05:15 +01003003 t->hreq.eoh += delta;
3004 t->hreq.hdr_idx.v[old_idx].next = cur_hdr->next;
3005 t->hreq.hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003006 cur_hdr->len = 0;
3007
3008 cur_end = NULL; /* null-term has been rewritten */
3009 }
3010 break;
3011 case ACT_DENY:
3012 if (!(t->flags & (SN_CLALLOW | SN_CLTARPIT))) {
3013 t->flags |= SN_CLDENY;
3014 abort_filt = 1;
3015 }
3016 break;
3017 case ACT_TARPIT:
3018 if (!(t->flags & (SN_CLALLOW | SN_CLDENY))) {
3019 t->flags |= SN_CLTARPIT;
3020 abort_filt = 1;
3021 }
3022 break;
3023 //case ACT_PASS: /* FIXME: broken as of now. We should mark the header as "ignored". */
3024 // break;
3025 }
3026 }
3027 if (cur_end)
3028 *cur_end = term; /* restore the string terminator */
3029
3030 /* keep the link from this header to next one */
3031 old_idx = cur_idx;
3032 }
3033 exp = exp->next;
3034 }
3035}
3036
3037
3038
3039/*
3040 * Manager client-side cookie
3041 */
3042void manage_client_side_cookies(struct session *t, struct buffer *req)
3043{
3044 char *p1, *p2, *p3, *p4;
3045 char *del_colon, *del_cookie, *colon;
3046 int app_cookies;
3047
3048 appsess *asession_temp = NULL;
3049 appsess local_asession;
3050
3051 char *cur_ptr, *cur_end, *cur_next;
3052 int cur_idx, old_idx, abort_filt;
3053
3054 if (t->be->cookie_name == NULL &&
3055 t->be->appsession_name ==NULL &&
3056 t->fi->capture_name != NULL)
3057 return;
3058
3059
3060
Willy Tarreau2a324282006-12-05 00:05:46 +01003061 /* Iterate through the headers.
Willy Tarreau58f10d72006-12-04 02:26:12 +01003062 * we start with the start line.
3063 */
3064 old_idx = cur_idx = 0;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003065 cur_next = req->data + t->hreq.sor;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003066 abort_filt = 0;
3067
Willy Tarreau45e73e32006-12-17 00:05:15 +01003068 while ((cur_idx = t->hreq.hdr_idx.v[cur_idx].next)) {
Willy Tarreau58f10d72006-12-04 02:26:12 +01003069 struct hdr_idx_elem *cur_hdr;
3070
Willy Tarreau45e73e32006-12-17 00:05:15 +01003071 cur_hdr = &t->hreq.hdr_idx.v[cur_idx];
Willy Tarreau58f10d72006-12-04 02:26:12 +01003072 cur_ptr = cur_next;
3073 cur_end = cur_ptr + cur_hdr->len;
3074 cur_next = cur_end + cur_hdr->cr + 1;
3075
3076 /* We have one full header between cur_ptr and cur_end, and the
3077 * next header starts at cur_next. We're only interested in
3078 * "Cookie:" headers.
3079 */
3080
3081 if ((cur_end - cur_ptr <= 7) ||
3082 (strncasecmp(cur_ptr, "Cookie:", 7) != 0)) {
3083 old_idx = cur_idx;
3084 continue;
3085 }
3086
3087 /* Now look for cookies. Conforming to RFC2109, we have to support
3088 * attributes whose name begin with a '$', and associate them with
3089 * the right cookie, if we want to delete this cookie.
3090 * So there are 3 cases for each cookie read :
3091 * 1) it's a special attribute, beginning with a '$' : ignore it.
3092 * 2) it's a server id cookie that we *MAY* want to delete : save
3093 * some pointers on it (last semi-colon, beginning of cookie...)
3094 * 3) it's an application cookie : we *MAY* have to delete a previous
3095 * "special" cookie.
3096 * At the end of loop, if a "special" cookie remains, we may have to
3097 * remove it. If no application cookie persists in the header, we
3098 * *MUST* delete it
3099 */
3100
3101
3102 p1 = cur_ptr + 7; /* first char after 'Cookie:' */
3103 if (isspace((int)*p1)) /* try to get the first space with it */
3104 p1++;
3105
3106 colon = p1;
3107 /* del_cookie == NULL => nothing to be deleted */
3108 del_colon = del_cookie = NULL;
3109 app_cookies = 0;
3110
3111 while (p1 < cur_end) {
3112 /* skip spaces and colons, but keep an eye on these ones */
3113 while (p1 < cur_end) {
3114 if (*p1 == ';' || *p1 == ',')
3115 colon = p1;
3116 else if (!isspace((int)*p1))
3117 break;
3118 p1++;
3119 }
3120
3121 if (p1 == cur_end)
3122 break;
3123
3124 /* p1 is at the beginning of the cookie name */
3125 p2 = p1;
3126 while (p2 < cur_end && *p2 != '=')
3127 p2++;
3128
3129 if (p2 == cur_end)
3130 break;
3131
3132 p3 = p2 + 1; /* skips the '=' sign */
3133 if (p3 == cur_end)
3134 break;
3135
3136 p4 = p3;
3137 while (p4 < cur_end && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
3138 p4++;
3139
3140 /* here, we have the cookie name between p1 and p2,
3141 * and its value between p3 and p4.
3142 * we can process it :
3143 *
3144 * Cookie: NAME=VALUE;
3145 * | || || |
3146 * | || || +--> p4
3147 * | || |+-------> p3
3148 * | || +--------> p2
3149 * | |+------------> p1
3150 * | +-------------> colon
3151 * +--------------------> cur_ptr
3152 */
3153
3154 if (*p1 == '$') {
3155 /* skip this one */
3156 }
3157 else {
3158 /* first, let's see if we want to capture it */
3159 if (t->fi->capture_name != NULL &&
3160 t->logs.cli_cookie == NULL &&
3161 (p4 - p1 >= t->fi->capture_namelen) &&
3162 memcmp(p1, t->fi->capture_name, t->fi->capture_namelen) == 0) {
3163 int log_len = p4 - p1;
3164
3165 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
3166 Alert("HTTP logging : out of memory.\n");
3167 } else {
3168 if (log_len > t->fi->capture_len)
3169 log_len = t->fi->capture_len;
3170 memcpy(t->logs.cli_cookie, p1, log_len);
3171 t->logs.cli_cookie[log_len] = 0;
3172 }
3173 }
3174
3175 if ((p2 - p1 == t->be->cookie_len) && (t->be->cookie_name != NULL) &&
3176 (memcmp(p1, t->be->cookie_name, p2 - p1) == 0)) {
3177 /* Cool... it's the right one */
3178 struct server *srv = t->be->srv;
3179 char *delim;
3180
3181 /* if we're in cookie prefix mode, we'll search the delimitor so that we
3182 * have the server ID betweek p3 and delim, and the original cookie between
3183 * delim+1 and p4. Otherwise, delim==p4 :
3184 *
3185 * Cookie: NAME=SRV~VALUE;
3186 * | || || | |
3187 * | || || | +--> p4
3188 * | || || +--------> delim
3189 * | || |+-----------> p3
3190 * | || +------------> p2
3191 * | |+----------------> p1
3192 * | +-----------------> colon
3193 * +------------------------> cur_ptr
3194 */
3195
3196 if (t->be->options & PR_O_COOK_PFX) {
3197 for (delim = p3; delim < p4; delim++)
3198 if (*delim == COOKIE_DELIM)
3199 break;
3200 }
3201 else
3202 delim = p4;
3203
3204
3205 /* Here, we'll look for the first running server which supports the cookie.
3206 * This allows to share a same cookie between several servers, for example
3207 * to dedicate backup servers to specific servers only.
3208 * However, to prevent clients from sticking to cookie-less backup server
3209 * when they have incidentely learned an empty cookie, we simply ignore
3210 * empty cookies and mark them as invalid.
3211 */
3212 if (delim == p3)
3213 srv = NULL;
3214
3215 while (srv) {
3216 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
3217 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
3218 /* we found the server and it's usable */
3219 t->flags &= ~SN_CK_MASK;
3220 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3221 t->srv = srv;
3222 break;
3223 } else {
3224 /* we found a server, but it's down */
3225 t->flags &= ~SN_CK_MASK;
3226 t->flags |= SN_CK_DOWN;
3227 }
3228 }
3229 srv = srv->next;
3230 }
3231
3232 if (!srv && !(t->flags & SN_CK_DOWN)) {
3233 /* no server matched this cookie */
3234 t->flags &= ~SN_CK_MASK;
3235 t->flags |= SN_CK_INVALID;
3236 }
3237
3238 /* depending on the cookie mode, we may have to either :
3239 * - delete the complete cookie if we're in insert+indirect mode, so that
3240 * the server never sees it ;
3241 * - remove the server id from the cookie value, and tag the cookie as an
3242 * application cookie so that it does not get accidentely removed later,
3243 * if we're in cookie prefix mode
3244 */
3245 if ((t->be->options & PR_O_COOK_PFX) && (delim != p4)) {
3246 int delta; /* negative */
3247
3248 delta = buffer_replace2(req, p3, delim + 1, NULL, 0);
3249 p4 += delta;
3250 cur_end += delta;
3251 cur_next += delta;
3252 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003253 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003254
3255 del_cookie = del_colon = NULL;
3256 app_cookies++; /* protect the header from deletion */
3257 }
3258 else if (del_cookie == NULL &&
3259 (t->be->options & (PR_O_COOK_INS | PR_O_COOK_IND)) == (PR_O_COOK_INS | PR_O_COOK_IND)) {
3260 del_cookie = p1;
3261 del_colon = colon;
3262 }
3263 } else {
3264 /* now we know that we must keep this cookie since it's
3265 * not ours. But if we wanted to delete our cookie
3266 * earlier, we cannot remove the complete header, but we
3267 * can remove the previous block itself.
3268 */
3269 app_cookies++;
3270
3271 if (del_cookie != NULL) {
3272 int delta; /* negative */
3273
3274 delta = buffer_replace2(req, del_cookie, p1, NULL, 0);
3275 p4 += delta;
3276 cur_end += delta;
3277 cur_next += delta;
3278 cur_hdr->len += delta;
Willy Tarreau45e73e32006-12-17 00:05:15 +01003279 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003280 del_cookie = del_colon = NULL;
3281 }
3282 }
3283
3284 if ((t->be->appsession_name != NULL) &&
3285 (memcmp(p1, t->be->appsession_name, p2 - p1) == 0)) {
3286 /* first, let's see if the cookie is our appcookie*/
3287
3288 /* Cool... it's the right one */
3289
3290 asession_temp = &local_asession;
3291
3292 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3293 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
3294 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
3295 return;
3296 }
3297
3298 memcpy(asession_temp->sessid, p3, t->be->appsession_len);
3299 asession_temp->sessid[t->be->appsession_len] = 0;
3300 asession_temp->serverid = NULL;
3301
3302 /* only do insert, if lookup fails */
3303 if (chtbl_lookup(&(t->be->htbl_proxy), (void *) &asession_temp) != 0) {
3304 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3305 /* free previously allocated memory */
3306 pool_free_to(apools.sessid, local_asession.sessid);
3307 Alert("Not enough memory process_cli():asession:calloc().\n");
3308 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3309 return;
3310 }
3311
3312 asession_temp->sessid = local_asession.sessid;
3313 asession_temp->serverid = local_asession.serverid;
3314 chtbl_insert(&(t->be->htbl_proxy), (void *) asession_temp);
3315 } else {
3316 /* free previously allocated memory */
3317 pool_free_to(apools.sessid, local_asession.sessid);
3318 }
3319
3320 if (asession_temp->serverid == NULL) {
3321 Alert("Found Application Session without matching server.\n");
3322 } else {
3323 struct server *srv = t->be->srv;
3324 while (srv) {
3325 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3326 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
3327 /* we found the server and it's usable */
3328 t->flags &= ~SN_CK_MASK;
3329 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3330 t->srv = srv;
3331 break;
3332 } else {
3333 t->flags &= ~SN_CK_MASK;
3334 t->flags |= SN_CK_DOWN;
3335 }
3336 }
3337 srv = srv->next;
3338 }/* end while(srv) */
3339 }/* end else if server == NULL */
3340
3341 tv_delayfrom(&asession_temp->expire, &now, t->be->appsession_timeout);
3342 }/* end if ((t->proxy->appsession_name != NULL) ... */
3343 }
3344
3345 /* we'll have to look for another cookie ... */
3346 p1 = p4;
3347 } /* while (p1 < cur_end) */
3348
3349 /* There's no more cookie on this line.
3350 * We may have marked the last one(s) for deletion.
3351 * We must do this now in two ways :
3352 * - if there is no app cookie, we simply delete the header ;
3353 * - if there are app cookies, we must delete the end of the
3354 * string properly, including the colon/semi-colon before
3355 * the cookie name.
3356 */
3357 if (del_cookie != NULL) {
3358 int delta;
3359 if (app_cookies) {
3360 delta = buffer_replace2(req, del_colon, cur_end, NULL, 0);
3361 cur_end = del_colon;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003362 cur_hdr->len += delta;
3363 } else {
3364 delta = buffer_replace2(req, cur_ptr, cur_next, NULL, 0);
Willy Tarreau58f10d72006-12-04 02:26:12 +01003365
3366 /* FIXME: this should be a separate function */
Willy Tarreau45e73e32006-12-17 00:05:15 +01003367 t->hreq.hdr_idx.v[old_idx].next = cur_hdr->next;
3368 t->hreq.hdr_idx.used--;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003369 cur_hdr->len = 0;
3370 }
Willy Tarreau45e73e32006-12-17 00:05:15 +01003371 cur_next += delta;
3372 t->hreq.eoh += delta;
Willy Tarreau58f10d72006-12-04 02:26:12 +01003373 }
3374
3375 /* keep the link from this header to next one */
3376 old_idx = cur_idx;
3377 } /* end of cookie processing on this header */
3378}
3379
3380
3381
3382/*
3383 * Try to retrieve a known appsession in the URI, then the associated server.
3384 * If the server is found, it's assigned to the session.
3385 */
3386
3387void get_srv_from_appsession(struct session *t, const char *begin, const char *end)
3388{
3389 appsess *asession_temp = NULL;
3390 appsess local_asession;
3391 char *request_line;
3392
3393 if (t->be->appsession_name == NULL ||
3394 (memcmp(begin, "GET ", 4) != 0 && memcmp(begin, "POST ", 5) != 0) ||
3395 (request_line = memchr(begin, ';', end - begin)) == NULL ||
3396 ((1 + t->be->appsession_name_len + 1 + t->be->appsession_len) > (end - request_line)))
3397 return;
3398
3399 /* skip ';' */
3400 request_line++;
3401
3402 /* look if we have a jsessionid */
3403 if (strncasecmp(request_line, t->be->appsession_name, t->be->appsession_name_len) != 0)
3404 return;
3405
3406 /* skip jsessionid= */
3407 request_line += t->be->appsession_name_len + 1;
3408
3409 /* First try if we already have an appsession */
3410 asession_temp = &local_asession;
3411
3412 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
3413 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
3414 send_log(t->be, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
3415 return;
3416 }
3417
3418 /* Copy the sessionid */
3419 memcpy(asession_temp->sessid, request_line, t->be->appsession_len);
3420 asession_temp->sessid[t->be->appsession_len] = 0;
3421 asession_temp->serverid = NULL;
3422
3423 /* only do insert, if lookup fails */
3424 if (chtbl_lookup(&(t->be->htbl_proxy), (void *)&asession_temp)) {
3425 if ((asession_temp = pool_alloc(appsess)) == NULL) {
3426 /* free previously allocated memory */
3427 pool_free_to(apools.sessid, local_asession.sessid);
3428 Alert("Not enough memory process_cli():asession:calloc().\n");
3429 send_log(t->be, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
3430 return;
3431 }
3432 asession_temp->sessid = local_asession.sessid;
3433 asession_temp->serverid = local_asession.serverid;
3434 chtbl_insert(&(t->be->htbl_proxy), (void *) asession_temp);
3435 }
3436 else {
3437 /* free previously allocated memory */
3438 pool_free_to(apools.sessid, local_asession.sessid);
3439 }
3440
3441 tv_delayfrom(&asession_temp->expire, &now, t->be->appsession_timeout);
3442 asession_temp->request_count++;
3443
3444#if defined(DEBUG_HASH)
3445 print_table(&(t->proxy->htbl_proxy));
3446#endif
3447 if (asession_temp->serverid == NULL) {
3448 Alert("Found Application Session without matching server.\n");
3449 } else {
3450 struct server *srv = t->be->srv;
3451 while (srv) {
3452 if (strcmp(srv->id, asession_temp->serverid) == 0) {
3453 if (srv->state & SRV_RUNNING || t->be->options & PR_O_PERSIST) {
3454 /* we found the server and it's usable */
3455 t->flags &= ~SN_CK_MASK;
3456 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
3457 t->srv = srv;
3458 break;
3459 } else {
3460 t->flags &= ~SN_CK_MASK;
3461 t->flags |= SN_CK_DOWN;
3462 }
3463 }
3464 srv = srv->next;
3465 }
3466 }
3467}
3468
3469
Willy Tarreaubaaee002006-06-26 02:48:02 +02003470/*
Willy Tarreau58f10d72006-12-04 02:26:12 +01003471 * Print a debug line with a header
3472 */
3473void debug_hdr(const char *dir, struct session *t, const char *start, const char *end)
3474{
3475 int len, max;
3476 len = sprintf(trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
3477 dir, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
3478 max = end - start;
3479 UBOUND(max, sizeof(trash) - len - 1);
3480 len += strlcpy2(trash + len, start, max + 1);
3481 trash[len++] = '\n';
3482 write(1, trash, len);
3483}
3484
3485
3486/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02003487 * Local variables:
3488 * c-indent-level: 8
3489 * c-basic-offset: 8
3490 * End:
3491 */