mod_usertrack.c revision 0329db7881b698897213e816552b0ab31f8d4d56
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye/* ====================================================================
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * The Apache Software License, Version 1.1
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * Redistribution and use in source and binary forms, with or without
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * modification, are permitted provided that the following conditions
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * 1. Redistributions of source code must retain the above copyright
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * notice, this list of conditions and the following disclaimer.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * 2. Redistributions in binary form must reproduce the above copyright
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * notice, this list of conditions and the following disclaimer in
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * the documentation and/or other materials provided with the
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * distribution.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * 3. The end-user documentation included with the redistribution,
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * if any, must include the following acknowledgment:
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * "This product includes software developed by the
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * Apache Software Foundation (http://www.apache.org/)."
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * Alternately, this acknowledgment may appear in the software itself,
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * if and wherever such third-party acknowledgments normally appear.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * 4. The names "Apache" and "Apache Software Foundation" must
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * not be used to endorse or promote products derived from this
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * software without prior written permission. For written
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * permission, please contact apache@apache.org.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * 5. Products derived from this software may not be called "Apache",
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * nor may "Apache" appear in their name, without prior written
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * permission of the Apache Software Foundation.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * SUCH DAMAGE.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * ====================================================================
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * This software consists of voluntary contributions made by many
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * individuals on behalf of the Apache Software Foundation. For more
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * information on the Apache Software Foundation, please see
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * Portions of this software are based upon public domain software
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * originally written at the National Center for Supercomputing Applications,
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * University of Illinois, Urbana-Champaign.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye/* User Tracking Module (Was mod_cookies.c)
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * *** IMPORTANT NOTE: This module is not designed to generate
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * *** cryptographically secure cookies. This means you should not
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * *** use cookies generated by this module for authentication purposes
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * This Apache module is designed to track users paths through a site.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * It uses the client-side state ("Cookie") protocol developed by Netscape.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * It is known to work on most browsers.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * Each time a page is requested we look to see if the browser is sending
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * us a Cookie: header that we previously generated.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * If we don't find one then the user hasn't been to this site since
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * starting their browser or their browser doesn't support cookies. So
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * we generate a unique Cookie for the transaction and send it back to
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * the browser (via a "Set-Cookie" header)
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * Future requests from the same browser should keep the same Cookie line.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * By matching up all the requests with the same cookie you can
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * work out exactly what path a user took through your site. To log
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * the cookie use the " %{Cookie}n " directive in a custom access log;
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * Example 1 : If you currently use the standard Log file format (CLF)
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * and use the command "TransferLog somefilename", add the line
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * LogFormat "%h %l %u %t \"%r\" %s %b %{Cookie}n"
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * to your config file.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * Example 2 : If you used to use the old "CookieLog" directive, you
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * can emulate it by adding the following command to your config file
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye * CustomLog filename "%{Cookie}n \"%r\" %t"
26eda24db2dc16f2cc45055efb39762fafd606deKnut Anders Hatlen * Mark Cox, mjc@apache.org, 6 July 95
c7eb123c8b2081a261deff3c401fbf92ddba1b58Jorgen Austvik * This file replaces mod_cookies.c
0466de7c67573e1ce5e0733325c1e5383270f5d5Knut Anders Hatlenmodule AP_MODULE_DECLARE_DATA usertrack_module;
5a0c5ad4116f5a4dd0dd5a0a4e6d02973cd5eef9Lubos Koscotypedef struct {
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austviktypedef enum {
5a0c5ad4116f5a4dd0dd5a0a4e6d02973cd5eef9Lubos Koscotypedef struct {
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik/* Make Cookie: Now we have to generate something that is going to be
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik * pretty unique. We can base it on the pid, time, hostip */
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik cookie_log_state *cls = ap_get_module_config(r->server->module_config,
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik /* 1024 == hardcoded constant */
1ed6b730409d4740e941142599767d5eac7e7d92Lubos Kosco const char *rname = ap_get_remote_host(r->connection, r->per_dir_config,
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye dcfg = ap_get_module_config(r->per_dir_config, &usertrack_module);
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye /* XXX: hmm, this should really tie in with mod_unique_id */
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye apr_snprintf(cookiebuf, sizeof(cookiebuf), "%s.%" APR_TIME_T_FMT, rname,
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye /* Cookie with date; as strftime '%a, %d-%h-%y %H:%M:%S GMT' */
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye new_cookie = apr_psprintf(r->pool, "%s=%s; path=/",
225d5411e0f1f0e690e3553aad7a97c648d566a1HemangLavana if ((dcfg->style == CT_UNSET) || (dcfg->style == CT_NETSCAPE)) {
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye "%s; expires=%s, "
75640e2b0da81c240758d747e76d30acd1ed194dKnut Anders Hatlen "%.2d-%s-%.2d %.2d:%.2d:%.2d GMT",
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye new_cookie = apr_psprintf(r->pool, "%s; max-age=%d",
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye new_cookie = apr_psprintf(r->pool, "%s=%s; path=/",
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye new_cookie = apr_pstrcat(r->pool, new_cookie, "; domain=",
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye ? "; version=1"
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye (dcfg->style == CT_COOKIE2 ? "Set-Cookie2" : "Set-Cookie"),
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye apr_table_setn(r->notes, "cookie", apr_pstrdup(r->pool, cookiebuf)); /* log first time */
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye cookie_dir_rec *dcfg = ap_get_module_config(r->per_dir_config,
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen if ((cookie = apr_table_get(r->headers_in,
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye : "Cookie"))))
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye if ((value = ap_strstr_c(cookie, dcfg->cookie_name))) {
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen value += strlen(dcfg->cookie_name) + 1; /* Skip over the '=' */
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen *cookieend = '\0'; /* Ignore anything after a ; */
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen /* Set the cookie in a note, for logging */
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen return DECLINED; /* There's already a cookie, no new one */
9cf297d9a579835e9336d587eaee187ca0954767Knut Anders Hatlenstatic void *make_cookie_log_state(apr_pool_t *p, server_rec *s)
9cf297d9a579835e9336d587eaee187ca0954767Knut Anders Hatlen (cookie_log_state *) apr_palloc(p, sizeof(cookie_log_state));
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen return (void *) cls;
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlenstatic void *make_cookie_dir(apr_pool_t *p, char *d)
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlen dcfg = (cookie_dir_rec *) apr_pcalloc(p, sizeof(cookie_dir_rec));
2dbc1835e0ae88ad102e2b9a85e5c7b5298b14b6Knut Anders Hatlenstatic const char *set_cookie_enable(cmd_parms *cmd, void *mconfig, int arg)
9cf297d9a579835e9336d587eaee187ca0954767Knut Anders Hatlenstatic const char *set_cookie_exp(cmd_parms *parms, void *dummy,
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye const char *arg)
c0550b01024b910b8c1468811c0ea663b10b1372Trond Norbye cls = ap_get_module_config(parms->server->module_config,
523201f786f6b12b7cf54091c6e5be167878cbeeTrond Norbye /* The simple case first - all numbers (we assume) */
523201f786f6b12b7cf54091c6e5be167878cbeeTrond Norbye if (apr_isdigit(arg[0]) && apr_isdigit(arg[strlen(arg) - 1])) {
c0550b01024b910b8c1468811c0ea663b10b1372Trond Norbye * The harder case - stolen from mod_expires
0a0811923cbbd2976425db6f4c78eed811c2825bKnut Anders Hatlen * CookieExpires "[plus] {<num> <type>}*"
0a0811923cbbd2976425db6f4c78eed811c2825bKnut Anders Hatlen word = ap_getword_conf(parms->pool, &arg);
0a0811923cbbd2976425db6f4c78eed811c2825bKnut Anders Hatlen word = ap_getword_conf(parms->pool, &arg);
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen /* {<num> <type>}* */
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen return "bad expires code, numeric value expected.";
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen word = ap_getword_conf(parms->pool, &arg);
cdf37a6f2e4e7ca653ef8e791cc8e720fa148a39Peter Bray return "bad expires code, missing <type>";
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen else if (!strncasecmp(word, "months", 2))
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen else if (!strncasecmp(word, "minutes", 2))
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen else if (!strncasecmp(word, "seconds", 1))
edcb01bf549171673fd0bb4239f2edfc7a810397Knut Anders Hatlen return "bad expires code, unrecognized type";
edcb01bf549171673fd0bb4239f2edfc7a810397Knut Anders Hatlen /* next <num> */
edcb01bf549171673fd0bb4239f2edfc7a810397Knut Anders Hatlen word = ap_getword_conf(parms->pool, &arg);
c7eb123c8b2081a261deff3c401fbf92ddba1b58Jorgen Austvikstatic const char *set_cookie_name(cmd_parms *cmd, void *mconfig,
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik cookie_dir_rec *dcfg = (cookie_dir_rec *) mconfig;
c7eb123c8b2081a261deff3c401fbf92ddba1b58Jorgen Austvik dcfg->cookie_name = apr_pstrdup(cmd->pool, name);
c7eb123c8b2081a261deff3c401fbf92ddba1b58Jorgen Austvik * Set the value for the 'Domain=' attribute.
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvikstatic const char *set_cookie_domain(cmd_parms *cmd, void *mconfig,
85e0595857351c6e22f75b8928967d14cb679ac5Jorgen Austvik * Apply the restrictions on cookie domain attributes.
85e0595857351c6e22f75b8928967d14cb679ac5Jorgen Austvik return "CookieDomain values may not be null";
c7eb123c8b2081a261deff3c401fbf92ddba1b58Jorgen Austvik return "CookieDomain values must begin with a dot";
c7eb123c8b2081a261deff3c401fbf92ddba1b58Jorgen Austvik return "CookieDomain values must contain at least one embedded dot";
1f17ba9e3c026d75f488227451416bd72a222afeTrond Norbye dcfg->cookie_domain = apr_pstrdup(cmd->pool, name);
1f17ba9e3c026d75f488227451416bd72a222afeTrond Norbye * Make a note of the cookie style we should use.
1f17ba9e3c026d75f488227451416bd72a222afeTrond Norbyestatic const char *set_cookie_style(cmd_parms *cmd, void *mconfig,
1f17ba9e3c026d75f488227451416bd72a222afeTrond Norbye const char *name)
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik return apr_psprintf(cmd->pool, "Invalid %s keyword: '%s'",
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvikstatic const command_rec cookie_log_cmds[] = {
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik AP_INIT_TAKE1("CookieExpires", set_cookie_exp, NULL, OR_FILEINFO,
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik "an expiry date code"),
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik AP_INIT_TAKE1("CookieDomain", set_cookie_domain, NULL, OR_FILEINFO,
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik "domain to which this cookie applies"),
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik AP_INIT_TAKE1("CookieStyle", set_cookie_style, NULL, OR_FILEINFO,
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik "'Netscape', 'Cookie' (RFC2109), or 'Cookie2' (RFC2965)"),
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik AP_INIT_FLAG("CookieTracking", set_cookie_enable, NULL, OR_FILEINFO,
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik "whether or not to enable cookies"),
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik AP_INIT_TAKE1("CookieName", set_cookie_name, NULL, OR_FILEINFO,
1e13442ac5687540ace78411d98155fca4b3791eKnut Anders Hatlen "name of the tracking cookie"),
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik ap_hook_fixups(spot_cookie,NULL,NULL,APR_HOOK_MIDDLE);
f09d46eefeb5e4db6dc11e02e417b448fa9362a9Jorgen Austvikmodule AP_MODULE_DECLARE_DATA usertrack_module = {
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik NULL, /* dir merger --- default is to override */