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