/src/h2o/lib/handler/access_log.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku |
3 | | * |
4 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | | * of this software and associated documentation files (the "Software"), to |
6 | | * deal in the Software without restriction, including without limitation the |
7 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
8 | | * sell copies of the Software, and to permit persons to whom the Software is |
9 | | * furnished to do so, subject to the following conditions: |
10 | | * |
11 | | * The above copyright notice and this permission notice shall be included in |
12 | | * all copies or substantial portions of the Software. |
13 | | * |
14 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
19 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
20 | | * IN THE SOFTWARE. |
21 | | */ |
22 | | #include <errno.h> |
23 | | #include <fcntl.h> |
24 | | #include <inttypes.h> |
25 | | #include <netdb.h> |
26 | | #include <netinet/in.h> |
27 | | #include <stdio.h> |
28 | | #include <stdlib.h> |
29 | | #include <sys/socket.h> |
30 | | #include <sys/types.h> |
31 | | #include "h2o.h" |
32 | | #include "h2o/serverutil.h" |
33 | | |
34 | | struct st_h2o_access_log_filehandle_t { |
35 | | h2o_logconf_t *logconf; |
36 | | int fd; |
37 | | }; |
38 | | |
39 | | struct st_h2o_access_logger_t { |
40 | | h2o_logger_t super; |
41 | | h2o_access_log_filehandle_t *fh; |
42 | | }; |
43 | | |
44 | | static void log_access(h2o_logger_t *_self, h2o_req_t *req) |
45 | 0 | { |
46 | 0 | struct st_h2o_access_logger_t *self = (struct st_h2o_access_logger_t *)_self; |
47 | 0 | h2o_access_log_filehandle_t *fh = self->fh; |
48 | 0 | char *logline, buf[4096]; |
49 | 0 | size_t len; |
50 | | |
51 | | /* stringify */ |
52 | 0 | len = sizeof(buf); |
53 | 0 | logline = h2o_log_request(fh->logconf, req, &len, buf); |
54 | | |
55 | | /* emit */ |
56 | 0 | write(fh->fd, logline, len); |
57 | | |
58 | | /* free memory */ |
59 | 0 | if (logline != buf) |
60 | 0 | free(logline); |
61 | 0 | } |
62 | | |
63 | | static void on_dispose_handle(void *_fh) |
64 | 0 | { |
65 | 0 | h2o_access_log_filehandle_t *fh = _fh; |
66 | |
|
67 | 0 | h2o_logconf_dispose(fh->logconf); |
68 | 0 | close(fh->fd); |
69 | 0 | } |
70 | | |
71 | | int h2o_access_log_open_log(const char *path) |
72 | 0 | { |
73 | 0 | int fd; |
74 | |
|
75 | 0 | if (path[0] == '|') { |
76 | 0 | int pipefds[2]; |
77 | 0 | pid_t pid; |
78 | 0 | char *argv[4] = {"/bin/sh", "-c", (char *)(path + 1), NULL}; |
79 | | /* create pipe */ |
80 | 0 | if (pipe(pipefds) != 0) { |
81 | 0 | h2o_perror("pipe failed"); |
82 | 0 | return -1; |
83 | 0 | } |
84 | 0 | if (fcntl(pipefds[1], F_SETFD, FD_CLOEXEC) == -1) { |
85 | 0 | h2o_perror("failed to set FD_CLOEXEC on pipefds[1]"); |
86 | 0 | return -1; |
87 | 0 | } |
88 | | /* spawn the logger */ |
89 | 0 | int mapped_fds[] = {pipefds[0], 0, /* map pipefds[0] to stdin */ |
90 | 0 | -1}; |
91 | 0 | if ((pid = h2o_spawnp(argv[0], argv, mapped_fds, 0)) == -1) { |
92 | 0 | h2o_error_printf("failed to open logger: %s:%s\n", path + 1, strerror(errno)); |
93 | 0 | return -1; |
94 | 0 | } |
95 | | /* close the read side of the pipefds and return the write side */ |
96 | 0 | close(pipefds[0]); |
97 | 0 | fd = pipefds[1]; |
98 | 0 | } else { |
99 | 0 | struct stat st; |
100 | 0 | int ret; |
101 | |
|
102 | 0 | ret = stat(path, &st); |
103 | 0 | if (ret == 0 && (st.st_mode & S_IFMT) == S_IFSOCK) { |
104 | 0 | struct sockaddr_un sa; |
105 | 0 | if (strlen(path) >= sizeof(sa.sun_path)) { |
106 | 0 | h2o_error_printf("path:%s is too long as a unix socket name", path); |
107 | 0 | return -1; |
108 | 0 | } |
109 | 0 | if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { |
110 | 0 | h2o_error_printf("failed to create socket for log file:%s:%s\n", path, strerror(errno)); |
111 | 0 | return -1; |
112 | 0 | } |
113 | 0 | memset(&sa, 0, sizeof(sa)); |
114 | 0 | sa.sun_family = AF_UNIX; |
115 | 0 | strcpy(sa.sun_path, path); |
116 | 0 | if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { |
117 | 0 | h2o_error_printf("failed to connect socket for log file:%s:%s\n", path, strerror(errno)); |
118 | 0 | close(fd); |
119 | 0 | return -1; |
120 | 0 | } |
121 | |
|
122 | 0 | } else { |
123 | 0 | if ((fd = open(path, O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC, 0644)) == -1) { |
124 | 0 | h2o_error_printf("failed to open log file:%s:%s\n", path, strerror(errno)); |
125 | 0 | return -1; |
126 | 0 | } |
127 | 0 | } |
128 | 0 | } |
129 | | |
130 | 0 | return fd; |
131 | 0 | } |
132 | | |
133 | | h2o_access_log_filehandle_t *h2o_access_log_open_handle(const char *path, const char *fmt, int escape) |
134 | 0 | { |
135 | 0 | h2o_logconf_t *logconf; |
136 | 0 | int fd; |
137 | 0 | h2o_access_log_filehandle_t *fh; |
138 | 0 | char errbuf[256]; |
139 | | |
140 | | /* default to combined log format */ |
141 | 0 | if (fmt == NULL) |
142 | 0 | fmt = "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\""; |
143 | 0 | if ((logconf = h2o_logconf_compile(fmt, escape, errbuf)) == NULL) { |
144 | 0 | h2o_error_printf("%s\n", errbuf); |
145 | 0 | return NULL; |
146 | 0 | } |
147 | | |
148 | | /* open log file */ |
149 | 0 | if ((fd = h2o_access_log_open_log(path)) == -1) { |
150 | 0 | h2o_logconf_dispose(logconf); |
151 | 0 | return NULL; |
152 | 0 | } |
153 | | |
154 | 0 | fh = h2o_mem_alloc_shared(NULL, sizeof(*fh), on_dispose_handle); |
155 | 0 | fh->logconf = logconf; |
156 | 0 | fh->fd = fd; |
157 | 0 | return fh; |
158 | 0 | } |
159 | | |
160 | | static void dispose(h2o_logger_t *_self) |
161 | 0 | { |
162 | 0 | struct st_h2o_access_logger_t *self = (void *)_self; |
163 | |
|
164 | 0 | h2o_mem_release_shared(self->fh); |
165 | 0 | } |
166 | | |
167 | | h2o_logger_t *h2o_access_log_register(h2o_pathconf_t *pathconf, h2o_access_log_filehandle_t *fh) |
168 | 0 | { |
169 | 0 | struct st_h2o_access_logger_t *self = (void *)h2o_create_logger(pathconf, sizeof(*self)); |
170 | |
|
171 | 0 | self->super.dispose = dispose; |
172 | 0 | self->super.log_access = log_access; |
173 | 0 | self->fh = fh; |
174 | 0 | h2o_mem_addref_shared(fh); |
175 | |
|
176 | 0 | return &self->super; |
177 | 0 | } |