Mercurial > hg > nginx-vendor-0-7
comparison src/http/ngx_http_log_module.c @ 50:72eb30262aac NGINX_0_1_25
nginx 0.1.25
*) Bugfix: nginx did run on Linux parisc.
*) Feature: nginx now does not start under FreeBSD if the sysctl
kern.ipc.somaxconn value is too big.
*) Bugfix: if a request was internally redirected by the
ngx_http_index_module module to the ngx_http_proxy_module or
ngx_http_fastcgi_module modules, then the index file was not closed
after request completion.
*) Feature: the "proxy_pass" can be used in location with regular
expression.
*) Feature: the ngx_http_rewrite_filter_module module supports the
condition like "if ($HTTP_USER_AGENT ~ MSIE)".
*) Bugfix: nginx started too slow if the large number of addresses and
text values were used in the "geo" directive.
*) Change: a variable name must be declared as "$name" in the "geo"
directive. The previous variant without "$" is still supported, but
will be removed soon.
*) Feature: the "%{VARIABLE}v" logging parameter.
*) Feature: the "set $name value" directive.
*) Bugfix: gcc 4.0 compatibility.
*) Feature: the --with-openssl-opt=OPTIONS autoconfiguration directive.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Sat, 19 Mar 2005 00:00:00 +0300 |
parents | |
children | bcb5fce0b038 |
comparison
equal
deleted
inserted
replaced
49:93dabbc9efb9 | 50:72eb30262aac |
---|---|
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 ngx_http_log_op_t *op); | |
15 static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, | |
16 ngx_http_log_op_t *op); | |
17 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, | |
18 ngx_http_log_op_t *op); | |
19 static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, | |
20 ngx_http_log_op_t *op); | |
21 static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, | |
22 ngx_http_log_op_t *op); | |
23 static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf, | |
24 ngx_http_log_op_t *op); | |
25 static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf, | |
26 ngx_http_log_op_t *op); | |
27 static u_char *ngx_http_log_length(ngx_http_request_t *r, u_char *buf, | |
28 ngx_http_log_op_t *op); | |
29 static u_char *ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, | |
30 ngx_http_log_op_t *op); | |
31 static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, | |
32 ngx_http_log_op_t *op); | |
33 | |
34 static size_t ngx_http_log_request_getlen(ngx_http_request_t *r, | |
35 uintptr_t data); | |
36 static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, | |
37 ngx_http_log_op_t *op); | |
38 | |
39 static ngx_int_t ngx_http_log_header_in_compile(ngx_conf_t *cf, | |
40 ngx_http_log_op_t *op, ngx_str_t *value); | |
41 static size_t ngx_http_log_header_in_getlen(ngx_http_request_t *r, | |
42 uintptr_t data); | |
43 static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, | |
44 ngx_http_log_op_t *op); | |
45 static size_t ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r, | |
46 uintptr_t data); | |
47 static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, | |
48 u_char *buf, ngx_http_log_op_t *op); | |
49 | |
50 static ngx_int_t ngx_http_log_header_out_compile(ngx_conf_t *cf, | |
51 ngx_http_log_op_t *op, ngx_str_t *value); | |
52 static size_t ngx_http_log_header_out_getlen(ngx_http_request_t *r, | |
53 uintptr_t data); | |
54 static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, | |
55 ngx_http_log_op_t *op); | |
56 static size_t ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r, | |
57 uintptr_t data); | |
58 static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, | |
59 u_char *buf, ngx_http_log_op_t *op); | |
60 | |
61 static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r, | |
62 u_char *buf, ngx_http_log_op_t *op); | |
63 static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, | |
64 u_char *buf, ngx_http_log_op_t *op); | |
65 | |
66 static ngx_table_elt_t *ngx_http_log_unknown_header(ngx_list_t *headers, | |
67 ngx_str_t *value); | |
68 | |
69 static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf, | |
70 ngx_http_log_op_t *op, ngx_str_t *value); | |
71 static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r, | |
72 uintptr_t data); | |
73 static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, | |
74 ngx_http_log_op_t *op); | |
75 | |
76 | |
77 static ngx_int_t ngx_http_log_set_formats(ngx_conf_t *cf); | |
78 static void *ngx_http_log_create_main_conf(ngx_conf_t *cf); | |
79 static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf); | |
80 static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, | |
81 void *child); | |
82 static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, | |
83 void *conf); | |
84 static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, | |
85 void *conf); | |
86 | |
87 | |
88 static ngx_command_t ngx_http_log_commands[] = { | |
89 | |
90 { ngx_string("log_format"), | |
91 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, | |
92 ngx_http_log_set_format, | |
93 NGX_HTTP_MAIN_CONF_OFFSET, | |
94 0, | |
95 NULL }, | |
96 | |
97 { ngx_string("access_log"), | |
98 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, | |
99 ngx_http_log_set_log, | |
100 NGX_HTTP_LOC_CONF_OFFSET, | |
101 0, | |
102 NULL }, | |
103 | |
104 ngx_null_command | |
105 }; | |
106 | |
107 | |
108 ngx_http_module_t ngx_http_log_module_ctx = { | |
109 ngx_http_log_set_formats, /* pre conf */ | |
110 | |
111 ngx_http_log_create_main_conf, /* create main configuration */ | |
112 NULL, /* init main configuration */ | |
113 | |
114 NULL, /* create server configuration */ | |
115 NULL, /* merge server configuration */ | |
116 | |
117 ngx_http_log_create_loc_conf, /* create location configration */ | |
118 ngx_http_log_merge_loc_conf /* merge location configration */ | |
119 }; | |
120 | |
121 | |
122 ngx_module_t ngx_http_log_module = { | |
123 NGX_MODULE, | |
124 &ngx_http_log_module_ctx, /* module context */ | |
125 ngx_http_log_commands, /* module directives */ | |
126 NGX_HTTP_MODULE, /* module type */ | |
127 NULL, /* init module */ | |
128 NULL /* init process */ | |
129 }; | |
130 | |
131 | |
132 static ngx_str_t http_access_log = ngx_string(NGX_HTTP_LOG_PATH); | |
133 | |
134 | |
135 static ngx_str_t ngx_http_combined_fmt = | |
136 ngx_string("%addr - - [%time] \"%request\" %status %apache_length " | |
137 "\"%{Referer}i\" \"%{User-Agent}i\""); | |
138 | |
139 | |
140 ngx_http_log_op_name_t ngx_http_log_fmt_ops[] = { | |
141 { ngx_string("addr"), INET_ADDRSTRLEN - 1, NULL, NULL, ngx_http_log_addr }, | |
142 { ngx_string("conn"), NGX_ATOMIC_T_LEN, NULL, NULL, | |
143 ngx_http_log_connection }, | |
144 { ngx_string("pipe"), 1, NULL, NULL, ngx_http_log_pipe }, | |
145 { ngx_string("time"), sizeof("28/Sep/1970:12:00:00 +0600") - 1, | |
146 NULL, NULL, ngx_http_log_time }, | |
147 { ngx_string("msec"), NGX_TIME_T_LEN + 4, NULL, NULL, ngx_http_log_msec }, | |
148 { ngx_string("request_time"), NGX_TIME_T_LEN, NULL, NULL, | |
149 ngx_http_log_request_time }, | |
150 { ngx_string("status"), 3, NULL, NULL, ngx_http_log_status }, | |
151 { ngx_string("length"), NGX_OFF_T_LEN, NULL, NULL, ngx_http_log_length }, | |
152 { ngx_string("apache_length"), NGX_OFF_T_LEN, | |
153 NULL, NULL, ngx_http_log_apache_length }, | |
154 { ngx_string("request_length"), NGX_SIZE_T_LEN, | |
155 NULL, NULL, ngx_http_log_request_length }, | |
156 | |
157 { ngx_string("request"), 0, NULL, | |
158 ngx_http_log_request_getlen, | |
159 ngx_http_log_request }, | |
160 | |
161 { ngx_string("i"), 0, ngx_http_log_header_in_compile, NULL, | |
162 ngx_http_log_header_in }, | |
163 { ngx_string("o"), 0, ngx_http_log_header_out_compile, NULL, | |
164 ngx_http_log_header_out }, | |
165 { ngx_string("v"), 0, ngx_http_log_variable_compile, NULL, | |
166 ngx_http_log_variable }, | |
167 | |
168 { ngx_null_string, 0, NULL, NULL, NULL } | |
169 }; | |
170 | |
171 | |
172 ngx_int_t | |
173 ngx_http_log_handler(ngx_http_request_t *r) | |
174 { | |
175 ngx_uint_t i, l; | |
176 u_char *line, *p; | |
177 size_t len; | |
178 ngx_http_log_t *log; | |
179 ngx_http_log_op_t *op; | |
180 ngx_http_log_loc_conf_t *lcf; | |
181 #if (NGX_WIN32) | |
182 u_long written; | |
183 #endif | |
184 | |
185 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
186 "http log handler"); | |
187 | |
188 lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module); | |
189 | |
190 if (lcf->off) { | |
191 return NGX_OK; | |
192 } | |
193 | |
194 log = lcf->logs->elts; | |
195 for (l = 0; l < lcf->logs->nelts; l++) { | |
196 | |
197 len = 0; | |
198 op = log[l].ops->elts; | |
199 for (i = 0; i < log[l].ops->nelts; i++) { | |
200 if (op[i].len == 0) { | |
201 len += op[i].getlen(r, op[i].data); | |
202 | |
203 } else { | |
204 len += op[i].len; | |
205 } | |
206 } | |
207 | |
208 #if (NGX_WIN32) | |
209 len += 2; | |
210 #else | |
211 len++; | |
212 #endif | |
213 | |
214 line = ngx_palloc(r->pool, len); | |
215 if (line == NULL) { | |
216 return NGX_ERROR; | |
217 } | |
218 | |
219 p = line; | |
220 | |
221 for (i = 0; i < log[l].ops->nelts; i++) { | |
222 p = op[i].run(r, p, &op[i]); | |
223 } | |
224 | |
225 #if (NGX_WIN32) | |
226 *p++ = CR; *p++ = LF; | |
227 WriteFile(log[l].file->fd, line, p - line, &written, NULL); | |
228 #else | |
229 *p++ = LF; | |
230 write(log[l].file->fd, line, p - line); | |
231 #endif | |
232 } | |
233 | |
234 return NGX_OK; | |
235 } | |
236 | |
237 | |
238 static u_char * | |
239 ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf, | |
240 ngx_http_log_op_t *op) | |
241 { | |
242 size_t len; | |
243 uintptr_t data; | |
244 | |
245 len = op->len; | |
246 data = op->data; | |
247 | |
248 while (len--) { | |
249 *buf++ = (u_char) (data & 0xff); | |
250 data >>= 8; | |
251 } | |
252 | |
253 return buf; | |
254 } | |
255 | |
256 | |
257 static u_char * | |
258 ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf, | |
259 ngx_http_log_op_t *op) | |
260 { | |
261 return ngx_cpymem(buf, (u_char *) op->data, op->len); | |
262 } | |
263 | |
264 | |
265 static u_char * | |
266 ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) | |
267 { | |
268 return ngx_cpymem(buf, r->connection->addr_text.data, | |
269 r->connection->addr_text.len); | |
270 } | |
271 | |
272 | |
273 static u_char * | |
274 ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, | |
275 ngx_http_log_op_t *op) | |
276 { | |
277 return ngx_sprintf(buf, "%ui", r->connection->number); | |
278 } | |
279 | |
280 | |
281 static u_char * | |
282 ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) | |
283 { | |
284 if (r->pipeline) { | |
285 *buf = 'p'; | |
286 } else { | |
287 *buf = '.'; | |
288 } | |
289 | |
290 return buf + 1; | |
291 } | |
292 | |
293 | |
294 static u_char * | |
295 ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) | |
296 { | |
297 return ngx_cpymem(buf, ngx_cached_http_log_time.data, | |
298 ngx_cached_http_log_time.len); | |
299 } | |
300 | |
301 | |
302 static u_char * | |
303 ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) | |
304 { | |
305 struct timeval tv; | |
306 | |
307 ngx_gettimeofday(&tv); | |
308 | |
309 return ngx_sprintf(buf, "%l.%03l", tv.tv_sec, tv.tv_usec / 1000); | |
310 } | |
311 | |
312 | |
313 static u_char * | |
314 ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf, | |
315 ngx_http_log_op_t *op) | |
316 { | |
317 time_t elapsed; | |
318 | |
319 elapsed = ngx_time() - r->start_time; | |
320 | |
321 return ngx_sprintf(buf, "%T", elapsed); | |
322 } | |
323 | |
324 | |
325 static size_t | |
326 ngx_http_log_request_getlen(ngx_http_request_t *r, uintptr_t data) | |
327 { | |
328 return r->request_line.len; | |
329 } | |
330 | |
331 | |
332 static u_char * | |
333 ngx_http_log_request(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) | |
334 { | |
335 return ngx_cpymem(buf, r->request_line.data, r->request_line.len); | |
336 } | |
337 | |
338 | |
339 static u_char * | |
340 ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) | |
341 { | |
342 return ngx_sprintf(buf, "%ui", | |
343 r->err_status ? r->err_status : r->headers_out.status); | |
344 } | |
345 | |
346 | |
347 static u_char * | |
348 ngx_http_log_length(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) | |
349 { | |
350 return ngx_sprintf(buf, "%O", r->connection->sent); | |
351 } | |
352 | |
353 | |
354 static u_char * | |
355 ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, | |
356 ngx_http_log_op_t *op) | |
357 { | |
358 off_t length; | |
359 | |
360 length = r->connection->sent - r->header_size; | |
361 | |
362 if (length > 0) { | |
363 return ngx_sprintf(buf, "%O", length); | |
364 } | |
365 | |
366 *buf = '0'; | |
367 | |
368 return buf + 1; | |
369 } | |
370 | |
371 | |
372 static u_char * | |
373 ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, | |
374 ngx_http_log_op_t *op) | |
375 { | |
376 return ngx_sprintf(buf, "%z", r->request_length); | |
377 } | |
378 | |
379 | |
380 static ngx_int_t | |
381 ngx_http_log_header_in_compile(ngx_conf_t *cf, ngx_http_log_op_t *op, | |
382 ngx_str_t *value) | |
383 { | |
384 ngx_uint_t i; | |
385 | |
386 op->len = 0; | |
387 | |
388 for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) { | |
389 | |
390 if (ngx_http_headers_in[i].name.len != value->len) { | |
391 continue; | |
392 } | |
393 | |
394 if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, value->data, | |
395 value->len) == 0) | |
396 { | |
397 op->getlen = ngx_http_log_header_in_getlen; | |
398 op->run = ngx_http_log_header_in; | |
399 op->data = ngx_http_headers_in[i].offset; | |
400 | |
401 return NGX_OK; | |
402 } | |
403 } | |
404 | |
405 op->getlen = ngx_http_log_unknown_header_in_getlen; | |
406 op->run = ngx_http_log_unknown_header_in; | |
407 op->data = (uintptr_t) value; | |
408 | |
409 return NGX_OK; | |
410 } | |
411 | |
412 | |
413 static size_t | |
414 ngx_http_log_header_in_getlen(ngx_http_request_t *r, uintptr_t data) | |
415 { | |
416 ngx_table_elt_t *h; | |
417 | |
418 h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); | |
419 | |
420 if (h) { | |
421 return h->value.len; | |
422 } | |
423 | |
424 return 1; | |
425 } | |
426 | |
427 | |
428 static u_char * | |
429 ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, | |
430 ngx_http_log_op_t *op) | |
431 { | |
432 ngx_table_elt_t *h; | |
433 | |
434 h = *(ngx_table_elt_t **) ((char *) &r->headers_in + op->data); | |
435 | |
436 if (h) { | |
437 return ngx_cpymem(buf, h->value.data, h->value.len); | |
438 } | |
439 | |
440 *buf = '-'; | |
441 | |
442 return buf + 1; | |
443 } | |
444 | |
445 | |
446 static size_t | |
447 ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r, uintptr_t data) | |
448 { | |
449 ngx_table_elt_t *h; | |
450 | |
451 h = ngx_http_log_unknown_header(&r->headers_in.headers, (ngx_str_t *) data); | |
452 | |
453 if (h) { | |
454 return h->value.len; | |
455 } | |
456 | |
457 return 1; | |
458 } | |
459 | |
460 | |
461 static u_char * | |
462 ngx_http_log_unknown_header_in(ngx_http_request_t *r, u_char *buf, | |
463 ngx_http_log_op_t *op) | |
464 { | |
465 ngx_table_elt_t *h; | |
466 | |
467 h = ngx_http_log_unknown_header(&r->headers_in.headers, | |
468 (ngx_str_t *) op->data); | |
469 | |
470 if (h) { | |
471 return ngx_cpymem(buf, h->value.data, h->value.len); | |
472 } | |
473 | |
474 *buf = '-'; | |
475 | |
476 return buf + 1; | |
477 } | |
478 | |
479 | |
480 static ngx_int_t | |
481 ngx_http_log_header_out_compile(ngx_conf_t *cf, ngx_http_log_op_t *op, | |
482 ngx_str_t *value) | |
483 { | |
484 ngx_uint_t i; | |
485 | |
486 op->len = 0; | |
487 | |
488 for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) { | |
489 | |
490 if (ngx_http_headers_out[i].name.len != value->len) { | |
491 continue; | |
492 } | |
493 | |
494 if (ngx_strncasecmp(ngx_http_headers_out[i].name.data, value->data, | |
495 value->len) == 0) | |
496 { | |
497 op->getlen = ngx_http_log_header_out_getlen; | |
498 op->run = ngx_http_log_header_out; | |
499 op->data = ngx_http_headers_out[i].offset; | |
500 | |
501 return NGX_OK; | |
502 } | |
503 } | |
504 | |
505 if (value->len == sizeof("Connection") - 1 | |
506 && ngx_strncasecmp(value->data, "Connection", value->len) == 0) | |
507 { | |
508 op->len = sizeof("keep-alive") - 1; | |
509 op->getlen = NULL; | |
510 op->run = ngx_http_log_connection_header_out; | |
511 op->data = 0; | |
512 return NGX_OK; | |
513 } | |
514 | |
515 if (value->len == sizeof("Transfer-Encoding") - 1 | |
516 && ngx_strncasecmp(value->data, "Transfer-Encoding", value->len) == 0) | |
517 { | |
518 op->len = sizeof("chunked") - 1; | |
519 op->getlen = NULL; | |
520 op->run = ngx_http_log_transfer_encoding_header_out; | |
521 op->data = 0; | |
522 return NGX_OK; | |
523 } | |
524 | |
525 op->getlen = ngx_http_log_unknown_header_out_getlen; | |
526 op->run = ngx_http_log_unknown_header_out; | |
527 op->data = (uintptr_t) value; | |
528 | |
529 return NGX_OK; | |
530 } | |
531 | |
532 | |
533 static size_t | |
534 ngx_http_log_header_out_getlen(ngx_http_request_t *r, uintptr_t data) | |
535 { | |
536 ngx_table_elt_t *h; | |
537 | |
538 h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data); | |
539 | |
540 if (h) { | |
541 return h->value.len; | |
542 } | |
543 | |
544 /* | |
545 * No header pointer was found. | |
546 * However, some headers: "Date", "Server", "Content-Length", | |
547 * and "Last-Modified" have a special handling in the header filter | |
548 * but we do not set up their pointers in the filter because | |
549 * they are too seldom needed to be logged. | |
550 */ | |
551 | |
552 if (data == offsetof(ngx_http_headers_out_t, date)) { | |
553 return ngx_cached_http_time.len; | |
554 } | |
555 | |
556 if (data == offsetof(ngx_http_headers_out_t, server)) { | |
557 return (sizeof(NGINX_VER) - 1); | |
558 } | |
559 | |
560 if (data == offsetof(ngx_http_headers_out_t, content_length)) { | |
561 if (r->headers_out.content_length_n == -1) { | |
562 return 1; | |
563 } | |
564 | |
565 return NGX_OFF_T_LEN; | |
566 } | |
567 | |
568 if (data == offsetof(ngx_http_headers_out_t, last_modified)) { | |
569 if (r->headers_out.last_modified_time == -1) { | |
570 return 1; | |
571 } | |
572 | |
573 return sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; | |
574 } | |
575 | |
576 return 1; | |
577 } | |
578 | |
579 | |
580 static u_char * | |
581 ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, | |
582 ngx_http_log_op_t *op) | |
583 { | |
584 ngx_table_elt_t *h; | |
585 | |
586 h = *(ngx_table_elt_t **) ((char *) &r->headers_out + op->data); | |
587 | |
588 if (h) { | |
589 return ngx_cpymem(buf, h->value.data, h->value.len); | |
590 } | |
591 | |
592 /* | |
593 * No header pointer was found. | |
594 * However, some headers: "Date", "Server", "Content-Length", | |
595 * and "Last-Modified" have a special handling in the header filter | |
596 * but we do not set up their pointers in the filter because | |
597 * they are too seldom needed to be logged. | |
598 */ | |
599 | |
600 if (op->data == offsetof(ngx_http_headers_out_t, date)) { | |
601 return ngx_cpymem(buf, ngx_cached_http_time.data, | |
602 ngx_cached_http_time.len); | |
603 } | |
604 | |
605 if (op->data == offsetof(ngx_http_headers_out_t, server)) { | |
606 return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1); | |
607 } | |
608 | |
609 if (op->data == offsetof(ngx_http_headers_out_t, content_length)) { | |
610 if (r->headers_out.content_length_n == -1) { | |
611 *buf = '-'; | |
612 | |
613 return buf + 1; | |
614 } | |
615 | |
616 return ngx_sprintf(buf, "%O", r->headers_out.content_length_n); | |
617 } | |
618 | |
619 if (op->data == offsetof(ngx_http_headers_out_t, last_modified)) { | |
620 if (r->headers_out.last_modified_time == -1) { | |
621 *buf = '-'; | |
622 | |
623 return buf + 1; | |
624 } | |
625 | |
626 return ngx_http_time(buf, r->headers_out.last_modified_time); | |
627 } | |
628 | |
629 *buf = '-'; | |
630 | |
631 return buf + 1; | |
632 } | |
633 | |
634 | |
635 static size_t | |
636 ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r, uintptr_t data) | |
637 { | |
638 ngx_table_elt_t *h; | |
639 | |
640 h = ngx_http_log_unknown_header(&r->headers_out.headers, | |
641 (ngx_str_t *) data); | |
642 | |
643 if (h) { | |
644 return h->value.len; | |
645 } | |
646 | |
647 return 1; | |
648 } | |
649 | |
650 | |
651 static u_char * | |
652 ngx_http_log_unknown_header_out(ngx_http_request_t *r, u_char *buf, | |
653 ngx_http_log_op_t *op) | |
654 { | |
655 ngx_table_elt_t *h; | |
656 | |
657 h = ngx_http_log_unknown_header(&r->headers_out.headers, | |
658 (ngx_str_t *) op->data); | |
659 | |
660 if (h) { | |
661 return ngx_cpymem(buf, h->value.data, h->value.len); | |
662 } | |
663 | |
664 *buf = '-'; | |
665 | |
666 return buf + 1; | |
667 } | |
668 | |
669 | |
670 static ngx_table_elt_t * | |
671 ngx_http_log_unknown_header(ngx_list_t *headers, ngx_str_t *value) | |
672 { | |
673 ngx_uint_t i; | |
674 ngx_list_part_t *part; | |
675 ngx_table_elt_t *h; | |
676 | |
677 part = &headers->part; | |
678 h = part->elts; | |
679 | |
680 for (i = 0; /* void */; i++) { | |
681 | |
682 if (i >= part->nelts) { | |
683 if (part->next == NULL) { | |
684 break; | |
685 } | |
686 | |
687 part = part->next; | |
688 h = part->elts; | |
689 i = 0; | |
690 } | |
691 | |
692 if (h[i].key.len != value->len) { | |
693 continue; | |
694 } | |
695 | |
696 if (ngx_strncasecmp(h[i].key.data, value->data, value->len) == 0) { | |
697 return &h[i]; | |
698 } | |
699 } | |
700 | |
701 return NULL; | |
702 } | |
703 | |
704 | |
705 static u_char * | |
706 ngx_http_log_connection_header_out(ngx_http_request_t *r, u_char *buf, | |
707 ngx_http_log_op_t *op) | |
708 { | |
709 if (r->keepalive) { | |
710 return ngx_cpymem(buf, "keep-alive", sizeof("keep-alive") - 1); | |
711 | |
712 } else { | |
713 return ngx_cpymem(buf, "close", sizeof("close") - 1); | |
714 } | |
715 } | |
716 | |
717 | |
718 static u_char * | |
719 ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, u_char *buf, | |
720 ngx_http_log_op_t *op) | |
721 { | |
722 if (r->chunked) { | |
723 return ngx_cpymem(buf, "chunked", sizeof("chunked") - 1); | |
724 } | |
725 | |
726 *buf = '-'; | |
727 | |
728 return buf + 1; | |
729 } | |
730 | |
731 | |
732 static ngx_int_t | |
733 ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op, | |
734 ngx_str_t *value) | |
735 { | |
736 ngx_uint_t i; | |
737 ngx_http_variable_t *var; | |
738 | |
739 for (i = 0; i < value->len; i++) { | |
740 value->data[i] = ngx_toupper(value->data[i]); | |
741 } | |
742 | |
743 var = ngx_http_add_variable(cf, value, 0); | |
744 if (var == NULL) { | |
745 return NGX_ERROR; | |
746 } | |
747 | |
748 op->len = 0; | |
749 op->getlen = ngx_http_log_variable_getlen; | |
750 op->run = ngx_http_log_variable; | |
751 op->data = var->index; | |
752 | |
753 return NGX_OK; | |
754 } | |
755 | |
756 | |
757 static size_t | |
758 ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data) | |
759 { | |
760 ngx_http_variable_value_t *value; | |
761 | |
762 value = ngx_http_get_indexed_variable(r, data); | |
763 | |
764 if (value == NULL | |
765 || value == NGX_HTTP_VARIABLE_NOT_FOUND | |
766 || value->text.len == 0) | |
767 { | |
768 return 1; | |
769 } | |
770 | |
771 return value->text.len; | |
772 } | |
773 | |
774 | |
775 static u_char * | |
776 ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) | |
777 { | |
778 ngx_http_variable_value_t *value; | |
779 | |
780 value = ngx_http_get_indexed_variable(r, op->data); | |
781 | |
782 if (value == NULL | |
783 || value == NGX_HTTP_VARIABLE_NOT_FOUND | |
784 || value->text.len == 0) | |
785 { | |
786 *buf = '-'; | |
787 return buf + 1; | |
788 } | |
789 | |
790 return ngx_cpymem(buf, value->text.data, value->text.len); | |
791 } | |
792 | |
793 | |
794 static ngx_int_t | |
795 ngx_http_log_set_formats(ngx_conf_t *cf) | |
796 { | |
797 ngx_http_log_op_name_t *op; | |
798 | |
799 for (op = ngx_http_log_fmt_ops; op->name.len; op++) { /* void */ } | |
800 op->run = NULL; | |
801 | |
802 return NGX_OK; | |
803 } | |
804 | |
805 | |
806 static void * | |
807 ngx_http_log_create_main_conf(ngx_conf_t *cf) | |
808 { | |
809 ngx_http_log_main_conf_t *conf; | |
810 | |
811 char *rc; | |
812 ngx_str_t *value; | |
813 | |
814 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t)); | |
815 if (conf == NULL) { | |
816 return NGX_CONF_ERROR; | |
817 } | |
818 | |
819 if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t)) | |
820 == NGX_ERROR) | |
821 { | |
822 return NGX_CONF_ERROR; | |
823 } | |
824 | |
825 cf->args->nelts = 0; | |
826 | |
827 value = ngx_array_push(cf->args); | |
828 if (value == NULL) { | |
829 return NGX_CONF_ERROR; | |
830 } | |
831 | |
832 value = ngx_array_push(cf->args); | |
833 if (value == NULL) { | |
834 return NGX_CONF_ERROR; | |
835 } | |
836 | |
837 value->len = sizeof("combined") - 1; | |
838 value->data = (u_char *) "combined"; | |
839 | |
840 value = ngx_array_push(cf->args); | |
841 if (value == NULL) { | |
842 return NGX_CONF_ERROR; | |
843 } | |
844 | |
845 *value = ngx_http_combined_fmt; | |
846 | |
847 rc = ngx_http_log_set_format(cf, NULL, conf); | |
848 if (rc != NGX_CONF_OK) { | |
849 return NULL; | |
850 } | |
851 | |
852 return conf; | |
853 } | |
854 | |
855 | |
856 static void * | |
857 ngx_http_log_create_loc_conf(ngx_conf_t *cf) | |
858 { | |
859 ngx_http_log_loc_conf_t *conf; | |
860 | |
861 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t)); | |
862 if (conf == NULL) { | |
863 return NGX_CONF_ERROR; | |
864 } | |
865 | |
866 return conf; | |
867 } | |
868 | |
869 | |
870 static char * | |
871 ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) | |
872 { | |
873 ngx_http_log_loc_conf_t *prev = parent; | |
874 ngx_http_log_loc_conf_t *conf = child; | |
875 | |
876 ngx_http_log_t *log; | |
877 ngx_http_log_fmt_t *fmt; | |
878 ngx_http_log_main_conf_t *lmcf; | |
879 | |
880 if (conf->logs == NULL) { | |
881 | |
882 if (conf->off) { | |
883 return NGX_CONF_OK; | |
884 } | |
885 | |
886 if (prev->logs) { | |
887 conf->logs = prev->logs; | |
888 | |
889 } else { | |
890 | |
891 if (prev->off) { | |
892 conf->off = prev->off; | |
893 return NGX_CONF_OK; | |
894 } | |
895 | |
896 conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t)); | |
897 if (conf->logs == NULL) { | |
898 return NGX_CONF_ERROR; | |
899 } | |
900 | |
901 log = ngx_array_push(conf->logs); | |
902 if (log == NULL) { | |
903 return NGX_CONF_ERROR; | |
904 } | |
905 | |
906 log->file = ngx_conf_open_file(cf->cycle, &http_access_log); | |
907 if (log->file == NULL) { | |
908 return NGX_CONF_ERROR; | |
909 } | |
910 | |
911 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module); | |
912 fmt = lmcf->formats.elts; | |
913 | |
914 /* the default "combined" format */ | |
915 log->ops = fmt[0].ops; | |
916 } | |
917 } | |
918 | |
919 return NGX_CONF_OK; | |
920 } | |
921 | |
922 | |
923 static char * | |
924 ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
925 { | |
926 ngx_http_log_loc_conf_t *llcf = conf; | |
927 | |
928 ngx_uint_t i; | |
929 ngx_str_t *value, name; | |
930 ngx_http_log_t *log; | |
931 ngx_http_log_fmt_t *fmt; | |
932 ngx_http_log_main_conf_t *lmcf; | |
933 | |
934 value = cf->args->elts; | |
935 | |
936 if (ngx_strcmp(value[1].data, "off") == 0) { | |
937 llcf->off = 1; | |
938 return NGX_CONF_OK; | |
939 } | |
940 | |
941 if (llcf->logs == NULL) { | |
942 llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t)); | |
943 if (llcf->logs == NULL) { | |
944 return NGX_CONF_ERROR; | |
945 } | |
946 } | |
947 | |
948 lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module); | |
949 | |
950 log = ngx_array_push(llcf->logs); | |
951 if (log == NULL) { | |
952 return NGX_CONF_ERROR; | |
953 } | |
954 | |
955 log->file = ngx_conf_open_file(cf->cycle, &value[1]); | |
956 if (log->file == NULL) { | |
957 return NGX_CONF_ERROR; | |
958 } | |
959 | |
960 if (cf->args->nelts == 3) { | |
961 name = value[2]; | |
962 } else { | |
963 name.len = sizeof("combined") - 1; | |
964 name.data = (u_char *) "combined"; | |
965 } | |
966 | |
967 fmt = lmcf->formats.elts; | |
968 for (i = 0; i < lmcf->formats.nelts; i++) { | |
969 if (fmt[i].name.len == name.len | |
970 && ngx_strcasecmp(fmt[i].name.data, name.data) == 0) | |
971 { | |
972 log->ops = fmt[i].ops; | |
973 return NGX_CONF_OK; | |
974 } | |
975 } | |
976 | |
977 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
978 "unknown log format \"%V\"", &name); | |
979 | |
980 return NGX_CONF_ERROR; | |
981 } | |
982 | |
983 | |
984 static char * | |
985 ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
986 { | |
987 ngx_http_log_main_conf_t *lmcf = conf; | |
988 | |
989 ngx_uint_t s, f, invalid; | |
990 u_char *data, *p, *fname; | |
991 size_t i, len, fname_len; | |
992 ngx_str_t *value, arg, *a; | |
993 ngx_http_log_op_t *op; | |
994 ngx_http_log_fmt_t *fmt; | |
995 ngx_http_log_op_name_t *name; | |
996 | |
997 value = cf->args->elts; | |
998 | |
999 fmt = lmcf->formats.elts; | |
1000 for (f = 0; f < lmcf->formats.nelts; f++) { | |
1001 if (fmt[f].name.len == value[1].len | |
1002 && ngx_strcmp(fmt->name.data, value[1].data) == 0) | |
1003 { | |
1004 return "duplicate \"log_format\" name"; | |
1005 } | |
1006 } | |
1007 | |
1008 fmt = ngx_array_push(&lmcf->formats); | |
1009 if (fmt == NULL) { | |
1010 return NGX_CONF_ERROR; | |
1011 } | |
1012 | |
1013 fmt->name = value[1]; | |
1014 | |
1015 fmt->ops = ngx_array_create(cf->pool, 20, sizeof(ngx_http_log_op_t)); | |
1016 if (fmt->ops == NULL) { | |
1017 return NGX_CONF_ERROR; | |
1018 } | |
1019 | |
1020 invalid = 0; | |
1021 data = NULL; | |
1022 arg.data = NULL; | |
1023 | |
1024 for (s = 2; s < cf->args->nelts && !invalid; s++) { | |
1025 | |
1026 i = 0; | |
1027 | |
1028 while (i < value[s].len) { | |
1029 | |
1030 op = ngx_array_push(fmt->ops); | |
1031 if (op == NULL) { | |
1032 return NGX_CONF_ERROR; | |
1033 } | |
1034 | |
1035 data = &value[s].data[i]; | |
1036 | |
1037 if (value[s].data[i] == '%') { | |
1038 i++; | |
1039 | |
1040 if (i == value[s].len) { | |
1041 invalid = 1; | |
1042 break; | |
1043 } | |
1044 | |
1045 if (value[s].data[i] == '{') { | |
1046 i++; | |
1047 | |
1048 arg.data = &value[s].data[i]; | |
1049 | |
1050 while (i < value[s].len && value[s].data[i] != '}') { | |
1051 i++; | |
1052 } | |
1053 | |
1054 arg.len = &value[s].data[i] - arg.data; | |
1055 | |
1056 if (i == value[s].len || arg.len == 0) { | |
1057 invalid = 1; | |
1058 break; | |
1059 } | |
1060 | |
1061 i++; | |
1062 | |
1063 } else { | |
1064 arg.len = 0; | |
1065 } | |
1066 | |
1067 fname = &value[s].data[i]; | |
1068 | |
1069 while (i < value[s].len | |
1070 && ((value[s].data[i] >= 'a' && value[s].data[i] <= 'z') | |
1071 || value[s].data[i] == '_')) | |
1072 { | |
1073 i++; | |
1074 } | |
1075 | |
1076 fname_len = &value[s].data[i] - fname; | |
1077 | |
1078 if (fname_len == 0) { | |
1079 invalid = 1; | |
1080 break; | |
1081 } | |
1082 | |
1083 for (name = ngx_http_log_fmt_ops; name->run; name++) { | |
1084 if (name->name.len == 0) { | |
1085 name = (ngx_http_log_op_name_t *) name->run; | |
1086 } | |
1087 | |
1088 if (name->name.len == fname_len | |
1089 && ngx_strncmp(name->name.data, fname, fname_len) == 0) | |
1090 { | |
1091 if (name->compile == NULL) { | |
1092 if (arg.len) { | |
1093 fname[fname_len] = '\0'; | |
1094 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1095 "\"%s\" must not have argument", | |
1096 data); | |
1097 return NGX_CONF_ERROR; | |
1098 } | |
1099 | |
1100 op->len = name->len; | |
1101 op->getlen = name->getlen; | |
1102 op->run = name->run; | |
1103 op->data = 0; | |
1104 | |
1105 break; | |
1106 } | |
1107 | |
1108 if (arg.len == 0) { | |
1109 fname[fname_len] = '\0'; | |
1110 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1111 "\"%s\" requires argument", | |
1112 data); | |
1113 return NGX_CONF_ERROR; | |
1114 } | |
1115 | |
1116 a = ngx_palloc(cf->pool, sizeof(ngx_str_t)); | |
1117 if (a == NULL) { | |
1118 return NGX_CONF_ERROR; | |
1119 } | |
1120 | |
1121 *a = arg; | |
1122 if (name->compile(cf, op, a) == NGX_ERROR) { | |
1123 return NGX_CONF_ERROR; | |
1124 } | |
1125 | |
1126 break; | |
1127 } | |
1128 } | |
1129 | |
1130 if (name->name.len == 0) { | |
1131 invalid = 1; | |
1132 break; | |
1133 } | |
1134 | |
1135 } else { | |
1136 i++; | |
1137 | |
1138 while (i < value[s].len && value[s].data[i] != '%') { | |
1139 i++; | |
1140 } | |
1141 | |
1142 len = &value[s].data[i] - data; | |
1143 | |
1144 if (len) { | |
1145 | |
1146 op->len = len; | |
1147 op->getlen = NULL; | |
1148 | |
1149 if (len <= sizeof(uintptr_t)) { | |
1150 op->run = ngx_http_log_copy_short; | |
1151 op->data = 0; | |
1152 | |
1153 while (len--) { | |
1154 op->data <<= 8; | |
1155 op->data |= data[len]; | |
1156 } | |
1157 | |
1158 } else { | |
1159 op->run = ngx_http_log_copy_long; | |
1160 | |
1161 p = ngx_palloc(cf->pool, len); | |
1162 if (p == NULL) { | |
1163 return NGX_CONF_ERROR; | |
1164 } | |
1165 | |
1166 ngx_memcpy(p, data, len); | |
1167 op->data = (uintptr_t) p; | |
1168 } | |
1169 } | |
1170 } | |
1171 } | |
1172 } | |
1173 | |
1174 if (invalid) { | |
1175 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
1176 "invalid parameter \"%s\"", data); | |
1177 return NGX_CONF_ERROR; | |
1178 } | |
1179 | |
1180 return NGX_CONF_OK; | |
1181 } |