View | Details | Raw Unified | Return to bug 65307
Collapse All | Expand All

(-)a/modules/metadata/mod_unique_id.c (-228 / +328 lines)
Lines 19-256 Link Here
19
 *
19
 *
20
 * Original author: Dean Gaudet <dgaudet@arctic.org>
20
 * Original author: Dean Gaudet <dgaudet@arctic.org>
21
 * UUencoding modified by: Alvaro Martinez Echevarria <alvaro@lander.es>
21
 * UUencoding modified by: Alvaro Martinez Echevarria <alvaro@lander.es>
22
 * Complete rewrite by: Atle Solbakken <atle@goliathdns.no>, April 2021
22
 */
23
 */
23
24
24
#define APR_WANT_BYTEFUNC   /* for htons() et al */
25
/* Enable when ready to use new library encoder
25
#include "apr_want.h"
26
 * #define WITH_APR_ENCODE
26
#include "apr_general.h"    /* for APR_OFFSETOF                */
27
 */
27
#include "apr_network_io.h"
28
29
/* Enable debug to error log
30
 * #define UNIQUE_ID_DEBUG
31
 */
28
32
33
#define THREADED_COUNTER "unique_id_counter"
34
35
#include "apr.h"
36
37
#ifdef WITH_APR_ENCODE
38
#    include "apr_encode.h"
39
#endif
40
#include "apr_thread_proc.h"
41
#include "apr_cstr.h"
42
43
#include "ap_mpm.h"
29
#include "httpd.h"
44
#include "httpd.h"
30
#include "http_config.h"
45
#include "http_config.h"
31
#include "http_log.h"
46
#include "http_log.h"
32
#include "http_protocol.h"  /* for ap_hook_post_read_request */
47
#include "http_protocol.h"
48
49
#ifdef HAVE_SYS_GETTID
50
#    include <sys/syscall.h>
51
#    include <sys/types.h>
52
#endif
53
54
#if APR_HAVE_UNISTD_H
55
#    include <unistd.h>
56
#endif
57
#if APR_HAVE_PROCESS_H
58
#    include <process.h>
59
#endif
33
60
34
#define ROOT_SIZE 10
61
typedef apr_uint16_t unique_counter;
35
62
36
typedef struct {
63
/* Unique ID structure members must be aligned on 1-byte boundaries */
37
    unsigned int stamp;
64
38
    char root[ROOT_SIZE];
65
#pragma pack(push)
39
    unsigned short counter;
66
#pragma pack(1)
40
    unsigned int thread_index;
67
68
typedef struct unique_id_rec {
69
    apr_uint32_t process_id;
70
    apr_uint64_t thread_id;
71
    apr_uint64_t timestamp;
72
    apr_uint16_t server_id;
73
    unique_counter counter;
41
} unique_id_rec;
74
} unique_id_rec;
42
75
43
/* We are using thread_index (the index into the scoreboard), because we
76
#ifndef WITH_APR_ENCODE
44
 * cannot guarantee the thread_id will be an integer.
77
typedef struct unique_id_rec_padded {
45
 */
78
    struct unique_id_rec unique_id;
79
    apr_uint16_t pad;
80
} unique_id_rec_padded;
81
#endif
82
83
#pragma pack(pop)
84
85
typedef struct unique_id_server_config_rec { 
86
    /* A value of -1 means not initialized, and 0 will be used. Max value is 65535. */
87
    int server_id;
88
} unique_id_server_config_rec;
46
89
47
/* Comments:
90
#if APR_HAS_THREADS
91
struct unique_thread_data {
92
    unique_counter counter;
93
};
94
#else
95
static unique_counter global_counter = 0;
96
#endif
97
98
module AP_MODULE_DECLARE_DATA unique_id_module;
99
100
/*
101
 * This module generates (almost) unique IDs for each request to a particular server.
48
 *
102
 *
49
 * We want an identifier which is unique across all hits, everywhere.
103
 * IDs are guaranteed to be unique across different servers for which the parameter
50
 * "everywhere" includes multiple httpd instances on the same machine, or on
104
 * UniqueIdServerId is set to a different value.
51
 * multiple machines.  Essentially "everywhere" should include all possible
52
 * httpds across all servers at a particular "site".  We make some assumptions
53
 * that if the site has a cluster of machines then their time is relatively
54
 * synchronized.  We also assume that the first address returned by a
55
 * gethostbyname (gethostname()) is unique across all the machines at the
56
 * "site".
57
 *
105
 *
58
 * The root is assumed to absolutely uniquely identify this one child
106
 * IDs are always unique on a particular server regardless of the UniqueIdServerId value.
59
 * from all other currently running children on all servers (including
60
 * this physical server if it is running multiple httpds) from each
61
 * other.
62
 *
107
 *
63
 * The stamp and counter are used to distinguish all hits for a
108
 * A combination of different parameters however ensure a low chance for ID collisions:
64
 * particular root.  The stamp is updated using r->request_time,
65
 * saving cpu cycles.  The counter is never reset, and is used to
66
 * permit up to 64k requests in a single second by a single thread.
67
 *
109
 *
68
 * The 144-bits of unique_id_rec are encoded using the alphabet
110
 * - Process ID of the running process
69
 * [A-Za-z0-9@-], resulting in 24 bytes of printable characters.  That is then
111
 * - Thread ID of the running thread
70
 * stuffed into the environment variable UNIQUE_ID so that it is available to
112
 * - Timestamp in microseconds
71
 * other modules.  The alphabet choice differs from normal base64 encoding
113
 * - 16 bit incrementing counter for each unique Thread ID
72
 * [A-Za-z0-9+/] because + and / are special characters in URLs and we want to
114
 * - 16 bit server ID manually set (defaults to 0)
73
 * make it easy to use UNIQUE_ID in URLs.
74
 *
115
 *
75
 * Note that UNIQUE_ID should be considered an opaque token by other
116
 * The resulting ID string will be a base64 encoded string (RFC4648) 32 characaters long. The
76
 * applications.  No attempt should be made to dissect its internal components.
117
 * length may change, applications storing the value should fit longer strings and not depend
77
 * It is an abstraction that may change in the future as the needs of this
118
 * on the size.
78
 * module change.
79
 *
119
 *
80
 * It is highly desirable that identifiers exist for "eternity".  But future
120
 * For non-threaded servers, the Thread ID will always be 0 and the counter is incremented
81
 * needs (such as much faster webservers, or moving to a
121
 * for each process and wraps around after some time.
82
 * multithreaded server) may dictate a need to change the contents of
83
 * unique_id_rec.  Such a future implementation should ensure that the first
84
 * field is still a time_t stamp.  By doing that, it is possible for a site to
85
 * have a "flag second" in which they stop all of their old-format servers,
86
 * wait one entire second, and then start all of their new-servers.  This
87
 * procedure will ensure that the new space of identifiers is completely unique
88
 * from the old space.  (Since the first four unencoded bytes always differ.)
89
 *
122
 *
90
 * Note: previous implementations used 32-bits of IP address plus pid
91
 * in place of the PRNG output in the "root" field.  This was
92
 * insufficient for IPv6-only hosts, required working DNS to determine
93
 * a unique IP address (fragile), and needed a [0, 1) second sleep
94
 * call at startup to avoid pid reuse.  Use of the PRNG avoids all
95
 * these issues.
96
 */
123
 */
97
124
98
/*
125
#if APR_IS_BIGENDIAN
99
 * Sun Jun  7 05:43:49 CEST 1998 -- Alvaro
126
#    define swap16(a) a
100
 * More comments:
127
#    define swap32(a) a
101
 * 1) The UUencoding procedure is now done in a general way, avoiding the problems
128
#    define swap64(a) a
102
 * with sizes and paddings that can arise depending on the architecture. Now the
129
#else
103
 * offsets and sizes of the elements of the unique_id_rec structure are calculated
130
#    define swap16(a) ( ((a>>8)  & 0xff) |              \
104
 * in unique_id_global_init; and then used to duplicate the structure without the
131
                        ((a<<8)  & 0xff00))
105
 * paddings that might exist. The multithreaded server fix should be now very easy:
132
#    define swap32(a) ( ((a>>24) & 0xff) |              \
106
 * just add a new "tid" field to the unique_id_rec structure, and increase by one
133
                        ((a>>8)  & 0xff00) |            \
107
 * UNIQUE_ID_REC_MAX.
134
			((a<<8)  & 0xff0000) |          \
108
 * 2) unique_id_rec.stamp has been changed from "time_t" to "unsigned int", because
135
			((a<<24) & 0xff000000))
109
 * its size is 64bits on some platforms (linux/alpha), and this caused problems with
136
#    define swap64(a) ( ((a>>56) & 0xff) |              \
110
 * htonl/ntohl. Well, this shouldn't be a problem till year 2106.
137
                        ((a>>40) & 0xff00) |            \
111
 */
138
			((a>>24) & 0xff0000) |          \
112
139
			((a>>8)  & 0xff000000) |        \
113
static unique_id_rec cur_unique_id;
140
			((a<<8)  & 0xff00000000) |      \
114
141
			((a<<24) & 0xff0000000000) |    \
115
/*
142
			((a<<40) & 0xff000000000000) |  \
116
 * Number of elements in the structure unique_id_rec.
143
			((a<<56) & 0xff00000000000000))
117
 */
144
#endif /* APR_IS_BIGENDIAN */
118
#define UNIQUE_ID_REC_MAX 4
145
119
146
static void byteswap_unique_id (unique_id_rec *unique_id)
120
static unsigned short unique_id_rec_offset[UNIQUE_ID_REC_MAX],
121
                      unique_id_rec_size[UNIQUE_ID_REC_MAX],
122
                      unique_id_rec_total_size,
123
                      unique_id_rec_size_uu;
124
125
static int unique_id_global_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server)
126
{
147
{
127
    /*
148
    unique_id->process_id = swap32(unique_id->process_id);
128
     * Calculate the sizes and offsets in cur_unique_id.
149
    unique_id->thread_id = swap64(unique_id->thread_id);
129
     */
150
    unique_id->timestamp = swap64(unique_id->timestamp);
130
    unique_id_rec_offset[0] = APR_OFFSETOF(unique_id_rec, stamp);
151
    unique_id->server_id = swap16(unique_id->server_id);
131
    unique_id_rec_size[0] = sizeof(cur_unique_id.stamp);
152
    unique_id->counter = swap16(unique_id->counter);
132
    unique_id_rec_offset[1] = APR_OFFSETOF(unique_id_rec, root);
133
    unique_id_rec_size[1] = sizeof(cur_unique_id.root);
134
    unique_id_rec_offset[2] = APR_OFFSETOF(unique_id_rec, counter);
135
    unique_id_rec_size[2] = sizeof(cur_unique_id.counter);
136
    unique_id_rec_offset[3] = APR_OFFSETOF(unique_id_rec, thread_index);
137
    unique_id_rec_size[3] = sizeof(cur_unique_id.thread_index);
138
    unique_id_rec_total_size = unique_id_rec_size[0] + unique_id_rec_size[1] +
139
                               unique_id_rec_size[2] + unique_id_rec_size[3];
140
141
    /*
142
     * Calculate the size of the structure when encoded.
143
     */
144
    unique_id_rec_size_uu = (unique_id_rec_total_size*8+5)/6;
145
146
    return OK;
147
}
153
}
148
154
149
static void unique_id_child_init(apr_pool_t *p, server_rec *s)
155
static void populate_unique_id (unique_id_rec *unique_id, apr_uint64_t thread_id, apr_uint32_t counter, apr_uint16_t server_id)
150
{
156
{
151
    ap_random_insecure_bytes(&cur_unique_id.root,
157
    unique_id->process_id = ((apr_uint32_t) getpid()) & 0x00000000ffffffff;
152
                             sizeof(cur_unique_id.root));
158
    unique_id->thread_id = thread_id;
153
159
    unique_id->timestamp = apr_time_now();
154
    /*
160
    unique_id->server_id = server_id;
155
     * If we use 0 as the initial counter we have a little less protection
161
    unique_id->counter = counter;
156
     * against restart problems, and a little less protection against a clock
157
     * going backwards in time.
158
     */
159
    ap_random_insecure_bytes(&cur_unique_id.counter,
160
                             sizeof(cur_unique_id.counter));
161
}
162
}
162
163
163
/* Use the base64url encoding per RFC 4648, avoiding characters which
164
static int get_server_id(apr_uint16_t *server_id, const request_rec *r)
164
 * are not safe in URLs.  ### TODO: can switch to apr_encode_*. */
165
{
165
static const char uuencoder[64] = {
166
    const unique_id_server_config_rec *conf;
166
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
167
167
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
168
    /* Note : Cast away const */
168
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
169
    if ((conf = ap_get_module_config((void *) r->server->module_config, &unique_id_module)) == NULL ||
169
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
170
         conf->server_id < -1 ||
170
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
171
	 conf->server_id > 65535
171
};
172
    ) {
173
        ap_log_error(APLOG_MARK, APLOG_ERR, HTTP_INTERNAL_SERVER_ERROR, r->server, "Server ID of Unique ID module not initialized correctly");
174
    	return HTTP_INTERNAL_SERVER_ERROR;
175
    }
172
176
173
#define THREADED_COUNTER "unique_id_counter"
177
    *server_id = conf->server_id < 0 ? 0 : conf->server_id;
174
178
175
static const char *gen_unique_id(const request_rec *r)
179
    return OK;
176
{
180
}
177
    char *str;
178
    /*
179
     * Buffer padded with two final bytes, used to copy the unique_id_rec
180
     * structure without the internal paddings that it could have.
181
     */
182
    unique_id_rec new_unique_id;
183
    struct {
184
        unique_id_rec foo;
185
        unsigned char pad[2];
186
    } paddedbuf;
187
    unsigned char *x,*y;
188
    unsigned short counter;
189
    int i,j,k;
190
181
191
#if APR_HAS_THREADS
182
#if APR_HAS_THREADS
192
    apr_status_t rv;
183
/* from server/log.c */
193
    unsigned short *pcounter;
184
static apr_uint64_t get_thread_id(const request_rec *r) {
194
    apr_thread_t *thread = r->connection->current_thread;
185
    pid_t tid = 0;
195
    
186
    int result;
196
    rv = apr_thread_data_get((void **)&pcounter, THREADED_COUNTER, thread);
187
    if (ap_mpm_query(AP_MPMQ_IS_THREADED, &result) == APR_SUCCESS
197
    if (rv == APR_SUCCESS && pcounter) {
188
        && result != AP_MPMQ_NOT_SUPPORTED)
198
        counter = *pcounter;
189
    {
190
        return (apr_uint64_t) apr_os_thread_current();
199
    }
191
    }
200
    else
192
193
#if defined(HAVE_GETTID) || defined(HAVE_SYS_GETTID)
194
#ifdef HAVE_GETTID
195
    tid = gettid();
196
#else
197
    tid = syscall(SYS_gettid);
201
#endif
198
#endif
202
    {
199
    return (apr_uint64_t) (tid == -1 ? 0 : tid);
203
        counter = cur_unique_id.counter;
200
#endif /* HAVE_GETTID || HAVE_SYS_GETTID */
201
}
202
#endif /* APR_HAS_THREADS */
203
204
static const char *create_unique_id_string(const request_rec *r)
205
{
206
    char *ret = NULL;
207
    unique_id_rec unique_id;
208
#ifndef WITH_APR_ENCODE    
209
    const
210
#endif
211
    apr_size_t ret_size = sizeof(unique_id) * 2;
212
    apr_uint16_t server_id = 0;
213
214
    if (get_server_id(&server_id, r) != OK) {
215
        goto out;
204
    }
216
    }
205
217
206
    memcpy(&new_unique_id.root, &cur_unique_id.root, ROOT_SIZE);
207
    new_unique_id.counter = htons(counter++);
208
#if APR_HAS_THREADS
218
#if APR_HAS_THREADS
209
    if (!pcounter) {
219
    {
210
        pcounter = apr_palloc(apr_thread_pool_get(thread), sizeof(*pcounter));
220
        struct unique_thread_data *thread_data = NULL;
221
        apr_thread_t *thread = r->connection->current_thread;
222
223
        if (apr_thread_data_get((void **) &thread_data, THREADED_COUNTER, thread) != APR_SUCCESS || thread_data == NULL) {
224
            thread_data = apr_pcalloc(apr_thread_pool_get(thread), sizeof(*thread_data));
225
            if (thread_data == NULL) {
226
                goto out;
227
            }
228
            thread_data->counter = 0;
229
            if (apr_thread_data_set(thread_data, THREADED_COUNTER, NULL, thread) != APR_SUCCESS) {
230
                goto out;
231
            }
232
        }
233
234
        populate_unique_id(&unique_id, get_thread_id(r), ++(thread_data->counter), server_id);
211
    }
235
    }
212
    
236
#else
213
    *pcounter = counter;
237
    populate_unique_id(&unique_id, 0, ++global_counter, server_id);
214
    rv = apr_thread_data_set(pcounter, THREADED_COUNTER, NULL, thread);
215
    if (rv != APR_SUCCESS)
216
#endif
238
#endif
217
    {
239
218
        cur_unique_id.counter = counter;
240
    byteswap_unique_id(&unique_id);
241
242
    if ((ret = (char *)apr_pcalloc(r->pool, ret_size)) == NULL) {
243
        goto out;
219
    }
244
    }
220
    new_unique_id.stamp = htonl((unsigned int)apr_time_sec(r->request_time));
245
221
    new_unique_id.thread_index = htonl((unsigned int)r->connection->id);
246
#ifdef WITH_APR_ENCODE    
222
247
    /* Use Base64 without the / per RFC 4648 */
223
    /* we'll use a temporal buffer to avoid uuencoding the possible internal
248
    if (apr_encode_base64(ret, (const char *) &unique_id, sizeof(unique_id), APR_ENCODE_URL|APR_ENCODE_NOPADDING, &ret_size) != APR_SUCCESS) {
224
     * paddings of the original structure */
249
        ret = NULL;
225
    x = (unsigned char *) &paddedbuf;
250
        goto out;
226
    k = 0;
227
    for (i = 0; i < UNIQUE_ID_REC_MAX; i++) {
228
        y = ((unsigned char *) &new_unique_id) + unique_id_rec_offset[i];
229
        for (j = 0; j < unique_id_rec_size[i]; j++, k++) {
230
            x[k] = y[j];
231
        }
232
    }
251
    }
233
    /*
252
#else
234
     * We reset two more bytes just in case padding is needed for the uuencoding.
253
    {
235
     */
254
        /* Use the base64url encoding per RFC 4648, avoiding characters which
236
    x[k++] = '\0';
255
         * are not safe in URLs. */
237
    x[k++] = '\0';
256
        static const char uuencoder[64] = {
238
257
           'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
239
    /* alloc str and do the uuencoding */
258
           'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
240
    str = (char *)apr_palloc(r->pool, unique_id_rec_size_uu + 1);
259
           'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
241
    k = 0;
260
           'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
242
    for (i = 0; i < unique_id_rec_total_size; i += 3) {
261
           '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_',
243
        y = x + i;
262
        };
244
        str[k++] = uuencoder[y[0] >> 2];
263
245
        str[k++] = uuencoder[((y[0] & 0x03) << 4) | ((y[1] & 0xf0) >> 4)];
264
        unique_id_rec_padded unique_id_padded = {
246
        if (k == unique_id_rec_size_uu) break;
265
            unique_id, 0
247
        str[k++] = uuencoder[((y[1] & 0x0f) << 2) | ((y[2] & 0xc0) >> 6)];
266
        };
248
        if (k == unique_id_rec_size_uu) break;
267
249
        str[k++] = uuencoder[y[2] & 0x3f];
268
        const unsigned char *src = (const unsigned char *) &unique_id_padded;
269
        const unsigned char *max = src + sizeof(unique_id);
270
        int wpos = 0;
271
        const unsigned char *pos;
272
273
        for (pos = src; pos < max; pos += 3) {    
274
            ret[wpos++] = uuencoder[pos[0] >> 2];
275
            ret[wpos++] = uuencoder[((pos[0] & 0x03) << 4) | ((pos[1] & 0xf0) >> 4)];
276
            if (pos + 1 == max) break;
277
            ret[wpos++] = uuencoder[((pos[1] & 0x0f) << 2) | ((pos[2] & 0xc0) >> 6)];
278
            if (pos + 2 == max) break;
279
            ret[wpos++] = uuencoder[pos[2] & 0x3f];
280
        }
281
282
        ret[wpos++] = '\0';
250
    }
283
    }
251
    str[k++] = '\0';
284
#endif
252
285
253
    return str;
286
 #ifdef UNIQUE_ID_DEBUG
287
    byteswap_unique_id(&unique_id); // Swap back for debug purposes
288
    ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
289
            "Unique ID generated: %s pid %" APR_UINT64_T_FMT " tid %" APR_UINT64_T_FMT " time %" APR_UINT64_T_FMT " server %" APR_UINT64_T_FMT " count %" APR_UINT64_T_FMT "",
290
            ret,
291
            (apr_uint64_t) unique_id.process_id,
292
            (apr_uint64_t) unique_id.thread_id,
293
            (apr_uint64_t) unique_id.timestamp,
294
            (apr_uint64_t) unique_id.server_id,
295
            (apr_uint64_t) unique_id.counter
296
    );
297
#endif /* UNIQUE_ID_DEBUG */
298
299
    out:
300
    return ret;
254
}
301
}
255
302
256
/*
303
/*
Lines 262-325 static const char *gen_unique_id(const request_rec *r) Link Here
262
 *   has been called, or not at all.
309
 *   has been called, or not at all.
263
 */
310
 */
264
311
265
static int generate_log_id(const conn_rec *c, const request_rec *r,
312
static int get_request_unique_id(const char **result_id, const request_rec *r)
266
                           const char **id)
267
{
313
{
314
    const char *id = NULL;
315
316
    /* Return any previously set ID or make a new one */
317
    if ( (id = apr_table_get(r->subprocess_env, "UNIQUE_ID")) == NULL &&
318
         (id = r->log_id) == NULL &&
319
         (id = create_unique_id_string(r)) == NULL
320
    ) {
321
        ap_log_error(APLOG_MARK, APLOG_ERR, HTTP_INTERNAL_SERVER_ERROR, r->server, "Unique ID generation failed");
322
        return HTTP_INTERNAL_SERVER_ERROR;
323
    }
324
325
    *result_id = id;
326
327
    return OK;
328
}
329
330
static int generate_log_id_hook(const conn_rec *c, const request_rec *r, const char **id)
331
{
332
    (void)(c);
333
268
    /* we do not care about connection ids */
334
    /* we do not care about connection ids */
269
    if (r == NULL)
335
    if (r == NULL)
270
        return DECLINED;
336
        return DECLINED;
271
337
272
    /* XXX: do we need special handling for internal redirects? */
338
    return get_request_unique_id(id, r);
339
}
273
340
274
    /* if set_unique_id() has been called for this request, use it */
341
static int post_read_request_hook(request_rec *r)
275
    *id = apr_table_get(r->subprocess_env, "UNIQUE_ID");
342
{
343
    const char *id = NULL;
276
344
277
    if (!*id)
345
    int ret = get_request_unique_id(&id, r);
278
        *id = gen_unique_id(r);
346
279
    return OK;
347
    if (id != NULL) {
348
        apr_table_setn(r->subprocess_env, "UNIQUE_ID", id);
349
    }
350
351
    return (ret == OK ? DECLINED : ret);
280
}
352
}
281
353
282
static int set_unique_id(request_rec *r)
354
static void register_hooks(apr_pool_t *p)
283
{
355
{
284
    const char *id = NULL;
356
    ap_hook_generate_log_id(generate_log_id_hook, NULL, NULL, APR_HOOK_MIDDLE);
285
    /* copy the unique_id if this is an internal redirect (we're never
357
    ap_hook_post_read_request(post_read_request_hook, NULL, NULL, APR_HOOK_MIDDLE);
286
     * actually called for sub requests, so we don't need to test for
358
}
287
     * them) */
359
288
    if (r->prev) {
360
static void *create_unique_id_server_config (apr_pool_t *p, server_rec *d)
289
       id = apr_table_get(r->subprocess_env, "REDIRECT_UNIQUE_ID");
361
{
362
    unique_id_server_config_rec *ret;
363
    if ((ret = apr_pcalloc(p, sizeof(unique_id_server_config_rec))) != NULL) {
364
        ret->server_id = -1;
365
    }
366
    return ret;
367
}
368
369
static void *merge_unique_id_server_config(apr_pool_t *p, void *basev, void *addv)
370
{
371
    unique_id_server_config_rec *base = (unique_id_server_config_rec *) basev;
372
    unique_id_server_config_rec *add = (unique_id_server_config_rec *) addv;
373
    unique_id_server_config_rec *new;
374
375
    if ((new = apr_pcalloc (p, sizeof(*new))) != NULL) {
376
        /* Default value is -1 which means not initialized */
377
        new->server_id = add->server_id >= 0 ? add->server_id : base->server_id;
378
    }
379
380
    return new;
381
}
382
383
static const char *set_server_id (cmd_parms *cmd, void *dummy, const char *arg)
384
{
385
    int tmp = -1;
386
    const char *err;
387
    unique_id_server_config_rec *conf;
388
389
    if ((err = ap_check_cmd_context (cmd, GLOBAL_ONLY)) != NULL) {
390
    	return err;
290
    }
391
    }
291
392
292
    if (!id) {
393
    conf = (unique_id_server_config_rec *) ap_get_module_config (
293
        /* if we have a log id, it was set by our generate_log_id() function
394
            cmd->server->module_config,
294
         * and we should reuse the same id
395
	    &unique_id_module
295
         */
396
    );
296
        id = r->log_id;
397
398
    if (conf == NULL) {
399
    	return "Unique ID: data not previously allocated";
297
    }
400
    }
298
401
299
    if (!id) {
402
    if (apr_cstr_atoi(&tmp, arg) != APR_SUCCESS || tmp < 0 || tmp > 65535) {
300
        id = gen_unique_id(r);
403
    	return "Unique ID: Invalid syntax in UniqueIdServerId parameter. Must be a number between 0 and 65535 inclusive.";
301
    }
404
    }
302
405
303
    /* set the environment variable */
406
    conf->server_id = tmp;
304
    apr_table_setn(r->subprocess_env, "UNIQUE_ID", id);
305
407
306
    return DECLINED;
408
    return NULL;
307
}
409
}
308
410
309
static void register_hooks(apr_pool_t *p)
411
static const command_rec unique_id_cmds[] =
310
{
412
{
311
    ap_hook_post_config(unique_id_global_init, NULL, NULL, APR_HOOK_MIDDLE);
413
    AP_INIT_TAKE1("UniqueIdServerId", set_server_id, NULL, RSRC_CONF, "Set a unique ID of server in the range 0 to 65535"),
312
    ap_hook_child_init(unique_id_child_init, NULL, NULL, APR_HOOK_MIDDLE);
414
    {NULL}
313
    ap_hook_post_read_request(set_unique_id, NULL, NULL, APR_HOOK_MIDDLE);
415
};
314
    ap_hook_generate_log_id(generate_log_id, NULL, NULL, APR_HOOK_MIDDLE);
315
}
316
416
317
AP_DECLARE_MODULE(unique_id) = {
417
AP_DECLARE_MODULE(unique_id) = {
318
    STANDARD20_MODULE_STUFF,
418
    STANDARD20_MODULE_STUFF,
319
    NULL,                       /* dir config creater */
419
    NULL,                           /* dir config creater */
320
    NULL,                       /* dir merger --- default is to override */
420
    NULL,                           /* dir merger --- default is to override */
321
    NULL,                       /* server config */
421
    create_unique_id_server_config, /* server config */
322
    NULL,                       /* merge server configs */
422
    merge_unique_id_server_config,  /* merge server configs */
323
    NULL,                       /* command apr_table_t */
423
    unique_id_cmds,                 /* command apr_table_t */
324
    register_hooks              /* register hooks */
424
    register_hooks                  /* register hooks */
325
};
425
};

Return to bug 65307