/* * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include "h2o.h" #include "h2o/serverutil.h" struct st_h2o_access_log_filehandle_t { h2o_logconf_t *logconf; int fd; }; struct st_h2o_access_logger_t { h2o_logger_t super; h2o_access_log_filehandle_t *fh; }; static void log_access(h2o_logger_t *_self, h2o_req_t *req) { struct st_h2o_access_logger_t *self = (struct st_h2o_access_logger_t *)_self; h2o_access_log_filehandle_t *fh = self->fh; char *logline, buf[4096]; size_t len; /* stringify */ len = sizeof(buf); logline = h2o_log_request(fh->logconf, req, &len, buf); /* emit */ write(fh->fd, logline, len); /* free memory */ if (logline != buf) free(logline); } static void on_dispose_handle(void *_fh) { h2o_access_log_filehandle_t *fh = _fh; h2o_logconf_dispose(fh->logconf); close(fh->fd); } int h2o_access_log_open_log(const char *path) { int fd; if (path[0] == '|') { int pipefds[2]; pid_t pid; char *argv[4] = {"/bin/sh", "-c", (char *)(path + 1), NULL}; /* create pipe */ if (pipe(pipefds) != 0) { perror("pipe failed"); return -1; } if (fcntl(pipefds[1], F_SETFD, FD_CLOEXEC) == -1) { perror("failed to set FD_CLOEXEC on pipefds[1]"); return -1; } /* spawn the logger */ int mapped_fds[] = {pipefds[0], 0, /* map pipefds[0] to stdin */ -1}; if ((pid = h2o_spawnp(argv[0], argv, mapped_fds, 0)) == -1) { fprintf(stderr, "failed to open logger: %s:%s\n", path + 1, strerror(errno)); return -1; } /* close the read side of the pipefds and return the write side */ close(pipefds[0]); fd = pipefds[1]; } else { if ((fd = open(path, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0644)) == -1) { fprintf(stderr, "failed to open log file:%s:%s\n", path, strerror(errno)); return -1; } } return fd; } h2o_access_log_filehandle_t *h2o_access_log_open_handle(const char *path, const char *fmt, int escape) { h2o_logconf_t *logconf; int fd; h2o_access_log_filehandle_t *fh; char errbuf[256]; /* default to combined log format */ if (fmt == NULL) fmt = "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\""; if ((logconf = h2o_logconf_compile(fmt, escape, errbuf)) == NULL) { fprintf(stderr, "%s\n", errbuf); return NULL; } /* open log file */ if ((fd = h2o_access_log_open_log(path)) == -1) { h2o_logconf_dispose(logconf); return NULL; } fh = h2o_mem_alloc_shared(NULL, sizeof(*fh), on_dispose_handle); fh->logconf = logconf; fh->fd = fd; return fh; } static void dispose(h2o_logger_t *_self) { struct st_h2o_access_logger_t *self = (void *)_self; h2o_mem_release_shared(self->fh); } h2o_logger_t *h2o_access_log_register(h2o_pathconf_t *pathconf, h2o_access_log_filehandle_t *fh) { struct st_h2o_access_logger_t *self = (void *)h2o_create_logger(pathconf, sizeof(*self)); self->super.dispose = dispose; self->super.log_access = log_access; self->fh = fh; h2o_mem_addref_shared(fh); return &self->super; }