Re: How does http_find_header() work?

From: Willy Tarreau <w#1wt.eu>
Date: Sun, 27 Mar 2011 20:22:03 +0200


Hi Roy,

On Sun, Mar 27, 2011 at 01:31:25PM -0400, Roy Smith wrote:
> I'm trying to modify haproxy-1.4.11 (on Ubuntu) to do some additional logging. I've added to http_sess_log(), some experimental code:
>
> --- a/src/proto_http.c Sat Mar 26 12:38:10 2011 -0400
> +++ b/src/proto_http.c Sat Mar 26 19:18:30 2011 -0400
> @@ -1081,6 +1081,7 @@
> static char tmpline[MAX_SYSLOG_LEN];
> int t_request;
> int hdr;
> + struct hdr_ctx ctx;
>
> /* if we don't want to log normal traffic, return now */
> err = (s->flags & (SN_ERR_MASK | SN_REDISP)) ||
> @@ -1149,6 +1150,14 @@
> '#', url_encode_map, uri);
> *(h++) = '"';
> }
> +
> + if (http_find_header("X-Unique-ID", txn->req.sol, &txn->hdr_idx, &ctx)) {
> + // if (h < tmpline + ctx.vlen - 4) {
> + // memcpy(tmpline, ctx.val, ctx.vlen);
> + // h += ctx.vlen;
> + // }
> + }
> +
> *h = '\0';
>
> svid = (tolog & LW_SVID) ?
>
> when this code runs, I get a segfault as soon as it tries to log anything. I'm obviously calling http_find_header() wrong, but I can't figure out what I should be doing. When I look at the resulting core file with gdb, it shows that txn->req.sol is not initialized.
>
> #0 http_find_header2 (name=0x44d6af "X-Unique-ID", len=11, sol=0x1 <Address 0x1 out of bounds>, idx=0x795960, ctx=0x7fff37575a80) at src/proto_http.c:513
> 513 eol = sol + idx->v[cur_idx].len;
>
> Is there something I need to be doing to initialize the sol element of the request?

There are several things which cannot work for your use case.

  1. the returned pointers are pointers to the data buffer. Thus, request headers can only be retrieved during the request processing, and response headers can only be retrieved during response processing. outside of these periods, you may find anything in the buffers.
  2. the headers are "indexed", in fact they're linked in a list of relative pointers and sizes pointer to by txn->hdr_idx. As you can see, there is only one list per transaction, because this list takes some space, and we never have to process request and response headers at the same time. So what you'd find will be indexes on the response headers at the end of a normally processed session.
  3. the buffers' "sol" pointer normally points to the first line of request or response during parsing. Once headers are parsed, we expect to possibly find chunked-encoded data which also need to be parsed and also require several pointers to be maintained. So at this point, the "sol" pointer is initialized to the beginning of the body, prepared to point to the beginning of any chunk size.

Your segfault is very likely caused by this sol pointer being much advanced in the buffer, and your indexes referencing large relative positions, causing and out-of-bounds on the buffer when checking whether the header you're looking for is present or not.

If you need to log some request data, you have to do that during the request processing, and copy them somewhere in the session. You should probably use the header capture for that, they'll do that for free. Alternatively, you may add a fixed size string to the session struct and use it for your needs.

Regards,
Willy Received on 2011/03/27 20:22

This archive was generated by hypermail 2.2.0 : 2011/03/27 20:30 CEST