blob: d4e97641d47e048e110fe0656b2e281ff0bba52f [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>
28#include <common/memory.h>
29#include <common/mini-clist.h>
30#include <common/standard.h>
31#include <common/time.h>
32#include <common/uri_auth.h>
33#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020034
35#include <types/capture.h>
36#include <types/client.h>
37#include <types/global.h>
38#include <types/httperr.h>
39#include <types/polling.h>
40#include <types/proxy.h>
41#include <types/server.h>
42
43#include <proto/backend.h>
44#include <proto/buffers.h>
45#include <proto/fd.h>
46#include <proto/log.h>
47#include <proto/proto_http.h>
48#include <proto/queue.h>
49#include <proto/session.h>
50#include <proto/task.h>
51
52
Willy Tarreau1c47f852006-07-09 08:22:27 +020053/* This is used by remote monitoring */
54const char *HTTP_200 =
55 "HTTP/1.0 200 OK\r\n"
56 "Cache-Control: no-cache\r\n"
57 "Connection: close\r\n"
58 "Content-Type: text/html\r\n"
59 "\r\n"
60 "<html><body><h1>200 OK</h1>\nHAProxy: service ready.\n</body></html>\n";
61
Willy Tarreaubaaee002006-06-26 02:48:02 +020062/* Warning: this one is an sprintf() fmt string, with <realm> as its only argument */
63const char *HTTP_401_fmt =
64 "HTTP/1.0 401 Unauthorized\r\n"
65 "Cache-Control: no-cache\r\n"
66 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +020067 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +020068 "WWW-Authenticate: Basic realm=\"%s\"\r\n"
69 "\r\n"
70 "<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n";
71
72
73#ifdef DEBUG_FULL
74static char *cli_stnames[5] = {"HDR", "DAT", "SHR", "SHW", "CLS" };
75static char *srv_stnames[7] = {"IDL", "CON", "HDR", "DAT", "SHR", "SHW", "CLS" };
76#endif
77
78
79/*
80 * returns a message to the client ; the connection is shut down for read,
81 * and the request is cleared so that no server connection can be initiated.
82 * The client must be in a valid state for this (HEADER, DATA ...).
83 * Nothing is performed on the server side.
84 * The reply buffer doesn't need to be empty before this.
85 */
86void client_retnclose(struct session *s, int len, const char *msg)
87{
88 FD_CLR(s->cli_fd, StaticReadEvent);
89 FD_SET(s->cli_fd, StaticWriteEvent);
90 tv_eternity(&s->crexpire);
91 if (s->proxy->clitimeout)
92 tv_delayfrom(&s->cwexpire, &now, s->proxy->clitimeout);
93 else
94 tv_eternity(&s->cwexpire);
95 shutdown(s->cli_fd, SHUT_RD);
96 s->cli_state = CL_STSHUTR;
97 buffer_flush(s->rep);
98 buffer_write(s->rep, msg, len);
99 s->req->l = 0;
100}
101
102
103/*
104 * returns a message into the rep buffer, and flushes the req buffer.
105 * The reply buffer doesn't need to be empty before this.
106 */
107void client_return(struct session *s, int len, const char *msg)
108{
109 buffer_flush(s->rep);
110 buffer_write(s->rep, msg, len);
111 s->req->l = 0;
112}
113
114
115/* This function turns the server state into the SV_STCLOSE, and sets
116 * indicators accordingly. Note that if <status> is 0, no message is
117 * returned.
118 */
119void srv_close_with_err(struct session *t, int err, int finst,
120 int status, int msglen, char *msg)
121{
122 t->srv_state = SV_STCLOSE;
123 if (status > 0) {
124 t->logs.status = status;
125 if (t->proxy->mode == PR_MODE_HTTP)
126 client_return(t, msglen, msg);
127 }
128 if (!(t->flags & SN_ERR_MASK))
129 t->flags |= err;
130 if (!(t->flags & SN_FINST_MASK))
131 t->flags |= finst;
132}
133
134
135/* Processes the client and server jobs of a session task, then
136 * puts it back to the wait queue in a clean state, or
137 * cleans up its resources if it must be deleted. Returns
138 * the time the task accepts to wait, or TIME_ETERNITY for
139 * infinity.
140 */
141int process_session(struct task *t)
142{
143 struct session *s = t->context;
144 int fsm_resync = 0;
145
146 do {
147 fsm_resync = 0;
148 //fprintf(stderr,"before_cli:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
149 fsm_resync |= process_cli(s);
150 //fprintf(stderr,"cli/srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
151 fsm_resync |= process_srv(s);
152 //fprintf(stderr,"after_srv:cli=%d, srv=%d\n", s->cli_state, s->srv_state);
153 } while (fsm_resync);
154
155 if (s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE) {
156 struct timeval min1, min2;
157 s->res_cw = s->res_cr = s->res_sw = s->res_sr = RES_SILENT;
158
159 tv_min(&min1, &s->crexpire, &s->cwexpire);
160 tv_min(&min2, &s->srexpire, &s->swexpire);
161 tv_min(&min1, &min1, &s->cnexpire);
162 tv_min(&t->expire, &min1, &min2);
163
164 /* restore t to its place in the task list */
165 task_queue(t);
166
167#ifdef DEBUG_FULL
168 /* DEBUG code : this should never ever happen, otherwise it indicates
169 * that a task still has something to do and will provoke a quick loop.
170 */
171 if (tv_remain2(&now, &t->expire) <= 0)
172 exit(100);
173#endif
174
175 return tv_remain2(&now, &t->expire); /* nothing more to do */
176 }
177
178 s->proxy->nbconn--;
179 actconn--;
180
181 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
182 int len;
183 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n", s->uniq_id, s->proxy->id, (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
184 write(1, trash, len);
185 }
186
187 s->logs.t_close = tv_diff(&s->logs.tv_accept, &now);
188 if (s->rep != NULL)
189 s->logs.bytes = s->rep->total;
190
191 /* let's do a final log if we need it */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200192 if (s->logs.logwait &&
193 !(s->flags & SN_MONITOR) &&
194 (!(s->proxy->options & PR_O_NULLNOLOG) || s->req->total))
Willy Tarreaubaaee002006-06-26 02:48:02 +0200195 sess_log(s);
196
197 /* the task MUST not be in the run queue anymore */
198 task_delete(t);
199 session_free(s);
200 task_free(t);
201 return TIME_ETERNITY; /* rest in peace for eternity */
202}
203
204
205/*
206 * FIXME: This should move to the HTTP_flow_analyzer code
207 */
208
209/*
210 * manages the client FSM and its socket. BTW, it also tries to handle the
211 * cookie. It returns 1 if a state has changed (and a resync may be needed),
212 * 0 else.
213 */
214int process_cli(struct session *t)
215{
216 int s = t->srv_state;
217 int c = t->cli_state;
218 struct buffer *req = t->req;
219 struct buffer *rep = t->rep;
220 int method_checked = 0;
221 appsess *asession_temp = NULL;
222 appsess local_asession;
223
224#ifdef DEBUG_FULL
225 fprintf(stderr,"process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%d.%d,%d.%d\n",
226 cli_stnames[c], srv_stnames[s],
227 FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
228 t->crexpire.tv_sec, t->crexpire.tv_usec,
229 t->cwexpire.tv_sec, t->cwexpire.tv_usec);
230#endif
231 //fprintf(stderr,"process_cli: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
232 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
233 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
234 //);
235 if (c == CL_STHEADERS) {
236 /* now parse the partial (or complete) headers */
237 while (req->lr < req->r) { /* this loop only sees one header at each iteration */
238 char *ptr;
239 int delete_header;
240 char *request_line = NULL;
241
242 ptr = req->lr;
243
244 /* look for the end of the current header */
245 while (ptr < req->r && *ptr != '\n' && *ptr != '\r')
246 ptr++;
247
248 if (ptr == req->h) { /* empty line, end of headers */
249 int line, len;
250
251 /*
252 * first, let's check that it's not a leading empty line, in
253 * which case we'll ignore and remove it (according to RFC2616).
254 */
255 if (req->h == req->data) {
256 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
257 if (ptr > req->r - 2) {
258 /* this is a partial header, let's wait for more to come */
259 req->lr = ptr;
260 break;
261 }
262
263 /* now we know that *ptr is either \r or \n,
264 * and that there are at least 1 char after it.
265 */
266 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
267 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
268 else
269 req->lr = ptr + 2; /* \r\n or \n\r */
270 /* ignore empty leading lines */
271 buffer_replace2(req, req->h, req->lr, NULL, 0);
272 req->h = req->lr;
273 continue;
274 }
275
276 /* we can only get here after an end of headers */
277 /* we'll have something else to do here : add new headers ... */
278
279 if (t->flags & SN_CLDENY) {
280 /* no need to go further */
281 t->logs.status = 403;
282 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now); /* let's log the request time */
283 client_retnclose(t, t->proxy->errmsg.len403, t->proxy->errmsg.msg403);
284 if (!(t->flags & SN_ERR_MASK))
285 t->flags |= SN_ERR_PRXCOND;
286 if (!(t->flags & SN_FINST_MASK))
287 t->flags |= SN_FINST_R;
288 return 1;
289 }
290
291 /* Right now, we know that we have processed the entire headers
292 * and that unwanted requests have been filtered out. We can do
293 * whatever we want.
294 */
Willy Tarreau1c47f852006-07-09 08:22:27 +0200295
296
297 /* check if the URI matches the monitor_uri. To speed-up the
298 * test, we include the leading and trailing spaces in the
299 * comparison.
300 */
301 if ((t->proxy->monitor_uri_len != 0) &&
302 (t->req_line.len >= t->proxy->monitor_uri_len)) {
303 char *p = t->req_line.str;
304 int idx = 0;
305
306 /* skip the method so that we accept any method */
307 while (idx < t->req_line.len && p[idx] != ' ')
308 idx++;
309 p += idx;
310
311 if (t->req_line.len - idx >= t->proxy->monitor_uri_len &&
312 !memcmp(p, t->proxy->monitor_uri, t->proxy->monitor_uri_len)) {
313 /*
314 * We have found the monitor URI
315 */
316 t->flags |= SN_MONITOR;
317 t->logs.status = 200;
318 client_retnclose(t, strlen(HTTP_200), HTTP_200);
319 if (!(t->flags & SN_ERR_MASK))
320 t->flags |= SN_ERR_PRXCOND;
321 if (!(t->flags & SN_FINST_MASK))
322 t->flags |= SN_FINST_R;
323 return 1;
324 }
325 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200326
327 if (t->proxy->uri_auth != NULL
328 && t->req_line.len >= t->proxy->uri_auth->uri_len + 4) { /* +4 for "GET /" */
329 if (!memcmp(t->req_line.str + 4,
330 t->proxy->uri_auth->uri_prefix, t->proxy->uri_auth->uri_len)
331 && !memcmp(t->req_line.str, "GET ", 4)) {
332 struct user_auth *user;
333 int authenticated;
334
335 /* we are in front of a interceptable URI. Let's check
336 * if there's an authentication and if it's valid.
337 */
338 user = t->proxy->uri_auth->users;
339 if (!user) {
340 /* no user auth required, it's OK */
341 authenticated = 1;
342 } else {
343 authenticated = 0;
344
345 /* a user list is defined, we have to check.
346 * skip 21 chars for "Authorization: Basic ".
347 */
348 if (t->auth_hdr.len < 21 || memcmp(t->auth_hdr.str + 14, " Basic ", 7))
349 user = NULL;
350
351 while (user) {
352 if ((t->auth_hdr.len == user->user_len + 21)
353 && !memcmp(t->auth_hdr.str+21, user->user_pwd, user->user_len)) {
354 authenticated = 1;
355 break;
356 }
357 user = user->next;
358 }
359 }
360
361 if (!authenticated) {
362 int msglen;
363
364 /* no need to go further */
365
366 msglen = sprintf(trash, HTTP_401_fmt, t->proxy->uri_auth->auth_realm);
367 t->logs.status = 401;
368 client_retnclose(t, msglen, trash);
369 if (!(t->flags & SN_ERR_MASK))
370 t->flags |= SN_ERR_PRXCOND;
371 if (!(t->flags & SN_FINST_MASK))
372 t->flags |= SN_FINST_R;
373 return 1;
374 }
375
376 t->cli_state = CL_STSHUTR;
377 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
378 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
379 t->data_source = DATA_SRC_STATS;
380 t->data_state = DATA_ST_INIT;
381 produce_content(t);
382 return 1;
383 }
384 }
385
386
387 for (line = 0; line < t->proxy->nb_reqadd; line++) {
388 len = sprintf(trash, "%s\r\n", t->proxy->req_add[line]);
389 buffer_replace2(req, req->h, req->h, trash, len);
390 }
391
392 if (t->proxy->options & PR_O_FWDFOR) {
393 if (t->cli_addr.ss_family == AF_INET) {
394 unsigned char *pn;
395 pn = (unsigned char *)&((struct sockaddr_in *)&t->cli_addr)->sin_addr;
396 len = sprintf(trash, "X-Forwarded-For: %d.%d.%d.%d\r\n",
397 pn[0], pn[1], pn[2], pn[3]);
398 buffer_replace2(req, req->h, req->h, trash, len);
399 }
400 else if (t->cli_addr.ss_family == AF_INET6) {
401 char pn[INET6_ADDRSTRLEN];
402 inet_ntop(AF_INET6,
403 (const void *)&((struct sockaddr_in6 *)(&t->cli_addr))->sin6_addr,
404 pn, sizeof(pn));
405 len = sprintf(trash, "X-Forwarded-For: %s\r\n", pn);
406 buffer_replace2(req, req->h, req->h, trash, len);
407 }
408 }
409
410 /* add a "connection: close" line if needed */
411 if (t->proxy->options & PR_O_HTTP_CLOSE)
412 buffer_replace2(req, req->h, req->h, "Connection: close\r\n", 19);
413
414 if (!memcmp(req->data, "POST ", 5)) {
415 /* this is a POST request, which is not cacheable by default */
416 t->flags |= SN_POST;
417 }
418
419 t->cli_state = CL_STDATA;
420 req->rlim = req->data + BUFSIZE; /* no more rewrite needed */
421
422 t->logs.t_request = tv_diff(&t->logs.tv_accept, &now);
423 /* FIXME: we'll set the client in a wait state while we try to
424 * connect to the server. Is this really needed ? wouldn't it be
425 * better to release the maximum of system buffers instead ?
426 * The solution is to enable the FD but set its time-out to
427 * eternity as long as the server-side does not enable data xfer.
428 * CL_STDATA also has to take care of this, which is done below.
429 */
430 //FD_CLR(t->cli_fd, StaticReadEvent);
431 //tv_eternity(&t->crexpire);
432
433 /* FIXME: if we break here (as up to 1.1.23), having the client
434 * shutdown its connection can lead to an abort further.
435 * it's better to either return 1 or even jump directly to the
436 * data state which will save one schedule.
437 */
438 //break;
439
440 if (!t->proxy->clitimeout ||
441 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
442 /* If the client has no timeout, or if the server is not ready yet,
443 * and we know for sure that it can expire, then it's cleaner to
444 * disable the timeout on the client side so that too low values
445 * cannot make the sessions abort too early.
446 *
447 * FIXME-20050705: the server needs a way to re-enable this time-out
448 * when it switches its state, otherwise a client can stay connected
449 * indefinitely. This now seems to be OK.
450 */
451 tv_eternity(&t->crexpire);
452
453 goto process_data;
454 }
455
456 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
457 if (ptr > req->r - 2) {
458 /* this is a partial header, let's wait for more to come */
459 req->lr = ptr;
460 break;
461 }
462
463 /* now we know that *ptr is either \r or \n,
464 * and that there are at least 1 char after it.
465 */
466 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
467 req->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
468 else
469 req->lr = ptr + 2; /* \r\n or \n\r */
470
471 /*
472 * now we know that we have a full header ; we can do whatever
473 * we want with these pointers :
474 * req->h = beginning of header
475 * ptr = end of header (first \r or \n)
476 * req->lr = beginning of next line (next rep->h)
477 * req->r = end of data (not used at this stage)
478 */
479
480 if (!method_checked && (t->proxy->appsession_name != NULL) &&
481 ((memcmp(req->h, "GET ", 4) == 0) || (memcmp(req->h, "POST ", 4) == 0)) &&
482 ((request_line = memchr(req->h, ';', req->lr - req->h)) != NULL)) {
483
484 /* skip ; */
485 request_line++;
486
487 /* look if we have a jsessionid */
488
489 if (strncasecmp(request_line, t->proxy->appsession_name, t->proxy->appsession_name_len) == 0) {
490
491 /* skip jsessionid= */
492 request_line += t->proxy->appsession_name_len + 1;
493
494 /* First try if we allready have an appsession */
495 asession_temp = &local_asession;
496
497 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
498 Alert("Not enough memory process_cli():asession_temp->sessid:calloc().\n");
499 send_log(t->proxy, LOG_ALERT, "Not enough Memory process_cli():asession_temp->sessid:calloc().\n");
500 return 0;
501 }
502
503 /* Copy the sessionid */
504 memcpy(asession_temp->sessid, request_line, t->proxy->appsession_len);
505 asession_temp->sessid[t->proxy->appsession_len] = 0;
506 asession_temp->serverid = NULL;
507
508 /* only do insert, if lookup fails */
509 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *)&asession_temp)) {
510 if ((asession_temp = pool_alloc(appsess)) == NULL) {
511 Alert("Not enough memory process_cli():asession:calloc().\n");
512 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
513 return 0;
514 }
515 asession_temp->sessid = local_asession.sessid;
516 asession_temp->serverid = local_asession.serverid;
517 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
518 } /* end if (chtbl_lookup()) */
519 else {
520 /*free wasted memory;*/
521 pool_free_to(apools.sessid, local_asession.sessid);
522 }
523
524 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
525 asession_temp->request_count++;
526
527#if defined(DEBUG_HASH)
528 print_table(&(t->proxy->htbl_proxy));
529#endif
530
531 if (asession_temp->serverid == NULL) {
532 Alert("Found Application Session without matching server.\n");
533 } else {
534 struct server *srv = t->proxy->srv;
535 while (srv) {
536 if (strcmp(srv->id, asession_temp->serverid) == 0) {
537 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
538 /* we found the server and it's usable */
539 t->flags &= ~SN_CK_MASK;
540 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
541 t->srv = srv;
542 break;
543 } else {
544 t->flags &= ~SN_CK_MASK;
545 t->flags |= SN_CK_DOWN;
546 }
547 } /* end if (strcmp()) */
548 srv = srv->next;
549 }/* end while(srv) */
550 }/* end else of if (asession_temp->serverid == NULL) */
551 }/* end if (strncasecmp(request_line,t->proxy->appsession_name,apssesion_name_len) == 0) */
552 else {
553 //fprintf(stderr,">>>>>>>>>>>>>>>>>>>>>>NO SESSION\n");
554 }
555 method_checked = 1;
556 } /* end if (!method_checked ...) */
557 else{
558 //printf("No Methode-Header with Session-String\n");
559 }
560
561 if (t->logs.logwait & LW_REQ) {
562 /* we have a complete HTTP request that we must log */
563 int urilen;
564
565 if ((t->logs.uri = pool_alloc(requri)) == NULL) {
566 Alert("HTTP logging : out of memory.\n");
567 t->logs.status = 500;
568 client_retnclose(t, t->proxy->errmsg.len500, t->proxy->errmsg.msg500);
569 if (!(t->flags & SN_ERR_MASK))
570 t->flags |= SN_ERR_PRXCOND;
571 if (!(t->flags & SN_FINST_MASK))
572 t->flags |= SN_FINST_R;
573 return 1;
574 }
575
576 urilen = ptr - req->h;
577 if (urilen >= REQURI_LEN)
578 urilen = REQURI_LEN - 1;
579 memcpy(t->logs.uri, req->h, urilen);
580 t->logs.uri[urilen] = 0;
581
582 if (!(t->logs.logwait &= ~LW_REQ))
583 sess_log(t);
584 }
585 else if (t->logs.logwait & LW_REQHDR) {
586 struct cap_hdr *h;
587 int len;
588 for (h = t->proxy->req_cap; h; h = h->next) {
589 if ((h->namelen + 2 <= ptr - req->h) &&
590 (req->h[h->namelen] == ':') &&
591 (strncasecmp(req->h, h->name, h->namelen) == 0)) {
592
593 if (t->req_cap[h->index] == NULL)
594 t->req_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
595
596 len = ptr - (req->h + h->namelen + 2);
597 if (len > h->len)
598 len = h->len;
599
600 memcpy(t->req_cap[h->index], req->h + h->namelen + 2, len);
601 t->req_cap[h->index][len]=0;
602 }
603 }
604
605 }
606
607 delete_header = 0;
608
609 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
610 int len, max;
611 len = sprintf(trash, "%08x:%s.clihdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
612 max = ptr - req->h;
613 UBOUND(max, sizeof(trash) - len - 1);
614 len += strlcpy2(trash + len, req->h, max + 1);
615 trash[len++] = '\n';
616 write(1, trash, len);
617 }
618
619
620 /* remove "connection: " if needed */
621 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
622 && (strncasecmp(req->h, "Connection: ", 12) == 0)) {
623 delete_header = 1;
624 }
625
626 /* try headers regexps */
627 if (!delete_header && t->proxy->req_exp != NULL
628 && !(t->flags & SN_CLDENY)) {
629 struct hdr_exp *exp;
630 char term;
631
632 term = *ptr;
633 *ptr = '\0';
634 exp = t->proxy->req_exp;
635 do {
636 if (regexec(exp->preg, req->h, MAX_MATCH, pmatch, 0) == 0) {
637 switch (exp->action) {
638 case ACT_ALLOW:
639 if (!(t->flags & SN_CLDENY))
640 t->flags |= SN_CLALLOW;
641 break;
642 case ACT_REPLACE:
643 if (!(t->flags & SN_CLDENY)) {
644 int len = exp_replace(trash, req->h, exp->replace, pmatch);
645 ptr += buffer_replace2(req, req->h, ptr, trash, len);
646 }
647 break;
648 case ACT_REMOVE:
649 if (!(t->flags & SN_CLDENY))
650 delete_header = 1;
651 break;
652 case ACT_DENY:
653 if (!(t->flags & SN_CLALLOW))
654 t->flags |= SN_CLDENY;
655 break;
656 case ACT_PASS: /* we simply don't deny this one */
657 break;
658 }
659 break;
660 }
661 } while ((exp = exp->next) != NULL);
662 *ptr = term; /* restore the string terminator */
663 }
664
665 /* Now look for cookies. Conforming to RFC2109, we have to support
666 * attributes whose name begin with a '$', and associate them with
667 * the right cookie, if we want to delete this cookie.
668 * So there are 3 cases for each cookie read :
669 * 1) it's a special attribute, beginning with a '$' : ignore it.
670 * 2) it's a server id cookie that we *MAY* want to delete : save
671 * some pointers on it (last semi-colon, beginning of cookie...)
672 * 3) it's an application cookie : we *MAY* have to delete a previous
673 * "special" cookie.
674 * At the end of loop, if a "special" cookie remains, we may have to
675 * remove it. If no application cookie persists in the header, we
676 * *MUST* delete it
677 */
678 if (!delete_header &&
679 (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
680 && !(t->flags & SN_CLDENY) && (ptr >= req->h + 8)
681 && (strncasecmp(req->h, "Cookie: ", 8) == 0)) {
682 char *p1, *p2, *p3, *p4;
683 char *del_colon, *del_cookie, *colon;
684 int app_cookies;
685
686 p1 = req->h + 8; /* first char after 'Cookie: ' */
687 colon = p1;
688 /* del_cookie == NULL => nothing to be deleted */
689 del_colon = del_cookie = NULL;
690 app_cookies = 0;
691
692 while (p1 < ptr) {
693 /* skip spaces and colons, but keep an eye on these ones */
694 while (p1 < ptr) {
695 if (*p1 == ';' || *p1 == ',')
696 colon = p1;
697 else if (!isspace((int)*p1))
698 break;
699 p1++;
700 }
701
702 if (p1 == ptr)
703 break;
704
705 /* p1 is at the beginning of the cookie name */
706 p2 = p1;
707 while (p2 < ptr && *p2 != '=')
708 p2++;
709
710 if (p2 == ptr)
711 break;
712
713 p3 = p2 + 1; /* skips the '=' sign */
714 if (p3 == ptr)
715 break;
716
717 p4 = p3;
718 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';' && *p4 != ',')
719 p4++;
720
721 /* here, we have the cookie name between p1 and p2,
722 * and its value between p3 and p4.
723 * we can process it :
724 *
725 * Cookie: NAME=VALUE;
726 * | || || |
727 * | || || +--> p4
728 * | || |+-------> p3
729 * | || +--------> p2
730 * | |+------------> p1
731 * | +-------------> colon
732 * +--------------------> req->h
733 */
734
735 if (*p1 == '$') {
736 /* skip this one */
737 }
738 else {
739 /* first, let's see if we want to capture it */
740 if (t->proxy->capture_name != NULL &&
741 t->logs.cli_cookie == NULL &&
742 (p4 - p1 >= t->proxy->capture_namelen) &&
743 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
744 int log_len = p4 - p1;
745
746 if ((t->logs.cli_cookie = pool_alloc(capture)) == NULL) {
747 Alert("HTTP logging : out of memory.\n");
748 } else {
749 if (log_len > t->proxy->capture_len)
750 log_len = t->proxy->capture_len;
751 memcpy(t->logs.cli_cookie, p1, log_len);
752 t->logs.cli_cookie[log_len] = 0;
753 }
754 }
755
756 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
757 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
758 /* Cool... it's the right one */
759 struct server *srv = t->proxy->srv;
760 char *delim;
761
762 /* if we're in cookie prefix mode, we'll search the delimitor so that we
763 * have the server ID betweek p3 and delim, and the original cookie between
764 * delim+1 and p4. Otherwise, delim==p4 :
765 *
766 * Cookie: NAME=SRV~VALUE;
767 * | || || | |
768 * | || || | +--> p4
769 * | || || +--------> delim
770 * | || |+-----------> p3
771 * | || +------------> p2
772 * | |+----------------> p1
773 * | +-----------------> colon
774 * +------------------------> req->h
775 */
776
777 if (t->proxy->options & PR_O_COOK_PFX) {
778 for (delim = p3; delim < p4; delim++)
779 if (*delim == COOKIE_DELIM)
780 break;
781 }
782 else
783 delim = p4;
784
785
786 /* Here, we'll look for the first running server which supports the cookie.
787 * This allows to share a same cookie between several servers, for example
788 * to dedicate backup servers to specific servers only.
789 * However, to prevent clients from sticking to cookie-less backup server
790 * when they have incidentely learned an empty cookie, we simply ignore
791 * empty cookies and mark them as invalid.
792 */
793 if (delim == p3)
794 srv = NULL;
795
796 while (srv) {
797 if ((srv->cklen == delim - p3) && !memcmp(p3, srv->cookie, delim - p3)) {
798 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
799 /* we found the server and it's usable */
800 t->flags &= ~SN_CK_MASK;
801 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
802 t->srv = srv;
803 break;
804 } else {
805 /* we found a server, but it's down */
806 t->flags &= ~SN_CK_MASK;
807 t->flags |= SN_CK_DOWN;
808 }
809 }
810 srv = srv->next;
811 }
812
813 if (!srv && !(t->flags & SN_CK_DOWN)) {
814 /* no server matched this cookie */
815 t->flags &= ~SN_CK_MASK;
816 t->flags |= SN_CK_INVALID;
817 }
818
819 /* depending on the cookie mode, we may have to either :
820 * - delete the complete cookie if we're in insert+indirect mode, so that
821 * the server never sees it ;
822 * - remove the server id from the cookie value, and tag the cookie as an
823 * application cookie so that it does not get accidentely removed later,
824 * if we're in cookie prefix mode
825 */
826 if ((t->proxy->options & PR_O_COOK_PFX) && (delim != p4)) {
827 buffer_replace2(req, p3, delim + 1, NULL, 0);
828 p4 -= (delim + 1 - p3);
829 ptr -= (delim + 1 - p3);
830 del_cookie = del_colon = NULL;
831 app_cookies++; /* protect the header from deletion */
832 }
833 else if (del_cookie == NULL &&
834 (t->proxy->options & (PR_O_COOK_INS | PR_O_COOK_IND)) == (PR_O_COOK_INS | PR_O_COOK_IND)) {
835 del_cookie = p1;
836 del_colon = colon;
837 }
838 } else {
839 /* now we know that we must keep this cookie since it's
840 * not ours. But if we wanted to delete our cookie
841 * earlier, we cannot remove the complete header, but we
842 * can remove the previous block itself.
843 */
844 app_cookies++;
845
846 if (del_cookie != NULL) {
847 buffer_replace2(req, del_cookie, p1, NULL, 0);
848 p4 -= (p1 - del_cookie);
849 ptr -= (p1 - del_cookie);
850 del_cookie = del_colon = NULL;
851 }
852 }
853
854 if ((t->proxy->appsession_name != NULL) &&
855 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
856 /* first, let's see if the cookie is our appcookie*/
857
858 /* Cool... it's the right one */
859
860 asession_temp = &local_asession;
861
862 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
863 Alert("Not enough memory process_cli():asession->sessid:malloc().\n");
864 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession->sessid:malloc().\n");
865 return 0;
866 }
867
868 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
869 asession_temp->sessid[t->proxy->appsession_len] = 0;
870 asession_temp->serverid = NULL;
871
872 /* only do insert, if lookup fails */
873 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
874 if ((asession_temp = pool_alloc(appsess)) == NULL) {
875 Alert("Not enough memory process_cli():asession:calloc().\n");
876 send_log(t->proxy, LOG_ALERT, "Not enough memory process_cli():asession:calloc().\n");
877 return 0;
878 }
879
880 asession_temp->sessid = local_asession.sessid;
881 asession_temp->serverid = local_asession.serverid;
882 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
883 } else {
884 /* free wasted memory */
885 pool_free_to(apools.sessid, local_asession.sessid);
886 }
887
888 if (asession_temp->serverid == NULL) {
889 Alert("Found Application Session without matching server.\n");
890 } else {
891 struct server *srv = t->proxy->srv;
892 while (srv) {
893 if (strcmp(srv->id, asession_temp->serverid) == 0) {
894 if (srv->state & SRV_RUNNING || t->proxy->options & PR_O_PERSIST) {
895 /* we found the server and it's usable */
896 t->flags &= ~SN_CK_MASK;
897 t->flags |= SN_CK_VALID | SN_DIRECT | SN_ASSIGNED;
898 t->srv = srv;
899 break;
900 } else {
901 t->flags &= ~SN_CK_MASK;
902 t->flags |= SN_CK_DOWN;
903 }
904 }
905 srv = srv->next;
906 }/* end while(srv) */
907 }/* end else if server == NULL */
908
909 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
910 }/* end if ((t->proxy->appsession_name != NULL) ... */
911 }
912
913 /* we'll have to look for another cookie ... */
914 p1 = p4;
915 } /* while (p1 < ptr) */
916
917 /* There's no more cookie on this line.
918 * We may have marked the last one(s) for deletion.
919 * We must do this now in two ways :
920 * - if there is no app cookie, we simply delete the header ;
921 * - if there are app cookies, we must delete the end of the
922 * string properly, including the colon/semi-colon before
923 * the cookie name.
924 */
925 if (del_cookie != NULL) {
926 if (app_cookies) {
927 buffer_replace2(req, del_colon, ptr, NULL, 0);
928 /* WARNING! <ptr> becomes invalid for now. If some code
929 * below needs to rely on it before the end of the global
930 * header loop, we need to correct it with this code :
931 */
932 ptr = del_colon;
933 }
934 else
935 delete_header = 1;
936 }
937 } /* end of cookie processing on this header */
938
939 /* let's look if we have to delete this header */
940 if (delete_header && !(t->flags & SN_CLDENY)) {
941 buffer_replace2(req, req->h, req->lr, NULL, 0);
942 /* WARNING: ptr is not valid anymore, since the header may have
943 * been deleted or truncated ! */
944 } else {
945 /* try to catch the first line as the request */
946 if (t->req_line.len < 0) {
947 t->req_line.str = req->h;
948 t->req_line.len = ptr - req->h;
949 }
950
951 /* We might also need the 'Authorization: ' header */
952 if (t->auth_hdr.len < 0 &&
953 t->proxy->uri_auth != NULL &&
954 ptr > req->h + 15 &&
955 !strncasecmp("Authorization: ", req->h, 15)) {
956 t->auth_hdr.str = req->h;
957 t->auth_hdr.len = ptr - req->h;
958 }
959 }
960
961 req->h = req->lr;
962 } /* while (req->lr < req->r) */
963
964 /* end of header processing (even if incomplete) */
965
966 if ((req->l < req->rlim - req->data) && ! FD_ISSET(t->cli_fd, StaticReadEvent)) {
967 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
968 * full. We cannot loop here since event_cli_read will disable it only if
969 * req->l == rlim-data
970 */
971 FD_SET(t->cli_fd, StaticReadEvent);
972 if (t->proxy->clitimeout)
973 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
974 else
975 tv_eternity(&t->crexpire);
976 }
977
978 /* Since we are in header mode, if there's no space left for headers, we
979 * won't be able to free more later, so the session will never terminate.
980 */
981 if (req->l >= req->rlim - req->data) {
982 t->logs.status = 400;
983 client_retnclose(t, t->proxy->errmsg.len400, t->proxy->errmsg.msg400);
984 if (!(t->flags & SN_ERR_MASK))
985 t->flags |= SN_ERR_PRXCOND;
986 if (!(t->flags & SN_FINST_MASK))
987 t->flags |= SN_FINST_R;
988 return 1;
989 }
990 else if (t->res_cr == RES_ERROR || t->res_cr == RES_NULL) {
991 /* read error, or last read : give up. */
992 tv_eternity(&t->crexpire);
993 fd_delete(t->cli_fd);
994 t->cli_state = CL_STCLOSE;
995 if (!(t->flags & SN_ERR_MASK))
996 t->flags |= SN_ERR_CLICL;
997 if (!(t->flags & SN_FINST_MASK))
998 t->flags |= SN_FINST_R;
999 return 1;
1000 }
1001 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
1002
1003 /* read timeout : give up with an error message.
1004 */
1005 t->logs.status = 408;
1006 client_retnclose(t, t->proxy->errmsg.len408, t->proxy->errmsg.msg408);
1007 if (!(t->flags & SN_ERR_MASK))
1008 t->flags |= SN_ERR_CLITO;
1009 if (!(t->flags & SN_FINST_MASK))
1010 t->flags |= SN_FINST_R;
1011 return 1;
1012 }
1013
1014 return t->cli_state != CL_STHEADERS;
1015 }
1016 else if (c == CL_STDATA) {
1017 process_data:
1018 /* FIXME: this error handling is partly buggy because we always report
1019 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
1020 * or HEADER phase. BTW, it's not logical to expire the client while
1021 * we're waiting for the server to connect.
1022 */
1023 /* read or write error */
1024 if (t->res_cw == RES_ERROR || t->res_cr == RES_ERROR) {
1025 tv_eternity(&t->crexpire);
1026 tv_eternity(&t->cwexpire);
1027 fd_delete(t->cli_fd);
1028 t->cli_state = CL_STCLOSE;
1029 if (!(t->flags & SN_ERR_MASK))
1030 t->flags |= SN_ERR_CLICL;
1031 if (!(t->flags & SN_FINST_MASK)) {
1032 if (t->pend_pos)
1033 t->flags |= SN_FINST_Q;
1034 else if (s == SV_STCONN)
1035 t->flags |= SN_FINST_C;
1036 else
1037 t->flags |= SN_FINST_D;
1038 }
1039 return 1;
1040 }
1041 /* last read, or end of server write */
1042 else if (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
1043 FD_CLR(t->cli_fd, StaticReadEvent);
1044 tv_eternity(&t->crexpire);
1045 shutdown(t->cli_fd, SHUT_RD);
1046 t->cli_state = CL_STSHUTR;
1047 return 1;
1048 }
1049 /* last server read and buffer empty */
1050 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
1051 FD_CLR(t->cli_fd, StaticWriteEvent);
1052 tv_eternity(&t->cwexpire);
1053 shutdown(t->cli_fd, SHUT_WR);
1054 /* We must ensure that the read part is still alive when switching
1055 * to shutw */
1056 FD_SET(t->cli_fd, StaticReadEvent);
1057 if (t->proxy->clitimeout)
1058 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
1059 t->cli_state = CL_STSHUTW;
1060 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1061 return 1;
1062 }
1063 /* read timeout */
1064 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
1065 FD_CLR(t->cli_fd, StaticReadEvent);
1066 tv_eternity(&t->crexpire);
1067 shutdown(t->cli_fd, SHUT_RD);
1068 t->cli_state = CL_STSHUTR;
1069 if (!(t->flags & SN_ERR_MASK))
1070 t->flags |= SN_ERR_CLITO;
1071 if (!(t->flags & SN_FINST_MASK)) {
1072 if (t->pend_pos)
1073 t->flags |= SN_FINST_Q;
1074 else if (s == SV_STCONN)
1075 t->flags |= SN_FINST_C;
1076 else
1077 t->flags |= SN_FINST_D;
1078 }
1079 return 1;
1080 }
1081 /* write timeout */
1082 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
1083 FD_CLR(t->cli_fd, StaticWriteEvent);
1084 tv_eternity(&t->cwexpire);
1085 shutdown(t->cli_fd, SHUT_WR);
1086 /* We must ensure that the read part is still alive when switching
1087 * to shutw */
1088 FD_SET(t->cli_fd, StaticReadEvent);
1089 if (t->proxy->clitimeout)
1090 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
1091
1092 t->cli_state = CL_STSHUTW;
1093 if (!(t->flags & SN_ERR_MASK))
1094 t->flags |= SN_ERR_CLITO;
1095 if (!(t->flags & SN_FINST_MASK)) {
1096 if (t->pend_pos)
1097 t->flags |= SN_FINST_Q;
1098 else if (s == SV_STCONN)
1099 t->flags |= SN_FINST_C;
1100 else
1101 t->flags |= SN_FINST_D;
1102 }
1103 return 1;
1104 }
1105
1106 if (req->l >= req->rlim - req->data) {
1107 /* no room to read more data */
1108 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
1109 /* stop reading until we get some space */
1110 FD_CLR(t->cli_fd, StaticReadEvent);
1111 tv_eternity(&t->crexpire);
1112 }
1113 } else {
1114 /* there's still some space in the buffer */
1115 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
1116 FD_SET(t->cli_fd, StaticReadEvent);
1117 if (!t->proxy->clitimeout ||
1118 (t->srv_state < SV_STDATA && t->proxy->srvtimeout))
1119 /* If the client has no timeout, or if the server not ready yet, and we
1120 * know for sure that it can expire, then it's cleaner to disable the
1121 * timeout on the client side so that too low values cannot make the
1122 * sessions abort too early.
1123 */
1124 tv_eternity(&t->crexpire);
1125 else
1126 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
1127 }
1128 }
1129
1130 if ((rep->l == 0) ||
1131 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
1132 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1133 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
1134 tv_eternity(&t->cwexpire);
1135 }
1136 } else {
1137 /* buffer not empty */
1138 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1139 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
1140 if (t->proxy->clitimeout) {
1141 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
1142 /* FIXME: to prevent the client from expiring read timeouts during writes,
1143 * we refresh it. */
1144 t->crexpire = t->cwexpire;
1145 }
1146 else
1147 tv_eternity(&t->cwexpire);
1148 }
1149 }
1150 return 0; /* other cases change nothing */
1151 }
1152 else if (c == CL_STSHUTR) {
1153 if (t->res_cw == RES_ERROR) {
1154 tv_eternity(&t->cwexpire);
1155 fd_delete(t->cli_fd);
1156 t->cli_state = CL_STCLOSE;
1157 if (!(t->flags & SN_ERR_MASK))
1158 t->flags |= SN_ERR_CLICL;
1159 if (!(t->flags & SN_FINST_MASK)) {
1160 if (t->pend_pos)
1161 t->flags |= SN_FINST_Q;
1162 else if (s == SV_STCONN)
1163 t->flags |= SN_FINST_C;
1164 else
1165 t->flags |= SN_FINST_D;
1166 }
1167 return 1;
1168 }
1169 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)
1170 && !(t->flags & SN_SELF_GEN)) {
1171 tv_eternity(&t->cwexpire);
1172 fd_delete(t->cli_fd);
1173 t->cli_state = CL_STCLOSE;
1174 return 1;
1175 }
1176 else if (tv_cmp2_ms(&t->cwexpire, &now) <= 0) {
1177 tv_eternity(&t->cwexpire);
1178 fd_delete(t->cli_fd);
1179 t->cli_state = CL_STCLOSE;
1180 if (!(t->flags & SN_ERR_MASK))
1181 t->flags |= SN_ERR_CLITO;
1182 if (!(t->flags & SN_FINST_MASK)) {
1183 if (t->pend_pos)
1184 t->flags |= SN_FINST_Q;
1185 else if (s == SV_STCONN)
1186 t->flags |= SN_FINST_C;
1187 else
1188 t->flags |= SN_FINST_D;
1189 }
1190 return 1;
1191 }
1192
1193 if (t->flags & SN_SELF_GEN) {
1194 produce_content(t);
1195 if (rep->l == 0) {
1196 tv_eternity(&t->cwexpire);
1197 fd_delete(t->cli_fd);
1198 t->cli_state = CL_STCLOSE;
1199 return 1;
1200 }
1201 }
1202
1203 if ((rep->l == 0)
1204 || ((s == SV_STHEADERS) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
1205 if (FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1206 FD_CLR(t->cli_fd, StaticWriteEvent); /* stop writing */
1207 tv_eternity(&t->cwexpire);
1208 }
1209 } else {
1210 /* buffer not empty */
1211 if (! FD_ISSET(t->cli_fd, StaticWriteEvent)) {
1212 FD_SET(t->cli_fd, StaticWriteEvent); /* restart writing */
1213 if (t->proxy->clitimeout) {
1214 tv_delayfrom(&t->cwexpire, &now, t->proxy->clitimeout);
1215 /* FIXME: to prevent the client from expiring read timeouts during writes,
1216 * we refresh it. */
1217 t->crexpire = t->cwexpire;
1218 }
1219 else
1220 tv_eternity(&t->cwexpire);
1221 }
1222 }
1223 return 0;
1224 }
1225 else if (c == CL_STSHUTW) {
1226 if (t->res_cr == RES_ERROR) {
1227 tv_eternity(&t->crexpire);
1228 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 (t->res_cr == RES_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
1243 tv_eternity(&t->crexpire);
1244 fd_delete(t->cli_fd);
1245 t->cli_state = CL_STCLOSE;
1246 return 1;
1247 }
1248 else if (tv_cmp2_ms(&t->crexpire, &now) <= 0) {
1249 tv_eternity(&t->crexpire);
1250 fd_delete(t->cli_fd);
1251 t->cli_state = CL_STCLOSE;
1252 if (!(t->flags & SN_ERR_MASK))
1253 t->flags |= SN_ERR_CLITO;
1254 if (!(t->flags & SN_FINST_MASK)) {
1255 if (t->pend_pos)
1256 t->flags |= SN_FINST_Q;
1257 else if (s == SV_STCONN)
1258 t->flags |= SN_FINST_C;
1259 else
1260 t->flags |= SN_FINST_D;
1261 }
1262 return 1;
1263 }
1264 else if (req->l >= req->rlim - req->data) {
1265 /* no room to read more data */
1266
1267 /* FIXME-20050705: is it possible for a client to maintain a session
1268 * after the timeout by sending more data after it receives a close ?
1269 */
1270
1271 if (FD_ISSET(t->cli_fd, StaticReadEvent)) {
1272 /* stop reading until we get some space */
1273 FD_CLR(t->cli_fd, StaticReadEvent);
1274 tv_eternity(&t->crexpire);
1275 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1276 }
1277 } else {
1278 /* there's still some space in the buffer */
1279 if (! FD_ISSET(t->cli_fd, StaticReadEvent)) {
1280 FD_SET(t->cli_fd, StaticReadEvent);
1281 if (t->proxy->clitimeout)
1282 tv_delayfrom(&t->crexpire, &now, t->proxy->clitimeout);
1283 else
1284 tv_eternity(&t->crexpire);
1285 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1286 }
1287 }
1288 return 0;
1289 }
1290 else { /* CL_STCLOSE: nothing to do */
1291 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1292 int len;
1293 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1294 write(1, trash, len);
1295 }
1296 return 0;
1297 }
1298 return 0;
1299}
1300
1301
1302/*
1303 * manages the server FSM and its socket. It returns 1 if a state has changed
1304 * (and a resync may be needed), 0 else.
1305 */
1306int process_srv(struct session *t)
1307{
1308 int s = t->srv_state;
1309 int c = t->cli_state;
1310 struct buffer *req = t->req;
1311 struct buffer *rep = t->rep;
1312 appsess *asession_temp = NULL;
1313 appsess local_asession;
1314 int conn_err;
1315
1316#ifdef DEBUG_FULL
1317 fprintf(stderr,"process_srv: c=%s, s=%s\n", cli_stnames[c], srv_stnames[s]);
1318#endif
1319 //fprintf(stderr,"process_srv: c=%d, s=%d, cr=%d, cw=%d, sr=%d, sw=%d\n", c, s,
1320 //FD_ISSET(t->cli_fd, StaticReadEvent), FD_ISSET(t->cli_fd, StaticWriteEvent),
1321 //FD_ISSET(t->srv_fd, StaticReadEvent), FD_ISSET(t->srv_fd, StaticWriteEvent)
1322 //);
1323 if (s == SV_STIDLE) {
1324 if (c == CL_STHEADERS)
1325 return 0; /* stay in idle, waiting for data to reach the client side */
1326 else if (c == CL_STCLOSE || c == CL_STSHUTW ||
1327 (c == CL_STSHUTR &&
1328 (t->req->l == 0 || t->proxy->options & PR_O_ABRT_CLOSE))) { /* give up */
1329 tv_eternity(&t->cnexpire);
1330 if (t->pend_pos)
1331 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1332 /* note that this must not return any error because it would be able to
1333 * overwrite the client_retnclose() output.
1334 */
1335 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C, 0, 0, NULL);
1336
1337 return 1;
1338 }
1339 else {
1340 /* Right now, we will need to create a connection to the server.
1341 * We might already have tried, and got a connection pending, in
1342 * which case we will not do anything till it's pending. It's up
1343 * to any other session to release it and wake us up again.
1344 */
1345 if (t->pend_pos) {
1346 if (tv_cmp2_ms(&t->cnexpire, &now) > 0)
1347 return 0;
1348 else {
1349 /* we've been waiting too long here */
1350 tv_eternity(&t->cnexpire);
1351 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1352 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
1353 503, t->proxy->errmsg.len503, t->proxy->errmsg.msg503);
1354 if (t->srv)
1355 t->srv->failed_conns++;
1356 t->proxy->failed_conns++;
1357 return 1;
1358 }
1359 }
1360
1361 do {
1362 /* first, get a connection */
1363 if (srv_redispatch_connect(t))
1364 return t->srv_state != SV_STIDLE;
1365
1366 /* try to (re-)connect to the server, and fail if we expire the
1367 * number of retries.
1368 */
1369 if (srv_retryable_connect(t)) {
1370 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1371 return t->srv_state != SV_STIDLE;
1372 }
1373
1374 } while (1);
1375 }
1376 }
1377 else if (s == SV_STCONN) { /* connection in progress */
1378 if (c == CL_STCLOSE || c == CL_STSHUTW ||
1379 (c == CL_STSHUTR &&
1380 (t->req->l == 0 || t->proxy->options & PR_O_ABRT_CLOSE))) { /* give up */
1381 tv_eternity(&t->cnexpire);
1382 fd_delete(t->srv_fd);
1383 if (t->srv)
1384 t->srv->cur_sess--;
1385
1386 /* note that this must not return any error because it would be able to
1387 * overwrite the client_retnclose() output.
1388 */
1389 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, 0, NULL);
1390 return 1;
1391 }
1392 if (t->res_sw == RES_SILENT && tv_cmp2_ms(&t->cnexpire, &now) > 0) {
1393 //fprintf(stderr,"1: c=%d, s=%d, now=%d.%06d, exp=%d.%06d\n", c, s, now.tv_sec, now.tv_usec, t->cnexpire.tv_sec, t->cnexpire.tv_usec);
1394 return 0; /* nothing changed */
1395 }
1396 else if (t->res_sw == RES_SILENT || t->res_sw == RES_ERROR) {
1397 /* timeout, asynchronous connect error or first write error */
1398 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
1399
1400 fd_delete(t->srv_fd);
1401 if (t->srv)
1402 t->srv->cur_sess--;
1403
1404 if (t->res_sw == RES_SILENT)
1405 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
1406 else
1407 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
1408
1409 /* ensure that we have enough retries left */
1410 if (srv_count_retry_down(t, conn_err))
1411 return 1;
1412
1413 do {
1414 /* Now we will try to either reconnect to the same server or
1415 * connect to another server. If the connection gets queued
1416 * because all servers are saturated, then we will go back to
1417 * the SV_STIDLE state.
1418 */
1419 if (srv_retryable_connect(t)) {
1420 t->logs.t_queue = tv_diff(&t->logs.tv_accept, &now);
1421 return t->srv_state != SV_STCONN;
1422 }
1423
1424 /* we need to redispatch the connection to another server */
1425 if (srv_redispatch_connect(t))
1426 return t->srv_state != SV_STCONN;
1427 } while (1);
1428 }
1429 else { /* no error or write 0 */
1430 t->logs.t_connect = tv_diff(&t->logs.tv_accept, &now);
1431
1432 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
1433 if (req->l == 0) /* nothing to write */ {
1434 FD_CLR(t->srv_fd, StaticWriteEvent);
1435 tv_eternity(&t->swexpire);
1436 } else /* need the right to write */ {
1437 FD_SET(t->srv_fd, StaticWriteEvent);
1438 if (t->proxy->srvtimeout) {
1439 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
1440 /* FIXME: to prevent the server from expiring read timeouts during writes,
1441 * we refresh it. */
1442 t->srexpire = t->swexpire;
1443 }
1444 else
1445 tv_eternity(&t->swexpire);
1446 }
1447
1448 if (t->proxy->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
1449 FD_SET(t->srv_fd, StaticReadEvent);
1450 if (t->proxy->srvtimeout)
1451 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
1452 else
1453 tv_eternity(&t->srexpire);
1454
1455 t->srv_state = SV_STDATA;
1456 if (t->srv)
1457 t->srv->cum_sess++;
1458 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
1459
1460 /* if the user wants to log as soon as possible, without counting
1461 bytes from the server, then this is the right moment. */
1462 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
1463 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
1464 sess_log(t);
1465 }
1466 }
1467 else {
1468 t->srv_state = SV_STHEADERS;
1469 if (t->srv)
1470 t->srv->cum_sess++;
1471 rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */
1472 }
1473 tv_eternity(&t->cnexpire);
1474 return 1;
1475 }
1476 }
1477 else if (s == SV_STHEADERS) { /* receiving server headers */
1478 /* now parse the partial (or complete) headers */
1479 while (rep->lr < rep->r) { /* this loop only sees one header at each iteration */
1480 char *ptr;
1481 int delete_header;
1482
1483 ptr = rep->lr;
1484
1485 /* look for the end of the current header */
1486 while (ptr < rep->r && *ptr != '\n' && *ptr != '\r')
1487 ptr++;
1488
1489 if (ptr == rep->h) {
1490 int line, len;
1491
1492 /* we can only get here after an end of headers */
1493
1494 /* first, we'll block if security checks have caught nasty things */
1495 if (t->flags & SN_CACHEABLE) {
1496 if ((t->flags & SN_CACHE_COOK) &&
1497 (t->flags & SN_SCK_ANY) &&
1498 (t->proxy->options & PR_O_CHK_CACHE)) {
1499
1500 /* we're in presence of a cacheable response containing
1501 * a set-cookie header. We'll block it as requested by
1502 * the 'checkcache' option, and send an alert.
1503 */
1504 tv_eternity(&t->srexpire);
1505 tv_eternity(&t->swexpire);
1506 fd_delete(t->srv_fd);
1507 if (t->srv) {
1508 t->srv->cur_sess--;
1509 t->srv->failed_secu++;
1510 }
1511 t->proxy->failed_secu++;
1512 t->srv_state = SV_STCLOSE;
1513 t->logs.status = 502;
1514 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
1515 if (!(t->flags & SN_ERR_MASK))
1516 t->flags |= SN_ERR_PRXCOND;
1517 if (!(t->flags & SN_FINST_MASK))
1518 t->flags |= SN_FINST_H;
1519
1520 Alert("Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
1521 send_log(t->proxy, LOG_ALERT, "Blocking cacheable cookie in response from instance %s, server %s.\n", t->proxy->id, t->srv->id);
1522
1523 /* We used to have a free connection slot. Since we'll never use it,
1524 * we have to inform the server that it may be used by another session.
1525 */
1526 if (may_dequeue_tasks(t->srv, t->proxy))
1527 task_wakeup(&rq, t->srv->queue_mgt);
1528
1529 return 1;
1530 }
1531 }
1532
1533 /* next, we'll block if an 'rspideny' or 'rspdeny' filter matched */
1534 if (t->flags & SN_SVDENY) {
1535 tv_eternity(&t->srexpire);
1536 tv_eternity(&t->swexpire);
1537 fd_delete(t->srv_fd);
1538 if (t->srv) {
1539 t->srv->cur_sess--;
1540 t->srv->failed_secu++;
1541 }
1542 t->proxy->failed_secu++;
1543 t->srv_state = SV_STCLOSE;
1544 t->logs.status = 502;
1545 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
1546 if (!(t->flags & SN_ERR_MASK))
1547 t->flags |= SN_ERR_PRXCOND;
1548 if (!(t->flags & SN_FINST_MASK))
1549 t->flags |= SN_FINST_H;
1550 /* We used to have a free connection slot. Since we'll never use it,
1551 * we have to inform the server that it may be used by another session.
1552 */
1553 if (may_dequeue_tasks(t->srv, t->proxy))
1554 task_wakeup(&rq, t->srv->queue_mgt);
1555
1556 return 1;
1557 }
1558
1559 /* we'll have something else to do here : add new headers ... */
1560
1561 if ((t->srv) && !(t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_INS) &&
1562 (!(t->proxy->options & PR_O_COOK_POST) || (t->flags & SN_POST))) {
1563 /* the server is known, it's not the one the client requested, we have to
1564 * insert a set-cookie here, except if we want to insert only on POST
1565 * requests and this one isn't. Note that servers which don't have cookies
1566 * (eg: some backup servers) will return a full cookie removal request.
1567 */
1568 len = sprintf(trash, "Set-Cookie: %s=%s; path=/\r\n",
1569 t->proxy->cookie_name,
1570 t->srv->cookie ? t->srv->cookie : "; Expires=Thu, 01-Jan-1970 00:00:01 GMT");
1571
1572 t->flags |= SN_SCK_INSERTED;
1573
1574 /* Here, we will tell an eventual cache on the client side that we don't
1575 * want it to cache this reply because HTTP/1.0 caches also cache cookies !
1576 * Some caches understand the correct form: 'no-cache="set-cookie"', but
1577 * others don't (eg: apache <= 1.3.26). So we use 'private' instead.
1578 */
1579 if (t->proxy->options & PR_O_COOK_NOC)
1580 //len += sprintf(newhdr + len, "Cache-control: no-cache=\"set-cookie\"\r\n");
1581 len += sprintf(trash + len, "Cache-control: private\r\n");
1582
1583 if (rep->data + rep->l < rep->h)
1584 /* The data has been stolen, we will crash cleanly instead of corrupting memory */
1585 *(int *)0 = 0;
1586 buffer_replace2(rep, rep->h, rep->h, trash, len);
1587 }
1588
1589 /* headers to be added */
1590 for (line = 0; line < t->proxy->nb_rspadd; line++) {
1591 len = sprintf(trash, "%s\r\n", t->proxy->rsp_add[line]);
1592 buffer_replace2(rep, rep->h, rep->h, trash, len);
1593 }
1594
1595 /* add a "connection: close" line if needed */
1596 if (t->proxy->options & PR_O_HTTP_CLOSE)
1597 buffer_replace2(rep, rep->h, rep->h, "Connection: close\r\n", 19);
1598
1599 t->srv_state = SV_STDATA;
1600 rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
1601 t->logs.t_data = tv_diff(&t->logs.tv_accept, &now);
1602
1603 /* client connection already closed or option 'httpclose' required :
1604 * we close the server's outgoing connection right now.
1605 */
1606 if ((req->l == 0) &&
1607 (c == CL_STSHUTR || c == CL_STCLOSE || t->proxy->options & PR_O_FORCE_CLO)) {
1608 FD_CLR(t->srv_fd, StaticWriteEvent);
1609 tv_eternity(&t->swexpire);
1610
1611 /* We must ensure that the read part is still alive when switching
1612 * to shutw */
1613 FD_SET(t->srv_fd, StaticReadEvent);
1614 if (t->proxy->srvtimeout)
1615 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
1616
1617 shutdown(t->srv_fd, SHUT_WR);
1618 t->srv_state = SV_STSHUTW;
1619 }
1620
1621 /* if the user wants to log as soon as possible, without counting
1622 bytes from the server, then this is the right moment. */
1623 if (t->proxy->to_log && !(t->logs.logwait & LW_BYTES)) {
1624 t->logs.t_close = t->logs.t_data; /* to get a valid end date */
1625 t->logs.bytes = rep->h - rep->data;
1626 sess_log(t);
1627 }
1628 break;
1629 }
1630
1631 /* to get a complete header line, we need the ending \r\n, \n\r, \r or \n too */
1632 if (ptr > rep->r - 2) {
1633 /* this is a partial header, let's wait for more to come */
1634 rep->lr = ptr;
1635 break;
1636 }
1637
1638 // fprintf(stderr,"h=%p, ptr=%p, lr=%p, r=%p, *h=", rep->h, ptr, rep->lr, rep->r);
1639 // write(2, rep->h, ptr - rep->h); fprintf(stderr,"\n");
1640
1641 /* now we know that *ptr is either \r or \n,
1642 * and that there are at least 1 char after it.
1643 */
1644 if ((ptr[0] == ptr[1]) || (ptr[1] != '\r' && ptr[1] != '\n'))
1645 rep->lr = ptr + 1; /* \r\r, \n\n, \r[^\n], \n[^\r] */
1646 else
1647 rep->lr = ptr + 2; /* \r\n or \n\r */
1648
1649 /*
1650 * now we know that we have a full header ; we can do whatever
1651 * we want with these pointers :
1652 * rep->h = beginning of header
1653 * ptr = end of header (first \r or \n)
1654 * rep->lr = beginning of next line (next rep->h)
1655 * rep->r = end of data (not used at this stage)
1656 */
1657
1658
1659 if (t->logs.status == -1) {
1660 t->logs.logwait &= ~LW_RESP;
1661 t->logs.status = atoi(rep->h + 9);
1662 switch (t->logs.status) {
1663 case 200:
1664 case 203:
1665 case 206:
1666 case 300:
1667 case 301:
1668 case 410:
1669 /* RFC2616 @13.4:
1670 * "A response received with a status code of
1671 * 200, 203, 206, 300, 301 or 410 MAY be stored
1672 * by a cache (...) unless a cache-control
1673 * directive prohibits caching."
1674 *
1675 * RFC2616 @9.5: POST method :
1676 * "Responses to this method are not cacheable,
1677 * unless the response includes appropriate
1678 * Cache-Control or Expires header fields."
1679 */
1680 if (!(t->flags & SN_POST) && (t->proxy->options & PR_O_CHK_CACHE))
1681 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
1682 break;
1683 default:
1684 break;
1685 }
1686 }
1687 else if (t->logs.logwait & LW_RSPHDR) {
1688 struct cap_hdr *h;
1689 int len;
1690 for (h = t->proxy->rsp_cap; h; h = h->next) {
1691 if ((h->namelen + 2 <= ptr - rep->h) &&
1692 (rep->h[h->namelen] == ':') &&
1693 (strncasecmp(rep->h, h->name, h->namelen) == 0)) {
1694
1695 if (t->rsp_cap[h->index] == NULL)
1696 t->rsp_cap[h->index] = pool_alloc_from(h->pool, h->len + 1);
1697
1698 len = ptr - (rep->h + h->namelen + 2);
1699 if (len > h->len)
1700 len = h->len;
1701
1702 memcpy(t->rsp_cap[h->index], rep->h + h->namelen + 2, len);
1703 t->rsp_cap[h->index][len]=0;
1704 }
1705 }
1706
1707 }
1708
1709 delete_header = 0;
1710
1711 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1712 int len, max;
1713 len = sprintf(trash, "%08x:%s.srvhdr[%04x:%04x]: ", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1714 max = ptr - rep->h;
1715 UBOUND(max, sizeof(trash) - len - 1);
1716 len += strlcpy2(trash + len, rep->h, max + 1);
1717 trash[len++] = '\n';
1718 write(1, trash, len);
1719 }
1720
1721 /* remove "connection: " if needed */
1722 if (!delete_header && (t->proxy->options & PR_O_HTTP_CLOSE)
1723 && (strncasecmp(rep->h, "Connection: ", 12) == 0)) {
1724 delete_header = 1;
1725 }
1726
1727 /* try headers regexps */
1728 if (!delete_header && t->proxy->rsp_exp != NULL
1729 && !(t->flags & SN_SVDENY)) {
1730 struct hdr_exp *exp;
1731 char term;
1732
1733 term = *ptr;
1734 *ptr = '\0';
1735 exp = t->proxy->rsp_exp;
1736 do {
1737 if (regexec(exp->preg, rep->h, MAX_MATCH, pmatch, 0) == 0) {
1738 switch (exp->action) {
1739 case ACT_ALLOW:
1740 if (!(t->flags & SN_SVDENY))
1741 t->flags |= SN_SVALLOW;
1742 break;
1743 case ACT_REPLACE:
1744 if (!(t->flags & SN_SVDENY)) {
1745 int len = exp_replace(trash, rep->h, exp->replace, pmatch);
1746 ptr += buffer_replace2(rep, rep->h, ptr, trash, len);
1747 }
1748 break;
1749 case ACT_REMOVE:
1750 if (!(t->flags & SN_SVDENY))
1751 delete_header = 1;
1752 break;
1753 case ACT_DENY:
1754 if (!(t->flags & SN_SVALLOW))
1755 t->flags |= SN_SVDENY;
1756 break;
1757 case ACT_PASS: /* we simply don't deny this one */
1758 break;
1759 }
1760 break;
1761 }
1762 } while ((exp = exp->next) != NULL);
1763 *ptr = term; /* restore the string terminator */
1764 }
1765
1766 /* check for cache-control: or pragma: headers */
1767 if (!delete_header && (t->flags & SN_CACHEABLE)) {
1768 if (strncasecmp(rep->h, "Pragma: no-cache", 16) == 0)
1769 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1770 else if (strncasecmp(rep->h, "Cache-control: ", 15) == 0) {
1771 if (strncasecmp(rep->h + 15, "no-cache", 8) == 0) {
1772 if (rep->h + 23 == ptr || rep->h[23] == ',')
1773 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1774 else {
1775 if (strncasecmp(rep->h + 23, "=\"set-cookie", 12) == 0
1776 && (rep->h[35] == '"' || rep->h[35] == ','))
1777 t->flags &= ~SN_CACHE_COOK;
1778 }
1779 } else if ((strncasecmp(rep->h + 15, "private", 7) == 0 &&
1780 (rep->h + 22 == ptr || rep->h[22] == ','))
1781 || (strncasecmp(rep->h + 15, "no-store", 8) == 0 &&
1782 (rep->h + 23 == ptr || rep->h[23] == ','))) {
1783 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1784 } else if (strncasecmp(rep->h + 15, "max-age=0", 9) == 0 &&
1785 (rep->h + 24 == ptr || rep->h[24] == ',')) {
1786 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1787 } else if (strncasecmp(rep->h + 15, "s-maxage=0", 10) == 0 &&
1788 (rep->h + 25 == ptr || rep->h[25] == ',')) {
1789 t->flags &= ~SN_CACHEABLE & ~SN_CACHE_COOK;
1790 } else if (strncasecmp(rep->h + 15, "public", 6) == 0 &&
1791 (rep->h + 21 == ptr || rep->h[21] == ',')) {
1792 t->flags |= SN_CACHEABLE | SN_CACHE_COOK;
1793 }
1794 }
1795 }
1796
1797 /* check for server cookies */
1798 if (!delete_header /*&& (t->proxy->options & PR_O_COOK_ANY)*/
1799 && (t->proxy->cookie_name != NULL || t->proxy->capture_name != NULL || t->proxy->appsession_name !=NULL)
1800 && (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
1801 char *p1, *p2, *p3, *p4;
1802
1803 t->flags |= SN_SCK_ANY;
1804
1805 p1 = rep->h + 12; /* first char after 'Set-Cookie: ' */
1806
1807 while (p1 < ptr) { /* in fact, we'll break after the first cookie */
1808 while (p1 < ptr && (isspace((int)*p1)))
1809 p1++;
1810
1811 if (p1 == ptr || *p1 == ';') /* end of cookie */
1812 break;
1813
1814 /* p1 is at the beginning of the cookie name */
1815 p2 = p1;
1816
1817 while (p2 < ptr && *p2 != '=' && *p2 != ';')
1818 p2++;
1819
1820 if (p2 == ptr || *p2 == ';') /* next cookie */
1821 break;
1822
1823 p3 = p2 + 1; /* skips the '=' sign */
1824 if (p3 == ptr)
1825 break;
1826
1827 p4 = p3;
1828 while (p4 < ptr && !isspace((int)*p4) && *p4 != ';')
1829 p4++;
1830
1831 /* here, we have the cookie name between p1 and p2,
1832 * and its value between p3 and p4.
1833 * we can process it.
1834 */
1835
1836 /* first, let's see if we want to capture it */
1837 if (t->proxy->capture_name != NULL &&
1838 t->logs.srv_cookie == NULL &&
1839 (p4 - p1 >= t->proxy->capture_namelen) &&
1840 memcmp(p1, t->proxy->capture_name, t->proxy->capture_namelen) == 0) {
1841 int log_len = p4 - p1;
1842
1843 if ((t->logs.srv_cookie = pool_alloc(capture)) == NULL) {
1844 Alert("HTTP logging : out of memory.\n");
1845 }
1846
1847 if (log_len > t->proxy->capture_len)
1848 log_len = t->proxy->capture_len;
1849 memcpy(t->logs.srv_cookie, p1, log_len);
1850 t->logs.srv_cookie[log_len] = 0;
1851 }
1852
1853 if ((p2 - p1 == t->proxy->cookie_len) && (t->proxy->cookie_name != NULL) &&
1854 (memcmp(p1, t->proxy->cookie_name, p2 - p1) == 0)) {
1855 /* Cool... it's the right one */
1856 t->flags |= SN_SCK_SEEN;
1857
1858 /* If the cookie is in insert mode on a known server, we'll delete
1859 * this occurrence because we'll insert another one later.
1860 * We'll delete it too if the "indirect" option is set and we're in
1861 * a direct access. */
1862 if (((t->srv) && (t->proxy->options & PR_O_COOK_INS)) ||
1863 ((t->flags & SN_DIRECT) && (t->proxy->options & PR_O_COOK_IND))) {
1864 /* this header must be deleted */
1865 delete_header = 1;
1866 t->flags |= SN_SCK_DELETED;
1867 }
1868 else if ((t->srv) && (t->proxy->options & PR_O_COOK_RW)) {
1869 /* replace bytes p3->p4 with the cookie name associated
1870 * with this server since we know it.
1871 */
1872 buffer_replace2(rep, p3, p4, t->srv->cookie, t->srv->cklen);
1873 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
1874 }
1875 else if ((t->srv) && (t->proxy->options & PR_O_COOK_PFX)) {
1876 /* insert the cookie name associated with this server
1877 * before existing cookie, and insert a delimitor between them..
1878 */
1879 buffer_replace2(rep, p3, p3, t->srv->cookie, t->srv->cklen + 1);
1880 p3[t->srv->cklen] = COOKIE_DELIM;
1881 t->flags |= SN_SCK_INSERTED | SN_SCK_DELETED;
1882 }
1883 break;
1884 }
1885
1886 /* first, let's see if the cookie is our appcookie*/
1887 if ((t->proxy->appsession_name != NULL) &&
1888 (memcmp(p1, t->proxy->appsession_name, p2 - p1) == 0)) {
1889
1890 /* Cool... it's the right one */
1891
1892 size_t server_id_len = strlen(t->srv->id) + 1;
1893 asession_temp = &local_asession;
1894
1895 if ((asession_temp->sessid = pool_alloc_from(apools.sessid, apools.ses_msize)) == NULL) {
1896 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
1897 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
1898 }
1899 memcpy(asession_temp->sessid, p3, t->proxy->appsession_len);
1900 asession_temp->sessid[t->proxy->appsession_len] = 0;
1901 asession_temp->serverid = NULL;
1902
1903 /* only do insert, if lookup fails */
1904 if (chtbl_lookup(&(t->proxy->htbl_proxy), (void *) &asession_temp) != 0) {
1905 if ((asession_temp = pool_alloc(appsess)) == NULL) {
1906 Alert("Not enought Memory process_srv():asession:calloc().\n");
1907 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession:calloc().\n");
1908 return 0;
1909 }
1910 asession_temp->sessid = local_asession.sessid;
1911 asession_temp->serverid = local_asession.serverid;
1912 chtbl_insert(&(t->proxy->htbl_proxy), (void *) asession_temp);
1913 }/* end if (chtbl_lookup()) */
1914 else {
1915 /* free wasted memory */
1916 pool_free_to(apools.sessid, local_asession.sessid);
1917 } /* end else from if (chtbl_lookup()) */
1918
1919 if (asession_temp->serverid == NULL) {
1920 if ((asession_temp->serverid = pool_alloc_from(apools.serverid, apools.ser_msize)) == NULL) {
1921 Alert("Not enought Memory process_srv():asession->sessid:malloc().\n");
1922 send_log(t->proxy, LOG_ALERT, "Not enought Memory process_srv():asession->sessid:malloc().\n");
1923 }
1924 asession_temp->serverid[0] = '\0';
1925 }
1926
1927 if (asession_temp->serverid[0] == '\0')
1928 memcpy(asession_temp->serverid,t->srv->id,server_id_len);
1929
1930 tv_delayfrom(&asession_temp->expire, &now, t->proxy->appsession_timeout);
1931
1932#if defined(DEBUG_HASH)
1933 print_table(&(t->proxy->htbl_proxy));
1934#endif
1935 break;
1936 }/* end if ((t->proxy->appsession_name != NULL) ... */
1937 else {
1938 // fprintf(stderr,"Ignoring unknown cookie : ");
1939 // write(2, p1, p2-p1);
1940 // fprintf(stderr," = ");
1941 // write(2, p3, p4-p3);
1942 // fprintf(stderr,"\n");
1943 }
1944 break; /* we don't want to loop again since there cannot be another cookie on the same line */
1945 } /* we're now at the end of the cookie value */
1946 } /* end of cookie processing */
1947
1948 /* check for any set-cookie in case we check for cacheability */
1949 if (!delete_header && !(t->flags & SN_SCK_ANY) &&
1950 (t->proxy->options & PR_O_CHK_CACHE) &&
1951 (strncasecmp(rep->h, "Set-Cookie: ", 12) == 0)) {
1952 t->flags |= SN_SCK_ANY;
1953 }
1954
1955 /* let's look if we have to delete this header */
1956 if (delete_header && !(t->flags & SN_SVDENY))
1957 buffer_replace2(rep, rep->h, rep->lr, "", 0);
1958
1959 rep->h = rep->lr;
1960 } /* while (rep->lr < rep->r) */
1961
1962 /* end of header processing (even if incomplete) */
1963
1964 if ((rep->l < rep->rlim - rep->data) && ! FD_ISSET(t->srv_fd, StaticReadEvent)) {
1965 /* fd in StaticReadEvent was disabled, perhaps because of a previous buffer
1966 * full. We cannot loop here since event_srv_read will disable it only if
1967 * rep->l == rlim-data
1968 */
1969 FD_SET(t->srv_fd, StaticReadEvent);
1970 if (t->proxy->srvtimeout)
1971 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
1972 else
1973 tv_eternity(&t->srexpire);
1974 }
1975
1976 /* read error, write error */
1977 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
1978 tv_eternity(&t->srexpire);
1979 tv_eternity(&t->swexpire);
1980 fd_delete(t->srv_fd);
1981 if (t->srv) {
1982 t->srv->cur_sess--;
1983 t->srv->failed_resp++;
1984 }
1985 t->proxy->failed_resp++;
1986
1987 t->srv_state = SV_STCLOSE;
1988 t->logs.status = 502;
1989 client_return(t, t->proxy->errmsg.len502, t->proxy->errmsg.msg502);
1990 if (!(t->flags & SN_ERR_MASK))
1991 t->flags |= SN_ERR_SRVCL;
1992 if (!(t->flags & SN_FINST_MASK))
1993 t->flags |= SN_FINST_H;
1994 /* We used to have a free connection slot. Since we'll never use it,
1995 * we have to inform the server that it may be used by another session.
1996 */
1997 if (may_dequeue_tasks(t->srv, t->proxy))
1998 task_wakeup(&rq, t->srv->queue_mgt);
1999
2000 return 1;
2001 }
2002 /* end of client write or end of server read.
2003 * since we are in header mode, if there's no space left for headers, we
2004 * won't be able to free more later, so the session will never terminate.
2005 */
2006 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE || rep->l >= rep->rlim - rep->data) {
2007 FD_CLR(t->srv_fd, StaticReadEvent);
2008 tv_eternity(&t->srexpire);
2009 shutdown(t->srv_fd, SHUT_RD);
2010 t->srv_state = SV_STSHUTR;
2011 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2012 return 1;
2013 }
2014 /* read timeout : return a 504 to the client.
2015 */
2016 else if (FD_ISSET(t->srv_fd, StaticReadEvent) && tv_cmp2_ms(&t->srexpire, &now) <= 0) {
2017 tv_eternity(&t->srexpire);
2018 tv_eternity(&t->swexpire);
2019 fd_delete(t->srv_fd);
2020 if (t->srv) {
2021 t->srv->cur_sess--;
2022 t->srv->failed_resp++;
2023 }
2024 t->proxy->failed_resp++;
2025 t->srv_state = SV_STCLOSE;
2026 t->logs.status = 504;
2027 client_return(t, t->proxy->errmsg.len504, t->proxy->errmsg.msg504);
2028 if (!(t->flags & SN_ERR_MASK))
2029 t->flags |= SN_ERR_SRVTO;
2030 if (!(t->flags & SN_FINST_MASK))
2031 t->flags |= SN_FINST_H;
2032 /* We used to have a free connection slot. Since we'll never use it,
2033 * we have to inform the server that it may be used by another session.
2034 */
2035 if (may_dequeue_tasks(t->srv, t->proxy))
2036 task_wakeup(&rq, t->srv->queue_mgt);
2037
2038 return 1;
2039 }
2040 /* last client read and buffer empty */
2041 /* FIXME!!! here, we don't want to switch to SHUTW if the
2042 * client shuts read too early, because we may still have
2043 * some work to do on the headers.
2044 * The side-effect is that if the client completely closes its
2045 * connection during SV_STHEADER, the connection to the server
2046 * is kept until a response comes back or the timeout is reached.
2047 */
2048 else if ((/*c == CL_STSHUTR ||*/ c == CL_STCLOSE) && (req->l == 0)) {
2049 FD_CLR(t->srv_fd, StaticWriteEvent);
2050 tv_eternity(&t->swexpire);
2051
2052 /* We must ensure that the read part is still alive when switching
2053 * to shutw */
2054 FD_SET(t->srv_fd, StaticReadEvent);
2055 if (t->proxy->srvtimeout)
2056 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2057
2058 shutdown(t->srv_fd, SHUT_WR);
2059 t->srv_state = SV_STSHUTW;
2060 return 1;
2061 }
2062 /* write timeout */
2063 /* FIXME!!! here, we don't want to switch to SHUTW if the
2064 * client shuts read too early, because we may still have
2065 * some work to do on the headers.
2066 */
2067 else if (FD_ISSET(t->srv_fd, StaticWriteEvent) && tv_cmp2_ms(&t->swexpire, &now) <= 0) {
2068 FD_CLR(t->srv_fd, StaticWriteEvent);
2069 tv_eternity(&t->swexpire);
2070 shutdown(t->srv_fd, SHUT_WR);
2071 /* We must ensure that the read part is still alive when switching
2072 * to shutw */
2073 FD_SET(t->srv_fd, StaticReadEvent);
2074 if (t->proxy->srvtimeout)
2075 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2076
2077 /* We must ensure that the read part is still alive when switching
2078 * to shutw */
2079 FD_SET(t->srv_fd, StaticReadEvent);
2080 if (t->proxy->srvtimeout)
2081 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2082
2083 t->srv_state = SV_STSHUTW;
2084 if (!(t->flags & SN_ERR_MASK))
2085 t->flags |= SN_ERR_SRVTO;
2086 if (!(t->flags & SN_FINST_MASK))
2087 t->flags |= SN_FINST_H;
2088 return 1;
2089 }
2090
2091 if (req->l == 0) {
2092 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2093 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2094 tv_eternity(&t->swexpire);
2095 }
2096 }
2097 else { /* client buffer not empty */
2098 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2099 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2100 if (t->proxy->srvtimeout) {
2101 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2102 /* FIXME: to prevent the server from expiring read timeouts during writes,
2103 * we refresh it. */
2104 t->srexpire = t->swexpire;
2105 }
2106 else
2107 tv_eternity(&t->swexpire);
2108 }
2109 }
2110
2111 /* be nice with the client side which would like to send a complete header
2112 * FIXME: COMPLETELY BUGGY !!! not all headers may be processed because the client
2113 * would read all remaining data at once ! The client should not write past rep->lr
2114 * when the server is in header state.
2115 */
2116 //return header_processed;
2117 return t->srv_state != SV_STHEADERS;
2118 }
2119 else if (s == SV_STDATA) {
2120 /* read or write error */
2121 if (t->res_sw == RES_ERROR || t->res_sr == RES_ERROR) {
2122 tv_eternity(&t->srexpire);
2123 tv_eternity(&t->swexpire);
2124 fd_delete(t->srv_fd);
2125 if (t->srv) {
2126 t->srv->cur_sess--;
2127 t->srv->failed_resp++;
2128 }
2129 t->proxy->failed_resp++;
2130 t->srv_state = SV_STCLOSE;
2131 if (!(t->flags & SN_ERR_MASK))
2132 t->flags |= SN_ERR_SRVCL;
2133 if (!(t->flags & SN_FINST_MASK))
2134 t->flags |= SN_FINST_D;
2135 /* We used to have a free connection slot. Since we'll never use it,
2136 * we have to inform the server that it may be used by another session.
2137 */
2138 if (may_dequeue_tasks(t->srv, t->proxy))
2139 task_wakeup(&rq, t->srv->queue_mgt);
2140
2141 return 1;
2142 }
2143 /* last read, or end of client write */
2144 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
2145 FD_CLR(t->srv_fd, StaticReadEvent);
2146 tv_eternity(&t->srexpire);
2147 shutdown(t->srv_fd, SHUT_RD);
2148 t->srv_state = SV_STSHUTR;
2149 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
2150 return 1;
2151 }
2152 /* end of client read and no more data to send */
2153 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
2154 FD_CLR(t->srv_fd, StaticWriteEvent);
2155 tv_eternity(&t->swexpire);
2156 shutdown(t->srv_fd, SHUT_WR);
2157 /* We must ensure that the read part is still alive when switching
2158 * to shutw */
2159 FD_SET(t->srv_fd, StaticReadEvent);
2160 if (t->proxy->srvtimeout)
2161 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2162
2163 t->srv_state = SV_STSHUTW;
2164 return 1;
2165 }
2166 /* read timeout */
2167 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
2168 FD_CLR(t->srv_fd, StaticReadEvent);
2169 tv_eternity(&t->srexpire);
2170 shutdown(t->srv_fd, SHUT_RD);
2171 t->srv_state = SV_STSHUTR;
2172 if (!(t->flags & SN_ERR_MASK))
2173 t->flags |= SN_ERR_SRVTO;
2174 if (!(t->flags & SN_FINST_MASK))
2175 t->flags |= SN_FINST_D;
2176 return 1;
2177 }
2178 /* write timeout */
2179 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
2180 FD_CLR(t->srv_fd, StaticWriteEvent);
2181 tv_eternity(&t->swexpire);
2182 shutdown(t->srv_fd, SHUT_WR);
2183 /* We must ensure that the read part is still alive when switching
2184 * to shutw */
2185 FD_SET(t->srv_fd, StaticReadEvent);
2186 if (t->proxy->srvtimeout)
2187 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2188 t->srv_state = SV_STSHUTW;
2189 if (!(t->flags & SN_ERR_MASK))
2190 t->flags |= SN_ERR_SRVTO;
2191 if (!(t->flags & SN_FINST_MASK))
2192 t->flags |= SN_FINST_D;
2193 return 1;
2194 }
2195
2196 /* recompute request time-outs */
2197 if (req->l == 0) {
2198 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2199 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2200 tv_eternity(&t->swexpire);
2201 }
2202 }
2203 else { /* buffer not empty, there are still data to be transferred */
2204 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2205 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2206 if (t->proxy->srvtimeout) {
2207 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2208 /* FIXME: to prevent the server from expiring read timeouts during writes,
2209 * we refresh it. */
2210 t->srexpire = t->swexpire;
2211 }
2212 else
2213 tv_eternity(&t->swexpire);
2214 }
2215 }
2216
2217 /* recompute response time-outs */
2218 if (rep->l == BUFSIZE) { /* no room to read more data */
2219 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2220 FD_CLR(t->srv_fd, StaticReadEvent);
2221 tv_eternity(&t->srexpire);
2222 }
2223 }
2224 else {
2225 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2226 FD_SET(t->srv_fd, StaticReadEvent);
2227 if (t->proxy->srvtimeout)
2228 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2229 else
2230 tv_eternity(&t->srexpire);
2231 }
2232 }
2233
2234 return 0; /* other cases change nothing */
2235 }
2236 else if (s == SV_STSHUTR) {
2237 if (t->res_sw == RES_ERROR) {
2238 //FD_CLR(t->srv_fd, StaticWriteEvent);
2239 tv_eternity(&t->swexpire);
2240 fd_delete(t->srv_fd);
2241 if (t->srv) {
2242 t->srv->cur_sess--;
2243 t->srv->failed_resp++;
2244 }
2245 t->proxy->failed_resp++;
2246 //close(t->srv_fd);
2247 t->srv_state = SV_STCLOSE;
2248 if (!(t->flags & SN_ERR_MASK))
2249 t->flags |= SN_ERR_SRVCL;
2250 if (!(t->flags & SN_FINST_MASK))
2251 t->flags |= SN_FINST_D;
2252 /* We used to have a free connection slot. Since we'll never use it,
2253 * we have to inform the server that it may be used by another session.
2254 */
2255 if (may_dequeue_tasks(t->srv, t->proxy))
2256 task_wakeup(&rq, t->srv->queue_mgt);
2257
2258 return 1;
2259 }
2260 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
2261 //FD_CLR(t->srv_fd, StaticWriteEvent);
2262 tv_eternity(&t->swexpire);
2263 fd_delete(t->srv_fd);
2264 if (t->srv)
2265 t->srv->cur_sess--;
2266 //close(t->srv_fd);
2267 t->srv_state = SV_STCLOSE;
2268 /* We used to have a free connection slot. Since we'll never use it,
2269 * we have to inform the server that it may be used by another session.
2270 */
2271 if (may_dequeue_tasks(t->srv, t->proxy))
2272 task_wakeup(&rq, t->srv->queue_mgt);
2273
2274 return 1;
2275 }
2276 else if (tv_cmp2_ms(&t->swexpire, &now) <= 0) {
2277 //FD_CLR(t->srv_fd, StaticWriteEvent);
2278 tv_eternity(&t->swexpire);
2279 fd_delete(t->srv_fd);
2280 if (t->srv)
2281 t->srv->cur_sess--;
2282 //close(t->srv_fd);
2283 t->srv_state = SV_STCLOSE;
2284 if (!(t->flags & SN_ERR_MASK))
2285 t->flags |= SN_ERR_SRVTO;
2286 if (!(t->flags & SN_FINST_MASK))
2287 t->flags |= SN_FINST_D;
2288 /* We used to have a free connection slot. Since we'll never use it,
2289 * we have to inform the server that it may be used by another session.
2290 */
2291 if (may_dequeue_tasks(t->srv, t->proxy))
2292 task_wakeup(&rq, t->srv->queue_mgt);
2293
2294 return 1;
2295 }
2296 else if (req->l == 0) {
2297 if (FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2298 FD_CLR(t->srv_fd, StaticWriteEvent); /* stop writing */
2299 tv_eternity(&t->swexpire);
2300 }
2301 }
2302 else { /* buffer not empty */
2303 if (! FD_ISSET(t->srv_fd, StaticWriteEvent)) {
2304 FD_SET(t->srv_fd, StaticWriteEvent); /* restart writing */
2305 if (t->proxy->srvtimeout) {
2306 tv_delayfrom(&t->swexpire, &now, t->proxy->srvtimeout);
2307 /* FIXME: to prevent the server from expiring read timeouts during writes,
2308 * we refresh it. */
2309 t->srexpire = t->swexpire;
2310 }
2311 else
2312 tv_eternity(&t->swexpire);
2313 }
2314 }
2315 return 0;
2316 }
2317 else if (s == SV_STSHUTW) {
2318 if (t->res_sr == RES_ERROR) {
2319 //FD_CLR(t->srv_fd, StaticReadEvent);
2320 tv_eternity(&t->srexpire);
2321 fd_delete(t->srv_fd);
2322 if (t->srv) {
2323 t->srv->cur_sess--;
2324 t->srv->failed_resp++;
2325 }
2326 t->proxy->failed_resp++;
2327 //close(t->srv_fd);
2328 t->srv_state = SV_STCLOSE;
2329 if (!(t->flags & SN_ERR_MASK))
2330 t->flags |= SN_ERR_SRVCL;
2331 if (!(t->flags & SN_FINST_MASK))
2332 t->flags |= SN_FINST_D;
2333 /* We used to have a free connection slot. Since we'll never use it,
2334 * we have to inform the server that it may be used by another session.
2335 */
2336 if (may_dequeue_tasks(t->srv, t->proxy))
2337 task_wakeup(&rq, t->srv->queue_mgt);
2338
2339 return 1;
2340 }
2341 else if (t->res_sr == RES_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
2342 //FD_CLR(t->srv_fd, StaticReadEvent);
2343 tv_eternity(&t->srexpire);
2344 fd_delete(t->srv_fd);
2345 if (t->srv)
2346 t->srv->cur_sess--;
2347 //close(t->srv_fd);
2348 t->srv_state = SV_STCLOSE;
2349 /* We used to have a free connection slot. Since we'll never use it,
2350 * we have to inform the server that it may be used by another session.
2351 */
2352 if (may_dequeue_tasks(t->srv, t->proxy))
2353 task_wakeup(&rq, t->srv->queue_mgt);
2354
2355 return 1;
2356 }
2357 else if (tv_cmp2_ms(&t->srexpire, &now) <= 0) {
2358 //FD_CLR(t->srv_fd, StaticReadEvent);
2359 tv_eternity(&t->srexpire);
2360 fd_delete(t->srv_fd);
2361 if (t->srv)
2362 t->srv->cur_sess--;
2363 //close(t->srv_fd);
2364 t->srv_state = SV_STCLOSE;
2365 if (!(t->flags & SN_ERR_MASK))
2366 t->flags |= SN_ERR_SRVTO;
2367 if (!(t->flags & SN_FINST_MASK))
2368 t->flags |= SN_FINST_D;
2369 /* We used to have a free connection slot. Since we'll never use it,
2370 * we have to inform the server that it may be used by another session.
2371 */
2372 if (may_dequeue_tasks(t->srv, t->proxy))
2373 task_wakeup(&rq, t->srv->queue_mgt);
2374
2375 return 1;
2376 }
2377 else if (rep->l == BUFSIZE) { /* no room to read more data */
2378 if (FD_ISSET(t->srv_fd, StaticReadEvent)) {
2379 FD_CLR(t->srv_fd, StaticReadEvent);
2380 tv_eternity(&t->srexpire);
2381 }
2382 }
2383 else {
2384 if (! FD_ISSET(t->srv_fd, StaticReadEvent)) {
2385 FD_SET(t->srv_fd, StaticReadEvent);
2386 if (t->proxy->srvtimeout)
2387 tv_delayfrom(&t->srexpire, &now, t->proxy->srvtimeout);
2388 else
2389 tv_eternity(&t->srexpire);
2390 }
2391 }
2392 return 0;
2393 }
2394 else { /* SV_STCLOSE : nothing to do */
2395 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
2396 int len;
2397 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n", t->uniq_id, t->proxy->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
2398 write(1, trash, len);
2399 }
2400 return 0;
2401 }
2402 return 0;
2403}
2404
2405
2406/*
2407 * Produces data for the session <s> depending on its source. Expects to be
2408 * called with s->cli_state == CL_STSHUTR. Right now, only statistics can be
2409 * produced. It stops by itself by unsetting the SN_SELF_GEN flag from the
2410 * session, which it uses to keep on being called when there is free space in
2411 * the buffer, of simply by letting an empty buffer upon return. It returns 1
2412 * if it changes the session state from CL_STSHUTR, otherwise 0.
2413 */
2414int produce_content(struct session *s)
2415{
2416 struct buffer *rep = s->rep;
2417 struct proxy *px;
2418 struct server *sv;
2419 int msglen;
2420
2421 if (s->data_source == DATA_SRC_NONE) {
2422 s->flags &= ~SN_SELF_GEN;
2423 return 1;
2424 }
2425 else if (s->data_source == DATA_SRC_STATS) {
2426 msglen = 0;
2427
2428 if (s->data_state == DATA_ST_INIT) { /* the function had not been called yet */
2429 unsigned int up;
2430
2431 s->flags |= SN_SELF_GEN; // more data will follow
2432
2433 /* send the start of the HTTP response */
2434 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2435 "HTTP/1.0 200 OK\r\n"
2436 "Cache-Control: no-cache\r\n"
2437 "Connection: close\r\n"
Willy Tarreau791d66d2006-07-08 16:53:38 +02002438 "Content-Type: text/html\r\n"
Willy Tarreaubaaee002006-06-26 02:48:02 +02002439 "\r\n\r\n");
2440
2441 s->logs.status = 200;
2442 client_retnclose(s, msglen, trash); // send the start of the response.
2443 msglen = 0;
2444
2445 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
2446 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
2447 if (!(s->flags & SN_FINST_MASK))
2448 s->flags |= SN_FINST_R;
2449
2450 /* WARNING! This must fit in the first buffer !!! */
2451 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2452 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
2453 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
2454 "<style type=\"text/css\"><!--\n"
2455 "body {"
2456 " font-family: helvetica, arial;"
2457 " font-size: 12px;"
2458 " font-weight: normal;"
2459 " color: black;"
2460 " background: white;"
2461 "}\n"
2462 "td {"
2463 " font-size: 12px;"
2464 " align: center;"
2465 "}\n"
2466 "h1 {"
2467 " font-size: xx-large;"
2468 " margin-bottom: 0.5em;"
2469 "}\n"
2470 "h2 {"
2471 " font-family: helvetica, arial;"
2472 " font-size: x-large;"
2473 " font-weight: bold;"
2474 " font-style: italic;"
2475 " color: #6020a0;"
2476 " margin-top: 0em;"
2477 " margin-bottom: 0em;"
2478 "}\n"
2479 "h3 {"
2480 " font-family: helvetica, arial;"
2481 " font-size: 16px;"
2482 " font-weight: bold;"
2483 " color: #b00040;"
2484 " background: #e8e8d0;"
2485 " margin-top: 0em;"
2486 " margin-bottom: 0em;"
2487 "}\n"
2488 "li {"
2489 " margin-top: 0.25em;"
2490 " margin-right: 2em;"
2491 "}\n"
2492 ".hr {"
2493 " margin-top: 0.25em;"
2494 " border-color: black;"
2495 " border-bottom-style: solid;"
2496 "}\n"
2497 "table.tbl { border-collapse: collapse; border-width: 1px; border-style: solid; border-color: gray;}\n"
2498 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; border-color: gray; }\n"
2499 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray; }\n"
2500 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
2501 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
2502 "-->"
2503 "</style></head>");
2504
2505 if (buffer_write(rep, trash, msglen) != 0)
2506 return 0;
2507 msglen = 0;
2508
2509 up = (now.tv_sec - start_date.tv_sec);
2510
2511 /* WARNING! this has to fit the first packet too */
2512 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2513 "<body><h1>" PRODUCT_NAME "</h1>\n"
2514 "<h2>Statistics Report for pid %d</h2>\n"
2515 "<hr width=\"100%%\" class=\"hr\">\n"
2516 "<h3>&gt; General process information</h3>\n"
2517 "<table border=0><tr><td align=\"left\">\n"
2518 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
2519 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
2520 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
2521 "<b>maxsock = </b> %d<br>\n"
2522 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
2523 "</td><td width=\"10%%\">\n"
2524 "</td><td align=\"right\">\n"
2525 "<table class=\"lgd\">"
2526 "<tr><td bgcolor=\"#C0FFC0\">&nbsp;</td><td style=\"border-style: none;\">active UP </td>"
2527 "<td bgcolor=\"#B0D0FF\">&nbsp;</td><td style=\"border-style: none;\">backup UP </td></tr>"
2528 "<tr><td bgcolor=\"#FFFFA0\"></td><td style=\"border-style: none;\">active UP, going down </td>"
2529 "<td bgcolor=\"#C060FF\"></td><td style=\"border-style: none;\">backup UP, going down </td></tr>"
2530 "<tr><td bgcolor=\"#FFD020\"></td><td style=\"border-style: none;\">active DOWN, going up </td>"
2531 "<td bgcolor=\"#FF80FF\"></td><td style=\"border-style: none;\">backup DOWN, going up </td></tr>"
2532 "<tr><td bgcolor=\"#FF9090\"></td><td style=\"border-style: none;\">active or backup DOWN &nbsp;</td>"
2533 "<td bgcolor=\"#E0E0E0\"></td><td style=\"border-style: none;\">not checked </td></tr>"
2534 "</table>\n"
2535 "</tr></table>\n"
2536 "",
2537 pid, pid, global.nbproc,
2538 up / 86400, (up % 86400) / 3600,
2539 (up % 3600) / 60, (up % 60),
2540 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
2541 global.rlimit_memmax ? " MB" : "",
2542 global.rlimit_nofile,
2543 global.maxsock,
2544 global.maxconn,
2545 actconn
2546 );
2547
2548 if (buffer_write(rep, trash, msglen) != 0)
2549 return 0;
2550 msglen = 0;
2551
2552 s->data_state = DATA_ST_DATA;
2553 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
2554
2555 px = s->data_ctx.stats.px = proxy;
2556 s->data_ctx.stats.px_st = DATA_ST_INIT;
2557 }
2558
2559 while (s->data_ctx.stats.px) {
2560 int dispatch_sess, dispatch_cum;
2561 int failed_checks, down_trans;
2562 int failed_secu, failed_conns, failed_resp;
2563
2564 if (s->data_ctx.stats.px_st == DATA_ST_INIT) {
2565 /* we are on a new proxy */
2566 px = s->data_ctx.stats.px;
2567
2568 /* skip the disabled proxies */
2569 if (px->state == PR_STSTOPPED)
2570 goto next_proxy;
2571
2572 if (s->proxy->uri_auth && s->proxy->uri_auth->scope) {
2573 /* we have a limited scope, we have to check the proxy name */
2574 struct stat_scope *scope;
2575 int len;
2576
2577 len = strlen(px->id);
2578 scope = s->proxy->uri_auth->scope;
2579
2580 while (scope) {
2581 /* match exact proxy name */
2582 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
2583 break;
2584
2585 /* match '.' which means 'self' proxy */
2586 if (!strcmp(scope->px_id, ".") && px == s->proxy)
2587 break;
2588 scope = scope->next;
2589 }
2590
2591 /* proxy name not found */
2592 if (scope == NULL)
2593 goto next_proxy;
2594 }
2595
2596 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2597 "<h3>&gt; Proxy instance %s : "
2598 "%d conns (maxconn=%d), %d queued (%d unassigned), %d total conns</h3>\n"
2599 "",
2600 px->id,
2601 px->nbconn, px->maxconn, px->totpend, px->nbpend, px->cum_conn);
2602
2603 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2604 "<table cols=\"16\" class=\"tbl\">\n"
2605 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
2606 "<th colspan=5>Server</th>"
2607 "<th colspan=2>Queue</th>"
2608 "<th colspan=4>Sessions</th>"
2609 "<th colspan=5>Errors</th></tr>\n"
2610 "<tr align=\"center\" bgcolor=\"#20C0C0\">"
2611 "<th>Name</th><th>Weight</th><th>Status</th><th>Act.</th><th>Bck.</th>"
2612 "<th>Curr.</th><th>Max.</th>"
2613 "<th>Curr.</th><th>Max.</th><th>Limit</th><th>Cumul.</th>"
2614 "<th>Conn.</th><th>Resp.</th><th>Sec.</th><th>Check</th><th>Down</th></tr>\n");
2615
2616 if (buffer_write(rep, trash, msglen) != 0)
2617 return 0;
2618 msglen = 0;
2619
2620 s->data_ctx.stats.sv = px->srv;
2621 s->data_ctx.stats.px_st = DATA_ST_DATA;
2622 }
2623
2624 px = s->data_ctx.stats.px;
2625
2626 /* stats.sv has been initialized above */
2627 while (s->data_ctx.stats.sv != NULL) {
2628 static char *act_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FFD020", /*failing*/"#FFFFA0", /*up*/"#C0FFC0", /*unchecked*/"#E0E0E0" };
2629 static char *bck_tab_bg[5] = { /*down*/"#FF9090", /*rising*/"#FF80ff", /*failing*/"#C060FF", /*up*/"#B0D0FF", /*unchecked*/"#E0E0E0" };
2630 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;", "UP", "<i>no check</i>" };
2631 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP */
2632
2633 sv = s->data_ctx.stats.sv;
2634
2635 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
2636 if (!(sv->state & SRV_CHECKED))
2637 sv_state = 4;
2638 else if (sv->state & SRV_RUNNING)
2639 if (sv->health == sv->rise + sv->fall - 1)
2640 sv_state = 3; /* UP */
2641 else
2642 sv_state = 2; /* going down */
2643 else
2644 if (sv->health)
2645 sv_state = 1; /* going up */
2646 else
2647 sv_state = 0; /* DOWN */
2648
2649 /* name, weight */
2650 msglen += snprintf(trash, sizeof(trash),
2651 "<tr align=center bgcolor=\"%s\"><td>%s</td><td>%d</td><td>",
2652 (sv->state & SRV_BACKUP) ? bck_tab_bg[sv_state] : act_tab_bg[sv_state],
2653 sv->id, sv->uweight+1);
2654 /* status */
2655 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, srv_hlt_st[sv_state],
2656 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
2657 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
2658
2659 /* act, bck */
2660 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2661 "</td><td>%s</td><td>%s</td>",
2662 (sv->state & SRV_BACKUP) ? "-" : "Y",
2663 (sv->state & SRV_BACKUP) ? "Y" : "-");
2664
2665 /* queue : current, max */
2666 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2667 "<td align=right>%d</td><td align=right>%d</td>",
2668 sv->nbpend, sv->nbpend_max);
2669
2670 /* sessions : current, max, limit, cumul */
2671 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2672 "<td align=right>%d</td><td align=right>%d</td><td align=right>%s</td><td align=right>%d</td>",
2673 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess);
2674
2675 /* errors : connect, response, security */
2676 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2677 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
2678 sv->failed_conns, sv->failed_resp, sv->failed_secu);
2679
2680 /* check failures : unique, fatal */
2681 if (sv->state & SRV_CHECKED)
2682 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2683 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
2684 sv->failed_checks, sv->down_trans);
2685 else
2686 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2687 "<td align=right>-</td><td align=right>-</td></tr>\n");
2688
2689 if (buffer_write(rep, trash, msglen) != 0)
2690 return 0;
2691 msglen = 0;
2692
2693 s->data_ctx.stats.sv = sv->next;
2694 } /* while sv */
2695
2696 /* now we are past the last server, we'll dump information about the dispatcher */
2697
2698 /* We have to count down from the proxy to the servers to tell how
2699 * many sessions are on the dispatcher, and how many checks have
2700 * failed. We cannot count this during the servers dump because it
2701 * might be interrupted multiple times.
2702 */
2703 dispatch_sess = px->nbconn;
2704 dispatch_cum = px->cum_conn;
2705 failed_secu = px->failed_secu;
2706 failed_conns = px->failed_conns;
2707 failed_resp = px->failed_resp;
2708 failed_checks = down_trans = 0;
2709
2710 sv = px->srv;
2711 while (sv) {
2712 dispatch_sess -= sv->cur_sess;
2713 dispatch_cum -= sv->cum_sess;
2714 failed_conns -= sv->failed_conns;
2715 failed_resp -= sv->failed_resp;
2716 failed_secu -= sv->failed_secu;
2717 if (sv->state & SRV_CHECKED) {
2718 failed_checks += sv->failed_checks;
2719 down_trans += sv->down_trans;
2720 }
2721 sv = sv->next;
2722 }
2723
2724 /* name, weight, status, act, bck */
2725 msglen += snprintf(trash + msglen, sizeof(trash),
2726 "<tr align=center bgcolor=\"#e8e8d0\">"
2727 "<td>Dispatcher</td><td>-</td>"
2728 "<td>%s</td><td>-</td><td>-</td>",
2729 px->state == PR_STRUN ? "UP" : "DOWN");
2730
2731 /* queue : current, max */
2732 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2733 "<td align=right>%d</td><td align=right>%d</td>",
2734 px->nbpend, px->nbpend_max);
2735
2736 /* sessions : current, max, limit, cumul. */
2737 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2738 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>",
2739 dispatch_sess, px->nbconn_max, px->maxconn, dispatch_cum);
2740
2741 /* errors : connect, response, security */
2742 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2743 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
2744 failed_conns, failed_resp, failed_secu);
2745
2746 /* check failures : unique, fatal */
2747 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2748 "<td align=right>-</td><td align=right>-</td></tr>\n");
2749
2750
2751 /* now the summary for the whole proxy */
2752 /* name, weight, status, act, bck */
2753 msglen += snprintf(trash + msglen, sizeof(trash),
2754 "<tr align=center style=\"color: #ffff80; background: #20C0C0;\">"
2755 "<td><b>Total</b></td><td>-</td>"
2756 "<td><b>%s</b></td><td><b>%d</b></td><td><b>%d</b></td>",
2757 (px->state == PR_STRUN && ((px->srv == NULL) || px->srv_act || px->srv_bck)) ? "UP" : "DOWN",
2758 px->srv_act, px->srv_bck);
2759
2760 /* queue : current, max */
2761 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2762 "<td align=right><b>%d</b></td><td align=right><b>%d</b></td>",
2763 px->totpend, px->nbpend_max);
2764
2765 /* sessions : current, max, limit, cumul */
2766 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2767 "<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>",
2768 px->nbconn, px->nbconn_max, px->maxconn, px->cum_conn);
2769
2770 /* errors : connect, response, security */
2771 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2772 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>\n",
2773 px->failed_conns, px->failed_resp, px->failed_secu);
2774
2775 /* check failures : unique, fatal */
2776 msglen += snprintf(trash + msglen, sizeof(trash) - msglen,
2777 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
2778 failed_checks, down_trans);
2779
2780 msglen += snprintf(trash + msglen, sizeof(trash) - msglen, "</table><p>\n");
2781
2782 if (buffer_write(rep, trash, msglen) != 0)
2783 return 0;
2784 msglen = 0;
2785
2786 s->data_ctx.stats.px_st = DATA_ST_INIT;
2787 next_proxy:
2788 s->data_ctx.stats.px = px->next;
2789 } /* proxy loop */
2790 /* here, we just have reached the sv == NULL and px == NULL */
2791 s->flags &= ~SN_SELF_GEN;
2792 return 1;
2793 }
2794 else {
2795 /* unknown data source */
2796 s->logs.status = 500;
2797 client_retnclose(s, s->proxy->errmsg.len500, s->proxy->errmsg.msg500);
2798 if (!(s->flags & SN_ERR_MASK))
2799 s->flags |= SN_ERR_PRXCOND;
2800 if (!(s->flags & SN_FINST_MASK))
2801 s->flags |= SN_FINST_R;
2802 s->flags &= SN_SELF_GEN;
2803 return 1;
2804 }
2805}
2806
2807
2808/*
2809 * Local variables:
2810 * c-indent-level: 8
2811 * c-basic-offset: 8
2812 * End:
2813 */