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