summaryrefslogtreecommitdiff
path: root/src/mod_accesslog.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_accesslog.c')
-rw-r--r--src/mod_accesslog.c318
1 files changed, 159 insertions, 159 deletions
diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c
index bdd0dbc..b00cf06 100644
--- a/src/mod_accesslog.c
+++ b/src/mod_accesslog.c
@@ -29,7 +29,7 @@
typedef struct {
char key;
- enum {
+ enum {
FORMAT_UNSET,
FORMAT_UNSUPPORTED,
FORMAT_PERCENT,
@@ -41,7 +41,7 @@ typedef struct {
FORMAT_STATUS,
FORMAT_BYTES_OUT_NO_HEADER,
FORMAT_HEADER,
-
+
FORMAT_REMOTE_ADDR,
FORMAT_LOCAL_ADDR,
FORMAT_COOKIE,
@@ -59,20 +59,20 @@ typedef struct {
FORMAT_CONNECTION_STATUS,
FORMAT_BYTES_IN,
FORMAT_BYTES_OUT,
-
+
FORMAT_RESPONSE_HEADER
} type;
} format_mapping;
/**
- *
- *
+ *
+ *
* "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
- *
+ *
*/
-const format_mapping fmap[] =
-{
+const format_mapping fmap[] =
+{
{ '%', FORMAT_PERCENT },
{ 'h', FORMAT_REMOTE_HOST },
{ 'l', FORMAT_REMOTE_IDENT },
@@ -82,7 +82,7 @@ const format_mapping fmap[] =
{ 's', FORMAT_STATUS },
{ 'b', FORMAT_BYTES_OUT_NO_HEADER },
{ 'i', FORMAT_HEADER },
-
+
{ 'a', FORMAT_REMOTE_ADDR },
{ 'A', FORMAT_LOCAL_ADDR },
{ 'B', FORMAT_BYTES_OUT_NO_HEADER },
@@ -103,23 +103,23 @@ const format_mapping fmap[] =
{ 'X', FORMAT_CONNECTION_STATUS },
{ 'I', FORMAT_BYTES_IN },
{ 'O', FORMAT_BYTES_OUT },
-
+
{ 'o', FORMAT_RESPONSE_HEADER },
-
+
{ '\0', FORMAT_UNSET }
};
typedef struct {
enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
-
+
buffer *string;
int field;
} format_field;
typedef struct {
format_field **ptr;
-
+
size_t used;
size_t size;
} format_fields;
@@ -128,39 +128,39 @@ typedef struct {
buffer *access_logfile;
buffer *format;
unsigned short use_syslog;
-
-
+
+
int log_access_fd;
time_t last_generated_accesslog_ts;
time_t *last_generated_accesslog_ts_ptr;
-
-
+
+
buffer *access_logbuffer;
buffer *ts_accesslog_str;
-
+
format_fields *parsed_format;
} plugin_config;
typedef struct {
PLUGIN_DATA;
-
+
plugin_config **config_storage;
- plugin_config conf;
+ plugin_config conf;
} plugin_data;
INIT_FUNC(mod_accesslog_init) {
plugin_data *p;
-
+
p = calloc(1, sizeof(*p));
-
+
return p;
}
int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
size_t i, j, k = 0, start = 0;
-
+
for (i = 0; i < format->used - 1; i++) {
-
+
switch(format->ptr[i]) {
case '%':
if (start != i) {
@@ -173,19 +173,19 @@ int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
fields->size += 16;
fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
}
-
+
fields->ptr[fields->used] = malloc(sizeof(format_fields));
fields->ptr[fields->used]->type = FIELD_STRING;
fields->ptr[fields->used]->string = buffer_init();
-
+
buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
-
+
fields->used++;
}
-
-
+
+
/* we need a new field */
-
+
if (fields->size == 0) {
fields->size = 16;
fields->used = 0;
@@ -194,43 +194,43 @@ int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
fields->size += 16;
fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
}
-
+
/* search for the terminating command */
switch (format->ptr[i+1]) {
case '>':
case '<':
/* only for s */
-
+
for (j = 0; fmap[j].key != '\0'; j++) {
if (fmap[j].key != format->ptr[i+2]) continue;
-
+
/* found key */
-
+
fields->ptr[fields->used] = malloc(sizeof(format_fields));
fields->ptr[fields->used]->type = FIELD_FORMAT;
fields->ptr[fields->used]->field = fmap[j].type;
fields->ptr[fields->used]->string = NULL;
-
+
fields->used++;
-
+
break;
}
-
+
if (fmap[j].key == '\0') {
log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
return -1;
}
-
+
start = i + 3;
-
+
break;
case '{':
/* go forward to } */
-
+
for (k = i+2; k < format->used - 1; k++) {
if (format->ptr[k] == '}') break;
}
-
+
if (k == format->used - 1) {
log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
return -1;
@@ -239,62 +239,62 @@ int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
return -1;
}
-
+
for (j = 0; fmap[j].key != '\0'; j++) {
if (fmap[j].key != format->ptr[k+1]) continue;
-
+
/* found key */
-
+
fields->ptr[fields->used] = malloc(sizeof(format_fields));
fields->ptr[fields->used]->type = FIELD_FORMAT;
fields->ptr[fields->used]->field = fmap[j].type;
fields->ptr[fields->used]->string = buffer_init();
-
+
buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
-
+
fields->used++;
-
+
break;
}
-
+
if (fmap[j].key == '\0') {
log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
return -1;
}
-
+
start = k + 2;
-
+
break;
default:
for (j = 0; fmap[j].key != '\0'; j++) {
if (fmap[j].key != format->ptr[i+1]) continue;
-
+
/* found key */
-
+
fields->ptr[fields->used] = malloc(sizeof(format_fields));
fields->ptr[fields->used]->type = FIELD_FORMAT;
fields->ptr[fields->used]->field = fmap[j].type;
fields->ptr[fields->used]->string = NULL;
-
+
fields->used++;
-
+
break;
}
-
+
if (fmap[j].key == '\0') {
log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
return -1;
}
-
+
start = i + 2;
-
+
break;
}
-
+
break;
}
}
-
+
if (start < i) {
/* copy the string */
if (fields->size == 0) {
@@ -305,32 +305,32 @@ int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
fields->size += 16;
fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
}
-
+
fields->ptr[fields->used] = malloc(sizeof(format_fields));
fields->ptr[fields->used]->type = FIELD_STRING;
fields->ptr[fields->used]->string = buffer_init();
-
+
buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
-
+
fields->used++;
}
-
+
return 0;
}
FREE_FUNC(mod_accesslog_free) {
plugin_data *p = p_d;
size_t i;
-
+
if (!p) return HANDLER_GO_ON;
-
+
if (p->config_storage) {
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
if (!s) continue;
-
+
if (s->access_logbuffer->used) {
if (s->use_syslog) {
# ifdef HAVE_SYSLOG_H
@@ -342,14 +342,14 @@ FREE_FUNC(mod_accesslog_free) {
write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
}
}
-
+
if (s->log_access_fd != -1) close(s->log_access_fd);
-
+
buffer_free(s->ts_accesslog_str);
buffer_free(s->access_logbuffer);
buffer_free(s->format);
buffer_free(s->access_logfile);
-
+
if (s->parsed_format) {
size_t j;
for (j = 0; j < s->parsed_format->used; j++) {
@@ -359,36 +359,36 @@ FREE_FUNC(mod_accesslog_free) {
free(s->parsed_format->ptr);
free(s->parsed_format);
}
-
+
free(s);
}
-
+
free(p->config_storage);
}
-
+
free(p);
-
+
return HANDLER_GO_ON;
}
SETDEFAULTS_FUNC(log_access_open) {
plugin_data *p = p_d;
size_t i = 0;
-
- config_values_t cv[] = {
+
+ config_values_t cv[] = {
{ "accesslog.filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "accesslog.use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
{ "accesslog.format", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
-
+
if (!p) return HANDLER_ERROR;
-
+
p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s;
-
+
s = calloc(1, sizeof(plugin_config));
s->access_logfile = buffer_init();
s->format = buffer_init();
@@ -397,44 +397,44 @@ SETDEFAULTS_FUNC(log_access_open) {
s->log_access_fd = -1;
s->last_generated_accesslog_ts = 0;
s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
-
-
+
+
cv[0].destination = s->access_logfile;
cv[1].destination = &(s->use_syslog);
cv[2].destination = s->format;
-
+
p->config_storage[i] = s;
-
+
if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
return HANDLER_ERROR;
}
-
+
if (i == 0 && buffer_is_empty(s->format)) {
/* set a default logfile string */
-
+
buffer_copy_string(s->format, "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"");
}
-
+
/* parse */
-
+
if (s->format->used) {
s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
-
+
if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
- log_error_write(srv, __FILE__, __LINE__, "sb",
+ log_error_write(srv, __FILE__, __LINE__, "sb",
"parsing accesslog-definition failed:", s->format);
return HANDLER_ERROR;
}
#if 0
- /* debugging */
+ /* debugging */
for (j = 0; j < s->parsed_format->used; j++) {
switch (s->parsed_format->ptr[j]->type) {
case FIELD_FORMAT:
- log_error_write(srv, __FILE__, __LINE__, "ssds",
+ log_error_write(srv, __FILE__, __LINE__, "ssds",
"config:", "format", s->parsed_format->ptr[j]->field,
- s->parsed_format->ptr[j]->string ?
+ s->parsed_format->ptr[j]->string ?
s->parsed_format->ptr[j]->string->ptr : "" );
break;
case FIELD_STRING:
@@ -446,52 +446,52 @@ SETDEFAULTS_FUNC(log_access_open) {
}
#endif
}
-
+
if (s->use_syslog) {
/* ignore the next checks */
continue;
}
-
+
if (buffer_is_empty(s->access_logfile)) continue;
-
+
if (s->access_logfile->ptr[0] == '|') {
#ifdef HAVE_FORK
/* create write pipe and spawn process */
-
+
int to_log_fds[2];
pid_t pid;
-
+
if (pipe(to_log_fds)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
return HANDLER_ERROR;
}
-
+
/* fork, execve */
switch (pid = fork()) {
- case 0:
+ case 0:
/* child */
-
+
close(STDIN_FILENO);
dup2(to_log_fds[0], STDIN_FILENO);
close(to_log_fds[0]);
/* not needed */
close(to_log_fds[1]);
-
+
/* we don't need the client socket */
for (i = 3; i < 256; i++) {
close(i);
}
-
- /* exec the log-process (skip the | )
- *
+
+ /* exec the log-process (skip the | )
+ *
*/
-
+
execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, NULL);
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "spawning log-process failed: ", strerror(errno),
+ log_error_write(srv, __FILE__, __LINE__, "sss",
+ "spawning log-process failed: ", strerror(errno),
s->access_logfile->ptr + 1);
-
+
exit(-1);
break;
case -1:
@@ -500,27 +500,27 @@ SETDEFAULTS_FUNC(log_access_open) {
break;
default:
close(to_log_fds[0]);
-
+
s->log_access_fd = to_log_fds[1];
-
+
break;
}
#else
return -1;
#endif
- } else if (-1 == (s->log_access_fd =
+ } else if (-1 == (s->log_access_fd =
open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
-
- log_error_write(srv, __FILE__, __LINE__, "ssb",
- "opening access-log failed:",
+
+ log_error_write(srv, __FILE__, __LINE__, "ssb",
+ "opening access-log failed:",
strerror(errno), s->access_logfile);
-
+
return HANDLER_ERROR;
}
fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
-
+
}
-
+
return HANDLER_GO_ON;
}
@@ -529,7 +529,7 @@ SIGHUP_FUNC(log_access_cycle) {
size_t i;
if (!p->config_storage) return HANDLER_GO_ON;
-
+
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
@@ -544,26 +544,26 @@ SIGHUP_FUNC(log_access_cycle) {
} else if (s->log_access_fd != -1) {
write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
}
-
+
buffer_reset(s->access_logbuffer);
}
-
+
if (s->use_syslog == 0 &&
!buffer_is_empty(s->access_logfile) &&
s->access_logfile->ptr[0] != '|') {
-
+
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))) {
-
+
log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
-
+
return HANDLER_ERROR;
}
}
}
-
+
return HANDLER_GO_ON;
}
@@ -572,7 +572,7 @@ SIGHUP_FUNC(log_access_cycle) {
static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
size_t i, j;
plugin_config *s = p->config_storage[0];
-
+
PATCH(access_logfile);
PATCH(format);
PATCH(log_access_fd);
@@ -581,19 +581,19 @@ static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_d
PATCH(ts_accesslog_str);
PATCH(parsed_format);
PATCH(use_syslog);
-
+
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
-
+
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
-
+
/* merge config */
for (j = 0; j < dc->value->used; j++) {
data_unset *du = dc->value->data[j];
-
+
if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
PATCH(access_logfile);
PATCH(log_access_fd);
@@ -608,7 +608,7 @@ static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_d
}
}
}
-
+
return 0;
}
#undef PATCH
@@ -617,17 +617,17 @@ REQUESTDONE_FUNC(log_access_write) {
plugin_data *p = p_d;
buffer *b;
size_t j;
-
+
int newts = 0;
data_string *ds;
-
+
mod_accesslog_patch_connection(srv, con, p);
-
+
b = p->conf.access_logbuffer;
if (b->used == 0) {
buffer_copy_string(b, "");
}
-
+
for (j = 0; j < p->conf.parsed_format->used; j++) {
switch(p->conf.parsed_format->ptr[j]->type) {
case FIELD_STRING:
@@ -636,14 +636,14 @@ REQUESTDONE_FUNC(log_access_write) {
case FIELD_FORMAT:
switch(p->conf.parsed_format->ptr[j]->field) {
case FORMAT_TIMESTAMP:
-
+
/* cache the generated timestamp */
if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {
struct tm tm;
#if defined(HAVE_STRUCT_TM_GMTOFF)
long scd, hrs, min;
#endif
-
+
buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
#if defined(HAVE_STRUCT_TM_GMTOFF)
# ifdef HAVE_LOCALTIME_R
@@ -653,17 +653,17 @@ REQUESTDONE_FUNC(log_access_write) {
strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S ", localtime_r(&(srv->cur_ts)));
# endif
p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
-
+
buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-");
-
+
scd = abs(tm.tm_gmtoff);
hrs = scd / 3600;
min = (scd % 3600) / 60;
-
+
/* hours */
if (hrs < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
buffer_append_long(p->conf.ts_accesslog_str, hrs);
-
+
if (min < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
buffer_append_long(p->conf.ts_accesslog_str, min);
BUFFER_APPEND_STRING_CONST(p->conf.ts_accesslog_str, "]");
@@ -676,20 +676,20 @@ REQUESTDONE_FUNC(log_access_write) {
#endif
p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
#endif
-
+
*(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_REMOTE_HOST:
-
+
/* handle inet_ntop cache */
-
+
buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
-
+
break;
case FORMAT_REMOTE_IDENT:
/* ident */
@@ -710,10 +710,10 @@ REQUESTDONE_FUNC(log_access_write) {
case FORMAT_STATUS:
buffer_append_long(b, con->http_status);
break;
-
+
case FORMAT_BYTES_OUT_NO_HEADER:
if (con->bytes_written > 0) {
- buffer_append_off_t(b,
+ buffer_append_off_t(b,
con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
} else {
BUFFER_APPEND_STRING_CONST(b, "-");
@@ -772,7 +772,7 @@ REQUESTDONE_FUNC(log_access_write) {
}
break;
case FORMAT_REQUEST_PROTOCOL:
- buffer_append_string(b,
+ buffer_append_string(b,
con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0");
break;
case FORMAT_REQUEST_METHOD:
@@ -801,7 +801,7 @@ REQUESTDONE_FUNC(log_access_write) {
{ 'D', FORMAT_TIME_USED_MS },
{ 'e', FORMAT_ENV },
*/
-
+
break;
}
break;
@@ -809,7 +809,7 @@ REQUESTDONE_FUNC(log_access_write) {
break;
}
}
-
+
BUFFER_APPEND_STRING_CONST(b, "\n");
if (p->conf.use_syslog || /* syslog doesn't cache */
@@ -828,7 +828,7 @@ REQUESTDONE_FUNC(log_access_write) {
}
buffer_reset(b);
}
-
+
return HANDLER_GO_ON;
}
@@ -836,15 +836,15 @@ REQUESTDONE_FUNC(log_access_write) {
int mod_accesslog_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("accesslog");
-
+
p->init = mod_accesslog_init;
p->set_defaults= log_access_open;
p->cleanup = mod_accesslog_free;
-
+
p->handle_request_done = log_access_write;
p->handle_sighup = log_access_cycle;
-
+
p->data = NULL;
-
+
return 0;
}