|
|
|
@ -6,10 +6,6 @@
|
|
|
|
|
|
|
|
|
|
#include "plugin.h" |
|
|
|
|
|
|
|
|
|
#include "inet_ntop_cache.h" |
|
|
|
|
|
|
|
|
|
#include "sys-socket.h" |
|
|
|
|
|
|
|
|
|
#include <sys/types.h> |
|
|
|
|
#include <sys/stat.h> |
|
|
|
|
|
|
|
|
@ -45,7 +41,7 @@ typedef struct {
|
|
|
|
|
FORMAT_REMOTE_ADDR, |
|
|
|
|
FORMAT_LOCAL_ADDR, |
|
|
|
|
FORMAT_COOKIE, |
|
|
|
|
FORMAT_TIME_USED_MS, |
|
|
|
|
FORMAT_TIME_USED_US, |
|
|
|
|
FORMAT_ENV, |
|
|
|
|
FORMAT_FILENAME, |
|
|
|
|
FORMAT_REQUEST_PROTOCOL, |
|
|
|
@ -60,6 +56,7 @@ typedef struct {
|
|
|
|
|
FORMAT_BYTES_IN, |
|
|
|
|
FORMAT_BYTES_OUT, |
|
|
|
|
|
|
|
|
|
FORMAT_KEEPALIVE_COUNT, |
|
|
|
|
FORMAT_RESPONSE_HEADER |
|
|
|
|
} type; |
|
|
|
|
} format_mapping; |
|
|
|
@ -87,10 +84,11 @@ static const format_mapping fmap[] =
|
|
|
|
|
{ 'A', FORMAT_LOCAL_ADDR }, |
|
|
|
|
{ 'B', FORMAT_BYTES_OUT_NO_HEADER }, |
|
|
|
|
{ 'C', FORMAT_COOKIE }, |
|
|
|
|
{ 'D', FORMAT_TIME_USED_MS }, |
|
|
|
|
{ 'D', FORMAT_TIME_USED_US }, |
|
|
|
|
{ 'e', FORMAT_ENV }, |
|
|
|
|
{ 'f', FORMAT_FILENAME }, |
|
|
|
|
{ 'H', FORMAT_REQUEST_PROTOCOL }, |
|
|
|
|
{ 'k', FORMAT_KEEPALIVE_COUNT }, |
|
|
|
|
{ 'm', FORMAT_REQUEST_METHOD }, |
|
|
|
|
{ 'n', FORMAT_UNSUPPORTED }, /* we have no notes */ |
|
|
|
|
{ 'p', FORMAT_SERVER_PORT }, |
|
|
|
@ -110,11 +108,27 @@ 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 { |
|
|
|
|
enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type; |
|
|
|
|
|
|
|
|
|
buffer *string; |
|
|
|
|
int field; |
|
|
|
|
int opt; |
|
|
|
|
} format_field; |
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
@ -138,8 +152,6 @@ typedef struct {
|
|
|
|
|
time_t *last_generated_accesslog_ts_ptr; |
|
|
|
|
|
|
|
|
|
buffer *ts_accesslog_str; |
|
|
|
|
buffer *ts_accesslog_fmt_str; |
|
|
|
|
unsigned short append_tz_offset; |
|
|
|
|
|
|
|
|
|
format_fields *parsed_format; |
|
|
|
|
} plugin_config; |
|
|
|
@ -288,6 +300,7 @@ static int accesslog_parse_format(server *srv, format_fields *fields, buffer *fo
|
|
|
|
|
fields->ptr[fields->used]->type = FIELD_FORMAT; |
|
|
|
|
fields->ptr[fields->used]->field = fmap[j].type; |
|
|
|
|
fields->ptr[fields->used]->string = NULL; |
|
|
|
|
fields->ptr[fields->used]->opt = 0; |
|
|
|
|
|
|
|
|
|
fields->used++; |
|
|
|
|
|
|
|
|
@ -335,6 +348,7 @@ static int accesslog_parse_format(server *srv, format_fields *fields, buffer *fo
|
|
|
|
|
fields->ptr[fields->used]->type = FIELD_FORMAT; |
|
|
|
|
fields->ptr[fields->used]->field = fmap[j].type; |
|
|
|
|
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)); |
|
|
|
|
|
|
|
|
@ -368,6 +382,7 @@ static int accesslog_parse_format(server *srv, format_fields *fields, buffer *fo
|
|
|
|
|
fields->ptr[fields->used]->type = FIELD_FORMAT; |
|
|
|
|
fields->ptr[fields->used]->field = fmap[j].type; |
|
|
|
|
fields->ptr[fields->used]->string = NULL; |
|
|
|
|
fields->ptr[fields->used]->opt = 0; |
|
|
|
|
|
|
|
|
|
fields->used++; |
|
|
|
|
|
|
|
|
@ -434,7 +449,6 @@ FREE_FUNC(mod_accesslog_free) {
|
|
|
|
|
if (s->log_access_fd != -1) close(s->log_access_fd); |
|
|
|
|
|
|
|
|
|
buffer_free(s->ts_accesslog_str); |
|
|
|
|
buffer_free(s->ts_accesslog_fmt_str); |
|
|
|
|
buffer_free(s->access_logbuffer); |
|
|
|
|
buffer_free(s->format); |
|
|
|
|
buffer_free(s->access_logfile); |
|
|
|
@ -486,7 +500,6 @@ SETDEFAULTS_FUNC(log_access_open) {
|
|
|
|
|
s->format = buffer_init(); |
|
|
|
|
s->access_logbuffer = buffer_init(); |
|
|
|
|
s->ts_accesslog_str = buffer_init(); |
|
|
|
|
s->ts_accesslog_fmt_str = buffer_init(); |
|
|
|
|
s->log_access_fd = -1; |
|
|
|
|
s->last_generated_accesslog_ts = 0; |
|
|
|
|
s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts); |
|
|
|
@ -513,7 +526,7 @@ SETDEFAULTS_FUNC(log_access_open) {
|
|
|
|
|
/* parse */ |
|
|
|
|
|
|
|
|
|
if (!buffer_is_empty(s->format)) { |
|
|
|
|
size_t j, count; |
|
|
|
|
size_t j, tcount = 0; |
|
|
|
|
|
|
|
|
|
s->parsed_format = calloc(1, sizeof(*(s->parsed_format))); |
|
|
|
|
|
|
|
|
@ -525,25 +538,65 @@ SETDEFAULTS_FUNC(log_access_open) {
|
|
|
|
|
return HANDLER_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* make sure they didn't try to send the timestamp in twice...
|
|
|
|
|
* also, save the format string in a different variable (this |
|
|
|
|
* will save a few conditionals later) |
|
|
|
|
*/ |
|
|
|
|
count = 0; |
|
|
|
|
for (j = 0; j < s->parsed_format->used; j++) { |
|
|
|
|
if (FIELD_FORMAT == s->parsed_format->ptr[j]->type) { |
|
|
|
|
if (FORMAT_TIMESTAMP == s->parsed_format->ptr[j]->field) { |
|
|
|
|
if (!buffer_string_is_empty(s->parsed_format->ptr[j]->string)) { |
|
|
|
|
buffer_copy_string(s->ts_accesslog_fmt_str, s->parsed_format->ptr[j]->string->ptr); |
|
|
|
|
for (j = 0; j < s->parsed_format->used; ++j) { |
|
|
|
|
format_field * const f = s->parsed_format->ptr[j]; |
|
|
|
|
if (FIELD_FORMAT != f->type) continue; |
|
|
|
|
if (FORMAT_TIMESTAMP == f->field) { |
|
|
|
|
if (!buffer_string_is_empty(f->string)) { |
|
|
|
|
const char *ptr = f->string->ptr; |
|
|
|
|
if (0 == strncmp(ptr, "begin:", sizeof("begin:")-1)) { |
|
|
|
|
f->opt |= FORMAT_FLAG_TIME_BEGIN; |
|
|
|
|
ptr += sizeof("begin:")-1; |
|
|
|
|
} else if (0 == strncmp(ptr, "end:", sizeof("end:")-1)) { |
|
|
|
|
f->opt |= FORMAT_FLAG_TIME_END; |
|
|
|
|
ptr += sizeof("end:")-1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (++count > 1) { |
|
|
|
|
if (0 == strcmp(ptr, "sec")) f->opt |= FORMAT_FLAG_TIME_SEC; |
|
|
|
|
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", |
|
|
|
|
"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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* 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) { |
|
|
|
|
const char * const ptr = f->string->ptr; |
|
|
|
|
|
|
|
|
|
if (f->opt & ~(FORMAT_FLAG_TIME_SEC)) srv->srvconf.high_precision_timestamps = 1; |
|
|
|
|
|
|
|
|
|
if (buffer_string_is_empty(f->string) |
|
|
|
|
|| 0 == strcmp(ptr, "s") || 0 == strcmp(ptr, "sec")) f->opt |= FORMAT_FLAG_TIME_SEC; |
|
|
|
|
else if (0 == strcmp(ptr, "ms") || 0 == strcmp(ptr, "msec")) f->opt |= FORMAT_FLAG_TIME_MSEC; |
|
|
|
|
else if (0 == strcmp(ptr, "us") || 0 == strcmp(ptr, "usec")) f->opt |= FORMAT_FLAG_TIME_USEC; |
|
|
|
|
else if (0 == strcmp(ptr, "ns") || 0 == strcmp(ptr, "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)*/ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -567,16 +620,6 @@ SETDEFAULTS_FUNC(log_access_open) {
|
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s->append_tz_offset = 0; |
|
|
|
|
if (buffer_string_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) { |
|
|
|
|
/* ignore the next checks */ |
|
|
|
|
continue; |
|
|
|
@ -638,13 +681,10 @@ static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_d
|
|
|
|
|
plugin_config *s = p->config_storage[0]; |
|
|
|
|
|
|
|
|
|
PATCH(access_logfile); |
|
|
|
|
PATCH(format); |
|
|
|
|
PATCH(log_access_fd); |
|
|
|
|
PATCH(last_generated_accesslog_ts_ptr); |
|
|
|
|
PATCH(access_logbuffer); |
|
|
|
|
PATCH(ts_accesslog_str); |
|
|
|
|
PATCH(ts_accesslog_fmt_str); |
|
|
|
|
PATCH(append_tz_offset); |
|
|
|
|
PATCH(parsed_format); |
|
|
|
|
PATCH(use_syslog); |
|
|
|
|
PATCH(syslog_level); |
|
|
|
@ -666,12 +706,9 @@ static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_d
|
|
|
|
|
PATCH(log_access_fd); |
|
|
|
|
PATCH(access_logbuffer); |
|
|
|
|
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) { |
|
|
|
|
PATCH(format); |
|
|
|
|
PATCH(parsed_format); |
|
|
|
|
PATCH(last_generated_accesslog_ts_ptr); |
|
|
|
|
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"))) { |
|
|
|
|
PATCH(use_syslog); |
|
|
|
|
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.syslog-level"))) { |
|
|
|
@ -691,6 +728,7 @@ REQUESTDONE_FUNC(log_access_write) {
|
|
|
|
|
|
|
|
|
|
int newts = 0; |
|
|
|
|
data_string *ds; |
|
|
|
|
struct timespec ts = { 0, 0 }; |
|
|
|
|
|
|
|
|
|
mod_accesslog_patch_connection(srv, con, p); |
|
|
|
|
|
|
|
|
@ -708,34 +746,111 @@ REQUESTDONE_FUNC(log_access_write) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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: |
|
|
|
|
buffer_append_string_buffer(b, p->conf.parsed_format->ptr[j]->string); |
|
|
|
|
buffer_append_string_buffer(b, f->string); |
|
|
|
|
break; |
|
|
|
|
case FIELD_FORMAT: |
|
|
|
|
switch(p->conf.parsed_format->ptr[j]->field) { |
|
|
|
|
switch(f->field) { |
|
|
|
|
case FORMAT_TIMESTAMP: |
|
|
|
|
|
|
|
|
|
/* cache the generated timestamp */ |
|
|
|
|
if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) { |
|
|
|
|
if (f->opt & ~(FORMAT_FLAG_TIME_BEGIN|FORMAT_FLAG_TIME_END)) { |
|
|
|
|
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) clock_gettime(CLOCK_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) clock_gettime(CLOCK_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; |
|
|
|
|
#if defined(HAVE_STRUCT_TM_GMTOFF) |
|
|
|
|
long scd, hrs, min; |
|
|
|
|
#endif |
|
|
|
|
# endif /* HAVE_LOCALTIME_R */ |
|
|
|
|
#else /* HAVE_STRUCT_TM_GMTOFF */ |
|
|
|
|
# ifdef HAVE_GMTIME_R |
|
|
|
|
struct tm tm; |
|
|
|
|
# endif /* HAVE_GMTIME_R */ |
|
|
|
|
#endif /* HAVE_STRUCT_TM_GMTOFF */ |
|
|
|
|
|
|
|
|
|
if (!(f->opt & FORMAT_FLAG_TIME_BEGIN)) { |
|
|
|
|
t = *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts; |
|
|
|
|
newts = 1; |
|
|
|
|
} else { |
|
|
|
|
t = con->request_start; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if defined(HAVE_STRUCT_TM_GMTOFF) |
|
|
|
|
# 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 */ |
|
|
|
|
|
|
|
|
|
buffer_string_prepare_copy(p->conf.ts_accesslog_str, 255); |
|
|
|
|
#if defined(HAVE_STRUCT_TM_GMTOFF) |
|
|
|
|
# ifdef HAVE_LOCALTIME_R |
|
|
|
|
localtime_r(&(srv->cur_ts), &tm); |
|
|
|
|
buffer_append_strftime(p->conf.ts_accesslog_str, p->conf.ts_accesslog_fmt_str->ptr, &tm); |
|
|
|
|
# else /* HAVE_LOCALTIME_R */ |
|
|
|
|
buffer_append_strftime(p->conf.ts_accesslog_str, p->conf.ts_accesslog_fmt_str->ptr, localtime(&(srv->cur_ts))); |
|
|
|
|
# endif /* HAVE_LOCALTIME_R */ |
|
|
|
|
|
|
|
|
|
if (p->conf.append_tz_offset) { |
|
|
|
|
buffer_append_string_len(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-", 1); |
|
|
|
|
|
|
|
|
|
scd = labs(tm.tm_gmtoff); |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
min = (scd % 3600) / 60; |
|
|
|
|
|
|
|
|
@ -746,29 +861,38 @@ REQUESTDONE_FUNC(log_access_write) {
|
|
|
|
|
if (min < 10) buffer_append_string_len(p->conf.ts_accesslog_str, CONST_STR_LEN("0")); |
|
|
|
|
buffer_append_int(p->conf.ts_accesslog_str, min); |
|
|
|
|
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); |
|
|
|
|
buffer_append_strftime(p->conf.ts_accesslog_str, p->conf.ts_accesslog_fmt_str->ptr, &tm); |
|
|
|
|
# else /* HAVE_GMTIME_R */ |
|
|
|
|
buffer_append_strftime(p->conf.ts_accesslog_str, p->conf.ts_accesslog_fmt_str->ptr, gmtime(&(srv->cur_ts))); |
|
|
|
|
# endif /* HAVE_GMTIME_R */ |
|
|
|
|
#endif /* HAVE_STRUCT_TM_GMTOFF */ |
|
|
|
|
|
|
|
|
|
*(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts; |
|
|
|
|
newts = 1; |
|
|
|
|
buffer_append_string_buffer(b, p->conf.ts_accesslog_str); |
|
|
|
|
} |
|
|
|
|
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) clock_gettime(CLOCK_REALTIME, &ts); |
|
|
|
|
tdiff = (off_t)(ts.tv_sec - bs->tv_sec)*1000000000 + (ts.tv_nsec - bs->tv_nsec); |
|
|
|
|
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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
buffer_append_string_buffer(b, p->conf.ts_accesslog_str); |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
case FORMAT_REMOTE_ADDR: |
|
|
|
|
case FORMAT_REMOTE_HOST: |
|
|
|
|
|
|
|
|
|
/* handle inet_ntop cache */ |
|
|
|
|
|
|
|
|
|
buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr))); |
|
|
|
|
|
|
|
|
|
buffer_append_string_buffer(b, con->dst_addr_buf); |
|
|
|
|
break; |
|
|
|
|
case FORMAT_REMOTE_IDENT: |
|
|
|
|
/* ident */ |
|
|
|
@ -799,21 +923,21 @@ REQUESTDONE_FUNC(log_access_write) {
|
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
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); |
|
|
|
|
} else { |
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN("-")); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
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); |
|
|
|
|
} else { |
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN("-")); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
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); |
|
|
|
|
} else { |
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN("-")); |
|
|
|
@ -840,9 +964,6 @@ REQUESTDONE_FUNC(log_access_write) {
|
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN("-")); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case FORMAT_TIME_USED: |
|
|
|
|
buffer_append_int(b, srv->cur_ts - con->request_start); |
|
|
|
|
break; |
|
|
|
|
case FORMAT_SERVER_NAME: |
|
|
|
|
if (!buffer_string_is_empty(con->server_name)) { |
|
|
|
|
buffer_append_string_buffer(b, con->server_name); |
|
|
|
@ -867,6 +988,24 @@ REQUESTDONE_FUNC(log_access_write) {
|
|
|
|
|
case FORMAT_PERCENT: |
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN("%")); |
|
|
|
|
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: |
|
|
|
|
{ |
|
|
|
|
const char *colon; |
|
|
|
@ -900,14 +1039,38 @@ REQUESTDONE_FUNC(log_access_write) {
|
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN("X")); |
|
|
|
|
} |
|
|
|
|
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: |
|
|
|
|
/*
|
|
|
|
|
{ 'a', FORMAT_REMOTE_ADDR }, |
|
|
|
|
{ 'A', FORMAT_LOCAL_ADDR }, |
|
|
|
|
{ 'C', FORMAT_COOKIE }, |
|
|
|
|
{ 'D', FORMAT_TIME_USED_MS }, |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|