[English version]
mod_uid.c version 1.1
модуль, выдающий "правильные" cookies для подсчета посетителей
сайта
Download: ftp://ftp.lexa.ru/pub/apache-rus/contrib/
Оглавление
- Copyright
- Назначение
- Установка (Apache 1.x)
- Установка (Apache 2.0.x)
- Конфигурация
- Формат cookie
- Что можно записать в лог
- Почему не mod_usertrack
- TODO
Copyright
Copyright (C) 2000-2002 Alex Tutubalin, lexa@lexa.ru
Допускается распространение и использование в производных
продуктах на условиях аналогичных
Apache License
- должен быть сохранен копирайт автора и ссылка на
http://www.lexa.ru/lexa,
производный продукт не должен называться mod_uid
Прототип этого модуля был сделан автором при работе в компании
Rambler, данная версия cущественно
переработана
Автор благодарит Дмитрия Хрусталева за ценные советы.
Описание
Стандартные средства Apache не дают разумных средств трэкинга
пользователей (о проблемах mod_usertrack написано ниже), данный модуль
их предоставляет.
Что он делает:
- если пользователь отдал заголовок Cookie с правильным cookie-name,
то записывает эту Cookie в notes c именем uid_got (потом,
соответственно, это можно записать в лог)
- если пользователь пришел без нужной cookie - выдает ему заголовок
SetCookie и записывает выданную cookie в notes с именем uid_set
(и это можно тоже записать в лог)
- если включена встроенная поддержка P3P, то при выдаче заголовка
Set-Cookie выдается и заголовок P3P
Достоинства:
- в cookie присутствует дата ее выдачи и "номер сервиса"
(т.е. число, задаваемое при настройке), что позволяет понять когда
пользователь пришел на наш сайт впервые и куда именно он пришел.
- поддержана многосерверная работа - при аккуратной настройке (либо
при полном ее отсутствии :) гарантируется, что выданная
пользователю cookie будет уникальна
- выданная пользователю и полученная от него cookie не смешиваются в
лог-файле
- cookies имеют длину 128 бит, что позволяет для работы с ними в
анализаторе логов (быстрый поиск и т.п.) использовать готовый код,
предназначенный для работы с IPv6 (например, libpatricia)
- Поддержана P3P (в минимальном объеме)
Установка
При конфигурации Apache к параметрам ./configure нужно добавить
--add-module=/path/to/mod_uid.c:
tar xzvf apache_1.3xxx
tar xzvf mod_uid-1.0.xx.tar.gz
cd apache_1.3xx
./configure --prefix=/usr/local/apache ... --add-module=../mod_uid_1.0.xx/mod_uid.c other-params
make
make install
Установка (Apache 2.0)
Для работы с Apache 2.0 предназначен модуль mod_uid2.c
Сначала необходимо установить Apache 2.0.x, предположим, мы сделали
это в директорию /usr/local/apache
Для установки модуля mod_uid2 нужно использовать программу apxs:
tar xzvf mod_uid-1.xx.tar.gz
cd mod_uid-1.xx
/usr/local/apach/bin/apxs -i -c -a mod_uid2.c
эта команда скомпилирует модуль (ключ -c), установит его в каталог
Apache (ключ -i) и активирует модуль добавлением команды
LoadModule в httpd.conf (ключ -a)
Конфигурационные директивы
Все конфигурационные директивы можно указывать где угодно -
Server/VirtualServer/Location/... При указании в .htaccess должно быть
разрешено AllowOverride FileInfo (или All)
- UIDActive On/Off
- включить-выключить выдачу cookie.
Если выдача выключена, то
полученные от клиента cookies все-равно раскодируются и могут
быть записаны в log.
Default: On
- UIDCookieName string
- Имя cookie (default - uid)
Имя cookie, выдаваемой клиенту. Не должно пересекаться с
какими-то другими именами, используемыми на сайте.
- UIDService number
- "Номер сервиса" - строго положительное (ненулевое)
уникальное число, идентифицирующее данный
сервер в кластере, либо данный документ/набот документов.
Данный номер используется для двух целей:
- Если используется несколько серверов внутри одного
домена (с одинаковым параметром cookie domain=), либо с
одним hostname, то задание разных UIDService
приводит к тому, что выдаваемые разными серверами cookies
с гарантией будут уникальными.
- Использование разных UIDService для разных
разделов сервера позволяет при анализе логов выяснить, на
какой из разделов клиент пришел в первый раз.
Default: IP-адрес сервера.
- UIDDomain .domain.name
- Имя домена для которого выдается кука
В многосерверных конфигурациях позволяет иметь общее
пространство cookies для всех серверов (например, для
mail.rambler.ru, www.rambler.ru, info.rambler.ru используется
домен .rambler.ru)
Если нужно выключить domain= для какого-то набора документов,
оставив его включенным для сервера в целом, в соответствующем
разделе конфигурации (Location/Directory/...) нужно
использовать UIDDomain none
Defaulut: нет домена т.е. пользовательский браузер
будет возвращать cookie только на исходный сервер.
- UIDPath string
- Путь для которого выдается cookie (параметр path= в
Set-Cookie:)
Default: /
- UIDExpires number
UIDExpires plus 3 year 4 month 2 day 1 hour 15 minutes
-
Задание Expiration date для cookie.
UIDExpires number - прибавить number секунд к
текущему времени
UIDExpires plus 3 year 4 month 2 day 1 hour 15
minutes - то же самое, но выраженное по человечески.
Default: прибавляется 10 лет к текущей дате
- UIDP3P On/Off/Always
- Управление выдачей заголовка P3P одновременно с выдачей
cookie.
Варианты:
- Off - не выдавать заголовок P3P
- On - выдавать только если у Cookie выдается параметр
domain
- Always - выдавать всегда (т.е. даже без domain)
Default: Off
Эта директива нужна для удовлетворения ME IE6+ в
многосерверной конфигурации и, например, включения кода
"счетчика" с другого сервера на страницу. В случае, когда
cookie выдается без domain= или domain "покрывает" текущее имя
сервера для основного документа MS IE6+ с настройками
по-умолчанию удовлетворится и так, однако для составных
документов, собранных с разных серверов, cookie могут
подавляться.
mod_uid выдает только заголовок P3P (по-умолчанию -
только с compact policy), поддержка /w3c/p3p.xml и подобного
остается задачей владельца сервера.
Заголовок P3P выдается только если mod_uid выдает заголовок
Set-Cookie, т.е. если у вас выдаются и другие cookie и для них
тоже нужен P3P, то задачу выдачи P3P нужно решать отдельно и
самостоятельно.
- UIDP3PString string
- Текст заголовка P3P, выдаваемый клиенту.
Default: CP="NOI PSA OUR BUS UNI"
Формат Cookie
Формат куки:
В двоичном виде:
unsigned int cookie[4], где
cookie[0] - "номер сервиса" (задается через UIDService)
cookie[1] - время выдачи (unix time)
cookie[2] - pid процесса выдавшего куку
cookie[3] - старшие 24 бита - уникальный секвенсер
в пределах процесса (стартовое значение -
0x030303),
младшие 8 бит - номер версии куки (сейчас - 2)
Эти 128 бит переводятся в network byte order, кодируются в base64 и
отдаются клиенту (в версии 1 все отдавалось в host order, что
затрудняло поддержку кластеров серверов с разной
архитектурой).
Уникальность
Очевидно, что полную гарантию может дать только страховой полис и если
в пределах одного домена будет выдано более чем 2^128 cookies, то
какие-то из них будут повторяться. Однако при разработке формата cookie
были приложены усиля к тому, чтобы при разумном количестве cookies
они были бы уникальными.
- В случае, если "номера сервиса" уникален (свой у каждого сервера)
в пределах данного домена, разные серверы будут с гарантией
выдавать разные cookies.
- Включение в cookie времени выдачи и pid подразумевает, что pid-ы
разных процессов не повторяются в течение одной секунды. На
всех известных мне Unix-системах это так - pid-ы монотонно
возрастают до некоего максимума - 2^16 или более - т.е. для
повторения cookie[1]/cookie[2] в рамках одного сервера нужно
делать больше чем 2^16 fork() в секунду, что на сегодняшний
день малореально.
- Секвенсер (старшие 24 бита в cookie[3]) позволяет удостовериться
в уникальности cookie в пределах одного процесса в течение
одной секунды. Разрядность секвенсера позволяет выдавать до
1.0E+07 cookies одним процессом в секунду.
Что можно записать в лог
mod_uid пишет в notes ("заметки") одно из двух значений:
- Если от клиента была получена cookie, она помещается в note
"uid_got"
- Если клиенту была выдана cookie, она помещается в note "uid_set"
Cookies пишутся в лог как 4 32-битных 16-ричных числа в host-order
(т.е. для версии 2 производится преобразование network-host, для
версии 1 - все пишется как есть в предположении, что архитектура
сервера с момента выдачи cookie не изменилась)
В LogFormat эти notes можно использовать в виде \"%{uid_got}n\"
и \"%{uid_set}n\" соответственно.
При использовании LogFormat такого вида:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\"
\"%{User-Agent}i\" \"%{uid_got}n\" \"%{uid_set}n combined_cookie
мы получим примерно такие записи в log-е
Выданная клиенту Cookie:
62.104.212.93 - - [05/Jan/2002:00:02:06 +0300] "GET / HTTP/1.0" 200
13487 "-" "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x
4.90)" "-" "ruid=000000013C36184E00009A2100002901"
Полученная от клиента Cookie:
216.136.145.172 - - [05/Jan/2002:00:14:59 +0300] "GET /buttons/but-support-e.gif
HTTP/1.0" 200 252 "http://apache.lexa.ru/english/meta-http-eng.html"
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
"ruid=000000013C361B5000009A0100009501" "-"
Такой формат без проблем понимается распространенными анализаторами
логов, включая Webtrends, который по такому логу с удовольствием
считает Visitors.
Почему не mod_usertrack из поставки Apache
Потому что у него есть несколько недостатков:
- нет гарантий, что двум пользователям не будет выдана одинаковая
cookie, хотя конечно включение getpid(), remote_ip и времени до
миллисекунд сводит эту вероятность к минимуму
- нет поддержки многосерверной работы - а в этом случае возможность
выдачи одинаковой cookie возрастает
- в логе хочется иметь возможность видеть и выданную пользователю
cookie, причем видеть ее отдельно, mod_usertrack их перемешивает.
- Хочется иметь "номер сервиса" (см. выше) - чтобы понимать на какой
из наших сервисов пользователь зашел при первом своем визите.
TODO
-
Поддержка разных форматов (Netscape/Cookie/Cookie2 - как в
mod_usertrack), но только если появится реальная необходимость - пока
таковой необходимости не замечено.
- Есть смутное подозрение, что на multithread-apache и
многопроцессорных машине инкремент sequencer-а нужно обложить mutex-ами
|