Mercurial > hg > nginx-mail
comparison src/http/ngx_http_log_handler.c @ 0:f0b350454894 NGINX_0_1_0
nginx 0.1.0
*) The first public version.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 04 Oct 2004 00:00:00 +0400 |
parents | |
children | 4b2dafa26fe2 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0b350454894 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_http.h> | |
10 #include <nginx.h> | |
11 | |
12 | |
13 static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, | |
14 uintptr_t data); | |
15 static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, | |
16 uintptr_t data); | |
17 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, | |
18 uintptr_t data); | |
19 static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, | |
20 uintptr_t data); | |
21 static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, | |
22 uintptr_t data); | |
23 static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, | |
24 uintptr_t data); | |
25 static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf, | |
26 uintptr_t data); | |
27 static u_char *ngx_http_log_length(ngx_http_request_t *r, u_char *buf, | |
28 uintptr_t data); | |
29 static u_char *ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, | |
30 uintptr_t data); | |
31 static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, | |
32 uintptr_t data); | |
33 static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r, | |
34 u_char *buf, uintptr_t data); | |
35 static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, | |
36 u_char *buf, | |
37 uintptr_t data); | |
38 static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, | |
39 u_char *buf, uintptr_t data); | |
40 static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, | |
41 uintptr_t data); | |
42 static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, u_char *buf, | |
43 uintptr_t data); | |
44 | |
45 static ngx_int_t ngx_http_log_pre_conf(ngx_conf_t *cf); | |
46 static void *ngx_http_log_create_main_conf(ngx_conf_t *cf); | |
47 static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf); | |
48 static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, | |
49 void *child); | |
50 static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, | |
51 void *conf); | |
52 static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, | |
53 void *conf); | |
54 static ngx_int_t ngx_http_log_parse_format(ngx_conf_t *cf, ngx_array_t *ops, | |
55 ngx_str_t *line); | |
56 | |
57 | |
58 static ngx_command_t ngx_http_log_commands[] = { | |
59 | |
60 {ngx_string("log_format"), | |
61 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, | |
62 ngx_http_log_set_format, | |
63 NGX_HTTP_MAIN_CONF_OFFSET, | |
64 0, | |
65 NULL}, | |
66 | |
67 {ngx_string("access_log"), | |
68 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, | |
69 ngx_http_log_set_log, | |
70 NGX_HTTP_LOC_CONF_OFFSET, | |
71 0, | |
72 NULL}, | |
73 | |
74 ngx_null_command | |
75 }; | |
76 | |
77 | |
78 ngx_http_module_t ngx_http_log_module_ctx = { | |
79 ngx_http_log_pre_conf, /* pre conf */ | |
80 | |
81 ngx_http_log_create_main_conf, /* create main configuration */ | |
82 NULL, /* init main configuration */ | |
83 | |
84 NULL, /* create server configuration */ | |
85 NULL, /* merge server configuration */ | |
86 | |
87 ngx_http_log_create_loc_conf, /* create location configration */ | |
88 ngx_http_log_merge_loc_conf /* merge location configration */ | |
89 }; | |
90 | |
91 | |
92 ngx_module_t ngx_http_log_module = { | |
93 NGX_MODULE, | |
94 &ngx_http_log_module_ctx, /* module context */ | |
95 ngx_http_log_commands, /* module directives */ | |
96 NGX_HTTP_MODULE, /* module type */ | |
97 NULL, /* init module */ | |
98 NULL /* init child */ | |
99 }; | |
100 | |
101 | |
102 static ngx_str_t http_access_log = ngx_string(NGX_HTTP_LOG_PATH); | |
103 | |
104 | |
105 static ngx_str_t ngx_http_combined_fmt = | |
106 ngx_string("%addr - - [%time] \"%request\" %status %apache_length " | |
107 "\"%{Referer}i\" \"%{User-Agent}i\""); | |
108 | |
109 | |
110 ngx_http_log_op_name_t ngx_http_log_fmt_ops[] = { | |
111 { ngx_string("addr"), INET_ADDRSTRLEN - 1, ngx_http_log_addr }, | |
112 { ngx_string("conn"), NGX_INT32_LEN, ngx_http_log_connection }, | |
113 { ngx_string("pipe"), 1, ngx_http_log_pipe }, | |
114 { ngx_string("time"), sizeof("28/Sep/1970:12:00:00") - 1, | |
115 ngx_http_log_time }, | |
116 { ngx_string("msec"), TIME_T_LEN + 4, ngx_http_log_msec }, | |
117 { ngx_string("request"), 0, ngx_http_log_request }, | |
118 { ngx_string("status"), 3, ngx_http_log_status }, | |
119 { ngx_string("length"), NGX_OFF_T_LEN, ngx_http_log_length }, | |
120 { ngx_string("apache_length"), NGX_OFF_T_LEN, ngx_http_log_apache_length }, | |
121 { ngx_string("i"), NGX_HTTP_LOG_ARG, ngx_http_log_header_in }, | |
122 { ngx_string("o"), NGX_HTTP_LOG_ARG, ngx_http_log_header_out }, | |
123 { ngx_null_string, 0, NULL } | |
124 }; | |
125 | |
126 | |
127 ngx_int_t ngx_http_log_handler(ngx_http_request_t *r) | |
128 { | |
129 ngx_uint_t i, l; | |
130 uintptr_t data; | |
131 u_char *line, *p; | |
132 size_t len; | |
133 ngx_http_log_t *log; | |
134 ngx_http_log_op_t *op; | |
135 ngx_http_log_loc_conf_t *lcf; | |
136 #if (WIN32) | |
137 u_long written; | |
138 #endif | |
139 | |
140 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
141 "http log handler"); | |
142 | |
143 lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module); | |
144 | |
145 if (lcf->off) { | |
146 return NGX_OK; | |
147 } | |
148 | |
149 log = lcf->logs->elts; | |
150 for (l = 0; l < lcf->logs->nelts; l++) { | |
151 | |
152 len = 0; | |
153 op = log[l].ops->elts; | |
154 for (i = 0; i < log[l].ops->nelts; i++) { | |
155 if (op[i].len == 0) { | |
156 len += (size_t) op[i].op(r, NULL, op[i].data); | |
157 | |
158 } else { | |
159 len += op[i].len; | |
160 } | |
161 } | |
162 | |
163 #if (WIN32) | |
164 len += 2; | |
165 #else | |
166 len++; | |
167 #endif | |
168 | |
169 ngx_test_null(line, ngx_palloc(r->pool, len), NGX_ERROR); | |
170 p = line; | |
171 | |
172 for (i = 0; i < log[l].ops->nelts; i++) { | |
173 if (op[i].op == NGX_HTTP_LOG_COPY_SHORT) { | |
174 len = op[i].len; | |
175 data = op[i].data; | |
176 while (len--) { | |
177 *p++ = (char) (data & 0xff); | |
178 data >>= 8; | |
179 } | |
180 | |
181 } else if (op[i].op == NGX_HTTP_LOG_COPY_LONG) { | |
182 p = ngx_cpymem(p, (void *) op[i].data, op[i].len); | |
183 | |
184 } else { | |
185 p = op[i].op(r, p, op[i].data); | |
186 } | |
187 } | |
188 | |
189 #if (WIN32) | |
190 *p++ = CR; *p++ = LF; | |
191 WriteFile(log[l].file->fd, line, p - line, &written, NULL); | |
192 #else | |
193 *p++ = LF; | |
194 write(log[l].file->fd, line, p - line); | |
195 #endif | |
196 } | |
197 | |
198 return NGX_OK; | |
199 } | |
200 | |
201 | |
202 static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, | |
203 uintptr_t data) | |
204 { | |
205 return ngx_cpymem(buf, r->connection->addr_text.data, | |
206 r->connection->addr_text.len); | |
207 } | |
208 | |
209 | |
210 static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, | |
211 uintptr_t data) | |
212 { | |
213 return buf + ngx_snprintf((char *) buf, NGX_INT_T_LEN + 1, | |
214 "%" NGX_UINT_T_FMT, | |
215 r->connection->number); | |
216 } | |
217 | |
218 | |
219 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, | |
220 uintptr_t data) | |
221 { | |
222 if (r->pipeline) { | |
223 *buf = 'p'; | |
224 } else { | |
225 *buf = '.'; | |
226 } | |
227 | |
228 return buf + 1; | |
229 } | |
230 | |
231 | |
232 static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, | |
233 uintptr_t data) | |
234 { | |
235 return ngx_cpymem(buf, ngx_cached_http_log_time.data, | |
236 ngx_cached_http_log_time.len); | |
237 } | |
238 | |
239 | |
240 static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, | |
241 uintptr_t data) | |
242 { | |
243 struct timeval tv; | |
244 | |
245 ngx_gettimeofday(&tv); | |
246 | |
247 return buf + ngx_snprintf((char *) buf, TIME_T_LEN + 5, "%ld.%03ld", | |
248 tv.tv_sec, tv.tv_usec / 1000); | |
249 } | |
250 | |
251 | |
252 static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, | |
253 uintptr_t data) | |
254 { | |
255 if (buf == NULL) { | |
256 /* find the request line length */ | |
257 return (u_char *) r->request_line.len; | |
258 } | |
259 | |
260 return ngx_cpymem(buf, r->request_line.data, r->request_line.len); | |
261 } | |
262 | |
263 | |
264 static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf, | |
265 uintptr_t data) | |
266 { | |
267 return buf + ngx_snprintf((char *) buf, 4, "%" NGX_UINT_T_FMT, | |
268 r->err_status ? r->err_status : r->headers_out.status); | |
269 } | |
270 | |
271 | |
272 static u_char *ngx_http_log_length(ngx_http_request_t *r, u_char *buf, | |
273 uintptr_t data) | |
274 { | |
275 return buf + ngx_snprintf((char *) buf, NGX_OFF_T_LEN + 1, OFF_T_FMT, | |
276 r->connection->sent); | |
277 } | |
278 | |
279 | |
280 static u_char *ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, | |
281 uintptr_t data) | |
282 { | |
283 return buf + ngx_snprintf((char *) buf, NGX_OFF_T_LEN + 1, OFF_T_FMT, | |
284 r->connection->sent - r->header_size); | |
285 } | |
286 | |
287 | |
288 static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, | |
289 uintptr_t data) | |
290 { | |
291 ngx_uint_t i; | |
292 ngx_str_t *s; | |
293 ngx_table_elt_t *h; | |
294 ngx_http_log_op_t *op; | |
295 | |
296 if (r) { | |
297 h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); | |
298 | |
299 if (h == NULL) { | |
300 | |
301 /* no header */ | |
302 | |
303 if (buf) { | |
304 *buf = '-'; | |
305 } | |
306 | |
307 return buf + 1; | |
308 } | |
309 | |
310 if (buf == NULL) { | |
311 /* find the header length */ | |
312 return (u_char *) h->value.len; | |
313 } | |
314 | |
315 return ngx_cpymem(buf, h->value.data, h->value.len); | |
316 } | |
317 | |
318 /* find an offset while a format string compilation */ | |
319 | |
320 op = (ngx_http_log_op_t *) buf; | |
321 s = (ngx_str_t *) data; | |
322 | |
323 op->len = 0; | |
324 | |
325 for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) { | |
326 if (ngx_http_headers_in[i].name.len != s->len) { | |
327 continue; | |
328 } | |
329 | |
330 if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, s->data, s->len) | |
331 == 0) | |
332 { | |
333 op->op = ngx_http_log_header_in; | |
334 op->data = ngx_http_headers_in[i].offset; | |
335 return NULL; | |
336 } | |
337 } | |
338 | |
339 op->op = ngx_http_log_unknown_header_in; | |
340 op->data = (uintptr_t) s; | |
341 | |
342 return NULL; | |
343 } | |
344 | |
345 | |
346 static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, | |
347 u_char *buf, uintptr_t data) | |
348 { | |
349 ngx_uint_t i; | |
350 ngx_str_t *s; | |
351 ngx_list_part_t *part; | |
352 ngx_table_elt_t *h; | |
353 | |
354 s = (ngx_str_t *) data; | |
355 | |
356 part = &r->headers_in.headers.part; | |
357 h = part->elts; | |
358 | |
359 for (i = 0; /* void */; i++) { | |
360 | |
361 if (i >= part->nelts) { | |
362 if (part->next == NULL) { | |
363 break; | |
364 } | |
365 | |
366 part = part->next; | |
367 h = part->elts; | |
368 i = 0; | |
369 } | |
370 | |
371 if (h[i].key.len != s->len) { | |
372 continue; | |
373 } | |
374 | |
375 if (ngx_strncasecmp(h[i].key.data, s->data, s->len) == 0) { | |
376 if (buf == NULL) { | |
377 /* find the header length */ | |
378 return (u_char *) h[i].value.len; | |
379 } | |
380 | |
381 return ngx_cpymem(buf, h[i].value.data, h[i].value.len); | |
382 } | |
383 } | |
384 | |
385 /* no header */ | |
386 | |
387 if (buf) { | |
388 *buf = '-'; | |
389 } | |
390 | |
391 return buf + 1; | |
392 } | |
393 | |
394 | |
395 static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, | |
396 uintptr_t data) | |
397 { | |
398 ngx_uint_t i; | |
399 ngx_str_t *s; | |
400 ngx_table_elt_t *h; | |
401 ngx_http_log_op_t *op; | |
402 | |
403 if (r) { | |
404 | |
405 /* run-time execution */ | |
406 | |
407 if (r->http_version < NGX_HTTP_VERSION_10) { | |
408 if (buf) { | |
409 *buf = '-'; | |
410 } | |
411 | |
412 return buf + 1; | |
413 } | |
414 | |
415 h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data); | |
416 | |
417 if (h == NULL) { | |
418 | |
419 /* | |
420 * No header pointer was found. | |
421 * However, some headers: "Date", "Server", "Content-Length", | |
422 * and "Last-Modified" have a special handling in the header filter | |
423 * but we do not set up their pointers in the filter because | |
424 * they are too seldom needed to be logged. | |
425 */ | |
426 | |
427 if (data == offsetof(ngx_http_headers_out_t, date)) { | |
428 if (buf == NULL) { | |
429 return (u_char *) ngx_cached_http_time.len; | |
430 } | |
431 return ngx_cpymem(buf, ngx_cached_http_time.data, | |
432 ngx_cached_http_time.len); | |
433 } | |
434 | |
435 if (data == offsetof(ngx_http_headers_out_t, server)) { | |
436 if (buf == NULL) { | |
437 return (u_char *) (sizeof(NGINX_VER) - 1); | |
438 } | |
439 return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1); | |
440 } | |
441 | |
442 if (data == offsetof(ngx_http_headers_out_t, content_length)) { | |
443 if (r->headers_out.content_length_n == -1) { | |
444 if (buf) { | |
445 *buf = '-'; | |
446 } | |
447 return buf + 1; | |
448 } | |
449 | |
450 if (buf == NULL) { | |
451 return (u_char *) NGX_OFF_T_LEN; | |
452 } | |
453 return buf + ngx_snprintf((char *) buf, | |
454 NGX_OFF_T_LEN + 2, OFF_T_FMT, | |
455 r->headers_out.content_length_n); | |
456 } | |
457 | |
458 if (data == offsetof(ngx_http_headers_out_t, last_modified)) { | |
459 if (r->headers_out.last_modified_time == -1) { | |
460 if (buf) { | |
461 *buf = '-'; | |
462 } | |
463 return buf + 1; | |
464 } | |
465 | |
466 if (buf == NULL) { | |
467 return (u_char *) | |
468 sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; | |
469 } | |
470 return buf + ngx_http_time(buf, | |
471 r->headers_out.last_modified_time); | |
472 } | |
473 | |
474 if (buf) { | |
475 *buf = '-'; | |
476 } | |
477 | |
478 return buf + 1; | |
479 } | |
480 | |
481 if (buf == NULL) { | |
482 /* find the header length */ | |
483 return (u_char *) h->value.len; | |
484 } | |
485 | |
486 return ngx_cpymem(buf, h->value.data, h->value.len); | |
487 } | |
488 | |
489 /* find an offset while a format string compilation */ | |
490 | |
491 op = (ngx_http_log_op_t *) buf; | |
492 s = (ngx_str_t *) data; | |
493 | |
494 op->len = 0; | |
495 | |
496 for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) { | |
497 if (ngx_http_headers_out[i].name.len != s->len) { | |
498 continue; | |
499 } | |
500 | |
501 if (ngx_strncasecmp(ngx_http_headers_out[i].name.data, s->data, s->len) | |
502 == 0) | |
503 { | |
504 op->op = ngx_http_log_header_out; | |
505 op->data = ngx_http_headers_out[i].offset; | |
506 return NULL; | |
507 } | |
508 } | |
509 | |
510 if (s->len == sizeof("Connection") - 1 | |
511 && ngx_strncasecmp(s->data, "Connection", s->len) == 0) | |
512 { | |
513 op->op = ngx_http_log_connection_header_out; | |
514 op->data = (uintptr_t) NULL; | |
515 return NULL; | |
516 } | |
517 | |
518 if (s->len == sizeof("Transfer-Encoding") - 1 | |
519 && ngx_strncasecmp(s->data, "Transfer-Encoding", s->len) == 0) { | |
520 op->op = ngx_http_log_transfer_encoding_header_out; | |
521 op->data = (uintptr_t) NULL; | |
522 return NULL; | |
523 } | |
524 | |
525 op->op = ngx_http_log_unknown_header_out; | |
526 op->data = (uintptr_t) s; | |
527 | |
528 return NULL; | |
529 } | |
530 | |
531 | |
532 static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r, | |
533 u_char *buf, uintptr_t data) | |
534 { | |
535 if (buf == NULL) { | |
536 return (u_char *) ((r->keepalive) ? sizeof("keep-alive") - 1: | |
537 sizeof("close") - 1); | |
538 } | |
539 | |
540 if (r->keepalive) { | |
541 return ngx_cpymem(buf, "keep-alive", sizeof("keep-alive") - 1); | |
542 | |
543 } else { | |
544 return ngx_cpymem(buf, "close", sizeof("close") - 1); | |
545 } | |
546 } | |
547 | |
548 | |
549 static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, | |
550 u_char *buf, | |
551 uintptr_t data) | |
552 { | |
553 if (buf == NULL) { | |
554 return (u_char *) ((r->chunked) ? sizeof("chunked") - 1 : 1); | |
555 } | |
556 | |
557 if (r->chunked) { | |
558 return ngx_cpymem(buf, "chunked", sizeof("chunked") - 1); | |
559 } | |
560 | |
561 *buf = '-'; | |
562 | |
563 return buf + 1; | |
564 } | |
565 | |
566 | |
567 static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, | |
568 u_char *buf, | |
569 uintptr_t data) | |
570 { | |
571 ngx_uint_t i; | |
572 ngx_str_t *s; | |
573 ngx_list_part_t *part; | |
574 ngx_table_elt_t *h; | |
575 | |
576 s = (ngx_str_t *) data; | |
577 | |
578 part = &r->headers_out.headers.part; | |
579 h = part->elts; | |
580 | |
581 for (i = 0; /* void */; i++) { | |
582 | |
583 if (i >= part->nelts) { | |
584 if (part->next == NULL) { | |
585 break; | |
586 } | |
587 | |
588 part = part->next; | |
589 h = part->elts; | |
590 i = 0; | |
591 } | |
592 | |
593 if (h[i].key.len != s->len) { | |
594 continue; | |
595 } | |
596 | |
597 if (ngx_strncasecmp(h[i].key.data, s->data, s->len) == 0) { | |
598 if (buf == NULL) { | |
599 /* find the header length */ | |
600 return (u_char *) h[i].value.len; | |
601 } | |
602 | |
603 return ngx_cpymem(buf, h[i].value.data, h[i].value.len); | |
604 } | |
605 } | |
606 | |
607 /* no header */ | |
608 | |
609 if (buf) { | |
610 *buf = '-'; | |
611 } | |
612 | |
613 return buf + 1; | |
614 } | |
615 | |
616 | |
617 static ngx_int_t ngx_http_log_pre_conf(ngx_conf_t *cf) | |
618 { | |
619 ngx_http_log_op_name_t *op; | |
620 | |
621 for (op = ngx_http_log_fmt_ops; op->name.len; op++) { /* void */ } | |
622 op->op = NULL; | |
623 | |
624 return NGX_OK; | |
625 } | |
626 | |
627 | |
628 static void *ngx_http_log_create_main_conf(ngx_conf_t *cf) | |
629 { | |
630 ngx_http_log_main_conf_t *conf; | |
631 | |
632 char *rc; | |
633 ngx_str_t *value; | |
634 | |
635 if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t)))) { | |
636 return NGX_CONF_ERROR; | |
637 } | |
638 | |
639 ngx_init_array(conf->formats, cf->pool, 5, sizeof(ngx_http_log_fmt_t), | |
640 NGX_CONF_ERROR); | |
641 | |
642 cf->args->nelts = 0; | |
643 | |
644 if (!(value = ngx_push_array(cf->args))) { | |
645 return NGX_CONF_ERROR; | |
646 } | |
647 | |
648 if (!(value = ngx_push_array(cf->args))) { | |
649 return NGX_CONF_ERROR; | |
650 } | |
651 | |
652 value->len = sizeof("combined") - 1; | |
653 value->data = (u_char *) "combined"; | |
654 | |
655 if (!(value = ngx_push_array(cf->args))) { | |
656 return NGX_CONF_ERROR; | |
657 } | |
658 | |
659 *value = ngx_http_combined_fmt; | |
660 | |
661 rc = ngx_http_log_set_format(cf, NULL, conf); | |
662 if (rc != NGX_CONF_OK) { | |
663 return NULL; | |
664 } | |
665 | |
666 return conf; | |
667 } | |
668 | |
669 | |
670 static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf) | |
671 { | |
672 ngx_http_log_loc_conf_t *conf; | |
673 | |
674 if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t)))) { | |
675 return NGX_CONF_ERROR; | |
676 } | |
677 | |
678 return conf; | |
679 } | |
680 | |
681 | |
682 static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, | |
683 void *child) | |
684 { | |
685 ngx_http_log_loc_conf_t *prev = parent; | |
686 ngx_http_log_loc_conf_t *conf = child; | |
687 | |
688 ngx_http_log_t *log; | |
689 ngx_http_log_fmt_t *fmt; | |
690 ngx_http_log_main_conf_t *lmcf; | |
691 | |
692 if (conf->logs == NULL) { | |
693 | |
694 if (conf->off) { | |
695 return NGX_CONF_OK; | |
696 } | |
697 | |
698 if (prev->logs) { | |
699 conf->logs = prev->logs; | |
700 | |
701 } else { | |
702 | |
703 if (prev->off) { | |
704 conf->off = prev->off; | |
705 return NGX_CONF_OK; | |
706 } | |
707 | |
708 conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t)); | |
709 if (conf->logs == NULL) { | |
710 return NGX_CONF_ERROR; | |
711 } | |
712 | |
713 if (!(log = ngx_array_push(conf->logs))) { | |
714 return NGX_CONF_ERROR; | |
715 } | |
716 | |
717 log->file = ngx_conf_open_file(cf->cycle, &http_access_log); | |
718 if (log->file == NULL) { | |
719 return NGX_CONF_ERROR; | |
720 } | |
721 | |
722 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module); | |
723 fmt = lmcf->formats.elts; | |
724 | |
725 /* the default "combined" format */ | |
726 log->ops = fmt[0].ops; | |
727 } | |
728 } | |
729 | |
730 return NGX_CONF_OK; | |
731 } | |
732 | |
733 | |
734 static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, | |
735 void *conf) | |
736 { | |
737 ngx_http_log_loc_conf_t *llcf = conf; | |
738 | |
739 ngx_uint_t i; | |
740 ngx_str_t *value, name; | |
741 ngx_http_log_t *log; | |
742 ngx_http_log_fmt_t *fmt; | |
743 ngx_http_log_main_conf_t *lmcf; | |
744 | |
745 value = cf->args->elts; | |
746 | |
747 if (ngx_strcmp(value[1].data, "off") == 0) { | |
748 llcf->off = 1; | |
749 return NGX_CONF_OK; | |
750 } | |
751 | |
752 if (llcf->logs == NULL) { | |
753 llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t)); | |
754 if (llcf->logs == NULL) { | |
755 return NGX_CONF_ERROR; | |
756 } | |
757 } | |
758 | |
759 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module); | |
760 | |
761 if (!(log = ngx_array_push(llcf->logs))) { | |
762 return NGX_CONF_ERROR; | |
763 } | |
764 | |
765 if (!(log->file = ngx_conf_open_file(cf->cycle, &value[1]))) { | |
766 return NGX_CONF_ERROR; | |
767 } | |
768 | |
769 if (cf->args->nelts == 3) { | |
770 name = value[2]; | |
771 } else { | |
772 name.len = sizeof("combined") - 1; | |
773 name.data = (u_char *) "combined"; | |
774 } | |
775 | |
776 fmt = lmcf->formats.elts; | |
777 for (i = 0; i < lmcf->formats.nelts; i++) { | |
778 if (fmt[i].name.len == name.len | |
779 && ngx_strcasecmp(fmt[i].name.data, name.data) == 0) | |
780 { | |
781 log->ops = fmt[i].ops; | |
782 return NGX_CONF_OK; | |
783 } | |
784 } | |
785 | |
786 return NGX_CONF_OK; | |
787 } | |
788 | |
789 | |
790 static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, | |
791 void *conf) | |
792 { | |
793 ngx_http_log_main_conf_t *lmcf = conf; | |
794 | |
795 ngx_uint_t s, f, invalid; | |
796 u_char *data, *p, *fname; | |
797 size_t i, len, fname_len; | |
798 ngx_str_t *value, arg, *a; | |
799 ngx_http_log_op_t *op; | |
800 ngx_http_log_fmt_t *fmt; | |
801 ngx_http_log_op_name_t *name; | |
802 | |
803 value = cf->args->elts; | |
804 | |
805 fmt = lmcf->formats.elts; | |
806 for (f = 0; f < lmcf->formats.nelts; f++) { | |
807 if (fmt[f].name.len == value[1].len | |
808 && ngx_strcmp(fmt->name.data, value[1].data) == 0) | |
809 { | |
810 return "duplicate \"log_format\" name"; | |
811 } | |
812 } | |
813 | |
814 if (!(fmt = ngx_push_array(&lmcf->formats))) { | |
815 return NGX_CONF_ERROR; | |
816 } | |
817 | |
818 fmt->name = value[1]; | |
819 | |
820 if (!(fmt->ops = ngx_create_array(cf->pool, 20, | |
821 sizeof(ngx_http_log_op_t)))) { | |
822 return NGX_CONF_ERROR; | |
823 } | |
824 | |
825 invalid = 0; | |
826 data = NULL; | |
827 | |
828 for (s = 2; s < cf->args->nelts && !invalid; s++) { | |
829 | |
830 i = 0; | |
831 | |
832 while (i < value[s].len) { | |
833 | |
834 if (!(op = ngx_push_array(fmt->ops))) { | |
835 return NGX_CONF_ERROR; | |
836 } | |
837 | |
838 data = &value[s].data[i]; | |
839 | |
840 if (value[s].data[i] == '%') { | |
841 i++; | |
842 | |
843 if (i == value[s].len) { | |
844 invalid = 1; | |
845 break; | |
846 } | |
847 | |
848 if (value[s].data[i] == '{') { | |
849 i++; | |
850 | |
851 arg.data = &value[s].data[i]; | |
852 | |
853 while (i < value[s].len && value[s].data[i] != '}') { | |
854 i++; | |
855 } | |
856 | |
857 arg.len = &value[s].data[i] - arg.data; | |
858 | |
859 if (i == value[s].len || arg.len == 0) { | |
860 invalid = 1; | |
861 break; | |
862 } | |
863 | |
864 i++; | |
865 | |
866 } else { | |
867 arg.len = 0; | |
868 } | |
869 | |
870 fname = &value[s].data[i]; | |
871 | |
872 while (i < value[s].len | |
873 && ((value[s].data[i] >= 'a' && value[s].data[i] <= 'z') | |
874 || value[s].data[i] == '_')) | |
875 { | |
876 i++; | |
877 } | |
878 | |
879 fname_len = &value[s].data[i] - fname; | |
880 | |
881 if (fname_len == 0) { | |
882 invalid = 1; | |
883 break; | |
884 } | |
885 | |
886 for (name = ngx_http_log_fmt_ops; name->op; name++) { | |
887 if (name->name.len == 0) { | |
888 name = (ngx_http_log_op_name_t *) name->op; | |
889 } | |
890 | |
891 if (name->name.len == fname_len | |
892 && ngx_strncmp(name->name.data, fname, fname_len) == 0) | |
893 { | |
894 if (name->len != NGX_HTTP_LOG_ARG) { | |
895 if (arg.len) { | |
896 fname[fname_len] = '\0'; | |
897 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
898 "\"%s\" must not have argument", | |
899 data); | |
900 return NGX_CONF_ERROR; | |
901 } | |
902 | |
903 op->len = name->len; | |
904 op->op = name->op; | |
905 op->data = 0; | |
906 | |
907 break; | |
908 } | |
909 | |
910 if (arg.len == 0) { | |
911 fname[fname_len] = '\0'; | |
912 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
913 "\"%s\" requires argument", | |
914 data); | |
915 return NGX_CONF_ERROR; | |
916 } | |
917 | |
918 if (!(a = ngx_palloc(cf->pool, sizeof(ngx_str_t)))) { | |
919 return NGX_CONF_ERROR; | |
920 } | |
921 | |
922 *a = arg; | |
923 name->op(NULL, (u_char *) op, (uintptr_t) a); | |
924 | |
925 break; | |
926 } | |
927 } | |
928 | |
929 if (name->name.len == 0) { | |
930 invalid = 1; | |
931 break; | |
932 } | |
933 | |
934 } else { | |
935 i++; | |
936 | |
937 while (i < value[s].len && value[s].data[i] != '%') { | |
938 i++; | |
939 } | |
940 | |
941 len = &value[s].data[i] - data; | |
942 | |
943 if (len) { | |
944 | |
945 op->len = len; | |
946 | |
947 if (len <= sizeof(uintptr_t)) { | |
948 op->op = NGX_HTTP_LOG_COPY_SHORT; | |
949 op->data = 0; | |
950 | |
951 while (len--) { | |
952 op->data <<= 8; | |
953 op->data |= data[len]; | |
954 } | |
955 | |
956 } else { | |
957 op->op = NGX_HTTP_LOG_COPY_LONG; | |
958 | |
959 if (!(p = ngx_palloc(cf->pool, len))) { | |
960 return NGX_CONF_ERROR; | |
961 } | |
962 | |
963 ngx_memcpy(p, data, len); | |
964 op->data = (uintptr_t) p; | |
965 } | |
966 } | |
967 } | |
968 } | |
969 } | |
970 | |
971 if (invalid) { | |
972 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
973 "invalid parameter \"%s\"", data); | |
974 return NGX_CONF_ERROR; | |
975 } | |
976 | |
977 return NGX_CONF_OK; | |
978 } |