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