1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Valentin V. Bartenev
5 * Copyright (C) NGINX, Inc.
6 */
7
8 #include <nxt_router.h>
9 #include <nxt_conf.h>
10 #include <nxt_http.h>
11
12
13 typedef struct {
14 nxt_str_t path;
15 nxt_str_t format;
16 nxt_conf_value_t *expr;
17 } nxt_router_access_log_conf_t;
18
19
20 typedef struct {
21 nxt_str_t text;
22 nxt_router_access_log_t *access_log;
23 } nxt_router_access_log_ctx_t;
24
25
26 static void nxt_router_access_log_writer(nxt_task_t *task,
27 nxt_http_request_t *r, nxt_router_access_log_t *access_log,
28 nxt_tstr_t *format);
29 static void nxt_router_access_log_write_ready(nxt_task_t *task, void *obj,
30 void *data);
31 static void nxt_router_access_log_write_error(nxt_task_t *task, void *obj,
32 void *data);
33 static void nxt_router_access_log_ready(nxt_task_t *task,
34 nxt_port_recv_msg_t *msg, void *data);
35 static void nxt_router_access_log_error(nxt_task_t *task,
36 nxt_port_recv_msg_t *msg, void *data);
37 static void nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj,
38 void *data);
39 static void nxt_router_access_log_reopen_ready(nxt_task_t *task,
40 nxt_port_recv_msg_t *msg, void *data);
41 static void nxt_router_access_log_reopen_error(nxt_task_t *task,
42 nxt_port_recv_msg_t *msg, void *data);
43
44
45 static nxt_conf_map_t nxt_router_access_log_conf[] = {
46 {
47 nxt_string("path"),
48 NXT_CONF_MAP_STR,
49 offsetof(nxt_router_access_log_conf_t, path),
50 },
51
52 {
53 nxt_string("format"),
54 NXT_CONF_MAP_STR,
55 offsetof(nxt_router_access_log_conf_t, format),
56 },
57
58 {
59 nxt_string("if"),
60 NXT_CONF_MAP_PTR,
61 offsetof(nxt_router_access_log_conf_t, expr),
62 },
63 };
64
65
66 nxt_int_t
nxt_router_access_log_create(nxt_task_t * task,nxt_router_conf_t * rtcf,nxt_conf_value_t * value)67 nxt_router_access_log_create(nxt_task_t *task, nxt_router_conf_t *rtcf,
68 nxt_conf_value_t *value)
69 {
70 u_char *p;
71 nxt_int_t ret;
72 nxt_str_t str;
73 nxt_tstr_t *format;
74 nxt_router_t *router;
75 nxt_router_access_log_t *access_log;
76 nxt_router_access_log_conf_t alcf;
77
78 static nxt_str_t log_format_str = nxt_string("$remote_addr - - "
79 "[$time_local] \"$request_line\" $status $body_bytes_sent "
80 "\"$header_referer\" \"$header_user_agent\"");
81
82 nxt_memzero(&alcf, sizeof(nxt_router_access_log_conf_t));
83
84 alcf.format = log_format_str;
85
86 if (nxt_conf_type(value) == NXT_CONF_STRING) {
87 nxt_conf_get_string(value, &alcf.path);
88
89 } else {
90 ret = nxt_conf_map_object(rtcf->mem_pool, value,
91 nxt_router_access_log_conf,
92 nxt_nitems(nxt_router_access_log_conf),
93 &alcf);
94 if (ret != NXT_OK) {
95 nxt_alert(task, "access log map error");
96 return NXT_ERROR;
97 }
98 }
99
100 router = nxt_router;
101
102 access_log = router->access_log;
103
104 if (access_log != NULL && nxt_strstr_eq(&alcf.path, &access_log->path)) {
105 nxt_router_access_log_use(&router->lock, access_log);
106
107 } else {
108 access_log = nxt_malloc(sizeof(nxt_router_access_log_t)
109 + alcf.path.length);
110 if (access_log == NULL) {
111 nxt_alert(task, "failed to allocate access log structure");
112 return NXT_ERROR;
113 }
114
115 access_log->fd = -1;
116 access_log->handler = &nxt_router_access_log_writer;
117 access_log->count = 1;
118
119 access_log->path.length = alcf.path.length;
120 access_log->path.start = (u_char *) access_log
121 + sizeof(nxt_router_access_log_t);
122
123 nxt_memcpy(access_log->path.start, alcf.path.start, alcf.path.length);
124 }
125
126 str.length = alcf.format.length + 1;
127
128 str.start = nxt_malloc(str.length);
129 if (str.start == NULL) {
130 nxt_alert(task, "failed to allocate log format structure");
131 return NXT_ERROR;
132 }
133
134 p = nxt_cpymem(str.start, alcf.format.start, alcf.format.length);
135 *p = '\n';
136
137 format = nxt_tstr_compile(rtcf->tstr_state, &str, NXT_TSTR_LOGGING);
138 if (nxt_slow_path(format == NULL)) {
139 return NXT_ERROR;
140 }
141
142 rtcf->access_log = access_log;
143 rtcf->log_format = format;
144
145 if (alcf.expr != NULL) {
146 nxt_conf_get_string(alcf.expr, &str);
147
148 if (str.length > 0 && str.start[0] == '!') {
149 rtcf->log_negate = 1;
150
151 str.start++;
152 str.length--;
153 }
154
155 rtcf->log_expr = nxt_tstr_compile(rtcf->tstr_state, &str, 0);
156 if (nxt_slow_path(rtcf->log_expr == NULL)) {
157 return NXT_ERROR;
158 }
159 }
160
161 return NXT_OK;
162 }
163
164
165 static void
nxt_router_access_log_writer(nxt_task_t * task,nxt_http_request_t * r,nxt_router_access_log_t * access_log,nxt_tstr_t * format)166 nxt_router_access_log_writer(nxt_task_t *task, nxt_http_request_t *r,
167 nxt_router_access_log_t *access_log, nxt_tstr_t *format)
168 {
169 nxt_int_t ret;
170 nxt_router_conf_t *rtcf;
171 nxt_router_access_log_ctx_t *ctx;
172
173 ctx = nxt_mp_get(r->mem_pool, sizeof(nxt_router_access_log_ctx_t));
174 if (nxt_slow_path(ctx == NULL)) {
175 return;
176 }
177
178 ctx->access_log = access_log;
179
180 if (nxt_tstr_is_const(format)) {
181 nxt_tstr_str(format, &ctx->text);
182
183 nxt_router_access_log_write_ready(task, r, ctx);
184
185 } else {
186 rtcf = r->conf->socket_conf->router_conf;
187
188 ret = nxt_tstr_query_init(&r->tstr_query, rtcf->tstr_state,
189 &r->tstr_cache, r, r->mem_pool);
190 if (nxt_slow_path(ret != NXT_OK)) {
191 return;
192 }
193
194 nxt_tstr_query(task, r->tstr_query, format, &ctx->text);
195 nxt_tstr_query_resolve(task, r->tstr_query, ctx,
196 nxt_router_access_log_write_ready,
197 nxt_router_access_log_write_error);
198 }
199 }
200
201
202 static void
nxt_router_access_log_write_ready(nxt_task_t * task,void * obj,void * data)203 nxt_router_access_log_write_ready(nxt_task_t *task, void *obj, void *data)
204 {
205 nxt_http_request_t *r;
206 nxt_router_access_log_ctx_t *ctx;
207
208 r = obj;
209 ctx = data;
210
211 nxt_fd_write(ctx->access_log->fd, ctx->text.start, ctx->text.length);
212
213 nxt_http_request_close_handler(task, r, r->proto.any);
214 }
215
216
217 static void
nxt_router_access_log_write_error(nxt_task_t * task,void * obj,void * data)218 nxt_router_access_log_write_error(nxt_task_t *task, void *obj, void *data)
219 {
220
221 }
222
223
224 void
nxt_router_access_log_open(nxt_task_t * task,nxt_router_temp_conf_t * tmcf)225 nxt_router_access_log_open(nxt_task_t *task, nxt_router_temp_conf_t *tmcf)
226 {
227 uint32_t stream;
228 nxt_int_t ret;
229 nxt_buf_t *b;
230 nxt_port_t *main_port, *router_port;
231 nxt_runtime_t *rt;
232 nxt_router_access_log_t *access_log;
233
234 access_log = tmcf->router_conf->access_log;
235
236 b = nxt_buf_mem_alloc(tmcf->mem_pool, access_log->path.length + 1, 0);
237 if (nxt_slow_path(b == NULL)) {
238 goto fail;
239 }
240
241 b->completion_handler = nxt_buf_dummy_completion;
242
243 nxt_buf_cpystr(b, &access_log->path);
244 *b->mem.free++ = '\0';
245
246 rt = task->thread->runtime;
247 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
248 router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
249
250 stream = nxt_port_rpc_register_handler(task, router_port,
251 nxt_router_access_log_ready,
252 nxt_router_access_log_error,
253 -1, tmcf);
254 if (nxt_slow_path(stream == 0)) {
255 goto fail;
256 }
257
258 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
259 stream, router_port->id, b);
260
261 if (nxt_slow_path(ret != NXT_OK)) {
262 nxt_port_rpc_cancel(task, router_port, stream);
263 goto fail;
264 }
265
266 return;
267
268 fail:
269
270 nxt_router_conf_error(task, tmcf);
271 }
272
273
274 static void
nxt_router_access_log_ready(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)275 nxt_router_access_log_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
276 void *data)
277 {
278 nxt_router_temp_conf_t *tmcf;
279 nxt_router_access_log_t *access_log;
280
281 tmcf = data;
282
283 access_log = tmcf->router_conf->access_log;
284
285 access_log->fd = msg->fd[0];
286
287 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
288 nxt_router_conf_apply, task, tmcf, NULL);
289 }
290
291
292 static void
nxt_router_access_log_error(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)293 nxt_router_access_log_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
294 void *data)
295 {
296 nxt_router_temp_conf_t *tmcf;
297
298 tmcf = data;
299
300 nxt_router_conf_error(task, tmcf);
301 }
302
303
304 void
nxt_router_access_log_use(nxt_thread_spinlock_t * lock,nxt_router_access_log_t * access_log)305 nxt_router_access_log_use(nxt_thread_spinlock_t *lock,
306 nxt_router_access_log_t *access_log)
307 {
308 if (access_log == NULL) {
309 return;
310 }
311
312 nxt_thread_spin_lock(lock);
313
314 access_log->count++;
315
316 nxt_thread_spin_unlock(lock);
317 }
318
319
320 void
nxt_router_access_log_release(nxt_task_t * task,nxt_thread_spinlock_t * lock,nxt_router_access_log_t * access_log)321 nxt_router_access_log_release(nxt_task_t *task, nxt_thread_spinlock_t *lock,
322 nxt_router_access_log_t *access_log)
323 {
324 if (access_log == NULL) {
325 return;
326 }
327
328 nxt_thread_spin_lock(lock);
329
330 if (--access_log->count != 0) {
331 access_log = NULL;
332 }
333
334 nxt_thread_spin_unlock(lock);
335
336 if (access_log != NULL) {
337
338 if (access_log->fd != -1) {
339 nxt_fd_close(access_log->fd);
340 }
341
342 nxt_free(access_log);
343 }
344 }
345
346
347 typedef struct {
348 nxt_mp_t *mem_pool;
349 nxt_router_access_log_t *access_log;
350 } nxt_router_access_log_reopen_t;
351
352
353 void
nxt_router_access_log_reopen_handler(nxt_task_t * task,nxt_port_recv_msg_t * msg)354 nxt_router_access_log_reopen_handler(nxt_task_t *task, nxt_port_recv_msg_t *msg)
355 {
356 nxt_mp_t *mp;
357 uint32_t stream;
358 nxt_int_t ret;
359 nxt_buf_t *b;
360 nxt_port_t *main_port, *router_port;
361 nxt_runtime_t *rt;
362 nxt_router_access_log_t *access_log;
363 nxt_router_access_log_reopen_t *reopen;
364
365 access_log = nxt_router->access_log;
366
367 if (access_log == NULL) {
368 return;
369 }
370
371 mp = nxt_mp_create(1024, 128, 256, 32);
372 if (nxt_slow_path(mp == NULL)) {
373 return;
374 }
375
376 reopen = nxt_mp_get(mp, sizeof(nxt_router_access_log_reopen_t));
377 if (nxt_slow_path(reopen == NULL)) {
378 goto fail;
379 }
380
381 reopen->mem_pool = mp;
382 reopen->access_log = access_log;
383
384 b = nxt_buf_mem_alloc(mp, access_log->path.length + 1, 0);
385 if (nxt_slow_path(b == NULL)) {
386 goto fail;
387 }
388
389 b->completion_handler = nxt_router_access_log_reopen_completion;
390
391 nxt_buf_cpystr(b, &access_log->path);
392 *b->mem.free++ = '\0';
393
394 rt = task->thread->runtime;
395 main_port = rt->port_by_type[NXT_PROCESS_MAIN];
396 router_port = rt->port_by_type[NXT_PROCESS_ROUTER];
397
398 stream = nxt_port_rpc_register_handler(task, router_port,
399 nxt_router_access_log_reopen_ready,
400 nxt_router_access_log_reopen_error,
401 -1, reopen);
402 if (nxt_slow_path(stream == 0)) {
403 goto fail;
404 }
405
406 ret = nxt_port_socket_write(task, main_port, NXT_PORT_MSG_ACCESS_LOG, -1,
407 stream, router_port->id, b);
408
409 if (nxt_slow_path(ret != NXT_OK)) {
410 nxt_port_rpc_cancel(task, router_port, stream);
411 goto fail;
412 }
413
414 nxt_mp_retain(mp);
415
416 return;
417
418 fail:
419
420 nxt_mp_destroy(mp);
421 }
422
423
424 static void
nxt_router_access_log_reopen_completion(nxt_task_t * task,void * obj,void * data)425 nxt_router_access_log_reopen_completion(nxt_task_t *task, void *obj, void *data)
426 {
427 nxt_mp_t *mp;
428 nxt_buf_t *b;
429
430 b = obj;
431 mp = b->data;
432
433 nxt_mp_release(mp);
434 }
435
436
437 static void
nxt_router_access_log_reopen_ready(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)438 nxt_router_access_log_reopen_ready(nxt_task_t *task, nxt_port_recv_msg_t *msg,
439 void *data)
440 {
441 nxt_router_access_log_t *access_log;
442 nxt_router_access_log_reopen_t *reopen;
443
444 reopen = data;
445
446 access_log = reopen->access_log;
447
448 if (access_log == nxt_router->access_log) {
449
450 if (nxt_slow_path(dup2(msg->fd[0], access_log->fd) == -1)) {
451 nxt_alert(task, "dup2(%FD, %FD) failed %E",
452 msg->fd[0], access_log->fd, nxt_errno);
453 }
454 }
455
456 nxt_fd_close(msg->fd[0]);
457 nxt_mp_release(reopen->mem_pool);
458 }
459
460
461 static void
nxt_router_access_log_reopen_error(nxt_task_t * task,nxt_port_recv_msg_t * msg,void * data)462 nxt_router_access_log_reopen_error(nxt_task_t *task, nxt_port_recv_msg_t *msg,
463 void *data)
464 {
465 nxt_router_access_log_reopen_t *reopen;
466
467 reopen = data;
468
469 nxt_mp_release(reopen->mem_pool);
470 }
471