Diff for /embedaddon/lighttpd/src/mod_accesslog.c between versions 1.1.1.1 and 1.1.1.3

version 1.1.1.1, 2013/10/14 10:32:48 version 1.1.1.3, 2016/11/02 10:35:00
Line 1 Line 1
   #include "first.h"
   
 #include "base.h"  #include "base.h"
 #include "log.h"  #include "log.h"
 #include "buffer.h"  #include "buffer.h"
   
 #include "plugin.h"  #include "plugin.h"
   
 #include "inet_ntop_cache.h"  
   
 #include "sys-socket.h"  
   
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/stat.h>  #include <sys/stat.h>
   
Line 43  typedef struct { Line 41  typedef struct {
                         FORMAT_REMOTE_ADDR,                          FORMAT_REMOTE_ADDR,
                         FORMAT_LOCAL_ADDR,                          FORMAT_LOCAL_ADDR,
                         FORMAT_COOKIE,                          FORMAT_COOKIE,
                        FORMAT_TIME_USED_MS,                        FORMAT_TIME_USED_US,
                         FORMAT_ENV,                          FORMAT_ENV,
                         FORMAT_FILENAME,                          FORMAT_FILENAME,
                         FORMAT_REQUEST_PROTOCOL,                          FORMAT_REQUEST_PROTOCOL,
Line 58  typedef struct { Line 56  typedef struct {
                         FORMAT_BYTES_IN,                          FORMAT_BYTES_IN,
                         FORMAT_BYTES_OUT,                          FORMAT_BYTES_OUT,
   
                           FORMAT_KEEPALIVE_COUNT,
                         FORMAT_RESPONSE_HEADER                          FORMAT_RESPONSE_HEADER
         } type;          } type;
 } format_mapping;  } format_mapping;
Line 85  static const format_mapping fmap[] = Line 84  static const format_mapping fmap[] =
         { 'A', FORMAT_LOCAL_ADDR },          { 'A', FORMAT_LOCAL_ADDR },
         { 'B', FORMAT_BYTES_OUT_NO_HEADER },          { 'B', FORMAT_BYTES_OUT_NO_HEADER },
         { 'C', FORMAT_COOKIE },          { 'C', FORMAT_COOKIE },
        { 'D', FORMAT_TIME_USED_MS },        { 'D', FORMAT_TIME_USED_US },
         { 'e', FORMAT_ENV },          { 'e', FORMAT_ENV },
         { 'f', FORMAT_FILENAME },          { 'f', FORMAT_FILENAME },
         { 'H', FORMAT_REQUEST_PROTOCOL },          { 'H', FORMAT_REQUEST_PROTOCOL },
           { 'k', FORMAT_KEEPALIVE_COUNT },
         { 'm', FORMAT_REQUEST_METHOD },          { 'm', FORMAT_REQUEST_METHOD },
         { 'n', FORMAT_UNSUPPORTED }, /* we have no notes */          { 'n', FORMAT_UNSUPPORTED }, /* we have no notes */
         { 'p', FORMAT_SERVER_PORT },          { 'p', FORMAT_SERVER_PORT },
Line 108  static const format_mapping fmap[] = Line 108  static const format_mapping fmap[] =
 };  };
   
   
   enum e_optflags_time {
           /* format string is passed to strftime unless other format optflags set
            * (besides FORMAT_FLAG_TIME_BEGIN or FORMAT_FLAG_TIME_END) */
           FORMAT_FLAG_TIME_END       = 0x00,/* use request end time (default) */
           FORMAT_FLAG_TIME_BEGIN     = 0x01,/* use request start time */
           FORMAT_FLAG_TIME_SEC       = 0x02,/* request time as num  sec since epoch */
           FORMAT_FLAG_TIME_MSEC      = 0x04,/* request time as num msec since epoch */
           FORMAT_FLAG_TIME_USEC      = 0x08,/* request time as num usec since epoch */
           FORMAT_FLAG_TIME_NSEC      = 0x10,/* request time as num nsec since epoch */
           FORMAT_FLAG_TIME_MSEC_FRAC = 0x20,/* request time msec fraction */
           FORMAT_FLAG_TIME_USEC_FRAC = 0x40,/* request time usec fraction */
           FORMAT_FLAG_TIME_NSEC_FRAC = 0x80 /* request time nsec fraction */
   };
   
   
 typedef struct {  typedef struct {
         enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;          enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
   
         buffer *string;          buffer *string;
         int field;          int field;
           int opt;
 } format_field;  } format_field;
   
 typedef struct {  typedef struct {
Line 136  typedef struct { Line 152  typedef struct {
         time_t *last_generated_accesslog_ts_ptr;          time_t *last_generated_accesslog_ts_ptr;
   
         buffer *ts_accesslog_str;          buffer *ts_accesslog_str;
         buffer *ts_accesslog_fmt_str;  
         unsigned short append_tz_offset;  
   
         format_fields *parsed_format;          format_fields *parsed_format;
 } plugin_config;  } plugin_config;
Line 160  INIT_FUNC(mod_accesslog_init) { Line 174  INIT_FUNC(mod_accesslog_init) {
         return p;          return p;
 }  }
   
   static void accesslog_write_all(server *srv, const buffer *filename, int fd, const void* buf, size_t count) {
           if (-1 == write_all(fd, buf, count)) {
                   log_error_write(srv, __FILE__, __LINE__, "sbs",
                           "writing access log entry failed:", filename, strerror(errno));
           }
   }
   
 static void accesslog_append_escaped(buffer *dest, buffer *str) {  static void accesslog_append_escaped(buffer *dest, buffer *str) {
         char *ptr, *start, *end;          char *ptr, *start, *end;
   
         /* replaces non-printable chars with \xHH where HH is the hex representation of the byte */          /* replaces non-printable chars with \xHH where HH is the hex representation of the byte */
         /* exceptions: " => \", \ => \\, whitespace chars => \n \t etc. */          /* exceptions: " => \", \ => \\, whitespace chars => \n \t etc. */
        if (str->used == 0) return;        if (buffer_string_is_empty(str)) return;
        buffer_prepare_append(dest, str->used - 1);        buffer_string_prepare_append(dest, buffer_string_length(str));
   
        for (ptr = start = str->ptr, end = str->ptr + str->used - 1; ptr < end; ptr++) {        for (ptr = start = str->ptr, end = str->ptr + buffer_string_length(str); ptr < end; ptr++) {
                char const c = *ptr;                unsigned char const c = (unsigned char) *ptr;
                 if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {                  if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
                         /* nothing to change, add later as one block */                          /* nothing to change, add later as one block */
                 } else {                  } else {
Line 223  static void accesslog_append_escaped(buffer *dest, buf Line 244  static void accesslog_append_escaped(buffer *dest, buf
 static int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {  static int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
         size_t i, j, k = 0, start = 0;          size_t i, j, k = 0, start = 0;
   
        if (format->used == 0) return -1;        if (buffer_is_empty(format)) return -1;
   
        for (i = 0; i < format->used - 1; i++) {        for (i = 0; i < buffer_string_length(format); i++) {
                 switch(format->ptr[i]) {                  switch(format->ptr[i]) {
                 case '%':                  case '%':
                         if (i > 0 && start != i) {                          if (i > 0 && start != i) {
Line 279  static int accesslog_parse_format(server *srv, format_ Line 300  static int accesslog_parse_format(server *srv, format_
                                         fields->ptr[fields->used]->type = FIELD_FORMAT;                                          fields->ptr[fields->used]->type = FIELD_FORMAT;
                                         fields->ptr[fields->used]->field = fmap[j].type;                                          fields->ptr[fields->used]->field = fmap[j].type;
                                         fields->ptr[fields->used]->string = NULL;                                          fields->ptr[fields->used]->string = NULL;
                                           fields->ptr[fields->used]->opt = 0;
   
                                         fields->used++;                                          fields->used++;
   
Line 297  static int accesslog_parse_format(server *srv, format_ Line 319  static int accesslog_parse_format(server *srv, format_
                         case '{':                          case '{':
                                 /* go forward to } */                                  /* go forward to } */
   
                                for (k = i+2; k < format->used - 1; k++) {                                for (k = i+2; k < buffer_string_length(format); k++) {
                                         if (format->ptr[k] == '}') break;                                          if (format->ptr[k] == '}') break;
                                 }                                  }
   
                                if (k == format->used - 1) {                                if (k == buffer_string_length(format)) {
                                         log_error_write(srv, __FILE__, __LINE__, "s", "%{ has to be terminated by a }");                                          log_error_write(srv, __FILE__, __LINE__, "s", "%{ has to be terminated by a }");
                                         return -1;                                          return -1;
                                 }                                  }
Line 326  static int accesslog_parse_format(server *srv, format_ Line 348  static int accesslog_parse_format(server *srv, format_
                                         fields->ptr[fields->used]->type = FIELD_FORMAT;                                          fields->ptr[fields->used]->type = FIELD_FORMAT;
                                         fields->ptr[fields->used]->field = fmap[j].type;                                          fields->ptr[fields->used]->field = fmap[j].type;
                                         fields->ptr[fields->used]->string = buffer_init();                                          fields->ptr[fields->used]->string = buffer_init();
                                           fields->ptr[fields->used]->opt = 0;
   
                                         buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));                                          buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
   
Line 359  static int accesslog_parse_format(server *srv, format_ Line 382  static int accesslog_parse_format(server *srv, format_
                                         fields->ptr[fields->used]->type = FIELD_FORMAT;                                          fields->ptr[fields->used]->type = FIELD_FORMAT;
                                         fields->ptr[fields->used]->field = fmap[j].type;                                          fields->ptr[fields->used]->field = fmap[j].type;
                                         fields->ptr[fields->used]->string = NULL;                                          fields->ptr[fields->used]->string = NULL;
                                           fields->ptr[fields->used]->opt = 0;
   
                                         fields->used++;                                          fields->used++;
   
Line 414  FREE_FUNC(mod_accesslog_free) { Line 438  FREE_FUNC(mod_accesslog_free) {
                 for (i = 0; i < srv->config_context->used; i++) {                  for (i = 0; i < srv->config_context->used; i++) {
                         plugin_config *s = p->config_storage[i];                          plugin_config *s = p->config_storage[i];
   
                        if (!s) continue;                        if (NULL == s) continue;
   
                        if (s->access_logbuffer->used) {                        if (!buffer_string_is_empty(s->access_logbuffer)) {
                                 if (s->log_access_fd != -1) {                                  if (s->log_access_fd != -1) {
                                        write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);                                        accesslog_write_all(srv, s->access_logfile, s->log_access_fd, CONST_BUF_LEN(s->access_logbuffer));
                                 }                                  }
                         }                          }
   
                         if (s->log_access_fd != -1) close(s->log_access_fd);                          if (s->log_access_fd != -1) close(s->log_access_fd);
   
                         buffer_free(s->ts_accesslog_str);                          buffer_free(s->ts_accesslog_str);
                         buffer_free(s->ts_accesslog_fmt_str);  
                         buffer_free(s->access_logbuffer);                          buffer_free(s->access_logbuffer);
                         buffer_free(s->format);                          buffer_free(s->format);
                         buffer_free(s->access_logfile);                          buffer_free(s->access_logfile);
Line 446  FREE_FUNC(mod_accesslog_free) { Line 469  FREE_FUNC(mod_accesslog_free) {
                 free(p->config_storage);                  free(p->config_storage);
         }          }
   
         free(p);  
         if (p->syslog_logbuffer) buffer_free(p->syslog_logbuffer);          if (p->syslog_logbuffer) buffer_free(p->syslog_logbuffer);
           free(p);
   
         return HANDLER_GO_ON;          return HANDLER_GO_ON;
 }  }
Line 466  SETDEFAULTS_FUNC(log_access_open) { Line 489  SETDEFAULTS_FUNC(log_access_open) {
   
         if (!p) return HANDLER_ERROR;          if (!p) return HANDLER_ERROR;
   
        p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));        p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
   
         for (i = 0; i < srv->config_context->used; i++) {          for (i = 0; i < srv->config_context->used; i++) {
                   data_config const* config = (data_config const*)srv->config_context->data[i];
                 plugin_config *s;                  plugin_config *s;
   
                 s = calloc(1, sizeof(plugin_config));                  s = calloc(1, sizeof(plugin_config));
Line 476  SETDEFAULTS_FUNC(log_access_open) { Line 500  SETDEFAULTS_FUNC(log_access_open) {
                 s->format = buffer_init();                  s->format = buffer_init();
                 s->access_logbuffer = buffer_init();                  s->access_logbuffer = buffer_init();
                 s->ts_accesslog_str = buffer_init();                  s->ts_accesslog_str = buffer_init();
                 s->ts_accesslog_fmt_str = buffer_init();  
                 s->log_access_fd = -1;                  s->log_access_fd = -1;
                 s->last_generated_accesslog_ts = 0;                  s->last_generated_accesslog_ts = 0;
                 s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);                  s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
Line 490  SETDEFAULTS_FUNC(log_access_open) { Line 513  SETDEFAULTS_FUNC(log_access_open) {
   
                 p->config_storage[i] = s;                  p->config_storage[i] = s;
   
                if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {                if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
                         return HANDLER_ERROR;                          return HANDLER_ERROR;
                 }                  }
   
                if (i == 0 && buffer_is_empty(s->format)) {                if (i == 0 && buffer_string_is_empty(s->format)) {
                         /* set a default logfile string */                          /* set a default logfile string */
   
                         buffer_copy_string_len(s->format, CONST_STR_LEN("%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""));                          buffer_copy_string_len(s->format, CONST_STR_LEN("%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""));
Line 502  SETDEFAULTS_FUNC(log_access_open) { Line 525  SETDEFAULTS_FUNC(log_access_open) {
   
                 /* parse */                  /* parse */
   
                if (s->format->used) {                if (!buffer_is_empty(s->format)) {
                        size_t j, count;                        size_t j, tcount = 0;
   
                         s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));                          s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
   
Line 515  SETDEFAULTS_FUNC(log_access_open) { Line 538  SETDEFAULTS_FUNC(log_access_open) {
                                 return HANDLER_ERROR;                                  return HANDLER_ERROR;
                         }                          }
   
                        /* make sure they didn't try to send the timestamp in twice...                        for (j = 0; j < s->parsed_format->used; ++j) {
                         * also, save the format string in a different variable (this                                format_field * const f = s->parsed_format->ptr[j];
                         * will save a few conditionals later)                                if (FIELD_FORMAT != f->type) continue;
                         */                                if (FORMAT_TIMESTAMP == f->field) {
                        count = 0;                                        if (!buffer_string_is_empty(f->string)) {
                        for (j = 0; j < s->parsed_format->used; j++) {                                                const char *ptr = f->string->ptr;
                                if (FIELD_FORMAT == s->parsed_format->ptr[j]->type) {                                                if (0 == strncmp(ptr, "begin:", sizeof("begin:")-1)) {
                                        if (FORMAT_TIMESTAMP == s->parsed_format->ptr[j]->field) {                                                        f->opt |= FORMAT_FLAG_TIME_BEGIN;
                                                if (!buffer_is_empty(s->parsed_format->ptr[j]->string)) {                                                        ptr += sizeof("begin:")-1;
                                                        buffer_copy_string(s->ts_accesslog_fmt_str, s->parsed_format->ptr[j]->string->ptr);                                                } else if (0 == strncmp(ptr, "end:", sizeof("end:")-1)) {
                                                         f->opt |= FORMAT_FLAG_TIME_END;
                                                         ptr += sizeof("end:")-1;
                                                 }                                                  }
                                                if      (0 == strcmp(ptr, "sec"))       f->opt |= FORMAT_FLAG_TIME_SEC;
                                                if (++count > 1) {                                                else if (0 == strcmp(ptr, "msec"))      f->opt |= FORMAT_FLAG_TIME_MSEC;
                                                 else if (0 == strcmp(ptr, "usec"))      f->opt |= FORMAT_FLAG_TIME_USEC;
                                                 else if (0 == strcmp(ptr, "nsec"))      f->opt |= FORMAT_FLAG_TIME_NSEC;
                                                 else if (0 == strcmp(ptr, "msec_frac")) f->opt |= FORMAT_FLAG_TIME_MSEC_FRAC;
                                                 else if (0 == strcmp(ptr, "usec_frac")) f->opt |= FORMAT_FLAG_TIME_USEC_FRAC;
                                                 else if (0 == strcmp(ptr, "nsec_frac")) f->opt |= FORMAT_FLAG_TIME_NSEC_FRAC;
                                                 else if (NULL == strchr(ptr, '%')) {
                                                         log_error_write(srv, __FILE__, __LINE__, "sb",                                                          log_error_write(srv, __FILE__, __LINE__, "sb",
                                                                "you may not use the timestamp twice in the same access log:", s->format);                                                                "constant string for time format (misspelled token? or missing '%'):", s->format);
   
                                                         return HANDLER_ERROR;                                                          return HANDLER_ERROR;
                                                 }                                                  }
                                         }                                          }
   
                                           /* make sure they didn't try to send the timestamp in twice
                                            * (would invalidate s->ts_accesslog_str cache of timestamp str) */
                                           if (!(f->opt & ~(FORMAT_FLAG_TIME_BEGIN|FORMAT_FLAG_TIME_END|FORMAT_FLAG_TIME_SEC)) && ++tcount > 1) {
                                                   log_error_write(srv, __FILE__, __LINE__, "sb",
                                                           "you may not use strftime timestamp format %{}t twice in the same access log:", s->format);
   
                                                   return HANDLER_ERROR;
                                           }
   
                                           if (f->opt & FORMAT_FLAG_TIME_BEGIN) srv->srvconf.high_precision_timestamps = 1;
                                   } else if (FORMAT_TIME_USED_US == f->field) {
                                           f->opt |= FORMAT_FLAG_TIME_USEC;
                                           srv->srvconf.high_precision_timestamps = 1;
                                   } else if (FORMAT_TIME_USED == f->field) {
                                           if (f->opt & ~(FORMAT_FLAG_TIME_SEC)) srv->srvconf.high_precision_timestamps = 1;
   
                                           if (buffer_string_is_empty(f->string)
                                                 || buffer_is_equal_string(f->string, CONST_STR_LEN("s"))
                                                 || buffer_is_equal_string(f->string, CONST_STR_LEN("sec")))  f->opt |= FORMAT_FLAG_TIME_SEC;
                                           else if (buffer_is_equal_string(f->string, CONST_STR_LEN("ms"))
                                                 || buffer_is_equal_string(f->string, CONST_STR_LEN("msec"))) f->opt |= FORMAT_FLAG_TIME_MSEC;
                                           else if (buffer_is_equal_string(f->string, CONST_STR_LEN("us"))
                                                 || buffer_is_equal_string(f->string, CONST_STR_LEN("usec"))) f->opt |= FORMAT_FLAG_TIME_USEC;
                                           else if (buffer_is_equal_string(f->string, CONST_STR_LEN("ns"))
                                                 || buffer_is_equal_string(f->string, CONST_STR_LEN("nsec"))) f->opt |= FORMAT_FLAG_TIME_NSEC;
                                           else {
                                                   log_error_write(srv, __FILE__, __LINE__, "sb",
                                                           "invalid time unit in %{UNIT}T:", s->format);
   
                                                   return HANDLER_ERROR;
                                           }
                                   } else if (FORMAT_COOKIE == f->field) {
                                           if (buffer_string_is_empty(f->string)) f->type = FIELD_STRING; /*(blank)*/
                                 }                                  }
                         }                          }
   
Line 557  SETDEFAULTS_FUNC(log_access_open) { Line 622  SETDEFAULTS_FUNC(log_access_open) {
 #endif  #endif
                 }                  }
   
                 s->append_tz_offset = 0;  
                 if (buffer_is_empty(s->ts_accesslog_fmt_str)) {  
 #if defined(HAVE_STRUCT_TM_GMTOFF)  
                         BUFFER_COPY_STRING_CONST(s->ts_accesslog_fmt_str, "[%d/%b/%Y:%H:%M:%S ");  
                         s->append_tz_offset = 1;  
 #else  
                         BUFFER_COPY_STRING_CONST(s->ts_accesslog_fmt_str, "[%d/%b/%Y:%H:%M:%S +0000]");  
 #endif  
                 }  
   
                 if (s->use_syslog) {                  if (s->use_syslog) {
                         /* ignore the next checks */                          /* ignore the next checks */
                         continue;                          continue;
                 }                  }
   
                if (s->access_logfile->used < 2) continue;                if (buffer_string_is_empty(s->access_logfile)) continue;
   
                   if (srv->srvconf.preflight_check) continue;
   
                 if (-1 == (s->log_access_fd = open_logfile_or_pipe(srv, s->access_logfile->ptr)))                  if (-1 == (s->log_access_fd = open_logfile_or_pipe(srv, s->access_logfile->ptr)))
                         return HANDLER_ERROR;                          return HANDLER_ERROR;
   
Line 591  SIGHUP_FUNC(log_access_cycle) { Line 648  SIGHUP_FUNC(log_access_cycle) {
         for (i = 0; i < srv->config_context->used; i++) {          for (i = 0; i < srv->config_context->used; i++) {
                 plugin_config *s = p->config_storage[i];                  plugin_config *s = p->config_storage[i];
   
                if (s->access_logbuffer->used) {                if (!buffer_string_is_empty(s->access_logbuffer)) {
                         if (s->log_access_fd != -1) {                          if (s->log_access_fd != -1) {
                                write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);                                accesslog_write_all(srv, s->access_logfile, s->log_access_fd, CONST_BUF_LEN(s->access_logbuffer));
                         }                          }
   
                         buffer_reset(s->access_logbuffer);                          buffer_reset(s->access_logbuffer);
                 }                  }
   
                if (s->use_syslog == 0 &&                if (s->use_syslog == 0
                    s->access_logfile->used > 1 &&                        && !buffer_string_is_empty(s->access_logfile)
                    s->access_logfile->ptr[0] != '|') {                        && s->access_logfile->ptr[0] != '|') {
   
                        close(s->log_access_fd);                        if (-1 != s->log_access_fd) close(s->log_access_fd);
   
                         if (-1 == (s->log_access_fd =                          if (-1 == (s->log_access_fd =
                                    open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {                                     open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
Line 612  SIGHUP_FUNC(log_access_cycle) { Line 669  SIGHUP_FUNC(log_access_cycle) {
   
                                 return HANDLER_ERROR;                                  return HANDLER_ERROR;
                         }                          }
#ifdef FD_CLOEXEC                        fd_close_on_exec(s->log_access_fd);
                        fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC); 
#endif 
                 }                  }
         }          }
   
Line 628  static int mod_accesslog_patch_connection(server *srv, Line 683  static int mod_accesslog_patch_connection(server *srv,
         plugin_config *s = p->config_storage[0];          plugin_config *s = p->config_storage[0];
   
         PATCH(access_logfile);          PATCH(access_logfile);
         PATCH(format);  
         PATCH(log_access_fd);          PATCH(log_access_fd);
         PATCH(last_generated_accesslog_ts_ptr);          PATCH(last_generated_accesslog_ts_ptr);
         PATCH(access_logbuffer);          PATCH(access_logbuffer);
         PATCH(ts_accesslog_str);          PATCH(ts_accesslog_str);
         PATCH(ts_accesslog_fmt_str);  
         PATCH(append_tz_offset);  
         PATCH(parsed_format);          PATCH(parsed_format);
         PATCH(use_syslog);          PATCH(use_syslog);
         PATCH(syslog_level);          PATCH(syslog_level);
Line 656  static int mod_accesslog_patch_connection(server *srv, Line 708  static int mod_accesslog_patch_connection(server *srv,
                                 PATCH(log_access_fd);                                  PATCH(log_access_fd);
                                 PATCH(access_logbuffer);                                  PATCH(access_logbuffer);
                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {                          } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
                                 PATCH(format);  
                                 PATCH(parsed_format);                                  PATCH(parsed_format);
                                 PATCH(last_generated_accesslog_ts_ptr);                                  PATCH(last_generated_accesslog_ts_ptr);
                                 PATCH(ts_accesslog_str);                                  PATCH(ts_accesslog_str);
                                 PATCH(ts_accesslog_fmt_str);  
                                 PATCH(append_tz_offset);  
                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {                          } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
                                 PATCH(use_syslog);                                  PATCH(use_syslog);
                         } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.syslog-level"))) {                          } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.syslog-level"))) {
Line 681  REQUESTDONE_FUNC(log_access_write) { Line 730  REQUESTDONE_FUNC(log_access_write) {
   
         int newts = 0;          int newts = 0;
         data_string *ds;          data_string *ds;
           struct timespec ts = { 0, 0 };
   
         mod_accesslog_patch_connection(srv, con, p);          mod_accesslog_patch_connection(srv, con, p);
   
Line 693  REQUESTDONE_FUNC(log_access_write) { Line 743  REQUESTDONE_FUNC(log_access_write) {
                 b = p->conf.access_logbuffer;                  b = p->conf.access_logbuffer;
         }          }
   
        if (b->used == 0) {        if (buffer_is_empty(b)) {
                buffer_copy_string_len(b, CONST_STR_LEN(""));                buffer_string_set_length(b, 0);
         }          }
   
         for (j = 0; j < p->conf.parsed_format->used; j++) {          for (j = 0; j < p->conf.parsed_format->used; j++) {
                switch(p->conf.parsed_format->ptr[j]->type) {                const format_field * const f = p->conf.parsed_format->ptr[j];
                 switch(f->type) {
                 case FIELD_STRING:                  case FIELD_STRING:
                        buffer_append_string_buffer(b, p->conf.parsed_format->ptr[j]->string);                        buffer_append_string_buffer(b, f->string);
                         break;                          break;
                 case FIELD_FORMAT:                  case FIELD_FORMAT:
                        switch(p->conf.parsed_format->ptr[j]->field) {                        switch(f->field) {
                         case FORMAT_TIMESTAMP:                          case FORMAT_TIMESTAMP:
   
                                /* cache the generated timestamp */                                if (f->opt & ~(FORMAT_FLAG_TIME_BEGIN|FORMAT_FLAG_TIME_END)) {
                                if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {                                        if (f->opt & FORMAT_FLAG_TIME_SEC) {
                                                 time_t t = (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) ? srv->cur_ts : con->request_start;
                                                 buffer_append_int(b, (intmax_t)t);
                                         } else if (f->opt & (FORMAT_FLAG_TIME_MSEC|FORMAT_FLAG_TIME_USEC|FORMAT_FLAG_TIME_NSEC)) {
                                                 off_t t; /*(expected to be 64-bit since large file support enabled)*/
                                                 long ns;
                                                 if (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) {
                                                         if (0 == ts.tv_sec) log_clock_gettime_realtime(&ts);
                                                         t = (off_t)ts.tv_sec;
                                                         ns = ts.tv_nsec;
                                                 } else {
                                                         t = (off_t)con->request_start_hp.tv_sec;
                                                         ns = con->request_start_hp.tv_nsec;
                                                 }
                                                 if (f->opt & FORMAT_FLAG_TIME_MSEC) {
                                                         t *= 1000;
                                                         t += (ns + 999999) / 1000000; /* ceil */
                                                 } else if (f->opt & FORMAT_FLAG_TIME_USEC) {
                                                         t *= 1000000;
                                                         t += (ns + 999) / 1000; /* ceil */
                                                 } else {/*(f->opt & FORMAT_FLAG_TIME_NSEC)*/
                                                         t *= 1000000000;
                                                         t += ns;
                                                 }
                                                 buffer_append_int(b, (intmax_t)t);
                                         } else { /*(FORMAT_FLAG_TIME_MSEC_FRAC|FORMAT_FLAG_TIME_USEC_FRAC|FORMAT_FLAG_TIME_NSEC_FRAC)*/
                                                 long ns;
                                                 char *ptr;
                                                 if (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) {
                                                         if (0 == ts.tv_sec) log_clock_gettime_realtime(&ts);
                                                         ns = ts.tv_nsec;
                                                 } else {
                                                         ns = con->request_start_hp.tv_nsec;
                                                 }
                                                 /*assert(t < 1000000000);*/
                                                 if (f->opt & FORMAT_FLAG_TIME_MSEC_FRAC) {
                                                         ns +=  999999; /* ceil */
                                                         ns /= 1000000;
                                                         buffer_append_string_len(b, CONST_STR_LEN("000"));
                                                 } else if (f->opt & FORMAT_FLAG_TIME_USEC_FRAC) {
                                                         ns +=  999; /* ceil */
                                                         ns /= 1000;
                                                         buffer_append_string_len(b, CONST_STR_LEN("000000"));
                                                 } else {/*(f->opt & FORMAT_FLAG_TIME_NSEC_FRAC)*/
                                                         buffer_append_string_len(b, CONST_STR_LEN("000000000"));
                                                 }
                                                 for (ptr = b->ptr + buffer_string_length(b); ns > 0; ns /= 10)
                                                         *--ptr = (ns % 10) + '0';
                                         }
                                 } else if (!(f->opt & FORMAT_FLAG_TIME_BEGIN) && srv->cur_ts == *(p->conf.last_generated_accesslog_ts_ptr)) {
                                         buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
                                 } else {
                                         /* cache the generated timestamp (only if ! FORMAT_FLAG_TIME_BEGIN) */
                                         struct tm *tmptr;
                                         time_t t;
                                       #if defined(HAVE_STRUCT_TM_GMTOFF)
                                       # ifdef HAVE_LOCALTIME_R
                                         struct tm tm;                                          struct tm tm;
#if defined(HAVE_STRUCT_TM_GMTOFF)                                      # endif /* HAVE_LOCALTIME_R */
                                        long scd, hrs, min;                                      #else /* HAVE_STRUCT_TM_GMTOFF */
#endif                                      # ifdef HAVE_GMTIME_R
                                         struct tm tm;
                                       # endif /* HAVE_GMTIME_R */
                                       #endif /* HAVE_STRUCT_TM_GMTOFF */
   
                                        buffer_prepare_copy(p->conf.ts_accesslog_str, 255);                                        if (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) {
#if defined(HAVE_STRUCT_TM_GMTOFF)                                                t = *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
# ifdef HAVE_LOCALTIME_R                                                newts = 1;
                                        localtime_r(&(srv->cur_ts), &tm);                                        } else {
                                        strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, p->conf.ts_accesslog_fmt_str->ptr, &tm);                                                t = con->request_start;
# else /* HAVE_LOCALTIME_R */                                        }
                                        strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, p->conf.ts_accesslog_fmt_str->ptr, localtime_r(&(srv->cur_ts))); 
# endif /* HAVE_LOCALTIME_R */ 
                                        p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1; 
   
                                        if (p->conf.append_tz_offset) {                                      #if defined(HAVE_STRUCT_TM_GMTOFF)
                                                buffer_append_string_len(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-", 1);                                      # ifdef HAVE_LOCALTIME_R
                                         tmptr = localtime_r(&t, &tm);
                                       # else /* HAVE_LOCALTIME_R */
                                         tmptr = localtime(&t);
                                       # endif /* HAVE_LOCALTIME_R */
                                       #else /* HAVE_STRUCT_TM_GMTOFF */
                                       # ifdef HAVE_GMTIME_R
                                         tmptr = gmtime_r(&t, &tm);
                                       # else /* HAVE_GMTIME_R */
                                         tmptr = gmtime(&t);
                                       # endif /* HAVE_GMTIME_R */
                                       #endif /* HAVE_STRUCT_TM_GMTOFF */
   
                                                scd = abs(tm.tm_gmtoff);                                        buffer_string_prepare_copy(p->conf.ts_accesslog_str, 255);
 
                                         if (buffer_string_is_empty(f->string)) {
                                               #if defined(HAVE_STRUCT_TM_GMTOFF)
                                                 long scd, hrs, min;
                                                 buffer_append_strftime(p->conf.ts_accesslog_str, "[%d/%b/%Y:%H:%M:%S ", tmptr);
                                                 buffer_append_string_len(p->conf.ts_accesslog_str, tmptr->tm_gmtoff >= 0 ? "+" : "-", 1);
 
                                                 scd = labs(tmptr->tm_gmtoff);
                                                 hrs = scd / 3600;                                                  hrs = scd / 3600;
                                                 min = (scd % 3600) / 60;                                                  min = (scd % 3600) / 60;
   
                                                 /* hours */                                                  /* hours */
                                                 if (hrs < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));                                                  if (hrs < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));
                                                buffer_append_long(p->conf.ts_accesslog_str, hrs);                                                buffer_append_int(p->conf.ts_accesslog_str, hrs);
   
                                                 if (min < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));                                                  if (min < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0"));
                                                buffer_append_long(p->conf.ts_accesslog_str, min);                                                buffer_append_int(p->conf.ts_accesslog_str, min);
                                                 buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("]"));                                                  buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("]"));
                                                 #else
                                                   buffer_append_strftime(p->conf.ts_accesslog_str, "[%d/%b/%Y:%H:%M:%S +0000]", tmptr);
                                                 #endif /* HAVE_STRUCT_TM_GMTOFF */
                                           } else {
                                                   buffer_append_strftime(p->conf.ts_accesslog_str, f->string->ptr, tmptr);
                                         }                                          }
 #else /* HAVE_STRUCT_TM_GMTOFF */  
 # ifdef HAVE_GMTIME_R  
                                         gmtime_r(&(srv->cur_ts), &tm);  
                                         strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, p->conf.ts_accesslog_fmt_str->ptr, &tm);  
 # else /* HAVE_GMTIME_R */  
                                         strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, p->conf.ts_accesslog_fmt_str->ptr, gmtime(&(srv->cur_ts)));  
 # endif /* HAVE_GMTIME_R */  
                                         p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;  
 #endif /* HAVE_STRUCT_TM_GMTOFF */  
   
                                        *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;                                        buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
                                        newts = 1; 
                                 }                                  }
   
                                 buffer_append_string_buffer(b, p->conf.ts_accesslog_str);  
   
                                 break;                                  break;
                           case FORMAT_TIME_USED:
                           case FORMAT_TIME_USED_US:
                                   if (f->opt & FORMAT_FLAG_TIME_SEC) {
                                           buffer_append_int(b, srv->cur_ts - con->request_start);
                                   } else {
                                           const struct timespec * const bs = &con->request_start_hp;
                                           off_t tdiff; /*(expected to be 64-bit since large file support enabled)*/
                                           if (0 == ts.tv_sec) log_clock_gettime_realtime(&ts);
                                           tdiff = (off_t)(ts.tv_sec - bs->tv_sec)*1000000000 + (ts.tv_nsec - bs->tv_nsec);
                                           if (tdiff <= 0) {
                                                   /* sanity check for time moving backwards
                                                    * (daylight savings adjustment or leap seconds or ?) */
                                                   tdiff  = -1;
                                           } else if (f->opt & FORMAT_FLAG_TIME_MSEC) {
                                                   tdiff +=  999999; /* ceil */
                                                   tdiff /= 1000000;
                                           } else if (f->opt & FORMAT_FLAG_TIME_USEC) {
                                                   tdiff +=  999; /* ceil */
                                                   tdiff /= 1000;
                                           } /* else (f->opt & FORMAT_FLAG_TIME_NSEC) */
                                           buffer_append_int(b, (intmax_t)tdiff);
                                   }
                                   break;
                           case FORMAT_REMOTE_ADDR:
                         case FORMAT_REMOTE_HOST:                          case FORMAT_REMOTE_HOST:
                                buffer_append_string_buffer(b, con->dst_addr_buf);
                                /* handle inet_ntop cache */ 
 
                                buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr))); 
 
                                 break;                                  break;
                         case FORMAT_REMOTE_IDENT:                          case FORMAT_REMOTE_IDENT:
                                 /* ident */                                  /* ident */
                                 buffer_append_string_len(b, CONST_STR_LEN("-"));                                  buffer_append_string_len(b, CONST_STR_LEN("-"));
                                 break;                                  break;
                         case FORMAT_REMOTE_USER:                          case FORMAT_REMOTE_USER:
                                if (NULL != (ds = (data_string *)array_get_element(con->environment, "REMOTE_USER")) && ds->value->used > 1) {                                if (NULL != (ds = (data_string *)array_get_element(con->environment, "REMOTE_USER")) && !buffer_string_is_empty(ds->value)) {
                                         accesslog_append_escaped(b, ds->value);                                          accesslog_append_escaped(b, ds->value);
                                 } else {                                  } else {
                                         buffer_append_string_len(b, CONST_STR_LEN("-"));                                          buffer_append_string_len(b, CONST_STR_LEN("-"));
                                 }                                  }
                                 break;                                  break;
                         case FORMAT_REQUEST_LINE:                          case FORMAT_REQUEST_LINE:
                                if (con->request.request_line->used) {                                if (!buffer_string_is_empty(con->request.request_line)) {
                                         accesslog_append_escaped(b, con->request.request_line);                                          accesslog_append_escaped(b, con->request.request_line);
                                 }                                  }
                                 break;                                  break;
                         case FORMAT_STATUS:                          case FORMAT_STATUS:
                                buffer_append_long(b, con->http_status);                                buffer_append_int(b, con->http_status);
                                 break;                                  break;
   
                         case FORMAT_BYTES_OUT_NO_HEADER:                          case FORMAT_BYTES_OUT_NO_HEADER:
                                 if (con->bytes_written > 0) {                                  if (con->bytes_written > 0) {
                                        buffer_append_off_t(b,                                        buffer_append_int(b,
                                                             con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);                                                              con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
                                 } else {                                  } else {
                                         buffer_append_string_len(b, CONST_STR_LEN("-"));                                          buffer_append_string_len(b, CONST_STR_LEN("-"));
                                 }                                  }
                                 break;                                  break;
                         case FORMAT_HEADER:                          case FORMAT_HEADER:
                                if (NULL != (ds = (data_string *)array_get_element(con->request.headers, p->conf.parsed_format->ptr[j]->string->ptr))) {                                if (NULL != (ds = (data_string *)array_get_element(con->request.headers, f->string->ptr))) {
                                         accesslog_append_escaped(b, ds->value);                                          accesslog_append_escaped(b, ds->value);
                                 } else {                                  } else {
                                         buffer_append_string_len(b, CONST_STR_LEN("-"));                                          buffer_append_string_len(b, CONST_STR_LEN("-"));
                                 }                                  }
                                 break;                                  break;
                         case FORMAT_RESPONSE_HEADER:                          case FORMAT_RESPONSE_HEADER:
                                if (NULL != (ds = (data_string *)array_get_element(con->response.headers, p->conf.parsed_format->ptr[j]->string->ptr))) {                                if (NULL != (ds = (data_string *)array_get_element(con->response.headers, f->string->ptr))) {
                                         accesslog_append_escaped(b, ds->value);                                          accesslog_append_escaped(b, ds->value);
                                 } else {                                  } else {
                                         buffer_append_string_len(b, CONST_STR_LEN("-"));                                          buffer_append_string_len(b, CONST_STR_LEN("-"));
                                 }                                  }
                                 break;                                  break;
                         case FORMAT_ENV:                          case FORMAT_ENV:
                                if (NULL != (ds = (data_string *)array_get_element(con->environment, p->conf.parsed_format->ptr[j]->string->ptr))) {                                if (NULL != (ds = (data_string *)array_get_element(con->environment, f->string->ptr))) {
                                         accesslog_append_escaped(b, ds->value);                                          accesslog_append_escaped(b, ds->value);
                                 } else {                                  } else {
                                         buffer_append_string_len(b, CONST_STR_LEN("-"));                                          buffer_append_string_len(b, CONST_STR_LEN("-"));
                                 }                                  }
                                 break;                                  break;
                         case FORMAT_FILENAME:                          case FORMAT_FILENAME:
                                if (con->physical.path->used > 1) {                                if (!buffer_string_is_empty(con->physical.path)) {
                                         buffer_append_string_buffer(b, con->physical.path);                                          buffer_append_string_buffer(b, con->physical.path);
                                 } else {                                  } else {
                                         buffer_append_string_len(b, CONST_STR_LEN("-"));                                          buffer_append_string_len(b, CONST_STR_LEN("-"));
Line 820  REQUESTDONE_FUNC(log_access_write) { Line 958  REQUESTDONE_FUNC(log_access_write) {
                                 break;                                  break;
                         case FORMAT_BYTES_OUT:                          case FORMAT_BYTES_OUT:
                                 if (con->bytes_written > 0) {                                  if (con->bytes_written > 0) {
                                        buffer_append_off_t(b, con->bytes_written);                                        buffer_append_int(b, con->bytes_written);
                                 } else {                                  } else {
                                         buffer_append_string_len(b, CONST_STR_LEN("-"));                                          buffer_append_string_len(b, CONST_STR_LEN("-"));
                                 }                                  }
                                 break;                                  break;
                         case FORMAT_BYTES_IN:                          case FORMAT_BYTES_IN:
                                 if (con->bytes_read > 0) {                                  if (con->bytes_read > 0) {
                                        buffer_append_off_t(b, con->bytes_read);                                        buffer_append_int(b, con->bytes_read);
                                 } else {                                  } else {
                                         buffer_append_string_len(b, CONST_STR_LEN("-"));                                          buffer_append_string_len(b, CONST_STR_LEN("-"));
                                 }                                  }
                                 break;                                  break;
                         case FORMAT_TIME_USED:  
                                 buffer_append_long(b, srv->cur_ts - con->request_start);  
                                 break;  
                         case FORMAT_SERVER_NAME:                          case FORMAT_SERVER_NAME:
                                if (con->server_name->used > 1) {                                if (!buffer_string_is_empty(con->server_name)) {
                                         buffer_append_string_buffer(b, con->server_name);                                          buffer_append_string_buffer(b, con->server_name);
                                 } else {                                  } else {
                                         buffer_append_string_len(b, CONST_STR_LEN("-"));                                          buffer_append_string_len(b, CONST_STR_LEN("-"));
                                 }                                  }
                                 break;                                  break;
                         case FORMAT_HTTP_HOST:                          case FORMAT_HTTP_HOST:
                                if (con->uri.authority->used > 1) {                                if (!buffer_string_is_empty(con->uri.authority)) {
                                         accesslog_append_escaped(b, con->uri.authority);                                          accesslog_append_escaped(b, con->uri.authority);
                                 } else {                                  } else {
                                         buffer_append_string_len(b, CONST_STR_LEN("-"));                                          buffer_append_string_len(b, CONST_STR_LEN("-"));
Line 851  REQUESTDONE_FUNC(log_access_write) { Line 986  REQUESTDONE_FUNC(log_access_write) {
                                 break;                                  break;
                         case FORMAT_REQUEST_PROTOCOL:                          case FORMAT_REQUEST_PROTOCOL:
                                 buffer_append_string_len(b,                                  buffer_append_string_len(b,
                                                     con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0", 8);                                        con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0", 8);
                                 break;                                  break;
                         case FORMAT_REQUEST_METHOD:                          case FORMAT_REQUEST_METHOD:
                                 buffer_append_string(b, get_http_method_name(con->request.http_method));                                  buffer_append_string(b, get_http_method_name(con->request.http_method));
Line 859  REQUESTDONE_FUNC(log_access_write) { Line 994  REQUESTDONE_FUNC(log_access_write) {
                         case FORMAT_PERCENT:                          case FORMAT_PERCENT:
                                 buffer_append_string_len(b, CONST_STR_LEN("%"));                                  buffer_append_string_len(b, CONST_STR_LEN("%"));
                                 break;                                  break;
                           case FORMAT_LOCAL_ADDR:
                                   {
                                           /* (perf: not using getsockname() and inet_ntop_cache_get_ip())
                                            * (still useful if admin has configured explicit listen IPs) */
                                           const char *colon;
                                           buffer *srvtoken = con->srv_socket->srv_token;
                                           if (srvtoken->ptr[0] == '[') {
                                                   colon = strstr(srvtoken->ptr, "]:");
                                           } else {
                                                   colon = strchr(srvtoken->ptr, ':');
                                           }
                                           if (colon) {
                                                   buffer_append_string_len(b, srvtoken->ptr, (size_t)(colon - srvtoken->ptr));
                                           } else {
                                                   buffer_append_string_buffer(b, srvtoken);
                                           }
                                   }
                                   break;
                         case FORMAT_SERVER_PORT:                          case FORMAT_SERVER_PORT:
                                 {                                  {
                                         const char *colon;                                          const char *colon;
Line 871  REQUESTDONE_FUNC(log_access_write) { Line 1024  REQUESTDONE_FUNC(log_access_write) {
                                         if (colon) {                                          if (colon) {
                                                 buffer_append_string(b, colon+1);                                                  buffer_append_string(b, colon+1);
                                         } else {                                          } else {
                                                buffer_append_long(b, srv->srvconf.port);                                                buffer_append_int(b, srv->srvconf.port);
                                         }                                          }
                                 }                                  }
                                 break;                                  break;
Line 882  REQUESTDONE_FUNC(log_access_write) { Line 1035  REQUESTDONE_FUNC(log_access_write) {
                                 accesslog_append_escaped(b, con->uri.path_raw);                                  accesslog_append_escaped(b, con->uri.path_raw);
                                 break;                                  break;
                         case FORMAT_CONNECTION_STATUS:                          case FORMAT_CONNECTION_STATUS:
                                switch(con->keep_alive) {                                if (con->state == CON_STATE_RESPONSE_END) {
                                case 0: buffer_append_string_len(b, CONST_STR_LEN("-")); break;                                        if (0 == con->keep_alive) {
                                default: buffer_append_string_len(b, CONST_STR_LEN("+")); break;                                                buffer_append_string_len(b, CONST_STR_LEN("-"));
                                         } else {
                                                 buffer_append_string_len(b, CONST_STR_LEN("+"));
                                         }
                                 } else { /* CON_STATE_ERROR */
                                         buffer_append_string_len(b, CONST_STR_LEN("X"));
                                 }                                  }
                                 break;                                  break;
                           case FORMAT_KEEPALIVE_COUNT:
                                   if (con->request_count > 1) {
                                           buffer_append_int(b, (intmax_t)(con->request_count-1));
                                   } else {
                                           buffer_append_string_len(b, CONST_STR_LEN("0"));
                                   }
                                   break;
                           case FORMAT_COOKIE:
                                   if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
                                           char *str = ds->value->ptr;
                                           size_t len = buffer_string_length(f->string);
                                           do {
                                                   while (*str == ' ' || *str == '\t') ++str;
                                                   if (0 == strncmp(str, f->string->ptr, len) && str[len] == '=') {
                                                           char *v = str+len+1;
                                                           buffer *bstr;
                                                           for (str = v; *str != '\0' && *str != ';'; ++str) ;
                                                           if (str == v) break;
                                                           do { --str; } while (str > v && (*str == ' ' || *str == '\t'));
                                                           bstr = buffer_init();
                                                           buffer_copy_string_len(bstr, v, str - v + 1);
                                                           accesslog_append_escaped(b, bstr);
                                                           buffer_free(bstr);
                                                           break;
                                                   } else {
                                                           do { ++str; } while (*str != ' ' && *str != '\t' && *str != '\0');
                                                   }
                                                   while (*str == ' ' || *str == '\t') ++str;
                                           } while (*str++ == ';');
                                   }
                                   break;
                         default:                          default:
                                 /*  
                                  { 'a', FORMAT_REMOTE_ADDR },  
                                  { 'A', FORMAT_LOCAL_ADDR },  
                                  { 'C', FORMAT_COOKIE },  
                                  { 'D', FORMAT_TIME_USED_MS },  
                                  */  
   
                                 break;                                  break;
                         }                          }
                         break;                          break;
Line 903  REQUESTDONE_FUNC(log_access_write) { Line 1085  REQUESTDONE_FUNC(log_access_write) {
                 }                  }
         }          }
   
           if (p->conf.use_syslog) { /* syslog doesn't cache */
   #ifdef HAVE_SYSLOG_H
                   if (!buffer_string_is_empty(b)) {
                           /*(syslog appends a \n on its own)*/
                           syslog(p->conf.syslog_level, "%s", b->ptr);
                           buffer_reset(b);
                   }
   #endif
                   return HANDLER_GO_ON;
           }
   
         buffer_append_string_len(b, CONST_STR_LEN("\n"));          buffer_append_string_len(b, CONST_STR_LEN("\n"));
   
        if (p->conf.use_syslog ||  /* syslog doesn't cache */        if ((!buffer_string_is_empty(p->conf.access_logfile) && p->conf.access_logfile->ptr[0] == '|') || /* pipes don't cache */
            (p->conf.access_logfile->used && p->conf.access_logfile->ptr[0] == '|') || /* pipes don't cache */ 
             newts ||              newts ||
            b->used > BUFFER_MAX_REUSE_SIZE) {            buffer_string_length(b) >= BUFFER_MAX_REUSE_SIZE) {
                if (p->conf.use_syslog) {                if (p->conf.log_access_fd >= 0) {
#ifdef HAVE_SYSLOG_H                        accesslog_write_all(srv, p->conf.access_logfile, p->conf.log_access_fd, CONST_BUF_LEN(b));
                        if (b->used > 2) { 
                                /* syslog appends a \n on its own */ 
                                syslog(p->conf.syslog_level, "%*s", (int) b->used - 2, b->ptr); 
                        } 
#endif 
                } else if (p->conf.log_access_fd != -1) { 
                        write(p->conf.log_access_fd, b->ptr, b->used - 1); 
                 }                  }
                 buffer_reset(b);                  buffer_reset(b);
         }          }

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>