]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: logs: Add HTTP request-line log format directives
authorAndrew Hayworth <andrew.hayworth@getbraintree.com>
Mon, 27 Apr 2015 21:37:03 +0000 (21:37 +0000)
committerWilly Tarreau <w@1wt.eu>
Tue, 28 Apr 2015 19:03:05 +0000 (21:03 +0200)
This commit adds 4 new log format variables that parse the
HTTP Request-Line for more specific logging than "%r" provides.

For example, we can parse the following HTTP Request-Line with
these new variables:

  "GET /foo?bar=baz HTTP/1.1"

- %HM: HTTP Method ("GET")
- %HV: HTTP Version ("HTTP/1.1")
- %HU: HTTP Request-URI ("/foo?bar=baz")
- %HP: HTTP Request-URI without query string ("/foo")

doc/configuration.txt
include/types/log.h
src/log.c

index a37f54c0124e47cad699c97089be3ce09d5f0807..b6b3f088fa98b0943a54d7e4040cbdc9e6c33356 100644 (file)
@@ -13159,6 +13159,10 @@ Please refer to the table below for currently defined variables :
   | H | %CC  | captured_request_cookie                       | string      |
   | H | %CS  | captured_response_cookie                      | string      |
   |   | %H   | hostname                                      | string      |
+  | H | %HM  | HTTP method (ex: POST)                        | string      |
+  | H | %HP  | HTTP request URI without query string (path)  | string      |
+  | H | %HU  | HTTP request URI (ex: /foo?bar=baz)           | string      |
+  | H | %HV  | HTTP version (ex: HTTP/1.0)                   | string      |
   |   | %ID  | unique-id                                     | string      |
   |   | %ST  | status_code                                   | numeric     |
   |   | %T   | gmt_date_time                                 | date        |
index 345a09f19899ccf218c1163df32dc5af6f135227..bbfe0209fd04d4ff677776cd8c1444ec913f7a6c 100644 (file)
@@ -93,6 +93,10 @@ enum {
        LOG_FMT_HDRREQUESTLIST,
        LOG_FMT_HDRRESPONSLIST,
        LOG_FMT_REQ,
+       LOG_FMT_HTTP_METHOD,
+       LOG_FMT_HTTP_URI,
+       LOG_FMT_HTTP_PATH,
+       LOG_FMT_HTTP_VERSION,
        LOG_FMT_HOSTNAME,
        LOG_FMT_UNIQUEID,
        LOG_FMT_SSL_CIPHER,
index 866b11077af79c1374e81db9620eb903fb03710a..2affac3881744be7bf51a94d6124e012b45d8724 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -32,6 +32,7 @@
 #include <types/log.h>
 
 #include <proto/frontend.h>
+#include <proto/proto_http.h>
 #include <proto/log.h>
 #include <proto/sample.h>
 #include <proto/stream.h>
@@ -108,6 +109,10 @@ static const struct logformat_type logformat_keywords[] = {
        { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
        { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL },  /* header response */
        { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL },  /* header response list */
+       { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL },  /* HTTP method */
+       { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL },  /* HTTP path */
+       { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL },  /* HTTP full URI */
+       { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL },  /* HTTP version */
        { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
        { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL },       /* accept date millisecond */
        { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
@@ -923,11 +928,15 @@ int build_logline(struct stream *s, char *dst, size_t maxsize, struct list *list
        struct proxy *fe = sess->fe;
        struct proxy *be = s->be;
        struct http_txn *txn = s->txn;
+       struct chunk chunk;
        char *uri;
+       char *spc;
+       char *end;
        struct tm tm;
        int t_request;
        int hdr;
        int last_isspace = 1;
+       int nspaces = 0;
        char *tmplog;
        char *ret;
        int iret;
@@ -1523,6 +1532,161 @@ int build_logline(struct stream *s, char *dst, size_t maxsize, struct list *list
                                last_isspace = 0;
                                break;
 
+                       case LOG_FMT_HTTP_PATH: // %HP
+                               uri = txn->uri ? txn->uri : "<BADREQ>";
+
+                               if (tmp->options && LOG_OPT_QUOTE)
+                                       LOGCHAR('"');
+
+                               end = uri + strlen(uri);
+                               // look for the first whitespace character
+                               while (uri < end && !HTTP_IS_SPHT(*uri))
+                                       uri++;
+
+                               // keep advancing past multiple spaces
+                               while (uri < end && HTTP_IS_SPHT(*uri)) {
+                                       uri++; nspaces++;
+                               }
+
+                               // look for first space or question mark after url
+                               spc = uri;
+                               while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
+                                       spc++;
+
+                               if (!txn->uri || nspaces == 0) {
+                                       chunk.str = "<BADREQ>";
+                                       chunk.len = strlen("<BADREQ>");
+                               } else {
+                                       chunk.str = uri;
+                                       chunk.len = spc - uri;
+                               }
+
+                               ret = encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk);
+                               if (ret == NULL || *ret != '\0')
+                                       goto out;
+
+                               tmplog = ret;
+                               if (tmp->options && LOG_OPT_QUOTE)
+                                       LOGCHAR('"');
+
+                               last_isspace = 0;
+                               break;
+
+                       case LOG_FMT_HTTP_URI: // %HU
+                               uri = txn->uri ? txn->uri : "<BADREQ>";
+
+                               if (tmp->options && LOG_OPT_QUOTE)
+                                       LOGCHAR('"');
+
+                               end = uri + strlen(uri);
+                               // look for the first whitespace character
+                               while (uri < end && !HTTP_IS_SPHT(*uri))
+                                       uri++;
+
+                               // keep advancing past multiple spaces
+                               while (uri < end && HTTP_IS_SPHT(*uri)) {
+                                       uri++; nspaces++;
+                               }
+
+                               // look for first space after url
+                               spc = uri;
+                               while (spc < end && !HTTP_IS_SPHT(*spc))
+                                       spc++;
+
+                               if (!txn->uri || nspaces == 0) {
+                                       chunk.str = "<BADREQ>";
+                                       chunk.len = strlen("<BADREQ>");
+                               } else {
+                                       chunk.str = uri;
+                                       chunk.len = spc - uri;
+                               }
+
+                               ret = encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk);
+                               if (ret == NULL || *ret != '\0')
+                                       goto out;
+
+                               tmplog = ret;
+                               if (tmp->options && LOG_OPT_QUOTE)
+                                       LOGCHAR('"');
+
+                               last_isspace = 0;
+                               break;
+
+                       case LOG_FMT_HTTP_METHOD: // %HM
+                               uri = txn->uri ? txn->uri : "<BADREQ>";
+                               if (tmp->options && LOG_OPT_QUOTE)
+                                       LOGCHAR('"');
+
+                               end = uri + strlen(uri);
+                               // look for the first whitespace character
+                               spc = uri;
+                               while (spc < end && !HTTP_IS_SPHT(*spc))
+                                       spc++;
+
+                               if (spc == end) { // odd case, we have txn->uri, but we only got a verb
+                                       chunk.str = "<BADREQ>";
+                                       chunk.len = strlen("<BADREQ>");
+                               } else {
+                                       chunk.str = uri;
+                                       chunk.len = spc - uri;
+                               }
+
+                               ret = encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk);
+                               if (ret == NULL || *ret != '\0')
+                                       goto out;
+
+                               tmplog = ret;
+                               if (tmp->options && LOG_OPT_QUOTE)
+                                       LOGCHAR('"');
+
+                               last_isspace = 0;
+                               break;
+
+                       case LOG_FMT_HTTP_VERSION: // %HV
+                               uri = txn->uri ? txn->uri : "<BADREQ>";
+                               if (tmp->options && LOG_OPT_QUOTE)
+                                       LOGCHAR('"');
+
+                               end = uri + strlen(uri);
+                               // look for the first whitespace character
+                               while (uri < end && !HTTP_IS_SPHT(*uri))
+                                       uri++;
+
+                               // keep advancing past multiple spaces
+                               while (uri < end && HTTP_IS_SPHT(*uri)) {
+                                       uri++; nspaces++;
+                               }
+
+                               // look for the next whitespace character
+                               while (uri < end && !HTTP_IS_SPHT(*uri))
+                                       uri++;
+
+                               // keep advancing past multiple spaces
+                               while (uri < end && HTTP_IS_SPHT(*uri))
+                                       uri++;
+
+                               if (!txn->uri || nspaces == 0) {
+                                       chunk.str = "<BADREQ>";
+                                       chunk.len = strlen("<BADREQ>");
+                               } else if (uri == end) {
+                                       chunk.str = "HTTP/0.9";
+                                       chunk.len = strlen("HTTP/0.9");
+                               } else {
+                                       chunk.str = uri;
+                                       chunk.len = end - uri;
+                               }
+
+                               ret = encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk);
+                               if (ret == NULL || *ret != '\0')
+                                       goto out;
+
+                               tmplog = ret;
+                               if (tmp->options && LOG_OPT_QUOTE)
+                                       LOGCHAR('"');
+
+                               last_isspace = 0;
+                               break;
+
                        case LOG_FMT_COUNTER: // %rt
                                if (tmp->options & LOG_OPT_HEXA) {
                                        iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", s->uniq_id);