httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Martin Pool <...@linuxcare.com.au>
Subject Re: [PATCH] Re: mod_log_config: Cookie logging patch 1.3.X
Date Thu, 07 Dec 2000 00:52:58 GMT
On  7 Dec 2000, Martin Pool <mbp@linuxcare.com.au> wrote:

> > I understand the reasoning why not to include a new "feature" in 1.3, 
> > but meanwhile  %c is also new for 1.3.15, so that pretty much kills the
> > argument for me. :-)

Can we please use this patch instead?  It's parsing of the header is
much closer to the RFC.

  http://linuxcare.com.au/mbp/apache/apache-1.3.15dev-cookielog.patch

-- 
Martin Pool, Linuxcare, Inc.
+61 2 6262 8990
mbp@linuxcare.com, http://www.linuxcare.com/
Linuxcare. Support for the revolution.


This patch adds a new log format %{FOO}C, which logs the received
cookie FOO, if any.  It also adds a utility function to parse HTTP
attribute-value headers, and uses that code from mod_usertrack.c.

--
Martin Pool



Index: src/include/httpd.h
===================================================================
RCS file: /home/cvspublic/apache-1.3/src/include/httpd.h,v
retrieving revision 1.327
diff -u -r1.327 httpd.h
--- src/include/httpd.h 2000/11/14 09:57:01     1.327
+++ src/include/httpd.h 2000/12/07 00:42:41
@@ -1000,6 +1000,11 @@
 API_EXPORT(char *) ap_get_list_item(pool *p, const char **field);
 API_EXPORT(int) ap_find_list_item(pool *p, const char *line, const char *tok);
 
+API_EXPORT(int) ap_get_attr_value(pool *p, char const **line,
+                                 char const *wanted, char **valuep);
+API_EXPORT(int) ap_get_av_pair(pool *p, char const **lineptr,
+                              char **attr, char **value);
+
 API_EXPORT(char *) ap_get_token(pool *p, const char **accept_line, int accept_
white);
 API_EXPORT(int) ap_find_token(pool *p, const char *line, const char *tok);
 API_EXPORT(int) ap_find_last_token(pool *p, const char *line, const char *tok)
;
Index: src/main/util.c
===================================================================
RCS file: /home/cvspublic/apache-1.3/src/main/util.c,v
retrieving revision 1.192
diff -u -r1.192 util.c
--- src/main/util.c     2000/12/04 20:51:59     1.192
+++ src/main/util.c     2000/12/07 00:42:43
@@ -1344,12 +1344,62 @@
 }
 
 
+/* Retrieve the value of a specified attribute from an av-list.
+ * Attribute names are case-insensitive.
+ *
+ * Returns true if the attribute was found.  Even in this case VALUEP
+ * may still be null if the attribute was present with no value. */
+API_EXPORT(int) ap_get_attr_value(pool *p, char const **line,
+                                    char const *wanted,
+                                    char **valuep)
+{
+    char *name;
+
+    /* XXX: This will allocate copies of every item it scans, which is
+     * kind of inefficient.  But the headers should never be huge, and
+     * you know what they say about premature optimization. */
+    
+    while (ap_get_av_pair(p, line, &name, valuep)) {
+       if (!strcasecmp(name, wanted))
+           return 1;
+    }
+
+    *valuep = NULL;
+    return 0;
+}
+
+
+/* Retrieve an ATTRIBUTE=VALUE pair from an av-list.  (See RFC2068 and
+ * RFC2109 for the definition.)  The value may be missing, although
+ * most attributes require it.  Returns true if anything was found. */
+API_EXPORT(int) ap_get_av_pair(pool *p, char const **lineptr,
+                              char **attr, char **value)
+{
+    /* Read the first token, being the attribute. */
+    *attr = ap_get_token(p, lineptr, 0);
+    if (!**attr)
+       return 0;
+
+    /* We've already scanned trailing whitespace.  Now try to scan the
+     * '=' character. */
+    if (**lineptr != '=') 
+       return 1;
+
+    (*lineptr)++;
+
+    *value = ap_get_token(p, lineptr, 0);
+    return 1;
+}
+
+
 /* Retrieve a token, spacing over it and returning a pointer to
  * the first non-white byte afterwards.  Note that these tokens
  * are delimited by semis and commas; and can also be delimited
  * by whitespace at the caller's option.
- */
-
+ *
+ * Strictly, HTTP tokens cannot be quoted or contain whitespace.  But
+ * accepting this makes us more forgiving in what we accept, and
+ * allows this function also to be used to read quoted strings.  */
 API_EXPORT(char *) ap_get_token(pool *p, const char **accept_line, int accept_
white)
 {
     const char *ptr = *accept_line;
@@ -1368,12 +1418,17 @@
      * (comments are already gone).
      */
 
-    while (*ptr && (accept_white || !ap_isspace(*ptr))
-          && *ptr != ';' && *ptr != ',') {
-       if (*ptr++ == '"')
+    while (*ptr) {
+       if (*ptr++ == '"') {
            while (*ptr)
                if (*ptr++ == '"')
                    break;
+       } else if (accept_white && ap_isspace(*ptr)) {
+           /* not stricly part of a token, but the caller wants to accept it a
nyhow */
+           ;
+       } else if (TEST_CHAR(*ptr, T_HTTP_TOKEN_STOP)) {
+           break;
+       }
     }
 
     tok_len = ptr - tok_start;
Index: src/modules/standard/mod_log_config.c
===================================================================
RCS file: /home/cvspublic/apache-1.3/src/modules/standard/mod_log_config.c,v
retrieving revision 1.85
diff -u -r1.85 mod_log_config.c
--- src/modules/standard/mod_log_config.c       2000/11/14 09:57:22     1.85
+++ src/modules/standard/mod_log_config.c       2000/12/07 00:42:45
@@ -124,13 +124,14 @@
  *         'X' = connection aborted before the response completed.
  *         '+' = connection may be kept alive after the response is sent.
  *         '-' = connection will be closed after the response is sent.
+ * %...{FU}C:  Value of cookie FU received in request
  * %...{FOOBAR}e:  The contents of the environment variable FOOBAR
  * %...f:  filename
  * %...h:  remote host
  * %...a:  remote IP-address
  * %...A:  local IP-address
  * %...{Foobar}i:  The contents of Foobar: header line(s) in the request
- *                 sent to the client.
+ *                 sent by the client.
  * %...l:  remote logname (from identd, if supplied)
  * %...{Foobar}n:  The contents of note "Foobar" from another module.
  * %...{Foobar}o:  The contents of Foobar: header line(s) in the reply.
@@ -481,6 +482,29 @@
 
     return "-";
 }
+static const char *log_cookie(request_rec *r, char *wanted)
+{
+    char *cookie, *value;
+    
+    /* Apache does not keep cookies parsed out, so we must scan
+     * through the request headers to find matches.  Although it's
+     * possible that there might be multiple cookies of the same name
+     * for different domains that would be a pretty crazy design, so
+     * we don't handle it at the moment. */
+    char const *hdr = ap_table_get(r->headers_in, "Cookie");
+
+    if (!hdr)
+       return NULL;
+
+    if (ap_get_attr_value(r->pool, &hdr, wanted, &value))
+       return value;
+    else
+       return NULL;
+}
+
+
+
+
 /*****************************************************************
  *
  * Parsing the log format string
@@ -563,6 +587,9 @@
     },
     {
         'q', log_request_query, 0
+    },
+    {
+       'C', log_cookie, 0
     },
     {
         'c', log_connection_status, 0
Index: src/modules/standard/mod_usertrack.c
===================================================================
RCS file: /home/cvspublic/apache-1.3/src/modules/standard/mod_usertrack.c,v
retrieving revision 1.46
diff -u -r1.46 mod_usertrack.c
--- src/modules/standard/mod_usertrack.c        2000/11/14 09:57:28     1.46
+++ src/modules/standard/mod_usertrack.c        2000/12/07 00:42:45
@@ -230,20 +230,13 @@
     }
 
     if ((cookie = ap_table_get(r->headers_in, "Cookie")))
-        if ((value = strstr(cookie, dcfg->cookie_name))) {
-            char *cookiebuf, *cookieend;
-
-            value += strlen(dcfg->cookie_name) + 1;  /* Skip over the '=' */
-            cookiebuf = ap_pstrdup(r->pool, value);
-            cookieend = strchr(cookiebuf, ';');
-            if (cookieend)
-                *cookieend = '\0';      /* Ignore anything after a ; */
-
+       if (ap_get_attr_value(r->pool, &cookie, dcfg->cookie_name, &value))
{
             /* Set the cookie in a note, for logging */
-            ap_table_setn(r->notes, "cookie", cookiebuf);
+            ap_table_setn(r->notes, "cookie", value);
 
             return DECLINED;    /* There's already a cookie, no new one */
         }
+    
     make_cookie(r);
     return OK;                  /* We set our cookie */
 }


Mime
View raw message