From f073a83b1d4181f82e545275e49422df59bde6b0 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 1 Mar 2009 23:21:47 +0100 Subject: [PATCH] [MEDIUM] store a complete dump of request and response errors in proxies Each proxy instance, either frontend or backend, now has some room dedicated to storing a complete dated request or response in case of parsing error. This will make it possible to consult errors in order to find the exact cause, which is particularly important for troubleshooting faulty applications. --- include/types/proxy.h | 12 ++++++++++++ src/proto_http.c | 31 ++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/include/types/proxy.h b/include/types/proxy.h index 2f6779150..9adf5cde2 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -123,6 +123,17 @@ struct fwrr_group { int next_weight; /* total weight of the next time range */ }; +struct error_snapshot { + struct timeval when; /* date of this event, (tv_sec == 0) means "never" */ + unsigned int len; /* original length of the last invalid request/response */ + unsigned int pos; /* position of the first invalid character */ + unsigned int sid; /* ID of the faulty session */ + struct server *srv; /* server associated with the error (or NULL) */ + struct proxy *oe; /* other end = frontend or backend involved */ + struct sockaddr_storage src; /* client's address */ + char buf[BUFSIZE]; /* copy of the beginning of the message */ +}; + struct proxy { struct listener *listen; /* the listen addresses and sockets */ struct in_addr mon_net, mon_mask; /* don't forward connections from this net (network order) FIXME: should support IPv6 */ @@ -259,6 +270,7 @@ struct proxy { int next_svid; /* next server-id, used for SNMP */ unsigned int backlog; /* force the frontend's listen backlog */ unsigned int bind_proc; /* bitmask of processes using this proxy. 0 = all. */ + struct error_snapshot invalid_req, invalid_rep; /* captures of last errors */ }; struct switching_rule { diff --git a/src/proto_http.c b/src/proto_http.c index 86b411ea8..c88a93c72 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -1538,7 +1538,7 @@ int http_process_request(struct session *s, struct buffer *req) * For the parsing, we use a 28 states FSM. * * Here is the information we currently have : - * req->data + req->som = beginning of request + * req->data + msg->som = beginning of request * req->data + req->eoh = end of processed headers / start of current one * req->data + req->eol = end of current header or line (LF or CRLF) * req->lr = first non-visited byte @@ -2317,6 +2317,21 @@ int http_process_request(struct session *s, struct buffer *req) return 1; return_bad_req: /* let's centralize all bad requests */ + if (unlikely(msg->msg_state == HTTP_MSG_ERROR)) { + /* we detected a parsing error. We want to archive this request + * in the dedicated proxy area for later troubleshooting. + */ + struct error_snapshot *es = &s->fe->invalid_req; + int maxlen = MIN(req->r - req->data + msg->som, sizeof(es->buf)); + memcpy(es->buf, req->data + msg->som, maxlen); + es->pos = req->lr - req->data + msg->som; + es->len = req->r - req->data + msg->som; + es->when = now; + es->sid = s->uniq_id; + es->srv = s->srv; + es->oe = s->be; + es->src = s->cli_addr; + } txn->req.msg_state = HTTP_MSG_ERROR; txn->status = 400; req->analysers = 0; @@ -2539,6 +2554,20 @@ int process_response(struct session *t) if (unlikely(msg->msg_state != HTTP_MSG_BODY)) { /* Invalid response */ if (unlikely(msg->msg_state == HTTP_MSG_ERROR)) { + /* we detected a parsing error. We want to archive this response + * in the dedicated proxy area for later troubleshooting. + */ + struct error_snapshot *es = &t->be->invalid_rep; + int maxlen = MIN(rep->r - rep->data + msg->som, sizeof(es->buf)); + memcpy(es->buf, rep->data + msg->som, maxlen); + es->pos = rep->lr - rep->data + msg->som; + es->len = rep->r - rep->data + msg->som; + es->when = now; + es->sid = t->uniq_id; + es->srv = t->srv; + es->oe = t->fe; + es->src = t->cli_addr; + hdr_response_bad: //buffer_shutr(rep); //buffer_shutw(req);