-.\" $OpenBSD: httpd.conf.5,v 1.12 2014/07/31 14:18:38 reyk Exp $
+.\" $OpenBSD: httpd.conf.5,v 1.13 2014/08/01 21:51:02 doug Exp $
.\"
.\" Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
.\"
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 31 2014 $
+.Dd $Mdocdate: August 1 2014 $
.Dt HTTPD.CONF 5
.Os
.Sh NAME
.Ic listen on
and
.Ic location .
+.It Oo Ic no Oc Ic log Op Ar style
+Enable writing an access log to syslog.
+The
+.Ar style
+can be
+.Ar common
+or
+.Ar combined .
+It is similar to the Apache and nginx logging format.
+If not specified, the default is
+.Ar common .
.It Ic root Ar directory
Set the document root of the server.
The
-/* $OpenBSD: httpd.h,v 1.27 2014/08/01 08:34:46 florian Exp $ */
+/* $OpenBSD: httpd.h,v 1.28 2014/08/01 21:51:02 doug Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
"\10\01NODELAY\02NO_NODELAY\03SACK\04NO_SACK" \
"\05SOCKET_BUFFER_SIZE\06IP_TTL\07IP_MINTTL\10NO_SPLICE"
+enum log_format {
+ LOG_FORMAT_NONE = -1,
+ LOG_FORMAT_COMMON = 0,
+ LOG_FORMAT_COMBINED,
+};
+
struct server_config {
u_int32_t id;
char name[MAXHOSTNAMELEN];
u_int8_t tcpipttl;
u_int8_t tcpipminttl;
+ enum log_format logformat;
+
TAILQ_ENTRY(server_config) entry;
};
TAILQ_HEAD(serverhosts, server_config);
const char *
server_http_host(struct sockaddr_storage *, char *, size_t);
void server_http_date(char *, size_t);
+int server_log_http(struct client *, u_int, size_t);
/* server_file.c */
int server_file(struct httpd *, struct client *);
-/* $OpenBSD: parse.y,v 1.13 2014/07/31 14:18:38 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.14 2014/08/01 21:51:02 doug Exp $ */
/*
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
%token ALL AUTO DIRECTORY FCGI INDEX LISTEN LOCATION LOG NO ON PORT
%token PREFORK ROOT SERVER SOCKET TYPES UPDATES VERBOSE
-%token ERROR INCLUDE
+%token ERROR INCLUDE COMMON COMBINED
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.number> loglevel
}
| DIRECTORY dirflags
| DIRECTORY '{' dirflags_l '}'
+ | logformat
| fastcgi
| LOCATION STRING {
struct server *s;
}
;
+logformat : LOG COMMON {
+ srv->srv_conf.logformat = LOG_FORMAT_COMMON;
+ }
+ | LOG COMBINED {
+ srv->srv_conf.logformat = LOG_FORMAT_COMBINED;
+ }
+ | NO LOG {
+ srv->srv_conf.logformat = LOG_FORMAT_NONE;
+ }
+ ;
+
types : TYPES '{' optnl mediaopts_l '}'
;
static const struct keywords keywords[] = {
{ "all", ALL },
{ "auto", AUTO },
+ { "combined", COMBINED },
+ { "common", COMMON },
{ "directory", DIRECTORY },
{ "fastcgi", FCGI },
{ "include", INCLUDE },
-/* $OpenBSD: server_http.c,v 1.25 2014/07/31 18:07:11 reyk Exp $ */
+/* $OpenBSD: server_http.c,v 1.26 2014/08/01 21:51:02 doug Exp $ */
/*
* Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
#include <stdio.h>
#include <err.h>
#include <pwd.h>
+#include <syslog.h>
#include <event.h>
#include <fnmatch.h>
if (desc == NULL || (error = server_httperror_byid(code)) == NULL)
return (-1);
+ if (server_log_http(clt, code, size) == -1)
+ return (-1);
+
kv_purge(&desc->http_headers);
/* Add error codes */
const struct http_error *eb = b;
return (ea->error_code - eb->error_code);
}
+
+int
+server_log_http(struct client *clt, u_int code, size_t len)
+{
+ static char tstamp[64];
+ static char ip[INET6_ADDRSTRLEN];
+ time_t t;
+ struct tm *tm;
+ struct server_config *srv_conf;
+ struct http_descriptor *desc;
+ struct kv key, *agent, *referrer;
+
+ if ((srv_conf = clt->clt_srv_conf) == NULL)
+ return (-1);
+ if ((desc = clt->clt_desc) == NULL)
+ return (-1);
+ if (srv_conf->logformat == LOG_FORMAT_NONE)
+ return (0);
+
+ if ((t = time(NULL)) == -1)
+ return (-1);
+ if ((tm = localtime(&t)) == NULL)
+ return (-1);
+ if (strftime(tstamp, sizeof(tstamp), "%d/%b/%Y:%H:%M:%S %z", tm) == 0)
+ return (-1);
+
+ if (clt->clt_ss.ss_family == AF_INET) {
+ struct sockaddr_in *in = (struct sockaddr_in *)&clt->clt_ss;
+ if (inet_ntop(AF_INET, &in->sin_addr, ip, sizeof(ip)) == NULL)
+ return (-1);
+ } else if (clt->clt_ss.ss_family == AF_INET6) {
+ struct sockaddr_in6 *in = (struct sockaddr_in6 *)&clt->clt_ss;
+ if (inet_ntop(AF_INET6, &in->sin6_addr, ip, sizeof(ip)) == NULL)
+ return (-1);
+ } else
+ return (-1);
+
+ /*
+ * For details on common log format, see:
+ * https://httpd.apache.org/docs/current/mod/mod_log_config.html
+ */
+ switch (srv_conf->logformat) {
+ case LOG_FORMAT_COMMON:
+ log_info("%s %s - - [%s] \"%s %s%s%s%s%s\" %03d %zu",
+ srv_conf->name, ip, tstamp,
+ server_httpmethod_byid(desc->http_method),
+ desc->http_path == NULL ? "" : desc->http_path,
+ desc->http_query == NULL ? "" : "?",
+ desc->http_query == NULL ? "" : desc->http_query,
+ desc->http_version == NULL ? "" : " ",
+ desc->http_version == NULL ? "" : desc->http_version,
+ code, len);
+ break;
+
+ case LOG_FORMAT_COMBINED:
+ key.kv_key = "Referer"; /* sic */
+ if ((referrer = kv_find(&desc->http_headers, &key)) != NULL &&
+ referrer->kv_value == NULL)
+ referrer = NULL;
+
+ key.kv_key = "User-Agent";
+ if ((agent = kv_find(&desc->http_headers, &key)) != NULL &&
+ agent->kv_value == NULL)
+ agent = NULL;
+
+ log_info("%s %s - - [%s] \"%s %s%s%s%s%s\" %03d %zu"
+ " \"%s\" \"%s\"",
+ srv_conf->name, ip, tstamp,
+ server_httpmethod_byid(desc->http_method),
+ desc->http_path == NULL ? "" : desc->http_path,
+ desc->http_query == NULL ? "" : "?",
+ desc->http_query == NULL ? "" : desc->http_query,
+ desc->http_version == NULL ? "" : " ",
+ desc->http_version == NULL ? "" : desc->http_version,
+ code, len,
+ referrer == NULL ? "" : referrer->kv_value,
+ agent == NULL ? "" : agent->kv_value);
+ break;
+
+ default:
+ return (-1);
+ }
+
+ return (0);
+}