Received: (from majordom@localhost) by hyperreal.org (8.8.5/8.8.5) id AAA06849; Mon, 18 Aug 1997 00:17:35 -0700 (PDT) Received: (from dgaudet@localhost) by hyperreal.org (8.8.5/8.8.5) id AAA06844 for apache-cvs; Mon, 18 Aug 1997 00:17:32 -0700 (PDT) Date: Mon, 18 Aug 1997 00:17:32 -0700 (PDT) From: Dean Gaudet Message-Id: <199708180717.AAA06844@hyperreal.org> To: apache-cvs@hyperreal.org Subject: cvs commit: apachen/src/modules/standard mod_unique_id.c mod_setenvif.c Sender: apache-cvs-owner@apache.org Precedence: bulk Reply-To: new-httpd@apache.org dgaudet 97/08/18 00:17:31 Modified: htdocs/manual new_features_1_3.html src CHANGES Configuration.tmpl src/core http_config.c http_config.h http_main.c http_protocol.c http_request.c http_request.h src/modules/standard mod_setenvif.c Added: src/modules/standard mod_unique_id.c Log: - API: added post_read_request phase - New module: mod_unique_id - open_logs is now done before init_modules, and init_modules is not called twice at initialization Reviewed by: Ben Laurie, Jim Jagielski, Paul Sutton (well, they didn't all give +1s but they didn't veto it either! :) Revision Changes Path 1.17 +7 -0 apachen/htdocs/manual/new_features_1_3.html Index: new_features_1_3.html =================================================================== RCS file: /export/home/cvs/apachen/htdocs/manual/new_features_1_3.html,v retrieving revision 1.16 retrieving revision 1.17 diff -u -r1.16 -r1.17 --- new_features_1_3.html 1997/08/17 11:40:10 1.16 +++ new_features_1_3.html 1997/08/18 07:17:19 1.17 @@ -212,6 +212,13 @@ and IRIX. +
  • Unique Identifiers
    + mod_uniqid can be included to generate a unique identifier that + distinguishes a hit from every other hit. ("Unique" has + some restrictions on it.) Documentation to be written. The + identifier is available in the environment variable + UNIQUE_ID. + 1.403 +17 -0 apachen/src/CHANGES Index: CHANGES =================================================================== RCS file: /export/home/cvs/apachen/src/CHANGES,v retrieving revision 1.402 retrieving revision 1.403 diff -u -r1.402 -r1.403 --- CHANGES 1997/08/18 07:09:16 1.402 +++ CHANGES 1997/08/18 07:17:21 1.403 @@ -1,5 +1,22 @@ Changes with Apache 1.3a2 + *) API: Added post_read_request API phase which is run right after reading + the request from a client, or right after an internal redirect. It is + useful for modules setting environment variables that depend only on + the headers/contents of the request. It does not run during subrequests + because subrequests inherit pretty much everything from the main + request. [Dean Gaudet] + + *) Added mod_unique_id which is used to generate a unique identifier for + each hit, available in the environment variable UNIQUE_ID. + [Dean Gaudet] + + *) init_modules is now called after the error logs have been opened. This + allows modules to emit information messages into the error logs. + init_modules is only called once in standalone config now, previously + it was called twice (once after each config file reading). + [Dean Gaudet] + *) Fixed proxy-pass-through feature of mod_rewrite; Added error logging information for case where proxy module is not available. [Marc Slemko] 1.72 +6 -0 apachen/src/Configuration.tmpl Index: Configuration.tmpl =================================================================== RCS file: /export/home/cvs/apachen/src/Configuration.tmpl,v retrieving revision 1.71 retrieving revision 1.72 diff -u -r1.71 -r1.72 --- Configuration.tmpl 1997/08/10 13:29:51 1.71 +++ Configuration.tmpl 1997/08/18 07:17:21 1.72 @@ -300,3 +300,9 @@ ## should be the last (highest priority) module. AddModule modules/standard/mod_setenvif.o + +## mod_unique_id generates unique identifiers for each hit, which are +## available in the environment variable UNIQUE_ID. It may not work on all +## systems, hence it is not included by default. + +# AddModule modules/standard/mod_unique_id.o 1.73 +7 -1 apachen/src/core/http_config.c Index: http_config.c =================================================================== RCS file: /export/home/cvs/apachen/src/core/http_config.c,v retrieving revision 1.72 retrieving revision 1.73 diff -u -r1.72 -r1.73 --- http_config.c 1997/08/06 20:21:21 1.72 +++ http_config.c 1997/08/18 07:17:24 1.73 @@ -259,7 +259,8 @@ XtOffsetOf (module, type_checker), XtOffsetOf (module, fixer_upper), XtOffsetOf (module, logger), - XtOffsetOf (module, header_parser) + XtOffsetOf (module, header_parser), + XtOffsetOf (module, post_read_request) }; #define NMETHODS (sizeof (method_offsets)/sizeof (method_offsets[0])) @@ -272,6 +273,7 @@ int fixer_upper; int logger; int header_parser; + int post_read_request; } offsets_into_method_ptrs; /* @@ -370,6 +372,10 @@ int header_parse (request_rec *r) { return run_method (r, offsets_into_method_ptrs.header_parser, 1); +} + +int run_post_read_request (request_rec *r) { + return run_method (r, offsets_into_method_ptrs.post_read_request, 1); } /* Auth stuff --- anything that defines one of these will presumably 1.44 +7 -8 apachen/src/core/http_config.h Index: http_config.h =================================================================== RCS file: /export/home/cvs/apachen/src/core/http_config.h,v retrieving revision 1.43 retrieving revision 1.44 diff -u -r1.43 -r1.44 --- http_config.h 1997/08/06 20:21:23 1.43 +++ http_config.h 1997/08/18 07:17:24 1.44 @@ -205,8 +205,9 @@ * supposed to handle this was configured wrong). * type_checker --- Determine MIME type of the requested entity; * sets content_type, _encoding and _language fields. - * logger --- log a transaction. Not supported yet out of sheer - * laziness on my part. + * logger --- log a transaction. + * post_read_request --- run right after read_request or internal_redirect, + * and not run during any subrequests. */ int (*translate_handler)(request_rec *); @@ -230,15 +231,12 @@ */ #ifdef ULTRIX_BRAIN_DEATH void (*child_init)(); -#else - void (*child_init)(server_rec *, pool *); -#endif -#ifdef ULTRIX_BRAIN_DEATH void (*child_exit)(); #else + void (*child_init)(server_rec *, pool *); void (*child_exit)(server_rec *, pool *); #endif - + int (*post_read_request)(request_rec *); } module; /* Initializer for the first few module slots, which are only @@ -248,7 +246,7 @@ * handle it back-compatibly, or at least signal an error). */ -#define MODULE_MAGIC_NUMBER 19970728 +#define MODULE_MAGIC_NUMBER 19970818 #define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, -1, __FILE__, NULL /* Generic accessors for other modules to get at their own module-specific @@ -323,5 +321,6 @@ int invoke_handler (request_rec *); int log_transaction (request_rec *r); int header_parse (request_rec *); +int run_post_read_request (request_rec *); #endif 1.204 +2 -2 apachen/src/core/http_main.c Index: http_main.c =================================================================== RCS file: /export/home/cvs/apachen/src/core/http_main.c,v retrieving revision 1.203 retrieving revision 1.204 diff -u -r1.203 -r1.204 --- http_main.c 1997/08/17 12:57:03 1.203 +++ http_main.c 1997/08/18 07:17:25 1.204 @@ -3082,8 +3082,8 @@ server_conf = read_config (pconf, ptrans, server_confname); setup_listeners (pconf); - init_modules (pconf, server_conf); open_logs (server_conf, pconf); + init_modules (pconf, server_conf); set_group_privs (); SAFE_ACCEPT(accept_mutex_init (pconf)); if (!is_graceful) { @@ -3305,7 +3305,6 @@ suexec_enabled = init_suexec(); server_conf = read_config (pconf, ptrans, server_confname); - init_modules (pconf, server_conf); if(standalone) { clear_pool (pconf); /* standalone_main rereads... */ @@ -3319,6 +3318,7 @@ NET_SIZE_T l; open_logs(server_conf, pconf); + init_modules (pconf, server_conf); set_group_privs(); default_server_hostnames (server_conf); 1.154 +7 -0 apachen/src/core/http_protocol.c Index: http_protocol.c =================================================================== RCS file: /export/home/cvs/apachen/src/core/http_protocol.c,v retrieving revision 1.153 retrieving revision 1.154 diff -u -r1.153 -r1.154 --- http_protocol.c 1997/08/17 13:42:25 1.153 +++ http_protocol.c 1997/08/18 07:17:26 1.154 @@ -63,6 +63,7 @@ #include "http_core.h" #include "http_protocol.h" #include "http_main.h" +#include "http_request.h" #include "http_log.h" /* For errors detected in basic auth * common support code... */ @@ -797,6 +798,7 @@ request_rec *read_request (conn_rec *conn) { request_rec *r = (request_rec *)pcalloc (conn->pool, sizeof(request_rec)); + int access_status; r->connection = conn; conn->server = conn->base_server; @@ -881,6 +883,11 @@ r->method_number = M_TRACE; else r->method_number = M_INVALID; /* Will eventually croak. */ + + if ((access_status = run_post_read_request (r))) { + die (access_status, r); + return NULL; + } return r; } 1.76 +11 -1 apachen/src/core/http_request.c Index: http_request.c =================================================================== RCS file: /export/home/cvs/apachen/src/core/http_request.c,v retrieving revision 1.75 retrieving revision 1.76 diff -u -r1.75 -r1.76 --- http_request.c 1997/08/17 20:21:36 1.75 +++ http_request.c 1997/08/18 07:17:26 1.76 @@ -913,7 +913,7 @@ void process_request_internal (request_rec *r) { int access_status; - + /* Kludge to be reading the assbackwards field outside of protocol.c, * but we've got to check for this sort of nonsense somewhere... */ @@ -1102,6 +1102,7 @@ { request_rec *new = (request_rec *)pcalloc(r->pool, sizeof(request_rec)); char t[256]; /* Long enough... */ + int access_status; new->connection = r->connection; new->server = r->server; @@ -1153,6 +1154,15 @@ ap_snprintf (t, sizeof(t), "%d", r->status); table_set (new->subprocess_env, "REDIRECT_STATUS", pstrdup (r->pool, t)); + + /* XXX: hmm. This is because mod_setenvif and mod_unique_id really need + * to do their thing on internal redirects as well. Perhaps this is + * a misnamed function. + */ + if ((access_status = run_post_read_request (new))) { + die (access_status, new); + return NULL; + } return new; } 1.14 +1 -0 apachen/src/core/http_request.h Index: http_request.h =================================================================== RCS file: /export/home/cvs/apachen/src/core/http_request.h,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- http_request.h 1997/07/15 21:39:57 1.13 +++ http_request.h 1997/08/18 07:17:27 1.14 @@ -92,4 +92,5 @@ /* Function called by main.c to handle first-level request */ void process_request (request_rec *); int default_handler (request_rec *); +void die(int type, request_rec *r); #endif 1.5 +5 -4 apachen/src/modules/standard/mod_setenvif.c Index: mod_setenvif.c =================================================================== RCS file: /export/home/cvs/apachen/src/modules/standard/mod_setenvif.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- mod_setenvif.c 1997/08/02 08:10:28 1.4 +++ mod_setenvif.c 1997/08/18 07:17:30 1.5 @@ -269,7 +269,7 @@ { NULL }, }; -static int fname_translate_setenvif(request_rec *r) +static int match_headers(request_rec *r) { server_rec *s = r->server; sei_cfg_rec *sconf = (sei_cfg_rec *)get_module_config(s->module_config, @@ -342,7 +342,7 @@ merge_setenvif_config, /* merge server configs */ setenvif_module_cmds, /* command table */ NULL, /* handlers */ - fname_translate_setenvif, /* filename translation */ + NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ @@ -350,6 +350,7 @@ NULL, /* fixups */ NULL, /* logger */ NULL, /* browser parse */ - NULL, /* child (process) initializer */ - NULL /* child (process) rundown handler */ + NULL, /* child_init */ + NULL, /* child_exit */ + match_headers /* post_read_request */ }; 1.1 apachen/src/modules/standard/mod_unique_id.c Index: mod_unique_id.c =================================================================== /* ==================================================================== * Copyright (c) 1995-1997 The Apache Group. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * 4. The names "Apache Server" and "Apache Group" must not be used to * endorse or promote products derived from this software without * prior written permission. * * 5. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Group and was originally based * on public domain software written at the National Center for * Supercomputing Applications, University of Illinois, Urbana-Champaign. * For more information on the Apache Group and the Apache HTTP server * project, please see . * */ /* * mod_uniqueid.c: generate a unique identifier for each request * * Original author: Dean Gaudet */ #include "httpd.h" #include "http_config.h" #include "http_log.h" #include "multithread.h" #include #include #ifdef MULTITHREAD #error sorry this module does not support multithreaded servers yet #endif typedef struct { time_t stamp; unsigned int in_addr; unsigned int pid; unsigned short counter; } unique_id_rec; /* Comments: * * We want an identifier which is unique across all hits, everywhere. * "everywhere" includes multiple httpd instances on the same machine, or on * multiple machines. Essentially "everywhere" should include all possible * httpds across all servers at a particular "site". We make some assumptions * that if the site has a cluster of machines then their time is relatively * synchronized. We also assume that the first address returned by a * gethostbyname (gethostname()) is unique across all the machines at the * "site". * * We also further assume that pids fit in 32-bits. If something uses more * than 32-bits, the fix is trivial, but it requires the unrolled uuencoding * loop to be extended. * A similar fix is needed to support multithreaded * servers, using a pid/tid combo. * * Together, the in_addr and pid are assumed to absolutely uniquely identify * this one child from all other currently running children on all servers * (including this physical server if it is running multiple httpds) from each * other. * * The stamp and counter are used to distinguish all hits for a particular * (in_addr,pid) pair. The stamp is updated using r->request_time, * saving cpu cycles. The counter is never reset, and is used to permit up to * 64k requests in a single second by a single child. * * The 112-bits of unique_id_rec are uuencoded using the alphabet * [A-Za-z0-9@-], resulting in 19 bytes of printable characters. That is then * stuffed into the environment variable UNIQUE_ID so that it is available to * other modules. The alphabet choice differs from normal base64 encoding * [A-Za-z0-9+/] because + and / are special characters in URLs and we want to * make it easy to use UNIQUE_ID in URLs. * * Note that UNIQUE_ID should be considered an opaque token by other * applications. No attempt should be made to dissect its internal components. * It is an abstraction that may change in the future as the needs of this * module change. * * It is highly desirable that identifiers exist for "eternity". But future * needs (such as much faster webservers, moving to 64-bit pids, or moving to a * multithreaded server) may dictate a need to change the contents of * unique_id_rec. Such a future implementation should ensure that the first * field is still a time_t stamp. By doing that, it is possible for a site to * have a "flag second" in which they stop all of their old-format servers, * wait one entire second, and then start all of their new-servers. This * procedure will ensure that the new space of identifiers is completely unique * from the old space. (Since the first four unencoded bytes always differ.) */ static unsigned global_in_addr; static APACHE_TLS unique_id_rec cur_unique_id; static void unique_id_global_init (server_rec *s, pool *p) { #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 #endif char str[MAXHOSTNAMELEN+1]; struct hostent *hent; #ifndef NO_GETTIMEOFDAY struct timeval tv; #endif /* First of all, verify some assumptions that have been made about * the contents of unique_id_rec. We do it this way because it * isn't affected by trailing padding. */ if (XtOffsetOf (unique_id_rec, counter) + sizeof (cur_unique_id.counter) != 14) { log_error ("mod_unique_id: sorry the size assumptions are wrong in mod_unique_id.c, please remove it from your server or fix the code!", s); exit (1); } /* Now get the global in_addr. Note that it is not sufficient to use * one of the addresses from the main_server, since those aren't as likely * to be unique as the physical address of the machine */ if (gethostname (str, sizeof (str) - 1) != 0) { log_unixerr ("gethostname", "mod_unique_id", "mod_unique_id requires the hostname of the server", s); exit (1); } if ((hent = gethostbyname (str)) == NULL) { log_printf (s, "mod_unique_id: unable to gethostbyname(\"%s\")", str); exit (1); } global_in_addr = ((struct in_addr *)hent->h_addr_list[0])->s_addr; log_printf (s, "mod_unique_id: using ip addr %s", inet_ntoa (*(struct in_addr *)hent->h_addr_list[0])); /* If the server is pummelled with restart requests we could possibly * end up in a situation where we're starting again during the same * second that has been used in previous identifiers. Avoid that * situation. * * In truth, for this to actually happen not only would it have to * restart in the same second, but it would have to somehow get the * same pids as one of the other servers that was running in that second. * Which would mean a 64k wraparound on pids ... not very likely at * all. * * But protecting against it is relatively cheap. We just sleep into * the next second. */ #ifdef NO_GETTIMEOFDAY sleep (1); #else if (gettimeofday (&tv, NULL) == -1) { sleep (1); } else if (tv.tv_usec) { tv.tv_sec = 0; tv.tv_usec = 1000000 - tv.tv_usec; select (0, NULL, NULL, NULL, &tv); } #endif } static void unique_id_child_init (server_rec *s, pool *p) { pid_t pid; #ifndef NO_GETTIMEOFDAY struct timeval tv; #endif /* Note that we use the pid because it's possible that on the same * physical machine there are multiple servers (i.e. using Listen). * But it's guaranteed that none of them will share the same pids * between children. * * XXX: for multithread this needs to use a pid/tid combo and probably * XXX: needs to be expanded to 32 bits */ pid = getpid(); cur_unique_id.pid = pid; /* Test our assumption that the pid is 16-bits. But note we can't just * test sizeof (pid_t) because on some machines pid_t is 32-bits but * pids are actually only 16-bits. It would have been really nice to * test this during global_init ... but oh well. */ if (cur_unique_id.pid != pid) { log_error ("mod_unique_id: oh no! pids are greater than 16-bits! I'm broken!", s); } cur_unique_id.in_addr = global_in_addr; /* If we use 0 as the initial counter we have a little less protection * against restart problems, and a little less protection against a * clock going backwards in time. */ #ifndef NO_GETTIMEOFDAY if (gettimeofday (&tv, NULL) == -1) { cur_unique_id.counter = 0; } else { cur_unique_id.counter = tv.tv_usec; } #else cur_unique_id.counter = 0; #endif /* We must always use network ordering for these bytes, so that identifiers * are comparable between machines of different byte orderings. Note * in_addr is already in network order. */ cur_unique_id.pid = htons (cur_unique_id.pid); cur_unique_id.counter = htons (cur_unique_id.counter); } /* NOTE: This is *NOT* the same encoding used by uuencode ... the last two * characters should be + and /. But those two characters have very special * meanings in URLs, and we want to make it easy to use identifiers in * URLs. So we replace them with @ and -. */ static const char uuencoder[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '@', '-', }; static int gen_unique_id (request_rec *r) { /* when we uuencode it will take 19 bytes plus \0 */ char str[19 + 1]; const unsigned char *x; unsigned short counter; cur_unique_id.stamp = htonl (r->request_time); /* do the uuencoding */ x = (const unsigned char *)&cur_unique_id; str[0] = uuencoder[x[0] >> 2]; str[1] = uuencoder[((x[0] & 0x03) << 4) | ((x[1] & 0xf0) >> 4)]; str[2] = uuencoder[((x[1] & 0x0f) << 2) | ((x[2] & 0xc0) >> 6)]; str[3] = uuencoder[x[2] & 0x3f]; x += 3; str[4] = uuencoder[x[0] >> 2]; str[5] = uuencoder[((x[0] & 0x03) << 4) | ((x[1] & 0xf0) >> 4)]; str[6] = uuencoder[((x[1] & 0x0f) << 2) | ((x[2] & 0xc0) >> 6)]; str[7] = uuencoder[x[2] & 0x3f]; x += 3; str[8] = uuencoder[x[0] >> 2]; str[9] = uuencoder[((x[0] & 0x03) << 4) | ((x[1] & 0xf0) >> 4)]; str[10] = uuencoder[((x[1] & 0x0f) << 2) | ((x[2] & 0xc0) >> 6)]; str[11] = uuencoder[x[2] & 0x3f]; x += 3; str[12] = uuencoder[x[0] >> 2]; str[13] = uuencoder[((x[0] & 0x03) << 4) | ((x[1] & 0xf0) >> 4)]; str[14] = uuencoder[((x[1] & 0x0f) << 2) | ((x[2] & 0xc0) >> 6)]; str[15] = uuencoder[x[2] & 0x3f]; x += 3; str[16] = uuencoder[x[0] >> 2]; str[17] = uuencoder[((x[0] & 0x03) << 4) | ((x[1] & 0xf0) >> 4)]; str[18] = uuencoder[((x[1] & 0x0f) << 2) | (( 0 & 0xc0) >> 6)]; str[19] = '\0'; table_set (r->subprocess_env, "UNIQUE_ID", str); /* and increment the identifier for the next call */ counter = ntohs (cur_unique_id.counter) + 1; cur_unique_id.counter = htons (counter); return DECLINED; } module MODULE_VAR_EXPORT unique_id_module = { STANDARD_MODULE_STUFF, unique_id_global_init, /* initializer */ NULL, /* dir config creater */ NULL, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server configs */ NULL, /* command table */ NULL, /* handlers */ NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL, /* logger */ NULL, /* header parser */ unique_id_child_init, /* child_init */ NULL, /* child_exit */ gen_unique_id /* post_read_request */ };