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