📄 mod_usertrack.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* User Tracking Module (Was mod_cookies.c) * * *** IMPORTANT NOTE: This module is not designed to generate * *** cryptographically secure cookies. This means you should not * *** use cookies generated by this module for authentication purposes * * This Apache module is designed to track users paths through a site. * It uses the client-side state ("Cookie") protocol developed by Netscape. * It is known to work on most browsers. * * Each time a page is requested we look to see if the browser is sending * us a Cookie: header that we previously generated. * * If we don't find one then the user hasn't been to this site since * starting their browser or their browser doesn't support cookies. So * we generate a unique Cookie for the transaction and send it back to * the browser (via a "Set-Cookie" header) * Future requests from the same browser should keep the same Cookie line. * * By matching up all the requests with the same cookie you can * work out exactly what path a user took through your site. To log * the cookie use the " %{Cookie}n " directive in a custom access log; * * Example 1 : If you currently use the standard Log file format (CLF) * and use the command "TransferLog somefilename", add the line * LogFormat "%h %l %u %t \"%r\" %s %b %{Cookie}n" * to your config file. * * Example 2 : If you used to use the old "CookieLog" directive, you * can emulate it by adding the following command to your config file * CustomLog filename "%{Cookie}n \"%r\" %t" * * Mark Cox, mjc@apache.org, 6 July 95 * * This file replaces mod_cookies.c */#include "httpd.h"#include "http_config.h"#include "http_core.h"#if !defined(WIN32) && !defined(MPE) && !defined(TPF41)#include <sys/time.h>#endifmodule MODULE_VAR_EXPORT usertrack_module;typedef struct { int always; time_t expires;} cookie_log_state;typedef enum { CT_UNSET, CT_NETSCAPE, CT_COOKIE, CT_COOKIE2} cookie_type_e;typedef enum { CF_NORMAL, CF_COMPACT} cookie_format_e;typedef struct { int enabled; cookie_type_e style; cookie_format_e format; char *cookie_name; char *cookie_domain; char *prefix_string; char *regexp_string; /* used to compile regexp; save for debugging */ regex_t *regexp; /* used to find usertrack cookie in cookie header */} cookie_dir_rec;/* Define this to allow post-2000 cookies. Cookies use two-digit dates, * so it might be dicey. (Netscape does it correctly, but others may not) */#define MILLENIAL_COOKIES/* Default name of the cookie */#define COOKIE_NAME "Apache"/* Make cookie id: Try to make something unique based on * pid, time, and hostid, plus the user-configurable prefix. * */static char * make_cookie_id(char * buffer, int bufsize, request_rec *r, cookie_format_e cformat){#if defined(NO_GETTIMEOFDAY) && !defined(NO_TIMES) clock_t mpe_times; struct tms mpe_tms;#elif !defined(WIN32) struct timeval tv;#ifdef NETWARE time_t tz = 0;#else struct timezone tz = {0, 0};#endif /* defined(NETWARE) */#endif cookie_dir_rec *dcfg; long reqtime = (long) r->request_time; long clocktime; unsigned long ipaddr = ntohl(r->connection->remote_addr.sin_addr.s_addr); const char *rname = ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME); dcfg = ap_get_module_config(r->per_dir_config, &usertrack_module);#if defined(NO_GETTIMEOFDAY) && !defined(NO_TIMES)/* We lack gettimeofday(), so we must use time() to obtain the epoch seconds, and then times() to obtain CPU clock ticks (milliseconds). Combine this together to obtain a hopefully unique cookie ID. */ mpe_times = times(&mpe_tms); clocktime = (long) mpe_tms.tms_utime; #elif defined(NETWARE) clocktime = (long) clock();#elif defined(WIN32) /* * We lack gettimeofday() and we lack times(). So we'll use * GetTickCount(), which returns milliseconds since Windows * was started. It should be relatively unique. */ clocktime = (long) GetTickCount();#else gettimeofday(&tv, &tz); reqtime = (long) tv.tv_sec; if (cformat == CF_COMPACT) clocktime = (long) (tv.tv_usec % 65535); else clocktime = (long) (tv.tv_usec / 1000);#endif if (cformat == CF_COMPACT) ap_snprintf(buffer, bufsize, "%s%lx%x%lx%lx", dcfg->prefix_string, ipaddr, (int) getpid(), reqtime, clocktime); else ap_snprintf(buffer, bufsize, "%s%s.%d%ld%ld", dcfg->prefix_string, rname, (int) getpid(), reqtime, clocktime); return buffer;}static void make_cookie(request_rec *r){ cookie_log_state *cls = ap_get_module_config(r->server->module_config, &usertrack_module); /* 1024 == hardcoded constant */ char cookiebuf[1024]; char *new_cookie; cookie_dir_rec *dcfg; dcfg = ap_get_module_config(r->per_dir_config, &usertrack_module); make_cookie_id(cookiebuf, sizeof(cookiebuf), r, dcfg->format); if (cls->expires) { struct tm *tms; time_t when; when = cls->expires; if ((dcfg->style == CT_UNSET) || (dcfg->style == CT_NETSCAPE)) { when += r->request_time;#ifndef MILLENIAL_COOKIES /* * Only two-digit date string, so we can't trust "00" or more. * Therefore, we knock it all back to just before midnight on * 1/1/2000 (which is 946684799) */ if (when > 946684799) when = 946684799;#endif } tms = gmtime(&when); /* Cookie with date; as strftime '%a, %d-%h-%y %H:%M:%S GMT' */ new_cookie = ap_psprintf(r->pool, "%s=%s; path=/", dcfg->cookie_name, cookiebuf); if ((dcfg->style == CT_UNSET) || (dcfg->style == CT_NETSCAPE)) { new_cookie = ap_psprintf(r->pool, "%s; " "expires=%s, %.2d-%s-%.2d " "%.2d:%.2d:%.2d GMT", new_cookie, ap_day_snames[tms->tm_wday], tms->tm_mday, ap_month_snames[tms->tm_mon], tms->tm_year % 100, tms->tm_hour, tms->tm_min, tms->tm_sec); } else { new_cookie = ap_psprintf(r->pool, "%s; max-age=%d", new_cookie, (int) when); } } else { new_cookie = ap_psprintf(r->pool, "%s=%s; path=/", dcfg->cookie_name, cookiebuf); } if (dcfg->cookie_domain != NULL) { new_cookie = ap_psprintf(r->pool, "%s; domain=%s", new_cookie, dcfg->cookie_domain); } if (dcfg->style == CT_COOKIE2) { new_cookie = ap_pstrcat(r->pool, new_cookie, "; version=1", NULL); } ap_table_addn(r->headers_out, (dcfg->style == CT_COOKIE2 ? "Set-Cookie2" : "Set-Cookie"), new_cookie); ap_table_setn(r->notes, "cookie", ap_pstrdup(r->pool, cookiebuf)); /* log first time */ return;}/* * dcfg->regexp is "^cookie_name=([^;]+)|;[ \t]+cookie_name=([^;]+)", * which has three subexpressions, $0..$2 */#define NUM_SUBS 3static void set_and_comp_regexp(cookie_dir_rec *dcfg, pool *p, const char *cookie_name) { int danger_chars = 0; const char *sp = cookie_name; /* * The goal is to end up with this regexp, * ^cookie_name=([^;]+)|;[\t]+cookie_name=([^;]+) * with cookie_name obviously substituted either * with the real cookie name set by the user in httpd.conf, * or with the default COOKIE_NAME. */ /* Anyway, we need to escape the cookie_name before pasting it * into the regex */ while (*sp) { if (!ap_isalnum(*sp)) { ++danger_chars; } ++sp; } if (danger_chars) { char *cp; cp = ap_palloc(p, sp - cookie_name + danger_chars + 1); /* 1 == \0 */ sp = cookie_name; cookie_name = cp; while (*sp) { if (!ap_isalnum(*sp)) { *cp++ = '\\'; } *cp++ = *sp++; } *cp = '\0'; } dcfg->regexp_string = ap_pstrcat(p, "^", cookie_name, "=([^;]+)|;[ \t]+", cookie_name, "=([^;]+)", NULL); dcfg->regexp = ap_pregcomp(p, dcfg->regexp_string, REG_EXTENDED); ap_assert(dcfg->regexp != NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -