]> granicus.if.org Git - apache/blob - modules/loggers/mod_log_config.c
SECURITY: CVE-2012-0021 (cve.mitre.org)
[apache] / modules / loggers / mod_log_config.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * Modified by djm@va.pubnix.com:
19  * If no TransferLog is given explicitly, decline to log.
20  *
21  * This is module implements the TransferLog directive (same as the
22  * common log module), and additional directives, LogFormat and CustomLog.
23  *
24  *
25  * Syntax:
26  *
27  *    TransferLog fn      Logs transfers to fn in standard log format, unless
28  *                        a custom format is set with LogFormat
29  *    LogFormat format    Set a log format from TransferLog files
30  *    CustomLog fn format
31  *                        Log to file fn with format given by the format
32  *                        argument
33  *
34  * There can be any number of TransferLog and CustomLog
35  * commands. Each request will be logged to _ALL_ the
36  * named files, in the appropriate format.
37  *
38  * If no TransferLog or CustomLog directive appears in a VirtualHost,
39  * the request will be logged to the log file(s) defined outside
40  * the virtual host section. If a TransferLog or CustomLog directive
41  * appears in the VirtualHost section, the log files defined outside
42  * the VirtualHost will _not_ be used. This makes this module compatable
43  * with the CLF and config log modules, where the use of TransferLog
44  * inside the VirtualHost section overrides its use outside.
45  *
46  * Examples:
47  *
48  *    TransferLog    logs/access_log
49  *    <VirtualHost>
50  *    LogFormat      "... custom format ..."
51  *    TransferLog    log/virtual_only
52  *    CustomLog      log/virtual_useragents "%t %{user-agent}i"
53  *    </VirtualHost>
54  *
55  * This will log using CLF to access_log any requests handled by the
56  * main server, while any requests to the virtual host will be logged
57  * with the "... custom format..." to virtual_only _AND_ using
58  * the custom user-agent log to virtual_useragents.
59  *
60  * Note that the NCSA referer and user-agent logs are easily added with
61  * CustomLog:
62  *   CustomLog   logs/referer  "%{referer}i -> %U"
63  *   CustomLog   logs/agent    "%{user-agent}i"
64  *
65  * RefererIgnore functionality can be obtained with conditional
66  * logging (SetEnvIf and CustomLog ... env=!VAR).
67  *
68  * But using this method allows much easier modification of the
69  * log format, e.g. to log hosts along with UA:
70  *   CustomLog   logs/referer "%{referer}i %U %h"
71  *
72  * The argument to LogFormat and CustomLog is a string, which can include
73  * literal characters copied into the log files, and '%' directives as
74  * follows:
75  *
76  * %...B:  bytes sent, excluding HTTP headers.
77  * %...b:  bytes sent, excluding HTTP headers in CLF format, i.e. a '-'
78  *         when no bytes where sent (rather than a '0'.
79  * %...{FOOBAR}C:  The contents of the HTTP cookie FOOBAR
80  * %...{FOOBAR}e:  The contents of the environment variable FOOBAR
81  * %...f:  filename
82  * %...h:  remote host
83  * %...a:  remote IP-address
84  * %...A:  local IP-address
85  * %...{Foobar}i:  The contents of Foobar: header line(s) in the request
86  *                 sent to the client.
87  * %...k:  number of keepalive requests served over this connection
88  * %...l:  remote logname (from identd, if supplied)
89  * %...{Foobar}n:  The contents of note "Foobar" from another module.
90  * %...{Foobar}o:  The contents of Foobar: header line(s) in the reply.
91  * %...p:  the canonical port for the server
92  * %...{format}p: the canonical port for the server, or the actual local
93  *                or remote port
94  * %...P:  the process ID of the child that serviced the request.
95  * %...{format}P: the process ID or thread ID of the child/thread that
96  *                serviced the request
97  * %...r:  first line of request
98  * %...s:  status.  For requests that got internally redirected, this
99  *         is status of the *original* request --- %...>s for the last.
100  * %...t:  time, in common log format time format
101  * %...{format}t:  The time, in the form given by format, which should
102  *                 be in strftime(3) format.
103  * %...T:  the time taken to serve the request, in seconds.
104  * %...D:  the time taken to serve the request, in micro seconds.
105  * %...u:  remote user (from auth; may be bogus if return status (%s) is 401)
106  * %...U:  the URL path requested.
107  * %...v:  the configured name of the server (i.e. which virtual host?)
108  * %...V:  the server name according to the UseCanonicalName setting
109  * %...m:  the request method
110  * %...H:  the request protocol
111  * %...q:  the query string prepended by "?", or empty if no query string
112  * %...X:  Status of the connection.
113  *         'X' = connection aborted before the response completed.
114  *         '+' = connection may be kept alive after the response is sent.
115  *         '-' = connection will be closed after the response is sent.
116  *         (This directive was %...c in late versions of Apache 1.3, but
117  *          this conflicted with the historical ssl %...{var}c syntax.)
118  * %...L:  Log-Id of the Request (or '-' if none)
119  * %...{c}L:  Log-Id of the Connection (or '-' if none)
120  *
121  * The '...' can be nothing at all (e.g. "%h %u %r %s %b"), or it can
122  * indicate conditions for inclusion of the item (which will cause it
123  * to be replaced with '-' if the condition is not met).  Note that
124  * there is no escaping performed on the strings from %r, %...i and
125  * %...o; some with long memories may remember that I thought this was
126  * a bad idea, once upon a time, and I'm still not comfortable with
127  * it, but it is difficult to see how to "do the right thing" with all
128  * of '%..i', unless we URL-escape everything and break with CLF.
129  *
130  * The forms of condition are a list of HTTP status codes, which may
131  * or may not be preceded by '!'.  Thus, '%400,501{User-agent}i' logs
132  * User-agent: on 400 errors and 501 errors (Bad Request, Not
133  * Implemented) only; '%!200,304,302{Referer}i' logs Referer: on all
134  * requests which did *not* return some sort of normal status.
135  *
136  * The default LogFormat reproduces CLF; see below.
137  *
138  * The way this is supposed to work with virtual hosts is as follows:
139  * a virtual host can have its own LogFormat, or its own TransferLog.
140  * If it doesn't have its own LogFormat, it inherits from the main
141  * server.  If it doesn't have its own TransferLog, it writes to the
142  * same descriptor (meaning the same process for "| ...").
143  *
144  * --- rst */
145
146 #include "apr_strings.h"
147 #include "apr_lib.h"
148 #include "apr_hash.h"
149 #include "apr_optional.h"
150 #include "apr_anylock.h"
151
152 #define APR_WANT_STRFUNC
153 #include "apr_want.h"
154
155 #include "ap_config.h"
156 #include "mod_log_config.h"
157 #include "httpd.h"
158 #include "http_config.h"
159 #include "http_core.h"          /* For REMOTE_NAME */
160 #include "http_log.h"
161 #include "http_protocol.h"
162 #include "util_time.h"
163 #include "ap_mpm.h"
164
165 #if APR_HAVE_UNISTD_H
166 #include <unistd.h>
167 #endif
168 #ifdef HAVE_LIMITS_H
169 #include <limits.h>
170 #endif
171
172 #define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b"
173
174 module AP_MODULE_DECLARE_DATA log_config_module;
175
176
177 static int xfer_flags = (APR_WRITE | APR_APPEND | APR_CREATE | APR_LARGEFILE);
178 static apr_fileperms_t xfer_perms = APR_OS_DEFAULT;
179 static apr_hash_t *log_hash;
180 static apr_status_t ap_default_log_writer(request_rec *r,
181                            void *handle,
182                            const char **strs,
183                            int *strl,
184                            int nelts,
185                            apr_size_t len);
186 static apr_status_t ap_buffered_log_writer(request_rec *r,
187                            void *handle,
188                            const char **strs,
189                            int *strl,
190                            int nelts,
191                            apr_size_t len);
192 static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
193                                         const char* name);
194 static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
195                                         const char* name);
196
197 static ap_log_writer_init* ap_log_set_writer_init(ap_log_writer_init *handle);
198 static ap_log_writer* ap_log_set_writer(ap_log_writer *handle);
199 static ap_log_writer *log_writer = ap_default_log_writer;
200 static ap_log_writer_init *log_writer_init = ap_default_log_writer_init;
201 static int buffered_logs = 0; /* default unbuffered */
202 static apr_array_header_t *all_buffered_logs = NULL;
203
204 /* POSIX.1 defines PIPE_BUF as the maximum number of bytes that is
205  * guaranteed to be atomic when writing a pipe.  And PIPE_BUF >= 512
206  * is guaranteed.  So we'll just guess 512 in the event the system
207  * doesn't have this.  Now, for file writes there is actually no limit,
208  * the entire write is atomic.  Whether all systems implement this
209  * correctly is another question entirely ... so we'll just use PIPE_BUF
210  * because it's probably a good guess as to what is implemented correctly
211  * everywhere.
212  */
213 #ifdef PIPE_BUF
214 #define LOG_BUFSIZE     PIPE_BUF
215 #else
216 #define LOG_BUFSIZE     (512)
217 #endif
218
219 /*
220  * multi_log_state is our per-(virtual)-server configuration. We store
221  * an array of the logs we are going to use, each of type config_log_state.
222  * If a default log format is given by LogFormat, store in default_format
223  * (backward compat. with mod_log_config).  We also store for each virtual
224  * server a pointer to the logs specified for the main server, so that if this
225  * vhost has no logs defined, we can use the main server's logs instead.
226  *
227  * So, for the main server, config_logs contains a list of the log files
228  * and server_config_logs is empty. For a vhost, server_config_logs
229  * points to the same array as config_logs in the main server, and
230  * config_logs points to the array of logs defined inside this vhost,
231  * which might be empty.
232  */
233
234 typedef struct {
235     const char *default_format_string;
236     apr_array_header_t *default_format;
237     apr_array_header_t *config_logs;
238     apr_array_header_t *server_config_logs;
239     apr_table_t *formats;
240 } multi_log_state;
241
242 /*
243  * config_log_state holds the status of a single log file. fname might
244  * be NULL, which means this module does no logging for this
245  * request. format might be NULL, in which case the default_format
246  * from the multi_log_state should be used, or if that is NULL as
247  * well, use the CLF.
248  * log_writer is NULL before the log file is opened and is
249  * set to a opaque structure (usually a fd) after it is opened.
250
251  */
252 typedef struct {
253     apr_file_t *handle;
254     apr_size_t outcnt;
255     char outbuf[LOG_BUFSIZE];
256     apr_anylock_t mutex;
257 } buffered_log;
258
259 typedef struct {
260     const char *fname;
261     const char *format_string;
262     apr_array_header_t *format;
263     void *log_writer;
264     char *condition_var;
265     ap_expr_info_t *condition_expr;
266 } config_log_state;
267
268 /*
269  * log_request_state holds request specific log data that is not
270  * part of the request_rec.
271  */
272 typedef struct {
273     apr_time_t request_end_time;
274 } log_request_state;
275
276 /*
277  * Format items...
278  * Note that many of these could have ap_sprintfs replaced with static buffers.
279  */
280
281 typedef struct {
282     ap_log_handler_fn_t *func;
283     char *arg;
284     int condition_sense;
285     int want_orig;
286     apr_array_header_t *conditions;
287 } log_format_item;
288
289 static char *pfmt(apr_pool_t *p, int i)
290 {
291     if (i <= 0) {
292         return "-";
293     }
294     else {
295         return apr_itoa(p, i);
296     }
297 }
298
299 static const char *constant_item(request_rec *dummy, char *stuff)
300 {
301     return stuff;
302 }
303
304 static const char *log_remote_host(request_rec *r, char *a)
305 {
306     return ap_escape_logitem(r->pool, ap_get_remote_host(r->connection,
307                                                          r->per_dir_config,
308                                                          REMOTE_NAME, NULL));
309 }
310
311 static const char *log_remote_address(request_rec *r, char *a)
312 {
313     if (a && !strcmp(a, "c")) {
314         return r->connection->client_ip;
315     }
316     else {
317         return r->useragent_ip;
318     }
319 }
320
321 static const char *log_local_address(request_rec *r, char *a)
322 {
323     return r->connection->local_ip;
324 }
325
326 static const char *log_remote_logname(request_rec *r, char *a)
327 {
328     return ap_escape_logitem(r->pool, ap_get_remote_logname(r));
329 }
330
331 static const char *log_remote_user(request_rec *r, char *a)
332 {
333     char *rvalue = r->user;
334
335     if (rvalue == NULL) {
336         rvalue = "-";
337     }
338     else if (strlen(rvalue) == 0) {
339         rvalue = "\"\"";
340     }
341     else {
342         rvalue = ap_escape_logitem(r->pool, rvalue);
343     }
344
345     return rvalue;
346 }
347
348 static const char *log_request_line(request_rec *r, char *a)
349 {
350     /* NOTE: If the original request contained a password, we
351      * re-write the request line here to contain XXXXXX instead:
352      * (note the truncation before the protocol string for HTTP/0.9 requests)
353      * (note also that r->the_request contains the unmodified request)
354      */
355     return ap_escape_logitem(r->pool,
356                              (r->parsed_uri.password)
357                                ? apr_pstrcat(r->pool, r->method, " ",
358                                              apr_uri_unparse(r->pool,
359                                                              &r->parsed_uri, 0),
360                                              r->assbackwards ? NULL : " ",
361                                              r->protocol, NULL)
362                                : r->the_request);
363 }
364
365 static const char *log_request_file(request_rec *r, char *a)
366 {
367     return ap_escape_logitem(r->pool, r->filename);
368 }
369 static const char *log_request_uri(request_rec *r, char *a)
370 {
371     return ap_escape_logitem(r->pool, r->uri);
372 }
373 static const char *log_request_method(request_rec *r, char *a)
374 {
375     return ap_escape_logitem(r->pool, r->method);
376 }
377 static const char *log_log_id(request_rec *r, char *a)
378 {
379     if (a && !strcmp(a, "c")) {
380         return r->connection->log_id ? r->connection->log_id : "-";
381     }
382     else {
383         return r->log_id ? r->log_id : "-";
384     }
385 }
386 static const char *log_request_protocol(request_rec *r, char *a)
387 {
388     return ap_escape_logitem(r->pool, r->protocol);
389 }
390 static const char *log_request_query(request_rec *r, char *a)
391 {
392     return (r->args) ? apr_pstrcat(r->pool, "?",
393                                    ap_escape_logitem(r->pool, r->args), NULL)
394                      : "";
395 }
396 static const char *log_status(request_rec *r, char *a)
397 {
398     return pfmt(r->pool, r->status);
399 }
400
401 static const char *log_handler(request_rec *r, char *a)
402 {
403     return ap_escape_logitem(r->pool, r->handler);
404 }
405
406 static const char *clf_log_bytes_sent(request_rec *r, char *a)
407 {
408     if (!r->sent_bodyct || !r->bytes_sent) {
409         return "-";
410     }
411     else {
412         return apr_off_t_toa(r->pool, r->bytes_sent);
413     }
414 }
415
416 static const char *log_bytes_sent(request_rec *r, char *a)
417 {
418     if (!r->sent_bodyct || !r->bytes_sent) {
419         return "0";
420     }
421     else {
422         return apr_off_t_toa(r->pool, r->bytes_sent);
423     }
424 }
425
426
427 static const char *log_header_in(request_rec *r, char *a)
428 {
429     return ap_escape_logitem(r->pool, apr_table_get(r->headers_in, a));
430 }
431
432 static APR_INLINE char *find_multiple_headers(apr_pool_t *pool,
433                                               const apr_table_t *table,
434                                               const char *key)
435 {
436     const apr_array_header_t *elts;
437     const apr_table_entry_t *t_elt;
438     const apr_table_entry_t *t_end;
439     apr_size_t len;
440     struct sle {
441         struct sle *next;
442         const char *value;
443         apr_size_t len;
444     } *result_list, *rp;
445
446     elts = apr_table_elts(table);
447
448     if (!elts->nelts) {
449         return NULL;
450     }
451
452     t_elt = (const apr_table_entry_t *)elts->elts;
453     t_end = t_elt + elts->nelts;
454     len = 1; /* \0 */
455     result_list = rp = NULL;
456
457     do {
458         if (!strcasecmp(t_elt->key, key)) {
459             if (!result_list) {
460                 result_list = rp = apr_palloc(pool, sizeof(*rp));
461             }
462             else {
463                 rp = rp->next = apr_palloc(pool, sizeof(*rp));
464                 len += 2; /* ", " */
465             }
466
467             rp->next = NULL;
468             rp->value = t_elt->val;
469             rp->len = strlen(rp->value);
470
471             len += rp->len;
472         }
473         ++t_elt;
474     } while (t_elt < t_end);
475
476     if (result_list) {
477         char *result = apr_palloc(pool, len);
478         char *cp = result;
479
480         rp = result_list;
481         while (rp) {
482             if (rp != result_list) {
483                 *cp++ = ',';
484                 *cp++ = ' ';
485             }
486             memcpy(cp, rp->value, rp->len);
487             cp += rp->len;
488             rp = rp->next;
489         }
490         *cp = '\0';
491
492         return result;
493     }
494
495     return NULL;
496 }
497
498 static const char *log_header_out(request_rec *r, char *a)
499 {
500     const char *cp = NULL;
501
502     if (!strcasecmp(a, "Content-type") && r->content_type) {
503         cp = ap_field_noparam(r->pool, r->content_type);
504     }
505     else if (!strcasecmp(a, "Set-Cookie")) {
506         cp = find_multiple_headers(r->pool, r->headers_out, a);
507     }
508     else {
509         cp = apr_table_get(r->headers_out, a);
510     }
511
512     return ap_escape_logitem(r->pool, cp);
513 }
514
515 static const char *log_note(request_rec *r, char *a)
516 {
517     return ap_escape_logitem(r->pool, apr_table_get(r->notes, a));
518 }
519 static const char *log_env_var(request_rec *r, char *a)
520 {
521     return ap_escape_logitem(r->pool, apr_table_get(r->subprocess_env, a));
522 }
523
524 static const char *log_cookie(request_rec *r, char *a)
525 {
526     const char *cookies_entry;
527
528     /*
529      * This supports Netscape version 0 cookies while being tolerant to
530      * some properties of RFC2109/2965 version 1 cookies:
531      * - case-insensitive match of cookie names
532      * - white space between the tokens
533      * It does not support the following version 1 features:
534      * - quoted strings as cookie values
535      * - commas to separate cookies
536      */
537
538     if ((cookies_entry = apr_table_get(r->headers_in, "Cookie"))) {
539         char *cookie, *last1, *last2;
540         char *cookies = apr_pstrdup(r->pool, cookies_entry);
541
542         while ((cookie = apr_strtok(cookies, ";", &last1))) {
543             char *name = apr_strtok(cookie, "=", &last2);
544             if (name) {
545                 char *value;
546                 apr_collapse_spaces(name, name);
547
548                 if (!strcasecmp(name, a) && (value = apr_strtok(NULL, "=", &last2))) {
549                     char *last;
550                     value += strspn(value, " \t");  /* Move past leading WS */
551                     last = value + strlen(value) - 1;
552                     while (last >= value && apr_isspace(*last)) {
553                        *last = '\0';
554                        --last;
555                     }
556
557                     return ap_escape_logitem(r->pool, value);
558                 }
559             }
560             cookies = NULL;
561         }
562     }
563     return NULL;
564 }
565
566 static const char *log_request_time_custom(request_rec *r, char *a,
567                                            apr_time_exp_t *xt)
568 {
569     apr_size_t retcode;
570     char tstr[MAX_STRING_LEN];
571     apr_strftime(tstr, &retcode, sizeof(tstr), a, xt);
572     return apr_pstrdup(r->pool, tstr);
573 }
574
575 #define DEFAULT_REQUEST_TIME_SIZE 32
576 typedef struct {
577     unsigned t;
578     char timestr[DEFAULT_REQUEST_TIME_SIZE];
579     unsigned t_validate;
580 } cached_request_time;
581
582 #define TIME_FMT_CUSTOM          0
583 #define TIME_FMT_CLF             1
584 #define TIME_FMT_ABS_SEC         2
585 #define TIME_FMT_ABS_MSEC        3
586 #define TIME_FMT_ABS_USEC        4
587 #define TIME_FMT_ABS_MSEC_FRAC   5
588 #define TIME_FMT_ABS_USEC_FRAC   6
589
590 #define TIME_CACHE_SIZE 4
591 #define TIME_CACHE_MASK 3
592 static cached_request_time request_time_cache[TIME_CACHE_SIZE];
593
594 static apr_time_t get_request_end_time(request_rec *r)
595 {
596     log_request_state *state = (log_request_state *)ap_get_module_config(r->request_config,
597                                                                          &log_config_module);
598     if (state->request_end_time == 0) {
599         state->request_end_time = apr_time_now();
600     }
601     return state->request_end_time;
602 }
603
604
605 static const char *log_request_time(request_rec *r, char *a)
606 {
607     apr_time_exp_t xt;
608     apr_time_t request_time = r->request_time;
609     int fmt_type = TIME_FMT_CUSTOM;
610     char *fmt = a;
611
612     if (fmt && *fmt) {
613         if (!strncmp(fmt, "begin", 5)) {
614             fmt += 5;
615             if (!*fmt) {
616                 fmt_type = TIME_FMT_CLF;
617             }
618             else if (*fmt == ':') {
619                 fmt++;
620                 a = fmt;
621             }
622         }
623         else if (!strncmp(fmt, "end", 3)) {
624             fmt += 3;
625             if (!*fmt) {
626                 request_time = get_request_end_time(r);
627                 fmt_type = TIME_FMT_CLF;
628             }
629             else if (*fmt == ':') {
630                 fmt++;
631                 a = fmt;
632                 request_time = get_request_end_time(r);
633             }
634         }
635         if (!strncmp(fmt, "msec", 4)) {
636             fmt += 4;
637             if (!*fmt) {
638                 fmt_type = TIME_FMT_ABS_MSEC;
639             }
640             else if (!strcmp(fmt, "_frac")) {
641                 fmt_type = TIME_FMT_ABS_MSEC_FRAC;
642             }
643         }
644         else if (!strncmp(fmt, "usec", 4)) {
645             fmt += 4;
646             if (!*fmt) {
647                 fmt_type = TIME_FMT_ABS_USEC;
648             }
649             else if (!strcmp(fmt, "_frac")) {
650                 fmt_type = TIME_FMT_ABS_USEC_FRAC;
651             }
652         }
653         else if (!strcmp(fmt, "sec")) {
654             fmt_type = TIME_FMT_ABS_SEC;
655         }
656         else if (!*fmt) {
657             fmt_type = TIME_FMT_CLF;
658         }
659     }
660     else {
661         fmt_type = TIME_FMT_CLF;
662     }
663
664     if (fmt_type >= TIME_FMT_ABS_SEC) {      /* Absolute (micro-/milli-)second time
665                                               * or msec/usec fraction
666                                               */
667         char* buf = apr_palloc(r->pool, 20);
668         switch (fmt_type) {
669         case TIME_FMT_ABS_SEC:
670             apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, apr_time_sec(request_time));
671             break;
672         case TIME_FMT_ABS_MSEC:
673             apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, apr_time_as_msec(request_time));
674             break;
675         case TIME_FMT_ABS_USEC:
676             apr_snprintf(buf, 20, "%" APR_TIME_T_FMT, request_time);
677             break;
678         case TIME_FMT_ABS_MSEC_FRAC:
679             apr_snprintf(buf, 20, "%03" APR_TIME_T_FMT, apr_time_msec(request_time));
680             break;
681         case TIME_FMT_ABS_USEC_FRAC:
682             apr_snprintf(buf, 20, "%06" APR_TIME_T_FMT, apr_time_usec(request_time));
683             break;
684         default:
685             return "-";
686         }
687         return buf;
688     }
689     else if (fmt_type == TIME_FMT_CUSTOM) {  /* Custom format */
690         /* The custom time formatting uses a very large temp buffer
691          * on the stack.  To avoid using so much stack space in the
692          * common case where we're not using a custom format, the code
693          * for the custom format in a separate function.  (That's why
694          * log_request_time_custom is not inlined right here.)
695          */
696         ap_explode_recent_localtime(&xt, request_time);
697         return log_request_time_custom(r, a, &xt);
698     }
699     else {                                   /* CLF format */
700         /* This code uses the same technique as ap_explode_recent_localtime():
701          * optimistic caching with logic to detect and correct race conditions.
702          * See the comments in server/util_time.c for more information.
703          */
704         cached_request_time* cached_time = apr_palloc(r->pool,
705                                                       sizeof(*cached_time));
706         unsigned t_seconds = (unsigned)apr_time_sec(request_time);
707         unsigned i = t_seconds & TIME_CACHE_MASK;
708         *cached_time = request_time_cache[i];
709         if ((t_seconds != cached_time->t) ||
710             (t_seconds != cached_time->t_validate)) {
711
712             /* Invalid or old snapshot, so compute the proper time string
713              * and store it in the cache
714              */
715             char sign;
716             int timz;
717
718             ap_explode_recent_localtime(&xt, request_time);
719             timz = xt.tm_gmtoff;
720             if (timz < 0) {
721                 timz = -timz;
722                 sign = '-';
723             }
724             else {
725                 sign = '+';
726             }
727             cached_time->t = t_seconds;
728             apr_snprintf(cached_time->timestr, DEFAULT_REQUEST_TIME_SIZE,
729                          "[%02d/%s/%d:%02d:%02d:%02d %c%.2d%.2d]",
730                          xt.tm_mday, apr_month_snames[xt.tm_mon],
731                          xt.tm_year+1900, xt.tm_hour, xt.tm_min, xt.tm_sec,
732                          sign, timz / (60*60), (timz % (60*60)) / 60);
733             cached_time->t_validate = t_seconds;
734             request_time_cache[i] = *cached_time;
735         }
736         return cached_time->timestr;
737     }
738 }
739
740 static const char *log_request_duration(request_rec *r, char *a)
741 {
742     apr_time_t duration = get_request_end_time(r) - r->request_time;
743     return apr_psprintf(r->pool, "%" APR_TIME_T_FMT, apr_time_sec(duration));
744 }
745
746 static const char *log_request_duration_microseconds(request_rec *r, char *a)
747 {
748     return apr_psprintf(r->pool, "%" APR_TIME_T_FMT,
749                         (get_request_end_time(r) - r->request_time));
750 }
751
752 /* These next two routines use the canonical name:port so that log
753  * parsers don't need to duplicate all the vhost parsing crud.
754  */
755 static const char *log_virtual_host(request_rec *r, char *a)
756 {
757     return ap_escape_logitem(r->pool, r->server->server_hostname);
758 }
759
760 static const char *log_server_port(request_rec *r, char *a)
761 {
762     apr_port_t port;
763
764     if (*a == '\0' || !strcasecmp(a, "canonical")) {
765         port = r->server->port ? r->server->port : ap_default_port(r);
766     }
767     else if (!strcasecmp(a, "remote")) {
768         port = r->useragent_addr->port;
769     }
770     else if (!strcasecmp(a, "local")) {
771         port = r->connection->local_addr->port;
772     }
773     else {
774         /* bogus format */
775         return a;
776     }
777     return apr_itoa(r->pool, (int)port);
778 }
779
780 /* This respects the setting of UseCanonicalName so that
781  * the dynamic mass virtual hosting trick works better.
782  */
783 static const char *log_server_name(request_rec *r, char *a)
784 {
785     return ap_escape_logitem(r->pool, ap_get_server_name(r));
786 }
787
788 static const char *log_pid_tid(request_rec *r, char *a)
789 {
790     if (*a == '\0' || !strcasecmp(a, "pid")) {
791         return ap_append_pid(r->pool, "", "");
792     }
793     else if (!strcasecmp(a, "tid") || !strcasecmp(a, "hextid")) {
794 #if APR_HAS_THREADS
795         apr_os_thread_t tid = apr_os_thread_current();
796 #else
797         int tid = 0; /* APR will format "0" anyway but an arg is needed */
798 #endif
799         return apr_psprintf(r->pool,
800 #if APR_MAJOR_VERSION > 1 || (APR_MAJOR_VERSION == 1 && APR_MINOR_VERSION >= 2)
801                             /* APR can format a thread id in hex */
802                             *a == 'h' ? "%pt" : "%pT",
803 #else
804                             /* APR is missing the feature, so always use decimal */
805                             "%pT",
806 #endif
807                             &tid);
808     }
809     /* bogus format */
810     return a;
811 }
812
813 static const char *log_connection_status(request_rec *r, char *a)
814 {
815     if (r->connection->aborted)
816         return "X";
817
818     if (r->connection->keepalive == AP_CONN_KEEPALIVE &&
819         (!r->server->keep_alive_max ||
820          (r->server->keep_alive_max - r->connection->keepalives) > 0)) {
821         return "+";
822     }
823     return "-";
824 }
825
826 static const char *log_requests_on_connection(request_rec *r, char *a)
827 {
828     int num = r->connection->keepalives ? r->connection->keepalives - 1 : 0;
829     return apr_itoa(r->pool, num);
830 }
831
832 /*****************************************************************
833  *
834  * Parsing the log format string
835  */
836
837 static char *parse_log_misc_string(apr_pool_t *p, log_format_item *it,
838                                    const char **sa)
839 {
840     const char *s;
841     char *d;
842
843     it->func = constant_item;
844     it->conditions = NULL;
845
846     s = *sa;
847     while (*s && *s != '%') {
848         s++;
849     }
850     /*
851      * This might allocate a few chars extra if there's a backslash
852      * escape in the format string.
853      */
854     it->arg = apr_palloc(p, s - *sa + 1);
855
856     d = it->arg;
857     s = *sa;
858     while (*s && *s != '%') {
859         if (*s != '\\') {
860             *d++ = *s++;
861         }
862         else {
863             s++;
864             switch (*s) {
865             case '\\':
866                 *d++ = '\\';
867                 s++;
868                 break;
869             case 'r':
870                 *d++ = '\r';
871                 s++;
872                 break;
873             case 'n':
874                 *d++ = '\n';
875                 s++;
876                 break;
877             case 't':
878                 *d++ = '\t';
879                 s++;
880                 break;
881             default:
882                 /* copy verbatim */
883                 *d++ = '\\';
884                 /*
885                  * Allow the loop to deal with this *s in the normal
886                  * fashion so that it handles end of string etc.
887                  * properly.
888                  */
889                 break;
890             }
891         }
892     }
893     *d = '\0';
894
895     *sa = s;
896     return NULL;
897 }
898
899 static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa)
900 {
901     const char *s = *sa;
902     ap_log_handler *handler;
903
904     if (*s != '%') {
905         return parse_log_misc_string(p, it, sa);
906     }
907
908     ++s;
909     it->condition_sense = 0;
910     it->conditions = NULL;
911
912     if (*s == '%') {
913         it->arg = "%";
914         it->func = constant_item;
915         *sa = ++s;
916
917         return NULL;
918     }
919
920     it->want_orig = -1;
921     it->arg = "";               /* For safety's sake... */
922
923     while (*s) {
924         int i;
925
926         switch (*s) {
927         case '!':
928             ++s;
929             it->condition_sense = !it->condition_sense;
930             break;
931
932         case '<':
933             ++s;
934             it->want_orig = 1;
935             break;
936
937         case '>':
938             ++s;
939             it->want_orig = 0;
940             break;
941
942         case ',':
943             ++s;
944             break;
945
946         case '{':
947             ++s;
948             it->arg = ap_getword(p, &s, '}');
949             break;
950
951         case '0':
952         case '1':
953         case '2':
954         case '3':
955         case '4':
956         case '5':
957         case '6':
958         case '7':
959         case '8':
960         case '9':
961             i = *s - '0';
962             while (apr_isdigit(*++s)) {
963                 i = i * 10 + (*s) - '0';
964             }
965             if (!it->conditions) {
966                 it->conditions = apr_array_make(p, 4, sizeof(int));
967             }
968             *(int *) apr_array_push(it->conditions) = i;
969             break;
970
971         default:
972             handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1);
973             if (!handler) {
974                 char dummy[2];
975
976                 dummy[0] = s[-1];
977                 dummy[1] = '\0';
978                 return apr_pstrcat(p, "Unrecognized LogFormat directive %",
979                                dummy, NULL);
980             }
981             it->func = handler->func;
982             if (it->want_orig == -1) {
983                 it->want_orig = handler->want_orig_default;
984             }
985             *sa = s;
986             return NULL;
987         }
988     }
989
990     return "Ran off end of LogFormat parsing args to some directive";
991 }
992
993 static apr_array_header_t *parse_log_string(apr_pool_t *p, const char *s, const char **err)
994 {
995     apr_array_header_t *a = apr_array_make(p, 30, sizeof(log_format_item));
996     char *res;
997
998     while (*s) {
999         if ((res = parse_log_item(p, (log_format_item *) apr_array_push(a), &s))) {
1000             *err = res;
1001             return NULL;
1002         }
1003     }
1004
1005     s = APR_EOL_STR;
1006     parse_log_item(p, (log_format_item *) apr_array_push(a), &s);
1007     return a;
1008 }
1009
1010 /*****************************************************************
1011  *
1012  * Actually logging.
1013  */
1014
1015 static const char *process_item(request_rec *r, request_rec *orig,
1016                           log_format_item *item)
1017 {
1018     const char *cp;
1019
1020     /* First, see if we need to process this thing at all... */
1021
1022     if (item->conditions && item->conditions->nelts != 0) {
1023         int i;
1024         int *conds = (int *) item->conditions->elts;
1025         int in_list = 0;
1026
1027         for (i = 0; i < item->conditions->nelts; ++i) {
1028             if (r->status == conds[i]) {
1029                 in_list = 1;
1030                 break;
1031             }
1032         }
1033
1034         if ((item->condition_sense && in_list)
1035             || (!item->condition_sense && !in_list)) {
1036             return "-";
1037         }
1038     }
1039
1040     /* We do.  Do it... */
1041
1042     cp = (*item->func) (item->want_orig ? orig : r, item->arg);
1043     return cp ? cp : "-";
1044 }
1045
1046 static void flush_log(buffered_log *buf)
1047 {
1048     if (buf->outcnt && buf->handle != NULL) {
1049         apr_file_write(buf->handle, buf->outbuf, &buf->outcnt);
1050         buf->outcnt = 0;
1051     }
1052 }
1053
1054
1055 static int config_log_transaction(request_rec *r, config_log_state *cls,
1056                                   apr_array_header_t *default_format)
1057 {
1058     log_format_item *items;
1059     const char **strs;
1060     int *strl;
1061     request_rec *orig;
1062     int i;
1063     apr_size_t len = 0;
1064     apr_array_header_t *format;
1065     char *envar;
1066     apr_status_t rv;
1067
1068     if (cls->fname == NULL) {
1069         return DECLINED;
1070     }
1071
1072     /*
1073      * See if we've got any conditional envariable-controlled logging decisions
1074      * to make.
1075      */
1076     if (cls->condition_var != NULL) {
1077         envar = cls->condition_var;
1078         if (*envar != '!') {
1079             if (apr_table_get(r->subprocess_env, envar) == NULL) {
1080                 return DECLINED;
1081             }
1082         }
1083         else {
1084             if (apr_table_get(r->subprocess_env, &envar[1]) != NULL) {
1085                 return DECLINED;
1086             }
1087         }
1088     }
1089     else if (cls->condition_expr != NULL) {
1090         const char *err;
1091         int rc = ap_expr_exec(r, cls->condition_expr, &err);
1092         if (rc < 0)
1093             ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(00644)
1094                            "Error evaluating log condition: %s", err);
1095         if (rc <= 0)
1096             return DECLINED;
1097     }
1098
1099     format = cls->format ? cls->format : default_format;
1100
1101     strs = apr_palloc(r->pool, sizeof(char *) * (format->nelts));
1102     strl = apr_palloc(r->pool, sizeof(int) * (format->nelts));
1103     items = (log_format_item *) format->elts;
1104
1105     orig = r;
1106     while (orig->prev) {
1107         orig = orig->prev;
1108     }
1109     while (r->next) {
1110         r = r->next;
1111     }
1112
1113     for (i = 0; i < format->nelts; ++i) {
1114         strs[i] = process_item(r, orig, &items[i]);
1115     }
1116
1117     for (i = 0; i < format->nelts; ++i) {
1118         len += strl[i] = strlen(strs[i]);
1119     }
1120     if (!log_writer) {
1121         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00645)
1122                 "log writer isn't correctly setup");
1123          return HTTP_INTERNAL_SERVER_ERROR;
1124     }
1125     rv = log_writer(r, cls->log_writer, strs, strl, format->nelts, len);
1126     if (rv != APR_SUCCESS)
1127         ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, APLOGNO(00646) "Error writing to %s",
1128                       cls->fname);
1129     return OK;
1130 }
1131
1132 static int multi_log_transaction(request_rec *r)
1133 {
1134     multi_log_state *mls = ap_get_module_config(r->server->module_config,
1135                                                 &log_config_module);
1136     config_log_state *clsarray;
1137     int i;
1138
1139     /*
1140      * Initialize per request state
1141      */
1142     log_request_state *state = apr_pcalloc(r->pool, sizeof(log_request_state));
1143     ap_set_module_config(r->request_config, &log_config_module, state);
1144
1145     /*
1146      * Log this transaction..
1147      */
1148     if (mls->config_logs->nelts) {
1149         clsarray = (config_log_state *) mls->config_logs->elts;
1150         for (i = 0; i < mls->config_logs->nelts; ++i) {
1151             config_log_state *cls = &clsarray[i];
1152
1153             config_log_transaction(r, cls, mls->default_format);
1154         }
1155     }
1156     else if (mls->server_config_logs) {
1157         clsarray = (config_log_state *) mls->server_config_logs->elts;
1158         for (i = 0; i < mls->server_config_logs->nelts; ++i) {
1159             config_log_state *cls = &clsarray[i];
1160
1161             config_log_transaction(r, cls, mls->default_format);
1162         }
1163     }
1164
1165     return OK;
1166 }
1167
1168 /*****************************************************************
1169  *
1170  * Module glue...
1171  */
1172
1173 static void *make_config_log_state(apr_pool_t *p, server_rec *s)
1174 {
1175     multi_log_state *mls;
1176
1177     mls = (multi_log_state *) apr_palloc(p, sizeof(multi_log_state));
1178     mls->config_logs = apr_array_make(p, 1, sizeof(config_log_state));
1179     mls->default_format_string = NULL;
1180     mls->default_format = NULL;
1181     mls->server_config_logs = NULL;
1182     mls->formats = apr_table_make(p, 4);
1183     apr_table_setn(mls->formats, "CLF", DEFAULT_LOG_FORMAT);
1184
1185     return mls;
1186 }
1187
1188 /*
1189  * Use the merger to simply add a pointer from the vhost log state
1190  * to the log of logs specified for the non-vhost configuration.  Make sure
1191  * vhosts inherit any globally-defined format names.
1192  */
1193
1194 static void *merge_config_log_state(apr_pool_t *p, void *basev, void *addv)
1195 {
1196     multi_log_state *base = (multi_log_state *) basev;
1197     multi_log_state *add = (multi_log_state *) addv;
1198
1199     add->server_config_logs = base->config_logs;
1200     if (!add->default_format) {
1201         add->default_format_string = base->default_format_string;
1202         add->default_format = base->default_format;
1203     }
1204     add->formats = apr_table_overlay(p, base->formats, add->formats);
1205
1206     return add;
1207 }
1208
1209 /*
1210  * Set the default logfile format, or define a nickname for a format string.
1211  */
1212 static const char *log_format(cmd_parms *cmd, void *dummy, const char *fmt,
1213                               const char *name)
1214 {
1215     const char *err_string = NULL;
1216     multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
1217                                                 &log_config_module);
1218
1219     /*
1220      * If we were given two arguments, the second is a name to be given to the
1221      * format.  This syntax just defines the nickname - it doesn't actually
1222      * make the format the default.
1223      */
1224     if (name != NULL) {
1225         parse_log_string(cmd->pool, fmt, &err_string);
1226         if (err_string == NULL) {
1227             apr_table_setn(mls->formats, name, fmt);
1228         }
1229     }
1230     else {
1231         mls->default_format_string = fmt;
1232         mls->default_format = parse_log_string(cmd->pool, fmt, &err_string);
1233     }
1234     return err_string;
1235 }
1236
1237
1238 static const char *add_custom_log(cmd_parms *cmd, void *dummy, const char *fn,
1239                                   const char *fmt, const char *envclause)
1240 {
1241     const char *err_string = NULL;
1242     multi_log_state *mls = ap_get_module_config(cmd->server->module_config,
1243                                                 &log_config_module);
1244     config_log_state *cls;
1245
1246     cls = (config_log_state *) apr_array_push(mls->config_logs);
1247     cls->condition_var = NULL;
1248     cls->condition_expr = NULL;
1249     if (envclause != NULL) {
1250         if (strncasecmp(envclause, "env=", 4) == 0) {
1251             if ((envclause[4] == '\0')
1252                 || ((envclause[4] == '!') && (envclause[5] == '\0'))) {
1253                 return "missing environment variable name";
1254             }
1255             cls->condition_var = apr_pstrdup(cmd->pool, &envclause[4]);
1256         }
1257         else if (strncasecmp(envclause, "expr=", 5) == 0) {
1258             const char *err;
1259             if ((envclause[5] == '\0'))
1260                 return "missing condition";
1261             cls->condition_expr = ap_expr_parse_cmd(cmd, &envclause[5],
1262                                                     AP_EXPR_FLAG_DONT_VARY,
1263                                                     &err, NULL);
1264             if (err)
1265                 return err;
1266         }
1267         else {
1268             return "error in condition clause";
1269         }
1270     }
1271
1272     cls->fname = fn;
1273     cls->format_string = fmt;
1274     if (fmt == NULL) {
1275         cls->format = NULL;
1276     }
1277     else {
1278         cls->format = parse_log_string(cmd->pool, fmt, &err_string);
1279     }
1280     cls->log_writer = NULL;
1281
1282     return err_string;
1283 }
1284
1285 static const char *set_transfer_log(cmd_parms *cmd, void *dummy,
1286                                     const char *fn)
1287 {
1288     return add_custom_log(cmd, dummy, fn, NULL, NULL);
1289 }
1290
1291 static const char *set_buffered_logs_on(cmd_parms *parms, void *dummy, int flag)
1292 {
1293     buffered_logs = flag;
1294     if (buffered_logs) {
1295         ap_log_set_writer_init(ap_buffered_log_writer_init);
1296         ap_log_set_writer(ap_buffered_log_writer);
1297     }
1298     else {
1299         ap_log_set_writer_init(ap_default_log_writer_init);
1300         ap_log_set_writer(ap_default_log_writer);
1301     }
1302     return NULL;
1303 }
1304 static const command_rec config_log_cmds[] =
1305 {
1306 AP_INIT_TAKE23("CustomLog", add_custom_log, NULL, RSRC_CONF,
1307      "a file name, a custom log format string or format name, "
1308      "and an optional \"env=\" or \"expr=\" clause (see docs)"),
1309 AP_INIT_TAKE1("TransferLog", set_transfer_log, NULL, RSRC_CONF,
1310      "the filename of the access log"),
1311 AP_INIT_TAKE12("LogFormat", log_format, NULL, RSRC_CONF,
1312      "a log format string (see docs) and an optional format name"),
1313 AP_INIT_FLAG("BufferedLogs", set_buffered_logs_on, NULL, RSRC_CONF,
1314                  "Enable Buffered Logging (experimental)"),
1315     {NULL}
1316 };
1317
1318 static config_log_state *open_config_log(server_rec *s, apr_pool_t *p,
1319                                          config_log_state *cls,
1320                                          apr_array_header_t *default_format)
1321 {
1322     if (cls->log_writer != NULL) {
1323         return cls;             /* virtual config shared w/main server */
1324     }
1325
1326     if (cls->fname == NULL) {
1327         return cls;             /* Leave it NULL to decline.  */
1328     }
1329
1330     cls->log_writer = log_writer_init(p, s, cls->fname);
1331     if (cls->log_writer == NULL)
1332         return NULL;
1333
1334     return cls;
1335 }
1336
1337 static int open_multi_logs(server_rec *s, apr_pool_t *p)
1338 {
1339     int i;
1340     multi_log_state *mls = ap_get_module_config(s->module_config,
1341                                              &log_config_module);
1342     config_log_state *clsarray;
1343     const char *dummy;
1344     const char *format;
1345
1346     if (mls->default_format_string) {
1347         format = apr_table_get(mls->formats, mls->default_format_string);
1348         if (format) {
1349             mls->default_format = parse_log_string(p, format, &dummy);
1350         }
1351     }
1352
1353     if (!mls->default_format) {
1354         mls->default_format = parse_log_string(p, DEFAULT_LOG_FORMAT, &dummy);
1355     }
1356
1357     if (mls->config_logs->nelts) {
1358         clsarray = (config_log_state *) mls->config_logs->elts;
1359         for (i = 0; i < mls->config_logs->nelts; ++i) {
1360             config_log_state *cls = &clsarray[i];
1361
1362             if (cls->format_string) {
1363                 format = apr_table_get(mls->formats, cls->format_string);
1364                 if (format) {
1365                     cls->format = parse_log_string(p, format, &dummy);
1366                 }
1367             }
1368
1369             if (!open_config_log(s, p, cls, mls->default_format)) {
1370                 /* Failure already logged by open_config_log */
1371                 return DONE;
1372             }
1373         }
1374     }
1375     else if (mls->server_config_logs) {
1376         clsarray = (config_log_state *) mls->server_config_logs->elts;
1377         for (i = 0; i < mls->server_config_logs->nelts; ++i) {
1378             config_log_state *cls = &clsarray[i];
1379
1380             if (cls->format_string) {
1381                 format = apr_table_get(mls->formats, cls->format_string);
1382                 if (format) {
1383                     cls->format = parse_log_string(p, format, &dummy);
1384                 }
1385             }
1386
1387             if (!open_config_log(s, p, cls, mls->default_format)) {
1388                 /* Failure already logged by open_config_log */
1389                 return DONE;
1390             }
1391         }
1392     }
1393
1394     return OK;
1395 }
1396
1397
1398 static apr_status_t flush_all_logs(void *data)
1399 {
1400     server_rec *s = data;
1401     multi_log_state *mls;
1402     apr_array_header_t *log_list;
1403     config_log_state *clsarray;
1404     buffered_log *buf;
1405     int i;
1406
1407     if (!buffered_logs)
1408         return APR_SUCCESS;
1409
1410     for (; s; s = s->next) {
1411         mls = ap_get_module_config(s->module_config, &log_config_module);
1412         log_list = NULL;
1413         if (mls->config_logs->nelts) {
1414             log_list = mls->config_logs;
1415         }
1416         else if (mls->server_config_logs) {
1417             log_list = mls->server_config_logs;
1418         }
1419         if (log_list) {
1420             clsarray = (config_log_state *) log_list->elts;
1421             for (i = 0; i < log_list->nelts; ++i) {
1422                 buf = clsarray[i].log_writer;
1423                 flush_log(buf);
1424             }
1425         }
1426     }
1427     return APR_SUCCESS;
1428 }
1429
1430
1431 static int init_config_log(apr_pool_t *pc, apr_pool_t *p, apr_pool_t *pt, server_rec *s)
1432 {
1433     int res;
1434
1435     /* First init the buffered logs array, which is needed when opening the logs. */
1436     if (buffered_logs) {
1437         all_buffered_logs = apr_array_make(p, 5, sizeof(buffered_log *));
1438     }
1439
1440     /* Next, do "physical" server, which gets default log fd and format
1441      * for the virtual servers, if they don't override...
1442      */
1443     res = open_multi_logs(s, p);
1444
1445     /* Then, virtual servers */
1446
1447     for (s = s->next; (res == OK) && s; s = s->next) {
1448         res = open_multi_logs(s, p);
1449     }
1450
1451     return res;
1452 }
1453
1454 static void init_child(apr_pool_t *p, server_rec *s)
1455 {
1456     int mpm_threads;
1457
1458     ap_mpm_query(AP_MPMQ_MAX_THREADS, &mpm_threads);
1459
1460     /* Now register the last buffer flush with the cleanup engine */
1461     if (buffered_logs) {
1462         int i;
1463         buffered_log **array = (buffered_log **)all_buffered_logs->elts;
1464
1465         apr_pool_cleanup_register(p, s, flush_all_logs, flush_all_logs);
1466
1467         for (i = 0; i < all_buffered_logs->nelts; i++) {
1468             buffered_log *this = array[i];
1469
1470 #if APR_HAS_THREADS
1471             if (mpm_threads > 1) {
1472                 apr_status_t rv;
1473
1474                 this->mutex.type = apr_anylock_threadmutex;
1475                 rv = apr_thread_mutex_create(&this->mutex.lock.tm,
1476                                              APR_THREAD_MUTEX_DEFAULT,
1477                                              p);
1478                 if (rv != APR_SUCCESS) {
1479                     ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, APLOGNO(00647)
1480                                  "could not initialize buffered log mutex, "
1481                                  "transfer log may become corrupted");
1482                     this->mutex.type = apr_anylock_none;
1483                 }
1484             }
1485             else
1486 #endif
1487             {
1488                 this->mutex.type = apr_anylock_none;
1489             }
1490         }
1491     }
1492 }
1493
1494 static void ap_register_log_handler(apr_pool_t *p, char *tag,
1495                                     ap_log_handler_fn_t *handler, int def)
1496 {
1497     ap_log_handler *log_struct = apr_palloc(p, sizeof(*log_struct));
1498     log_struct->func = handler;
1499     log_struct->want_orig_default = def;
1500
1501     apr_hash_set(log_hash, tag, 1, (const void *)log_struct);
1502 }
1503 static ap_log_writer_init* ap_log_set_writer_init(ap_log_writer_init *handle)
1504 {
1505     ap_log_writer_init *old = log_writer_init;
1506     log_writer_init = handle;
1507
1508     return old;
1509
1510 }
1511 static ap_log_writer *ap_log_set_writer(ap_log_writer *handle)
1512 {
1513     ap_log_writer *old = log_writer;
1514     log_writer = handle;
1515
1516     return old;
1517 }
1518
1519 static apr_status_t ap_default_log_writer( request_rec *r,
1520                            void *handle,
1521                            const char **strs,
1522                            int *strl,
1523                            int nelts,
1524                            apr_size_t len)
1525
1526 {
1527     char *str;
1528     char *s;
1529     int i;
1530     apr_status_t rv;
1531
1532     str = apr_palloc(r->pool, len + 1);
1533
1534     for (i = 0, s = str; i < nelts; ++i) {
1535         memcpy(s, strs[i], strl[i]);
1536         s += strl[i];
1537     }
1538
1539     rv = apr_file_write((apr_file_t*)handle, str, &len);
1540
1541     return rv;
1542 }
1543 static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s,
1544                                         const char* name)
1545 {
1546     if (*name == '|') {
1547         piped_log *pl;
1548
1549         pl = ap_open_piped_log(p, name + 1);
1550         if (pl == NULL) {
1551            return NULL;;
1552         }
1553         return ap_piped_log_write_fd(pl);
1554     }
1555     else {
1556         const char *fname = ap_server_root_relative(p, name);
1557         apr_file_t *fd;
1558         apr_status_t rv;
1559
1560         if (!fname) {
1561             ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, APLOGNO(00648)
1562                             "invalid transfer log path %s.", name);
1563             return NULL;
1564         }
1565         rv = apr_file_open(&fd, fname, xfer_flags, xfer_perms, p);
1566         if (rv != APR_SUCCESS) {
1567             ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00649)
1568                             "could not open transfer log file %s.", fname);
1569             return NULL;
1570         }
1571         return fd;
1572     }
1573 }
1574 static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s,
1575                                         const char* name)
1576 {
1577     buffered_log *b;
1578     b = apr_pcalloc(p, sizeof(buffered_log));
1579     b->handle = ap_default_log_writer_init(p, s, name);
1580
1581     if (b->handle) {
1582         *(buffered_log **)apr_array_push(all_buffered_logs) = b;
1583         return b;
1584     }
1585     else
1586         return NULL;
1587 }
1588 static apr_status_t ap_buffered_log_writer(request_rec *r,
1589                                            void *handle,
1590                                            const char **strs,
1591                                            int *strl,
1592                                            int nelts,
1593                                            apr_size_t len)
1594
1595 {
1596     char *str;
1597     char *s;
1598     int i;
1599     apr_status_t rv;
1600     buffered_log *buf = (buffered_log*)handle;
1601
1602     if ((rv = APR_ANYLOCK_LOCK(&buf->mutex)) != APR_SUCCESS) {
1603         return rv;
1604     }
1605
1606     if (len + buf->outcnt > LOG_BUFSIZE) {
1607         flush_log(buf);
1608     }
1609     if (len >= LOG_BUFSIZE) {
1610         apr_size_t w;
1611
1612         str = apr_palloc(r->pool, len + 1);
1613         for (i = 0, s = str; i < nelts; ++i) {
1614             memcpy(s, strs[i], strl[i]);
1615             s += strl[i];
1616         }
1617         w = len;
1618         rv = apr_file_write(buf->handle, str, &w);
1619
1620     }
1621     else {
1622         for (i = 0, s = &buf->outbuf[buf->outcnt]; i < nelts; ++i) {
1623             memcpy(s, strs[i], strl[i]);
1624             s += strl[i];
1625         }
1626         buf->outcnt += len;
1627         rv = APR_SUCCESS;
1628     }
1629
1630     APR_ANYLOCK_UNLOCK(&buf->mutex);
1631     return rv;
1632 }
1633
1634 static int log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
1635 {
1636     static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
1637
1638     log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
1639
1640     if (log_pfn_register) {
1641         log_pfn_register(p, "h", log_remote_host, 0);
1642         log_pfn_register(p, "a", log_remote_address, 0 );
1643         log_pfn_register(p, "A", log_local_address, 0 );
1644         log_pfn_register(p, "l", log_remote_logname, 0);
1645         log_pfn_register(p, "u", log_remote_user, 0);
1646         log_pfn_register(p, "t", log_request_time, 0);
1647         log_pfn_register(p, "f", log_request_file, 0);
1648         log_pfn_register(p, "b", clf_log_bytes_sent, 0);
1649         log_pfn_register(p, "B", log_bytes_sent, 0);
1650         log_pfn_register(p, "i", log_header_in, 0);
1651         log_pfn_register(p, "o", log_header_out, 0);
1652         log_pfn_register(p, "n", log_note, 0);
1653         log_pfn_register(p, "L", log_log_id, 1);
1654         log_pfn_register(p, "e", log_env_var, 0);
1655         log_pfn_register(p, "V", log_server_name, 0);
1656         log_pfn_register(p, "v", log_virtual_host, 0);
1657         log_pfn_register(p, "p", log_server_port, 0);
1658         log_pfn_register(p, "P", log_pid_tid, 0);
1659         log_pfn_register(p, "H", log_request_protocol, 0);
1660         log_pfn_register(p, "m", log_request_method, 0);
1661         log_pfn_register(p, "q", log_request_query, 0);
1662         log_pfn_register(p, "X", log_connection_status, 0);
1663         log_pfn_register(p, "C", log_cookie, 0);
1664         log_pfn_register(p, "k", log_requests_on_connection, 0);
1665         log_pfn_register(p, "r", log_request_line, 1);
1666         log_pfn_register(p, "D", log_request_duration_microseconds, 1);
1667         log_pfn_register(p, "T", log_request_duration, 1);
1668         log_pfn_register(p, "U", log_request_uri, 1);
1669         log_pfn_register(p, "s", log_status, 1);
1670         log_pfn_register(p, "R", log_handler, 1);
1671     }
1672
1673     /* reset to default conditions */
1674     ap_log_set_writer_init(ap_default_log_writer_init);
1675     ap_log_set_writer(ap_default_log_writer);
1676     buffered_logs = 0;
1677
1678     return OK;
1679 }
1680
1681 static void register_hooks(apr_pool_t *p)
1682 {
1683     ap_hook_pre_config(log_pre_config,NULL,NULL,APR_HOOK_REALLY_FIRST);
1684     ap_hook_child_init(init_child,NULL,NULL,APR_HOOK_MIDDLE);
1685     ap_hook_open_logs(init_config_log,NULL,NULL,APR_HOOK_MIDDLE);
1686     ap_hook_log_transaction(multi_log_transaction,NULL,NULL,APR_HOOK_MIDDLE);
1687
1688     /* Init log_hash before we register the optional function. It is
1689      * possible for the optional function, ap_register_log_handler,
1690      * to be called before any other mod_log_config hooks are called.
1691      * As a policy, we should init everything required by an optional function
1692      * before calling APR_REGISTER_OPTIONAL_FN.
1693      */
1694     log_hash = apr_hash_make(p);
1695     APR_REGISTER_OPTIONAL_FN(ap_register_log_handler);
1696     APR_REGISTER_OPTIONAL_FN(ap_log_set_writer_init);
1697     APR_REGISTER_OPTIONAL_FN(ap_log_set_writer);
1698 }
1699
1700 AP_DECLARE_MODULE(log_config) =
1701 {
1702     STANDARD20_MODULE_STUFF,
1703     NULL,                       /* create per-dir config */
1704     NULL,                       /* merge per-dir config */
1705     make_config_log_state,      /* server config */
1706     merge_config_log_state,     /* merge server config */
1707     config_log_cmds,            /* command apr_table_t */
1708     register_hooks              /* register hooks */
1709 };
1710