home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 8 / CDACTUAL8.iso / share / os2 / varios / apache / mod_cook.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-04  |  10.1 KB  |  299 lines

  1.  
  2. /* ====================================================================
  3.  * Copyright (c) 1995, 1996 The Apache Group.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer. 
  11.  *
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in
  14.  *    the documentation and/or other materials provided with the
  15.  *    distribution.
  16.  *
  17.  * 3. All advertising materials mentioning features or use of this
  18.  *    software must display the following acknowledgment:
  19.  *    "This product includes software developed by the Apache Group
  20.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  21.  *
  22.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  23.  *    endorse or promote products derived from this software without
  24.  *    prior written permission.
  25.  *
  26.  * 5. Redistributions of any form whatsoever must retain the following
  27.  *    acknowledgment:
  28.  *    "This product includes software developed by the Apache Group
  29.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  30.  *
  31.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  32.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  34.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  35.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  42.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  43.  * ====================================================================
  44.  *
  45.  * This software consists of voluntary contributions made by many
  46.  * individuals on behalf of the Apache Group and was originally based
  47.  * on public domain software written at the National Center for
  48.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  49.  * For more information on the Apache Group and the Apache HTTP server
  50.  * project, please see <http://www.apache.org/>.
  51.  *
  52.  */
  53.  
  54.  
  55. /* User Tracking Module
  56.  *
  57.  * This Apache module is designed to track users paths through a site.
  58.  * It uses the client-side state ("Cookie") protocol developed by Netscape.
  59.  * It is known to work on Netscape browsers, Microsoft Internet 
  60.  * Explorer and others currently being developed.
  61.  *
  62.  * Each time a page is requested we look to see if the browser is sending
  63.  * us a Cookie: header that we previously generated.
  64.  *
  65.  * If we don't find one then the user hasn't been to this site since
  66.  * starting their browser or their browser doesn't support cookies.  So
  67.  * we generate a unique Cookie for the transaction and send it back to
  68.  * the browser (via a "Set-Cookie" header)
  69.  * Future requests from the same browser should keep the same Cookie line.
  70.  *
  71.  * The cookie and request are logged to a file.  Use the directive
  72.  * "CookieLog somefilename" in one of the config files to enable the Cookie
  73.  * module.  By matching up all the requests with the same cookie you can
  74.  * work out exactly what path a user took through your site.
  75.  *
  76.  * Notes:
  77.  * 1.  This code doesn't log the initial transaction (the one that created
  78.  *     the cookie to start with).  If it did then the cookie log file would
  79.  *     be bigger than a normal access log.
  80.  * 2.  This module has been designed to not interfere with other Cookies
  81.  *     your site may be using; just avoid sending out cookies with
  82.  *     the name "Apache=" or things will get confused.
  83.  * 3.  If you want you can modify the Set-Cookie line so that the Cookie
  84.  *     never expires.  You would then get the same Cookie each time the
  85.  *     user revisits your site.
  86.  *
  87.  * Mark Cox, mark@ukweb.com, http://www.ukweb.com/~mark/, 6 July 95
  88.  *
  89.  * 6.12.95  MJC Now be more friendly.  Allow our cookies to overlap with
  90.  *              others the site may be using.  Use a more descriptive 
  91.  *              cookie name.
  92.  * 18.3.96  MJC Generate cookies for EVERY request no matter what the 
  93.  *              browser.  We never know when a new browser writer will
  94.  *              add cookie support.
  95.  * 31.3.95 JimC Allow the log to be sent to a pipe.  Copies the relevant
  96.  *              code from mod_log_agent.c.
  97.  * 24.5.96  MJC Improved documentation after receiving comments from users
  98.  *  4.7.96  MJC Bug, "else" missing since February caused logging twice
  99.  */
  100.  
  101. #include "httpd.h"
  102. #include "http_config.h"
  103. #include "http_core.h"
  104. #include <sys/time.h>
  105.  
  106. module cookies_module;
  107.  
  108. typedef struct {
  109.     char *fname;
  110.     int log_fd;
  111.     int always;
  112. } cookie_log_state;
  113.  
  114. /* Make Cookie: Now we have to generate something that is going to be
  115.  * pretty unique.  We can base it on the pid, time, hostip */
  116.  
  117. #define COOKIE_NAME "Apache="
  118.  
  119. void make_cookie(request_rec *r)
  120. {
  121.     struct timeval tv;
  122.     char new_cookie[100];    /* blurgh */
  123.     char *dot;
  124.     const char *rname = pstrdup(r->pool, 
  125.                 get_remote_host(r->connection, r->per_dir_config,
  126.                         REMOTE_NAME));
  127.     
  128.     struct timezone tz = { 0 , 0 };
  129.  
  130.     if ((dot = strchr(rname,'.'))) *dot='\0';    /* First bit of hostname */
  131.     gettimeofday(&tv, &tz);
  132.     sprintf(new_cookie,"%s%s%d%ld%d; path=/",
  133.         COOKIE_NAME, rname,
  134.         (int)getpid(),  
  135.         (long)tv.tv_sec, (int)tv.tv_usec/1000 );
  136.  
  137.     table_set(r->headers_out,"Set-Cookie",new_cookie);
  138.     return;
  139. }
  140.  
  141. int spot_cookie(request_rec *r)
  142. {
  143.     char *cookie;
  144.  
  145.     if ((cookie = table_get (r->headers_in, "Cookie")))
  146.         if (strstr(cookie,COOKIE_NAME))
  147.             return DECLINED;          /* Theres already a cookie, no new one */
  148.     make_cookie(r);
  149.     return OK;                        /* We set our cookie */
  150. }
  151.  
  152. static int cookie_flags = ( O_WRONLY | O_APPEND | O_CREAT );
  153.  
  154. #ifdef __EMX__
  155. /* OS/2 lacks support for users and groups */
  156. static mode_t cookie_mode = ( S_IREAD | S_IWRITE );
  157. #else
  158. static mode_t cookie_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
  159. #endif
  160.  
  161. void *make_cookie_log_state (pool *p, server_rec *s)
  162. {
  163.     cookie_log_state *cls =
  164.       (cookie_log_state *)palloc (p, sizeof (cookie_log_state));
  165.  
  166.     cls->fname = "";
  167.     cls->log_fd = -1;
  168.  
  169.     return (void *)cls;
  170. }
  171.  
  172. char *set_cookie_log (cmd_parms *parms, void *dummy, char *arg)
  173. {
  174.     cookie_log_state *cls = get_module_config (parms->server->module_config,
  175.                            &cookies_module);
  176.     cls->fname = arg;
  177.     return NULL;
  178. }
  179.  
  180. command_rec cookie_log_cmds[] = {
  181. { "CookieLog", set_cookie_log, NULL, RSRC_CONF, TAKE1,
  182.     "the filename of the cookie log" },
  183. { NULL }
  184. };
  185.  
  186. void cookie_log_child (void *cmd)
  187. {
  188.     /* Child process code for 'CookieLog "|..."';
  189.      * may want a common framework for this, since I expect it will
  190.      * be common for other foo-loggers to want this sort of thing...
  191.      */
  192.     
  193.     cleanup_for_exec();
  194.     signal (SIGHUP, SIG_IGN);
  195.     execl (SHELL_PATH, SHELL_PATH, "-c", (char *)cmd, NULL);
  196.     exit (1);
  197. }
  198.  
  199. void open_cookie_log (server_rec *s, pool *p)
  200. {
  201.     cookie_log_state *cls = get_module_config (s->module_config,
  202.                            &cookies_module);
  203.     char *fname = server_root_relative (p, cls->fname);
  204.  
  205.     if (cls->log_fd > 0) return; 
  206.  
  207.     if (*cls->fname == '|') {
  208.       FILE *dummy;
  209.       
  210.       spawn_child(p, cookie_log_child, (void *)(cls->fname+1),
  211.                 kill_after_timeout, &dummy, NULL);
  212.       
  213.       if (dummy == NULL) {
  214.       fprintf (stderr, "Couldn't fork child for CookieLog process\n");
  215.       exit (1);
  216.       }
  217.       
  218.       cls->log_fd = fileno (dummy);
  219.     }
  220.     else if(*cls->fname != '\0') {
  221.       if((cls->log_fd = popenf(p, fname, cookie_flags, cookie_mode)) < 0) {
  222.     fprintf(stderr, "httpd: could not open cookie log file %s.\n", fname);
  223.     perror("open");
  224.     exit(1);
  225.       }
  226.     }
  227. }
  228.  
  229. void init_cookie_log (server_rec *s, pool *p)
  230. {
  231.     for (; s; s = s->next) open_cookie_log (s, p);
  232. }
  233.  
  234. int cookie_log_transaction(request_rec *orig)
  235. {
  236.     cookie_log_state *cls = get_module_config (orig->server->module_config,
  237.                            &cookies_module);
  238.     char *str;
  239.     long timz;
  240.     struct tm *t;
  241.     char tstr[MAX_STRING_LEN],sign;
  242.     request_rec *r;
  243.     char *cookie,*cookiebuf,*cookieend;
  244.     char *value;
  245.  
  246.     for (r = orig; r->next; r = r->next)
  247.         continue;
  248.     if (*cls->fname == '\0')    /* Don't log cookies */
  249.       return DECLINED;
  250.  
  251.     if (!(cookie = table_get (r->headers_in, "Cookie")))
  252.         return DECLINED;    /* Theres no cookie, don't bother logging */
  253.     value=strstr(cookie,COOKIE_NAME);
  254.     if (!value) /* Only log cookies we generated! */
  255.         return DECLINED;
  256.     value+=strlen(COOKIE_NAME);
  257.     cookiebuf=pstrdup( r->pool, value );
  258.     cookieend=strchr(cookiebuf,';');
  259.     if (cookieend) *cookieend='\0';    /* Ignore anything after a ; */
  260.  
  261.     t = get_gmtoff(&timz);
  262.     sign = (timz < 0 ? '-' : '+');
  263.     if(timz < 0) 
  264.         timz = -timz;
  265.  
  266.     strftime(tstr,MAX_STRING_LEN,"\" [%d/%b/%Y:%H:%M:%S ",t);
  267.     if (r->status != -1)
  268.     sprintf(&tstr[strlen(tstr)], "%c%02ld%02ld] %d\n", sign, timz/3600,
  269.         timz%3600, r->status);
  270.     else
  271.     sprintf(&tstr[strlen(tstr)], "%c%02ld%02ld] -\n", sign, timz/3600,
  272.         timz%3600);
  273.  
  274.     str = pstrcat(orig->pool, cookiebuf, " \"", orig->the_request, tstr, NULL);
  275.     
  276.     write(cls->log_fd, str, strlen(str));
  277.  
  278.     return OK;
  279. }
  280.  
  281.  
  282. module cookies_module = {
  283.    STANDARD_MODULE_STUFF,
  284.    init_cookie_log,                /* initializer */
  285.    NULL,                        /* dir config creater */
  286.    NULL,                        /* dir merger --- default is to override */
  287.    make_cookie_log_state,        /* server config */
  288.    NULL,                        /* merge server configs */
  289.    cookie_log_cmds,                /* command table */
  290.    NULL,                        /* handlers */
  291.    NULL,                        /* filename translation */
  292.    NULL,                        /* check_user_id */
  293.    NULL,                        /* check auth */
  294.    NULL,                        /* check access */
  295.    NULL,                        /* type_checker */
  296.    spot_cookie,                    /* fixups */
  297.    cookie_log_transaction,        /* logger */
  298. };
  299.