comparison src/http/modules/ngx_http_log_module.c @ 4988:3849bb380605

Access log: the "gzip" parameter of the "access_log" directive. Note: this requires zlib version 1.2.0.4 or above to work.
author Valentin Bartenev <vbart@nginx.com>
date Sun, 23 Dec 2012 19:09:33 +0000
parents 3efc49b156d9
children f1a91825730a 3169a9b2250d
comparison
equal deleted inserted replaced
4987:66d001c5378c 4988:3849bb380605
6 6
7 7
8 #include <ngx_config.h> 8 #include <ngx_config.h>
9 #include <ngx_core.h> 9 #include <ngx_core.h>
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11
12 #if (NGX_ZLIB)
13 #include <zlib.h>
14 #endif
11 15
12 16
13 typedef struct ngx_http_log_op_s ngx_http_log_op_t; 17 typedef struct ngx_http_log_op_s ngx_http_log_op_t;
14 18
15 typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf, 19 typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf,
45 u_char *pos; 49 u_char *pos;
46 u_char *last; 50 u_char *last;
47 51
48 ngx_event_t *event; 52 ngx_event_t *event;
49 ngx_msec_t flush; 53 ngx_msec_t flush;
54 ngx_int_t gzip;
50 } ngx_http_log_buf_t; 55 } ngx_http_log_buf_t;
51 56
52 57
53 typedef struct { 58 typedef struct {
54 ngx_array_t *lengths; 59 ngx_array_t *lengths;
85 90
86 static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, 91 static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
87 u_char *buf, size_t len); 92 u_char *buf, size_t len);
88 static ssize_t ngx_http_log_script_write(ngx_http_request_t *r, 93 static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
89 ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len); 94 ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len);
95
96 #if (NGX_ZLIB)
97 static ssize_t ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len,
98 ngx_int_t level, ngx_log_t *log);
99
100 static void *ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size);
101 static void ngx_http_log_gzip_free(void *opaque, void *address);
102 #endif
90 103
91 static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log); 104 static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log);
92 static void ngx_http_log_flush_handler(ngx_event_t *ev); 105 static void ngx_http_log_flush_handler(ngx_event_t *ev);
93 106
94 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, 107 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
329 342
330 static void 343 static void
331 ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf, 344 ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
332 size_t len) 345 size_t len)
333 { 346 {
334 u_char *name; 347 u_char *name;
335 time_t now; 348 time_t now;
336 ssize_t n; 349 ssize_t n;
337 ngx_err_t err; 350 ngx_err_t err;
351 #if (NGX_ZLIB)
352 ngx_http_log_buf_t *buffer;
353 #endif
338 354
339 if (log->script == NULL) { 355 if (log->script == NULL) {
340 name = log->file->name.data; 356 name = log->file->name.data;
357
358 #if (NGX_ZLIB)
359 buffer = log->file->data;
360
361 if (buffer && buffer->gzip) {
362 n = ngx_http_log_gzip(log->file->fd, buf, len, buffer->gzip,
363 r->connection->log);
364 } else {
365 n = ngx_write_fd(log->file->fd, buf, len);
366 }
367 #else
341 n = ngx_write_fd(log->file->fd, buf, len); 368 n = ngx_write_fd(log->file->fd, buf, len);
369 #endif
342 370
343 } else { 371 } else {
344 name = NULL; 372 name = NULL;
345 n = ngx_http_log_script_write(r, log->script, &name, buf, len); 373 n = ngx_http_log_script_write(r, log->script, &name, buf, len);
346 } 374 }
484 512
485 return n; 513 return n;
486 } 514 }
487 515
488 516
517 #if (NGX_ZLIB)
518
519 static ssize_t
520 ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level,
521 ngx_log_t *log)
522 {
523 int rc, wbits, memlevel;
524 u_char *out;
525 size_t size;
526 ssize_t n;
527 z_stream zstream;
528 ngx_err_t err;
529 ngx_pool_t *pool;
530
531 wbits = MAX_WBITS;
532 memlevel = MAX_MEM_LEVEL - 1;
533
534 while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) {
535 wbits--;
536 memlevel--;
537 }
538
539 /*
540 * This is a formula from deflateBound() for conservative upper bound of
541 * compressed data plus 18 bytes of gzip wrapper.
542 */
543
544 size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18;
545
546 ngx_memzero(&zstream, sizeof(z_stream));
547
548 pool = ngx_create_pool(256, log);
549 if (pool == NULL) {
550 /* simulate successful logging */
551 return len;
552 }
553
554 pool->log = log;
555
556 zstream.zalloc = ngx_http_log_gzip_alloc;
557 zstream.zfree = ngx_http_log_gzip_free;
558 zstream.opaque = pool;
559
560 out = ngx_pnalloc(pool, size);
561 if (out == NULL) {
562 goto done;
563 }
564
565 zstream.next_in = buf;
566 zstream.avail_in = len;
567 zstream.next_out = out;
568 zstream.avail_out = size;
569
570 rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel,
571 Z_DEFAULT_STRATEGY);
572
573 if (rc != Z_OK) {
574 ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc);
575 goto done;
576 }
577
578 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0,
579 "deflate in: ni:%p no:%p ai:%ud ao:%ud",
580 zstream.next_in, zstream.next_out,
581 zstream.avail_in, zstream.avail_out);
582
583 rc = deflate(&zstream, Z_FINISH);
584
585 if (rc != Z_STREAM_END) {
586 ngx_log_error(NGX_LOG_ALERT, log, 0,
587 "deflate(Z_FINISH) failed: %d", rc);
588 goto done;
589 }
590
591 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, log, 0,
592 "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d",
593 zstream.next_in, zstream.next_out,
594 zstream.avail_in, zstream.avail_out,
595 rc);
596
597 size -= zstream.avail_out;
598
599 rc = deflateEnd(&zstream);
600
601 if (rc != Z_OK) {
602 ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc);
603 goto done;
604 }
605
606 n = ngx_write_fd(fd, out, size);
607
608 if (n != (ssize_t) size) {
609 err = (n == -1) ? ngx_errno : 0;
610
611 ngx_destroy_pool(pool);
612
613 ngx_set_errno(err);
614 return -1;
615 }
616
617 done:
618
619 ngx_destroy_pool(pool);
620
621 /* simulate successful logging */
622 return len;
623 }
624
625
626 static void *
627 ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size)
628 {
629 ngx_pool_t *pool = opaque;
630
631 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pool->log, 0,
632 "gzip alloc: n:%ud s:%ud", items, size);
633
634 return ngx_palloc(pool, items * size);
635 }
636
637
638 static void
639 ngx_http_log_gzip_free(void *opaque, void *address)
640 {
641 #if 0
642 ngx_pool_t *pool = opaque;
643
644 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "gzip free: %p", address);
645 #endif
646 }
647
648 #endif
649
650
489 static void 651 static void
490 ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log) 652 ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log)
491 { 653 {
492 size_t len; 654 size_t len;
493 ssize_t n; 655 ssize_t n;
499 661
500 if (len == 0) { 662 if (len == 0) {
501 return; 663 return;
502 } 664 }
503 665
666 #if (NGX_ZLIB)
667 if (buffer->gzip) {
668 n = ngx_http_log_gzip(file->fd, buffer->start, len, buffer->gzip, log);
669 } else {
670 n = ngx_write_fd(file->fd, buffer->start, len);
671 }
672 #else
504 n = ngx_write_fd(file->fd, buffer->start, len); 673 n = ngx_write_fd(file->fd, buffer->start, len);
674 #endif
505 675
506 if (n == -1) { 676 if (n == -1) {
507 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, 677 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
508 ngx_write_fd_n " to \"%s\" failed", 678 ngx_write_fd_n " to \"%s\" failed",
509 file->name.data); 679 file->name.data);
914 ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 1084 ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
915 { 1085 {
916 ngx_http_log_loc_conf_t *llcf = conf; 1086 ngx_http_log_loc_conf_t *llcf = conf;
917 1087
918 ssize_t size; 1088 ssize_t size;
1089 ngx_int_t gzip;
919 ngx_uint_t i, n; 1090 ngx_uint_t i, n;
920 ngx_msec_t flush; 1091 ngx_msec_t flush;
921 ngx_str_t *value, name, s; 1092 ngx_str_t *value, name, s;
922 ngx_http_log_t *log; 1093 ngx_http_log_t *log;
923 ngx_http_log_buf_t *buffer; 1094 ngx_http_log_buf_t *buffer;
1015 return NGX_CONF_ERROR; 1186 return NGX_CONF_ERROR;
1016 } 1187 }
1017 1188
1018 size = 0; 1189 size = 0;
1019 flush = 0; 1190 flush = 0;
1191 gzip = 0;
1020 1192
1021 for (i = 3; i < cf->args->nelts; i++) { 1193 for (i = 3; i < cf->args->nelts; i++) {
1022 1194
1023 if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) { 1195 if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) {
1024 s.len = value[i].len - 7; 1196 s.len = value[i].len - 7;
1046 "invalid flush time \"%V\"", &s); 1218 "invalid flush time \"%V\"", &s);
1047 return NGX_CONF_ERROR; 1219 return NGX_CONF_ERROR;
1048 } 1220 }
1049 1221
1050 continue; 1222 continue;
1223 }
1224
1225 if (ngx_strncmp(value[i].data, "gzip", 4) == 0
1226 && (value[i].len == 4 || value[i].data[4] == '='))
1227 {
1228 #if (NGX_ZLIB)
1229 if (size == 0) {
1230 size = 64 * 1024;
1231 }
1232
1233 if (value[i].len == 4) {
1234 gzip = Z_BEST_SPEED;
1235 continue;
1236 }
1237
1238 s.len = value[i].len - 5;
1239 s.data = value[i].data + 5;
1240
1241 gzip = ngx_atoi(s.data, s.len);
1242
1243 if (gzip < 1 || gzip > 9) {
1244 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1245 "invalid compression level \"%V\"", &s);
1246 return NGX_CONF_ERROR;
1247 }
1248
1249 continue;
1250
1251 #else
1252 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1253 "nginx was built without zlib support");
1254 return NGX_CONF_ERROR;
1255 #endif
1051 } 1256 }
1052 1257
1053 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1258 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1054 "invalid parameter \"%V\"", &value[i]); 1259 "invalid parameter \"%V\"", &value[i]);
1055 return NGX_CONF_ERROR; 1260 return NGX_CONF_ERROR;
1072 1277
1073 if (log->file->data) { 1278 if (log->file->data) {
1074 buffer = log->file->data; 1279 buffer = log->file->data;
1075 1280
1076 if (buffer->last - buffer->start != size 1281 if (buffer->last - buffer->start != size
1077 || buffer->flush != flush) 1282 || buffer->flush != flush
1283 || buffer->gzip != gzip)
1078 { 1284 {
1079 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1285 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1080 "access_log \"%V\" already defined " 1286 "access_log \"%V\" already defined "
1081 "with conflicting parameters", 1287 "with conflicting parameters",
1082 &value[1]); 1288 &value[1]);
1109 buffer->event->handler = ngx_http_log_flush_handler; 1315 buffer->event->handler = ngx_http_log_flush_handler;
1110 buffer->event->log = &cf->cycle->new_log; 1316 buffer->event->log = &cf->cycle->new_log;
1111 1317
1112 buffer->flush = flush; 1318 buffer->flush = flush;
1113 } 1319 }
1320
1321 buffer->gzip = gzip;
1114 1322
1115 log->file->flush = ngx_http_log_flush; 1323 log->file->flush = ngx_http_log_flush;
1116 log->file->data = buffer; 1324 log->file->data = buffer;
1117 } 1325 }
1118 1326